How to correctly print a multiline stdout?

Hello,

We run our database migrations using Ansible with something along these lines:

  • name: Run database migrations
    command: env/bin/python migrate.py -q chdir=$project_dir/releases/$release_date
    register: result
    changed_when: result.stdout

migrate.py prints the list of applied migrations to stdout.

We try to print this list because our developers want some feedback about which migrations were applied:

  • debug: msg=“{{result.stdout}}”

when: result.stdout

But all new lines are escaped to \n, which makes the output quite difficult to read.

Is there any solution to this?

In your own projects, how do you execute your database migrations? Do you try to get some feedback as what we try to achieve here? Or do you use another approach?

Thanks,

– Nicolas

Hi there,

Printing lines separately can be done like

  • name: Run database migrations
    command: env/bin/python migrate.py -q chdir=$project_dir/releases/$release_date
    register: result
    changed_when: result.stdout_lines

  • debug: msg=“{{item}}”

with_items: result.stdout_lines
when: result.stdout_lines

Cheers,

– Firat

4 Eylül 2013 Çarşamba 18:01:15 UTC+3 tarihinde Nicolas Grilly yazdı:

Waouh, that’s very clever :slight_smile:

But the output is still a bit “weird” for this use case:

ok: [host.domain.net] => (item=foo) => {“item”: “foo”, “msg”: “foo”}
ok: [host.domain.net] => (item=bar) => {“item”: “bar”, “msg”: “bar”}

Is there another way?

– Nicolas

Easiest way to debug this is just to use “-v” and it will output the previous data.

Yes, but if result.stdout contains new lines, they will show up escaped as
\n instead of "real" new lines, which makes it difficult to read. Any
advice on this?

You could try:

debug: msg="{{ print(result.stdout) }}"

The print() function should turn the \n's into new lines.

-jlk

It fails with the following error:

TASK: [debug msg="{{print(result.stdout)}}"]

Yep, we don’t export random functions here.

“{{ }}” is a call for string templating, it is not a place to insert arbitrary python code.

You wouldn’t want os.unlink() in there either! :slight_smile:

Hello Michael,

Yes, I know :slight_smile: It was the purpose of the small pull request James accepted
yesterday to update the documentation about Jinja2 expressions in playbooks.

This is why I was a quite surprised by Jesse suggestion. I just gave it a
try to make sure I was not missing something, and hopefully it doesn't work
:slight_smile:

Any idea on how to solve the problem I stated at the start of this
discussion: We have a playbook that executes database schema migrations,
and I want to print the list of applied migrations on the console?... The
list of applied migrations is printed on stdout by the migration command.

Cheers,

Nicolas

I don’t think what you want it is currently possible through ansible. Polling the output of a file would be a less hacky way to address your problem.

7 Eylül 2013 Cumartesi 16:16:28 UTC+3 tarihinde Nicolas Grilly yazdı:

It seems what we really want is a better way for the debug module to work with structured and multiline data, like:

debug: var=foo.stdout_lines

If you are really looking for specialized output, why bother using debug module? Add the following task and create some simple script to parse. The inventory_hostname will give the remote host corresponding to the stdout (you don’t want to mix those up).

  • local_action: command bash /my/local/path/writer.sh “$inventory_hostname” “{{ item }}”
    with_items: result.stdout_lines
    when: result.stdout

A simple bash script on your local machine (writer.sh)…

#!/bin/sh
echo $1 $2 >> out.log

I came looking for something similar, but there doesn’t seem to be a great way to format output (built in).

hope it helps

Probably because it requires writing bash in the middle of your Ansible playbook, which is something we want to avoid people having to do.

It would be much better to enhance the debug module as it would make the playbook more readable without resorting to hijinks.

Did anything ever come of this? I would really like to be able to print friendly “Provisioning succeeded! Here’s what to do next…” messages at the end of some of my playbooks.

–Brad

Not to my knowledge. I’d like to have a solution :slight_smile:

everything that has stdout, shoudl have stdout_lines, which is already
multiline, for those that don't just use split('/n').

Hi @Nicolas Grilly,
I met the same issue… It’s year 2022 already, did you get any solution? thanks.

Nope, no solution.

Hi,

there are multiple solutions, even if there's no perfect one that
works out of the box:

1. Use `debug: msg="{{ result.stdout_lines }}"`. Not perfect, but
   a lot better to read than `debug: msg="{{ result.stdout }}"`.

2. Check out the many callback plugins that exist:
   https://docs.ansible.com/ansible/latest/collections/index_callback.html
   Maybe one of them supports this? If not, you could write your own.
   (I would try
   https://docs.ansible.com/ansible/latest/collections/community/general/diy_callback.html
   - it seems to be very configurable, maybe it can do this?)

3. You could write an action plugin similar to `debug` that prints the
   given parameter without any quoting.

   (If someone wants to contribute something like that to
   community.general, I'm happy to review it.)

Cheers,
Felix

Try *yaml* callback
https://docs.ansible.com/ansible/latest/collections/community/general/yaml_callback.html

For example, the playbook

  > cat pb.yml
  - hosts: localhost
    vars:
      result:
        stdout: |
          line1
          line2
          line3
    tasks:
      - debug:
          var: result.stdout

gives (abridged)

  > ANSIBLE_STDOUT_CALLBACK=yaml ansible-playbook pb.yml

  ok: [localhost] =>
    result.stdout: |-
      line1
      line2
      line3