-1

I have the following Python file, teststout.py

import os,sys

class Logger(object):
    def __init__(self):
        self.terminal = sys.stdout
        self.log = open("odareplayout.log", "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

    def flush(self):
        # this flush method is needed for python 3 compatibility.
        # this handles the flush command by doing nothing.
        # you might want to specify some extra behavior here.
        pass

sys.stdout = Logger()

def main():
    print('Hello World')
    cmd = 'ansible-playbook test3.yaml'
    os.system(cmd)

if __name__ == '__main__':
    main ()

and the following playbook, test3.yaml

---
 - name: Test
   hosts: localhost

   vars:
     akash: "myhost"

   tasks:

   - name: Get timestamp from the system
     shell: "date +%Y-%m-%d%H-%M-%S"
     register: tstamp

   - name: date and time
     debug:
        var: ansible_date_time

And this is the output when I run the Python script with python3 teststout.py

Hello World

PLAY [Test] *************************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************
ok: [localhost]

TASK [Get timestamp from the system] ************************************************************************************************************
changed: [localhost]

TASK [date and time] ****************************************************************************************************************************
ok: [localhost] => {
    "ansible_date_time": {
        "date": "2023-03-23",
        "day": "23",
        "epoch": "1679547708",
        "hour": "05",
        "iso8601": "2023-03-23T05:01:48Z",
        "iso8601_basic": "20230323T050148745778",
        "iso8601_basic_short": "20230323T050148",
        "iso8601_micro": "2023-03-23T05:01:48.745778Z",
        "minute": "01",
        "month": "03",
        "second": "48",
        "time": "05:01:48",
        "tz": "UTC",
        "tz_offset": "+0000",
        "weekday": "Thursday",
        "weekday_number": "4",
        "weeknumber": "12",
        "year": "2023"
    }
}

PLAY RECAP **************************************************************************************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
cat odareplayout.log 
Hello World

If you see above, only print statement is getting captured in the file but I want to capture this entire output into a file along with the stdout.

I have already referred various posts and the Ansible documentation about Logging, but I didn't help.

Can someone please help here?

U880D
  • 8,601
  • 6
  • 24
  • 40
Akash-BLR
  • 63
  • 4
  • Does [Running shell command and capturing the output](https://stackoverflow.com/questions/4760215/) in Python answer your question? – U880D Mar 23 '23 at 06:00
  • Not really. Could you please help with an example ? – Akash-BLR Mar 27 '23 at 06:56
  • Since the linked thread explains the cause of the effect you are observing as well how to resolve it, can you explain why it is "_not really_" answering your question? Since linked thread also provides several different examples, what kind of other example your are expecting or looking for? – U880D Mar 27 '23 at 09:22

1 Answers1

0

Based on the already mentioned answers under Running shell command and capturing the output and your given example code print.py

#!/usr/bin/python

import os,sys
from subprocess import Popen, PIPE

class Logger(object):
    def __init__(self):
        self.terminal = sys.stdout
        self.log = open("print.log", "a") # to append

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

    def flush(self):
        # this flush method is needed for python 3 compatibility.
        # this handles the flush command by doing nothing.
        # you might want to specify some extra behavior here.
        pass

sys.stdout = Logger()

def main():
    print('Hello World')

    # Collecting STDOUT and STDERR

    output = Popen(["ansible-playbook", "debug.yml"], stdout=PIPE, stderr=PIPE)
    response = output.communicate()

    # Printing STDOUT only (since we get a list with two elements counting from zero)
    print(response[0]) 
    # print(response[1])

if __name__ == '__main__':
    main ()

called via python print.py for a sample playbook debug.yml

---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

  - debug:
      msg: "Hello World"

the output will result into the requested one

Hello World

PLAY [localhost] ***************************************************************
Monday 27 March 2023  18:29:25 +0200 (0:00:00.039)       0:00:00.039 **********

TASK [debug] *******************************************************************
ok: [localhost] =>
  msg: Hello World

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
Monday 27 March 2023  18:29:25 +0200 (0:00:00.048)       0:00:00.087 **********
===============================================================================
debug ------------------------------------------------------------------- 0.05s

and a log file print.log

~/test$ cat print.log
Hello World

PLAY [localhost] ***************************************************************
Monday 27 March 2023  18:29:25 +0200 (0:00:00.039)       0:00:00.039 **********

TASK [debug] *******************************************************************
ok: [localhost] =>
  msg: Hello World

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
Monday 27 March 2023  18:29:25 +0200 (0:00:00.048)       0:00:00.087 **********
===============================================================================
debug ------------------------------------------------------------------- 0.05s

The same approach is working from within Custom Modules like in Ansible Custom Module: Are print statements possible?

Just add under def run_module(): right before module.exit_json(**result)

    output = Popen(["python", "-c", "print ('Hello World');"], stdout=PIPE, stderr=PIPE)

    # Or for an STDERR example
    # output = Popen(["python", "--version"], stdout=PIPE, stderr=PIPE)

    response = output.communicate()
    result['stdout'] = response[0]
    result['stderr'] = response[1]

and don't forget to from subprocess import Popen, PIPE.


Please Note

The result and format of the playbook output depends on the configured Callback plugins, as well used versions and based on the installation environment.

~/test$ ansible-playbook --version
ansible-playbook [core 2.11.12]
...
  python version = 2.7.5 (default, May 27 2022, 11:27:32) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
  jinja version = 2.11.3
...
~/test$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.9 (Maipo)
U880D
  • 8,601
  • 6
  • 24
  • 40