8

Using Ansible I would like to be able to write the sysout of a task running a command to a local(i.e. on the managed server) log file. For the moment I can only do this using a task like this:

- name: Run my command
  shell: <command> <arg1> <arg3> ... |tee -a <local log file>

The reason to do this is that the takes a long time to complete(i.e. we cannot wait until it finishes to get its output) and would like to collect the output during its execution.

Is there any "Ansible" way to redirect to sysout of the command to a local log file during its execution without using the tee pipe?

trikelef
  • 518
  • 1
  • 7
  • 26

5 Answers5

9

You need to use register in the first task and now, you can create a second task to write the output to a local file

- name: shell command
  shell: my_shell_command
  register: myshell_output
- name: copy the output to a local file
  copy:
    content: "{{ myshell_output.stdout }}"
    dest: "/tmp/hello.txt"
  delegate_to: localhost
c4f4t0r
  • 5,301
  • 3
  • 31
  • 42
  • This could be a solution, but I would prefer to write to the log file during the my_shell_command execution not get the whole sysout after the execution completes. – trikelef Mar 19 '19 at 15:16
  • @trikelef ansible is not shell, that you do command | tee and so on, you need to change this logic, unless you will start to using ansible as wrapper – c4f4t0r Mar 19 '19 at 15:24
  • Indeed that's what I am trying to avoid. The problem is that since my_command is a long running one I would like to have the stdout to be redirected to a local file (where it would be monitored) or to ansible server (best fit but I have no solution for this) **before** the task (i.e. the my_command) finishes. – trikelef Mar 19 '19 at 15:30
0
- name: Run my command
    shell: <command> <arg1> <arg3> ... >> <local log file>
scriptracer
  • 101
  • 1
  • 1
    I believe the shell command is executed on the remote host so you won't be able to pipe the command output to a local file like that. The `local log file` in your example will be on the remote host. – Henrik Pingel Apr 16 '20 at 14:55
  • This does not answer OP's question - is there an Ansible way to do this? – Matt Apr 19 '20 at 23:32
0

I was able to run a python command using shell and redirect the output to a local file on the same host(i.e where my playbook was running) and view it using tail -F log_file while the ansible task was still executing. But it only worked when I gave executable as /bin/bash

- name: Run Python tool 
  shell: "python3 -m pythontool &> log_file"
  args:
     executable: /bin/bash
0

I tried below steps it went fine detailed output. Please try it

   - name: save output in file under current directory
      copy:
        content: "{{ myoutput.results | replace('\\n', '\n') }}"
        dest: "/tmp/maintainance/{{ inventory_hostname }}"
      delegate_to: localhost
ppuschmann
  • 610
  • 1
  • 6
  • 16
0

Ansible default, and by far the most common pattern, is to let the task finish and register the output at the end. It has an async feature, however you need to query the job it makes in your playbook.


Rather, consider using init script features to background it. You tagged this Linux, such a thing with robust logging is pretty easy in a systemd unit.

vmstat outputs data regularly to stdout, and makes for a simple example. I present the silliest way to log vmstat output: /etc/systemd/system/dumbstat.service

[Unit]
Description=Dumb vmstat wrapper service example
Documentation=https://serverfault.com/questions/958952/ansible-task-write-to-local-log-file

[Service]
Type=oneshot
ExecStart=/usr/bin/vmstat 5 12
StandardOutput=journal

[Install]
WantedBy=multi-user.target

Type=oneshot will wait in a starting state until the process exits. You may want a different type if you want more of an async fork and continue behavior.

Standard out is captured and available via the usual tools.

root@sf-958952:/var/log# systemctl status dumbstat
● dumbstat.service - Dumb vmstat wrapper service example
   Loaded: loaded (/etc/systemd/system/dumbstat.service; disabled; vendor preset: enabled)
   Active: activating (start) since Wed 2019-03-20 14:49:41 UTC; 7s ago
     Docs: https://serverfault.com/questions/958952/ansible-task-write-to-local-log-file
 Main PID: 3103 (vmstat)
    Tasks: 1 (limit: 4401)
   CGroup: /system.slice/dumbstat.service
           └─3103 /usr/bin/vmstat -w 5 12

Mar 20 14:49:41 sf-958952 systemd[1]: Starting Dumb vmstat wrapper service example...
Mar 20 14:49:41 sf-958952 vmstat[3103]: procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
Mar 20 14:49:41 sf-958952 vmstat[3103]:  r  b         swpd         free         buff        cache   si   so    bi    bo   in   cs  us  sy  id  wa  st
Mar 20 14:49:41 sf-958952 vmstat[3103]:  7  0            0      3104416        70260       417228    0    0   208    36   40  132   1   1  98   0   0
Mar 20 14:49:46 sf-958952 vmstat[3103]:  0  0            0      3107200        70260       417260    0    0     0     0   40  130   1   0  99   0   0

You also can filter the output by querying the systemd journal: journalctl _SYSTEMD_UNIT=dumbstat.service

By default the journal is forwarded to syslog, if you want a local file or to forward it somewhere.

Amusingly, system 240 and later can log direct to a file with StandardOutput=append: but that's too new for CentOS 7 or Ubuntu 18.04.


All of this has little to do with Ansible. You can deploy such a unit with the template module, and start it with the systemd module.

John Mahowald
  • 32,050
  • 2
  • 19
  • 34