-
-
Save asmartin/c03bdeeff6854a06bfb779cf6d2289bb to your computer and use it in GitHub Desktop.
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
# Documentation: http://blog.cliffano.com/2014/04/06/human-readable-ansible-playbook-log-output-using-callback-plugin/ | |
# Improved and made compatible with Ansible v2 | |
# Original Source: https://gist.github.com/cliffano/9868180 | |
# First Modified Version: https://gist.github.com/dmsimard/cd706de198c85a8255f6 | |
# This Version: https://gist.github.com/asmartin/c03bdeeff6854a06bfb779cf6d2289bb | |
# | |
# Changelog: | |
# 2017-03-28 - [asmartin] added support for no_log | |
from __future__ import (absolute_import, division, print_function) | |
__metaclass__ = type | |
from ansible.plugins.callback import CallbackBase | |
try: | |
import simplejson as json | |
except ImportError: | |
import json | |
# Fields to reformat output for | |
FIELDS = ['cmd', 'command', 'start', 'end', 'delta', 'msg', 'stdout', | |
'stderr', 'results'] | |
NO_LOG_FIELDS = ['cmd', 'command', 'msg', 'stdout', 'stderr', 'results'] | |
class CallbackModule(CallbackBase): | |
def __init__(self, *args, **kwargs): | |
super(CallbackModule, self).__init__(*args, **kwargs) | |
self.task = None | |
self.play = None | |
def human_log(self, data): | |
if type(data) == dict: | |
for field in FIELDS: | |
if field in data.keys() and data[field]: | |
if field in NO_LOG_FIELDS and getattr(self.task, 'no_log', False): | |
print("\n{0}: <output hidden via no_log>".format(field)) | |
else: | |
output = self._format_output(data[field]) | |
print("\n{0}: {1}".format(field, output.replace("\\n","\n"))) | |
def _format_output(self, output): | |
# Strip unicode | |
if type(output) == unicode: | |
output = output.encode('ascii', 'replace') | |
# If output is a dict | |
if type(output) == dict: | |
return json.dumps(output, indent=2) | |
# If output is a list of dicts | |
if type(output) == list and type(output[0]) == dict: | |
# This gets a little complicated because it potentially means | |
# nested results, usually because of with_items. | |
real_output = list() | |
for index, item in enumerate(output): | |
copy = item | |
if type(item) == dict: | |
for field in FIELDS: | |
if field in item.keys(): | |
copy[field] = self._format_output(item[field]) | |
real_output.append(copy) | |
return json.dumps(output, indent=2) | |
# If output is a list of strings | |
if type(output) == list and type(output[0]) != dict: | |
# Strip newline characters | |
real_output = list() | |
for item in output: | |
if "\n" in item: | |
for string in item.split("\n"): | |
real_output.append(string) | |
else: | |
real_output.append(item) | |
# Reformat lists with line breaks only if the total length is | |
# >75 chars | |
if len("".join(real_output)) > 75: | |
return "\n" + "\n".join(real_output) | |
else: | |
return " ".join(real_output) | |
# Otherwise it's a string, just return it | |
return output | |
def on_any(self, *args, **kwargs): | |
pass | |
def runner_on_failed(self, host, res, ignore_errors=False): | |
self.human_log(res) | |
def runner_on_ok(self, host, res): | |
self.human_log(res) | |
def runner_on_error(self, host, msg): | |
pass | |
def runner_on_skipped(self, host, item=None): | |
pass | |
def runner_on_unreachable(self, host, res): | |
self.human_log(res) | |
def runner_on_no_hosts(self): | |
pass | |
def runner_on_async_poll(self, host, res, jid, clock): | |
self.human_log(res) | |
def runner_on_async_ok(self, host, res, jid): | |
self.human_log(res) | |
def runner_on_async_failed(self, host, res, jid): | |
self.human_log(res) | |
def playbook_on_start(self): | |
pass | |
def playbook_on_notify(self, host, handler): | |
pass | |
def playbook_on_no_hosts_matched(self): | |
pass | |
def playbook_on_no_hosts_remaining(self): | |
pass | |
def playbook_on_task_start(self, name, is_conditional): | |
pass | |
def playbook_on_vars_prompt(self, varname, private=True, prompt=None, | |
encrypt=None, confirm=False, salt_size=None, | |
salt=None, default=None): | |
pass | |
def playbook_on_setup(self): | |
pass | |
def playbook_on_import_for_host(self, host, imported_file): | |
pass | |
def playbook_on_not_import_for_host(self, host, missing_file): | |
pass | |
def playbook_on_play_start(self, pattern): | |
pass | |
def playbook_on_stats(self, stats): | |
pass | |
def v2_playbook_on_play_start(self, play): | |
self.play = play | |
def v2_playbook_on_task_start(self, task, is_conditional): | |
self.task = task |
I was getting this error:
[WARNING]: Failure using method (v2_runner_on_ok) in callback plugin (</home/X/callback_plugins/human_log.CallbackModule object at 0x7f3b1bbb6c50>): 'ascii' codec can't encode character u'\u25cf' in position 0: ordinal not in range(128)
The problem seems to be if type(output) == unicode
is insufficient. Ansible wraps the unicode in a "ansible.vars.unsafe_proxy.AnsibleUnsafeText" class.
After the __future__ import
I added from ansible.vars.unsafe_proxy import AnsibleUnsafeText
and changed the conditional to if type(output) == unicode or type(output) == AnsibleUnsafeText:
forked this and implemented an updated fix as @mark-wagner demonstrated in previous comment here. Worked for me w/o any issue @Krishna1408.
https://gist.github.com/shanedroid/beca4902c6a1af1bd23b3c92f118f6ed
also worth noting that this callback plugin may no longer needed as the debug plugin can be used by default now, I have just switched to using that instead:
ansible/ansible#27078 (comment)
https://github.com/ansible/ansible/blob/v2.4.3.0-1/lib/ansible/plugins/callback/debug.py
https://gist.github.com/cliffano/9868180#gistcomment-1915662
Hi,
Thanks a lot for updating the code. I am getting below warning and logs are not being shown in human readable format:
defined
can you please help with it ?
Best Regards,
Kris