logview: add log_path parameter

Signed-off-by: Francois Andrieu <darknao@fedoraproject.org>
This commit is contained in:
Francois Andrieu 2020-08-16 22:17:28 +02:00
parent a221e0db50
commit aca152fe74
2 changed files with 42 additions and 22 deletions

View file

@ -15,7 +15,21 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
DOCUMENTATION = r'''
callback: logdetail
callback_type: notification
short_description: Logs playbook results, per date, playbook and host.
description: Logs playbook results, per date, playbook and host, in I(log_path).
options:
log_path:
description: The path where log files will be created.
default: /var/log/ansible
ini:
- section: callback_logdetail
key: log_path
env:
- name: ANSIBLE_LOGDETAIL_PATH
'''
import os import os
import time import time
@ -38,8 +52,6 @@ TIME_FORMAT="%b %d %Y %H:%M:%S"
MSG_FORMAT="%(now)s\t%(count)s\t%(category)s\t%(name)s\t%(data)s\n" MSG_FORMAT="%(now)s\t%(count)s\t%(category)s\t%(name)s\t%(data)s\n"
LOG_PATH = '/var/log/ansible'
def getlogin(): def getlogin():
try: try:
user = os.getlogin() user = os.getlogin()
@ -48,13 +60,13 @@ def getlogin():
return user return user
class LogMech(object): class LogMech(object):
def __init__(self): def __init__(self, logpath):
self.started = time.time() self.started = time.time()
self.pid = str(os.getpid()) self.pid = str(os.getpid())
self._pb_fn = None self._pb_fn = None
self._last_task_start = None self._last_task_start = None
self.play_info = {} self.play_info = {}
self.logpath = LOG_PATH self.logpath = logpath
if not os.path.exists(self.logpath): if not os.path.exists(self.logpath):
try: try:
os.makedirs(self.logpath, mode=0o750) os.makedirs(self.logpath, mode=0o750)
@ -163,7 +175,6 @@ class LogMech(object):
fd.close() fd.close()
logmech = LogMech()
class CallbackModule(CallbackBase): class CallbackModule(CallbackBase):
""" """
@ -181,40 +192,42 @@ class CallbackModule(CallbackBase):
self.playbook = None self.playbook = None
super(CallbackModule, self).__init__() super(CallbackModule, self).__init__()
self.set_options()
self.logmech = LogMech(self.get_option('log_path'))
def set_play_context(self, play_context): def set_play_context(self, play_context):
self.play_context = play_context self.play_context = play_context
def v2_runner_on_failed(self, result, ignore_errors=False): def v2_runner_on_failed(self, result, ignore_errors=False):
category = 'FAILED' category = 'FAILED'
logmech.log(result._host.get_name(), category, result._result, self.task, self._task_count) self.logmech.log(result._host.get_name(), category, result._result, self.task, self._task_count)
def v2_runner_on_ok(self, result): def v2_runner_on_ok(self, result):
category = 'OK' category = 'OK'
logmech.log(result._host.get_name(), category, result._result, self.task, self._task_count) self.logmech.log(result._host.get_name(), category, result._result, self.task, self._task_count)
def v2_runner_on_skipped(self, result): def v2_runner_on_skipped(self, result):
category = 'SKIPPED' category = 'SKIPPED'
res = {} res = {}
res['item'] = self._get_item_label(getattr(result._result, 'results', {})) res['item'] = self._get_item_label(getattr(result._result, 'results', {}))
logmech.log(result._host.get_name(), category, res, self.task, self._task_count) self.logmech.log(result._host.get_name(), category, res, self.task, self._task_count)
def v2_runner_on_unreachable(self, result): def v2_runner_on_unreachable(self, result):
category = 'UNREACHABLE' category = 'UNREACHABLE'
res = {} res = {}
res['output'] = result._result res['output'] = result._result
logmech.log(result._host.get_name(), category, res, self.task, self._task_count) self.logmech.log(result._host.get_name(), category, res, self.task, self._task_count)
def v2_runner_on_async_failed(self, result): def v2_runner_on_async_failed(self, result):
category = 'ASYNC_FAILED' category = 'ASYNC_FAILED'
logmech.log(result._host.get_name(), category, result._result, self.task, self._task_count) self.logmech.log(result._host.get_name(), category, result._result, self.task, self._task_count)
def v2_playbook_on_start(self, playbook): def v2_playbook_on_start(self, playbook):
self.playbook = playbook self.playbook = playbook
def v2_playbook_on_task_start(self, task, is_conditional): def v2_playbook_on_task_start(self, task, is_conditional):
self.task = task self.task = task
logmech._last_task_start = time.time() self.logmech._last_task_start = time.time()
self._task_count += 1 self._task_count += 1
def v2_playbook_on_setup(self): def v2_playbook_on_setup(self):
@ -223,12 +236,12 @@ class CallbackModule(CallbackBase):
def v2_playbook_on_import_for_host(self, result, imported_file): def v2_playbook_on_import_for_host(self, result, imported_file):
res = {} res = {}
res['imported_file'] = imported_file res['imported_file'] = imported_file
logmech.log(result._host.get_name(), 'IMPORTED', res, self.task) self.logmech.log(result._host.get_name(), 'IMPORTED', res, self.task)
def v2_playbook_on_not_import_for_host(self, result, missing_file): def v2_playbook_on_not_import_for_host(self, result, missing_file):
res = {} res = {}
res['missing_file'] = missing_file res['missing_file'] = missing_file
logmech.log(result._host.get_name(), 'NOTIMPORTED', res, self.task) self.logmech.log(result._host.get_name(), 'NOTIMPORTED', res, self.task)
def v2_playbook_on_play_start(self, play): def v2_playbook_on_play_start(self, play):
self._task_count = 0 self._task_count = 0
@ -238,7 +251,7 @@ class CallbackModule(CallbackBase):
path = os.path.abspath(self.playbook._file_name) path = os.path.abspath(self.playbook._file_name)
# tel the logger what the playbook is # tel the logger what the playbook is
logmech.playbook_id = path self.logmech.playbook_id = path
# if play count == 0 # if play count == 0
# write out playbook info now # write out playbook info now
@ -252,7 +265,7 @@ class CallbackModule(CallbackBase):
pb_info['playbook_checksum'] = secure_hash(path) pb_info['playbook_checksum'] = secure_hash(path)
pb_info['check'] = self.play_context.check_mode pb_info['check'] = self.play_context.check_mode
pb_info['diff'] = self.play_context.diff pb_info['diff'] = self.play_context.diff
logmech.play_log(json.dumps(pb_info, indent=4)) self.logmech.play_log(json.dumps(pb_info, indent=4))
self._play_count += 1 self._play_count += 1
# then write per-play info that doesn't duplcate the playbook info # then write per-play info that doesn't duplcate the playbook info
@ -263,9 +276,9 @@ class CallbackModule(CallbackBase):
info['number'] = self._play_count info['number'] = self._play_count
info['check'] = self.play_context.check_mode info['check'] = self.play_context.check_mode
info['diff'] = self.play_context.diff info['diff'] = self.play_context.diff
logmech.play_info = info self.logmech.play_info = info
try: try:
logmech.play_log(json.dumps(info, indent=4)) self.logmech.play_log(json.dumps(info, indent=4))
except TypeError: except TypeError:
print(("Failed to conver to JSON:", info)) print(("Failed to conver to JSON:", info))
@ -274,9 +287,9 @@ class CallbackModule(CallbackBase):
results = {} results = {}
for host in list(stats.processed.keys()): for host in list(stats.processed.keys()):
results[host] = stats.summarize(host) results[host] = stats.summarize(host)
logmech.log(host, 'STATS', results[host]) self.logmech.log(host, 'STATS', results[host])
logmech.play_log(json.dumps({'stats': results}, indent=4)) self.logmech.play_log(json.dumps({'stats': results}, indent=4))
logmech.play_log(json.dumps({'playbook_end': time.time()}, indent=4)) self.logmech.play_log(json.dumps({'playbook_end': time.time()}, indent=4))
print(('logs written to: %s' % logmech.logpath_play)) print(('logs written to: %s' % self.logmech.logpath_play))

View file

@ -7,6 +7,8 @@ import glob
from datetime import date, timedelta from datetime import date, timedelta
import gzip import gzip
import dateutil.parser as dateparser import dateutil.parser as dateparser
import configparser
from ansible.config.manager import find_ini_config_file
logpath = '/var/log/ansible' logpath = '/var/log/ansible'
search_terms = ['CHANGED', 'FAILED'] search_terms = ['CHANGED', 'FAILED']
@ -106,6 +108,11 @@ def search_logs(opts, logfiles):
def main(args): def main(args):
cfg = find_ini_config_file()
if cfg:
cp = configparser.ConfigParser()
cp.read(cfg)
logpath = cp.get('callback_logdetail', "log_path", fallback="/var/log/ansible")
opts, args = parse_args(args) opts, args = parse_args(args)
for pb in glob.glob(os.path.join(logpath, opts.playbook)): for pb in glob.glob(os.path.join(logpath, opts.playbook)):
pb_name = os.path.basename(pb) pb_name = os.path.basename(pb)