# Real-time Capture and Display of Ansible Output Logs in HTML via Flask and Python

**URL:** <https://forum.ansible.com/t/real-time-capture-and-display-of-ansible-output-logs-in-html-via-flask-and-python/3378>\
**Category:** Get Help\
**Tags:** python\
**Created:** [January 18, 2024, 3:17pm UTC](https://forum.ansible.com/t/real-time-capture-and-display-of-ansible-output-logs-in-html-via-flask-and-python/3378 "2024-01-18T15:17:21Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bart-Roels](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bart-roels/32/2027_2.png) [@Bart-Roels](https://forum.ansible.com/u/Bart-Roels)\
**Post date:** [January 18, 2024, 3:17pm UTC](https://forum.ansible.com/t/real-time-capture-and-display-of-ansible-output-logs-in-html-via-flask-and-python/3378/1 "2024-01-18T15:17:21Z")

</div>

I am currently experimenting with an Ansible playbook executed from a Flask application, and I’m aiming to capture the output logs in real-time, then send them to my HTML using [Socket.IO](http://Socket.IO). Despite attempting options like setting `quiet=False` and exploring `runner.events` , I have not achieved the desired results as the logs are only sent after the playbook completes. I am relatively new to the Ansible Python integration. Any guidance or suggestions would be greatly appreciated. Thanks! Don’t mind the passwords ist for a local test machine 🙂

````auto
import ansible_runner
@app.route('/generate_ansible_inventory', methods=['GET'])
def generate_ansible_inventory():
    # Load data from TinyDB
    vm_data_list = load_vm_from_db()

    # Create an empty inventory dictionary
    inventory = {"all": {"hosts": {}, "vars": {}}}

    # Loop through VMs in the TinyDB
    for vm_data in vm_data_list:
        # Add an inventory host
        inventory["all"]["hosts"][vm_data["vm_name"]] = {
            "ansible_host": vm_data["vm_ipv4_address"],
            "ansible_user": "bart",
            "ansible_ssh_pass": "bart",
            "ansible_become_pass": "bart"
        }

    # Save the inventory dictionary to a json file in the Ansible directory
    with open('ansible/inventory.json', 'w') as file:
        json.dump(inventory, file, indent=4)

    return jsonify(inventory)

# Run Ansible playbook asynchronously
def run_ansible_playbook_async(playbook_path, inventory_path):
    try:
        # Read the inventory from the JSON file
        with open(inventory_path, 'r') as file:
            inventory = json.load(file)

        # Run the playbook
        runner = ansible_runner.run(
            playbook=playbook_path,
            inventory=inventory,
            quiet=False, # Set quiet to False to capture logs
            stdout_callback=log_callback, # Set the callback for log messages
        )

        # Emit each log line to connected clients
        for event in runner.events:
            if event['event'] == 'runner_on_ok' and 'stdout' in event['stdout']:
                socketio.emit('ansible_output', {'log_message': event['stdout']['stdout_lines'][0]})
            elif event['event'] == 'runner_on_failed' and 'stderr' in event['stdout']:
                socketio.emit('ansible_output', {'log_message': event['stdout']['stdout_lines'][0]})

        # Print the output
        print("Playbook run status:", runner.status)
        print("Playbook run stats:", runner.stats)

    except Exception as e:
        print("Error running the Ansible playbook:", e)

# Route for running Ansible playbook
@app.route('/run_ansible_playbook', methods=['GET'])
def run_ansible_playbook():
    try:
        # Define playbook and inventory paths
        playbook_path = os.path.join(os.getcwd(), 'ansible', 'playbook.yml')
        inventory_path = os.path.join(os.getcwd(), 'ansible', 'inventory.json')

        # Start a new thread for running Ansible playbook asynchronously
        ansible_thread = Thread(target=run_ansible_playbook_async, args=(playbook_path, inventory_path))
        ansible_thread.start()

        return jsonify({"status": "Ansible playbook execution started in the background"})

    except Exception as e:
        return jsonify({"status": f"Error running Ansible playbook: {str(e)}"})

@app.route('/ansible_logs', methods=['GET'])
def ansible_logs():
    return render_template('ansible_logs.html')
```
````

---

<div class="post-metadata">

**Author:** ![Volkov\_Evgeny](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/volkov_evgeny/32/4592_2.png) [@Volkov\_Evgeny](https://forum.ansible.com/u/Volkov_Evgeny)\
**Post date:** [November 18, 2024, 10:16am UTC](https://forum.ansible.com/t/real-time-capture-and-display-of-ansible-output-logs-in-html-via-flask-and-python/3378/2 "2024-11-18T10:16:11Z")

</div>

I have achived it next way:

```auto
    @staticmethod
    def _run_process(command_line):
        logging.info(f'command_line: {command_line}')
        try:
            process = subprocess.Popen(command_line, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
            for line in iter(process.stdout.readline, b''):
                logging.info(line.decode(sys.stdout.encoding))

            process.wait()
            return True if process.returncode == 0 else False
        except Exception as err:
            logging.error(f'Process exception: {err}')
            return False

```
