12

One of my ansible tasks imports an Oracle database using impdp.

This generates a lot of output to the console so I have set no_log: True.

However, when this fails I want to see the log!

How can I make this particular task log to a file and not to the console?

7
  • You're using the command module? Jun 3, 2017 at 16:10
  • One idea [more of a hack] would be to write the logs to some external file, and then having a task after it which makes use of failed_when condition, and remove the log file, if the prev. task was succesful :)
    – Dawny33
    Jun 4, 2017 at 14:46
  • Why can you see the console output during successful runs anyway? I've not seen a configuration for, nor did I think it was possible to, show stdout during a successful task execution, it should just come up [ ok: host name ]. However when an error is detected the output gets dumped to the ansible control console (and any ansible logs defined) would you mind sharing the configuration which gives you the large stdout during a regular successful run?
    – hvindin
    Jun 4, 2017 at 15:00
  • @hvindin Put in -vvv after the ansible-playbook command for getting verbose logs.
    – Dawny33
    Jun 5, 2017 at 6:02
  • 1
    Registering a variable does seem the best logical move, see my comment on your answer for my opinions about what to do with the outputs from ansible triggered commands.
    – hvindin
    Jun 6, 2017 at 13:44

7 Answers 7

4

I think that all you need to do is to register the output of every command you need (store it in a variable) and then simply dump the variable in a file. That way you can review it later.

tasks:
  - name: Dump all vars
    action: template src=templates/dumpall.j2 dest=/tmp/ansible.all

Then in dumpall.j2:

Module Variables ("vars"):
--------------------------------
{{ vars | to_nice_json }} 

Environment Variables ("environment"):
--------------------------------
{{ environment | to_nice_json }} 

GROUP NAMES Variables ("group_names"):
--------------------------------
{{ group_names | to_nice_json }}

GROUPS Variables ("groups"):
--------------------------------
{{ groups | to_nice_json }}

HOST Variables ("hostvars"):
--------------------------------
{{ hostvars | to_nice_json }} 

The example I'm using is from here

4

[Converting my comment to an answer]

One way to do it would be to write the logs to some external file, and then having a task after it which makes use of failed_when condition, and remove the log file, if the previous task was successful.

Something like this should help you.

 - name: Run Py script
      command: <>.py  > <>.log
      become: yes
      register: PyScript
      ignore_errors: True

    - name: PyScript on success
      command: rm <>.log
      when: PyScript|succeeded

Note: This might not be the best way to handle your problem. But, this was a hack which helped me do my logging and monitoring.

1
  • 2
    I'd go one further and say you could keep your command writing to stdout/stderr then just dump them out as a response to a failure. So, as an example in your above example if you did want to halt execution in the event of a failure then using a fail task to just output the stdout and stderr registered in PyScript when the rc != 0 would seem a more holistic solution. If you use ansibles inbuilt mechanisms then if you have ansible logging set up on a control server, as an example, then that control server would log the failure in the ansible log. Which I think would be the correct place for it
    – hvindin
    Jun 6, 2017 at 13:43
3

I solved this by adding

ignore_errors: true
register: results

to the no_log-task. This makes ansible continue to the next task, even when the task fails. Then for the next task define a debug task, which always fails and outputs the registered variable, but only runs when the previous task failed:

- name: Error output
  debug:
     var: results
  failed_when: true
  when:
     results is failed

So even with no_log: true, this will make ansible display the output of the failed task. This solution is not logging it to a file as requested but fullfils your need to 'see the log when failed' , and of course, you can redirect or use tee to output the full ansible output to a file, which will, with this solution also contain the the log of the failed task.

2

What I do when I've a command to execute and wish to get the log only in case of failure is as follow (prefixed by a shell comamnd like /bin/sh -c '...' in case the initiator doesn't use a system call or execute the command directly without shell):

command 2>&1 > command-log.txt || cat command-log.txt

This will redirect error and standard output to a file and display the content of the file in case of failure only. If the command is very verbose and you don't wish to keep the log when it's ok you can go with:

command 2>&1 > command-log.txt && rm command-log.txt || cat command-log.txt

Quote for && and || usage from sh manpage:

The symbol && (||) causes the list following to be executed only if the preceding pipeline returns a zero (non zero) value.

That's probably not the most idiomatic way to do it with ansible but has the advantage of being very portable with any configuration management system giving the ability to display command stdout.

3
  • 1
    I love this answer but I think the > and the & are swapped. Do you mean 'command 2>&1...' rather than 'command 2>&1...'? Jul 29, 2020 at 18:27
  • You're right, I probably typed it quickly at that time. Thanks for the heads up
    – Tensibai
    Jul 30, 2020 at 6:52
  • Sadly, I wasn't able to get this to work within Ansible. Jul 31, 2020 at 18:35
0

Assuming ansible properly throws errors to stderr you can capture the output of errors in any program to a file using output redirection:

some command 2> error.log

However I don't think this is the case.

Instead you will likely want to refer to this guide to decide when errors will occur http://docs.ansible.com/ansible/playbooks_error_handling.html and then grep your output for strings that indicate an error before outputting to a file

ie.

ansible-playbook my-playbook | grep 'error' > error.log

-2

I think what you're looking for might be too simply redirect stdout and street to file.

Typically , some-command &> logfile.log

or some variant....

3
  • Which is only a partial answer, OP wants to see the log in case if error.
    – Tensibai
    Jun 4, 2017 at 10:13
  • I don't this is even a partial answer to this question. It is fine for a shell script, but useless for coding in ansible.
    – chicks
    Jun 4, 2017 at 12:01
  • @chicks I think it could be a valid workaround on a 'shell' method approach within ansible (which I don't know much)
    – Tensibai
    Jun 6, 2017 at 14:13
-2

Tee will be a very simple tool for logging, you can refer the following command.

eric@eric-MacBookPro:~$ ansible -m ping all | tee > /tmp/ansible.log
eric@eric-MacBookPro:~$ cat /tmp/ansible.log 
localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
1
  • 2
    1. This affects the entire run, not just one task. 2. There's no point to piping through tee if you're going to redirect its stdout to a file; that's not how you use the command. 3. If you were using tee properly, it would still output all the spam to the console, which OP doesn't want. Jun 3, 2017 at 16:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.