Repository: ansible/ansible

Issue:
Encoding problem in `profile_tasks` callback
##### ISSUE TYPE
- Bug Report
##### ANSIBLE VERSION

```
ansible 2.1.0.0
  config file = /home/alex/.ansible.cfg
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

`/home/alex/.ansible.cfg`:

```
[defaults]
callback_whitelist = timer,profile_tasks
```
##### OS / ENVIRONMENT

N/A
##### SUMMARY

When using non-ascii names for tasks, `profile_tasks` callback fail on recap with encoding error.
##### STEPS TO REPRODUCE

`playbook.yml`:

```
- hosts: localhost
  gather_facts: false
  tasks:
    - name: unicode éàè
      debug: var=inventory_hostname
```

`hosts`:

```
localhost ansible_connection=local
```

Execute the playbook:

```
ansible-playbook playbook.yml -i hosts
```
##### EXPECTED RESULTS

```
PLAY [localhost] ***************************************************************

TASK [unicode éàè] *************************************************************
Thursday 30 June 2016  16:35:16 +0200 (0:00:00.276)       0:00:00.276 *********
ok: [localhost] => {
    "inventory_hostname": "localhost"
}

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

Thursday 30 June 2016  16:35:17 +0200 (0:00:00.140)       0:00:00.416 *********
===============================================================================
unicode éàè -------------------------------------------------------------- 0.0s

Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
```
##### ACTUAL RESULTS

```
PLAY [localhost] ***************************************************************

TASK [unicode éàè] *************************************************************
Thursday 30 June 2016  16:35:16 +0200 (0:00:00.276)       0:00:00.276 *********
ok: [localhost] => {
    "inventory_hostname": "localhost"
}

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

Thursday 30 June 2016  16:35:17 +0200 (0:00:00.140)       0:00:00.416 *********
===============================================================================
 [WARNING]: Failure using method (v2_playbook_on_stats) in callback plugin
(</usr/lib/python2.7/site-packages/ansible/plugins/callback/profile_tasks.CallbackModule 
object at 0x6fffeac2ad0>): 'ascii' codec can't encode characters in position 8-10: 
ordinal not in range(128)

Playbook run took 0 days, 0 hours, 0 minutes, 0 seconds
```



Discussion:
A ugly hack that solve the problem:

``` diff
--- a/lib/ansible/plugins/callback/profile_tasks.py
+++ b/lib/ansible/plugins/callback/profile_tasks.py
@@ -27,6 +27,7 @@
 import os
 import time

+from ansible import utils
 from ansible.plugins.callback import CallbackBase

 # define start time
@@ -134,7 +135,9 @@
         # Print the timings
         for uuid, result in results:
             msg = ''
-            msg="{0:-<70}{1:->9}".format('{0} '.format(result['name']),' {0:.02f}s'.format(result['time']))
+            name = utils.unicode.to_bytes(result['name'])
+            msg="{0:-<70}{1:->9}".format('{0} '.format(name),' {0:.02f}s'.format(result['time']))
             if 'path' in result:
                 msg += "\n{0:-<79}".format( '{0} '.format(result['path']))
+            msg = utils.unicode.to_unicode(msg)
             self._display.display(msg)

```


Resolving patch:
diff --git a/lib/ansible/plugins/callback/profile_tasks.py b/lib/ansible/plugins/callback/profile_tasks.py
--- a/lib/ansible/plugins/callback/profile_tasks.py
+++ b/lib/ansible/plugins/callback/profile_tasks.py
@@ -133,8 +133,7 @@ def playbook_on_stats(self, stats):
 
         # Print the timings
         for uuid, result in results:
-            msg = ''
-            msg="{0:-<70}{1:->9}".format('{0} '.format(result['name']),' {0:.02f}s'.format(result['time']))
+            msg=u"{0:-<70} {1:->9}".format(result['name'],u' {0:.02f}s'.format(result['time']))
             if 'path' in result:
-                msg += "\n{0:-<79}".format( '{0} '.format(result['path']))
+                msg += u"\n{0:-<79}".format(result['path'])
             self._display.display(msg)


Test patch: