Repository: ansible/ansible

Issue:
debug with_items prints the whole item even if using loop_control label
##### ISSUE TYPE

 Bug Report

##### COMPONENT NAME
debug module


##### ANSIBLE VERSION
```
ansible 2.4.0.0
  config file = /home/valeriog/ANSIBLE_PROD/ansible.cfg
  configured module search path = [u'/home/valeriog/ANSIBLE_PROD/library']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Aug  2 2016, 04:20:16) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)]
```

##### CONFIGURATION
From ansible-config dump --only-changed:
"""
ANSIBLE_SSH_ARGS        = -o ControlPersist=5m
DEFAULT_HASH_BEHAVIOUR  = merge
DEFAULT_STDOUT_CALLBACK = skippy
HOST_KEY_CHECKING       = False
RETRY_FILES_ENABLED     = False
"""

##### OS / ENVIRONMENT
Redhat 7.3

##### SUMMARY
This is similar to #32947 but I'm only using loop_contorl/label (and not using loop_var).
The debug module print out on screen the whole content of each item instead of the content of the label var.

##### STEPS TO REPRODUCE
Save the following playbook to test.yml and run it with the command:  ansible-playbook -i localhost, test.yml

```
---
- name: TEST LOOP CONTROL LABEL
  hosts: all
  connection: local
  gather_facts: no

  tasks:
    - name: TEST LOOP CONTROL LABEL
      debug:
        msg: "{{ item.name }}"
      with_items:
        - name: server1
          disks: 3gb
          ram: 15Gb
          network:
            nic01: 100Gb
            nic02: 10Gb     
        - name: server2
          disks: 3gb
          ram: 15Gb
          network:
            nic01: 100Gb
            nic02: 10Gb     
        - name: server3
          disks: 3gb
          ram: 15Gb
          network:
            nic01: 100Gb
            nic02: 10Gb             
      loop_control:
        label: '{{ item.name }}'
```

##### EXPECTED RESULTS
Only the name of the server is printed out on screen

##### ACTUAL RESULTS
```
PLAY [TEST LOOP CONTROL LABEL] *********************************************************************

TASK [TEST LOOP CONTROL LABEL] *********************************************************************
ok: [localhost] => (item=server1) => {
    "item": {
        "disks": "3gb", 
        "name": "server1", 
        "network": {
            "nic01": "100Gb", 
            "nic02": "10Gb"
        }, 
        "ram": "15Gb"
    }, 
    "msg": "server1"
}
ok: [localhost] => (item=server2) => {
    "item": {
        "disks": "3gb", 
        "name": "server2", 
        "network": {
            "nic01": "100Gb", 
            "nic02": "10Gb"
        }, 
        "ram": "15Gb"
    }, 
    "msg": "server2"
}
ok: [localhost] => (item=server3) => {
    "item": {
        "disks": "3gb", 
        "name": "server3", 
        "network": {
            "nic01": "100Gb", 
            "nic02": "10Gb"
        }, 
        "ram": "15Gb"
    }, 
    "msg": "server3"
}

```



Discussion:
Files identified in the description:
* [lib/ansible/modules/utilities/logic/debug.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/utilities/logic/debug.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @dagwieers
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@valerio-gr The whole item is added to the module result (which is a case for all modules, not just `debug`) whether loop label is set or not, the thing that changes with loop label set is this `ok: [localhost] => (item=server1) => {` - only `item.name` is listed here and not the whole item. I don't think this is a bug.
@mkrizek,  Isn't that a bug? 
The result should just be the output of the msg variable and not include the item itself. 
Note: this example is taken pretty much straight from Ansible documentation as an example to limit what is going to be displayed but I still have the whole item displayed.
@mkrizek,
if that's not considered a bug. Can I change this to a Feature Request?
Maybe have a debug or loop control option to set (e.g. quiet: yes) to avoid the printout on screen of the item.
Basically what is printed on screen, should just be the content of the msg variable and not the items through which the loop is done (that can be include in msg if required btw).

Resolving patch:
diff --git a/lib/ansible/plugins/callback/__init__.py b/lib/ansible/plugins/callback/__init__.py
--- a/lib/ansible/plugins/callback/__init__.py
+++ b/lib/ansible/plugins/callback/__init__.py
@@ -55,7 +55,6 @@ class CallbackBase(AnsiblePlugin):
     '''
 
     def __init__(self, display=None, options=None):
-
         if display:
             self._display = display
         else:
@@ -78,6 +77,8 @@ def __init__(self, display=None, options=None):
         if options is not None:
             self.set_options(options)
 
+        self._hide_in_debug = ('changed', 'failed', 'item', 'skipped', 'invocation')
+
     ''' helper for callbacks, so they don't all have to include deepcopy '''
     _copy_result = deepcopy
 
@@ -236,7 +237,8 @@ def _process_items(self, result):
     def _clean_results(self, result, task_name):
         ''' removes data from results for display '''
         if task_name in ['debug']:
-            result.pop('invocation', None)
+            for hideme in self._hide_in_debug:
+                result.pop(hideme, None)
 
     def set_play_context(self, play_context):
         pass
diff --git a/lib/ansible/plugins/callback/default.py b/lib/ansible/plugins/callback/default.py
--- a/lib/ansible/plugins/callback/default.py
+++ b/lib/ansible/plugins/callback/default.py
@@ -68,7 +68,6 @@ def v2_runner_on_failed(self, result, ignore_errors=False):
     def v2_runner_on_ok(self, result):
 
         delegated_vars = result._result.get('_ansible_delegated_vars', None)
-        self._clean_results(result._result, result._task.action)
 
         if self._play.strategy == 'free' and self._last_task_banner != result._task._uuid:
             self._print_task_banner(result._task)
@@ -93,10 +92,9 @@ def v2_runner_on_ok(self, result):
         if result._task.loop and 'results' in result._result:
             self._process_items(result)
         else:
+            self._clean_results(result._result, result._task.action)
 
             if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result:
-                if result._task.action == 'debug' and 'changed' in result._result:
-                    del result._result['changed']
                 msg += " => %s" % (self._dump_results(result._result),)
             self._display.display(msg, color=color)
 


Test patch:
diff --git a/test/units/plugins/callback/test_callback.py b/test/units/plugins/callback/test_callback.py
--- a/test/units/plugins/callback/test_callback.py
+++ b/test/units/plugins/callback/test_callback.py
@@ -81,7 +81,7 @@ def test_clean_results_debug_task(self):
         self.assertTrue('a' in result)
         self.assertTrue('b' in result)
         self.assertFalse('invocation' in result)
-        self.assertTrue('changed' in result)
+        self.assertFalse('changed' in result)
 
     def test_clean_results_debug_task_no_invocation(self):
         cb = CallbackBase()
@@ -93,7 +93,7 @@ def test_clean_results_debug_task_no_invocation(self):
         cb._clean_results(result, 'debug')
         self.assertTrue('a' in result)
         self.assertTrue('b' in result)
-        self.assertTrue('changed' in result)
+        self.assertFalse('changed' in result)
         self.assertFalse('invocation' in result)
 
     def test_clean_results_debug_task_empty_results(self):