summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/general/plugins/modules/statsd.py
blob: 8bc0f0b1876972c3e4edf0c6ee306aafcf47201d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import absolute_import, division, print_function
__metaclass__ = type

DOCUMENTATION = '''
module: statsd
short_description: Send metrics to StatsD
version_added: 2.1.0
description:
  - The C(statsd) module sends metrics to StatsD.
  - For more information, see U(https://statsd-metrics.readthedocs.io/en/latest/).
  - Supported metric types are V(counter) and V(gauge).
    Currently unupported metric types are V(timer), V(set), and V(gaugedelta).
author: "Mark Mercado (@mamercad)"
requirements:
  - statsd
extends_documentation_fragment:
  - community.general.attributes
attributes:
  check_mode:
    support: none
  diff_mode:
    support: none
options:
  state:
    type: str
    description:
      - State of the check, only V(present) makes sense.
    choices: ["present"]
    default: present
  host:
    type: str
    default: localhost
    description:
      - StatsD host (hostname or IP) to send metrics to.
  port:
    type: int
    default: 8125
    description:
      - The port on O(host) which StatsD is listening on.
  protocol:
    type: str
    default: udp
    choices: ["udp", "tcp"]
    description:
      - The transport protocol to send metrics over.
  timeout:
    type: float
    default: 1.0
    description:
      - Sender timeout, only applicable if O(protocol) is V(tcp).
  metric:
    type: str
    required: true
    description:
      - The name of the metric.
  metric_type:
    type: str
    required: true
    choices: ["counter", "gauge"]
    description:
      - The type of metric.
  metric_prefix:
    type: str
    description:
      - The prefix to add to the metric.
    default: ''
  value:
    type: int
    required: true
    description:
      - The value of the metric.
  delta:
    type: bool
    default: false
    description:
      - If the metric is of type V(gauge), change the value by O(delta).
'''

EXAMPLES = '''
- name: Increment the metric my_counter by 1
  community.general.statsd:
    host: localhost
    port: 9125
    protocol: tcp
    metric: my_counter
    metric_type: counter
    value: 1

- name: Set the gauge my_gauge to 7
  community.general.statsd:
    host: localhost
    port: 9125
    protocol: tcp
    metric: my_gauge
    metric_type: gauge
    value: 7
'''


from ansible.module_utils.basic import (AnsibleModule, missing_required_lib)

try:
    from statsd import StatsClient, TCPStatsClient
    HAS_STATSD = True
except ImportError:
    HAS_STATSD = False


def udp_statsd_client(**client_params):
    return StatsClient(**client_params)


def tcp_statsd_client(**client_params):
    return TCPStatsClient(**client_params)


def main():

    module = AnsibleModule(
        argument_spec=dict(
            state=dict(type='str', default='present', choices=['present']),
            host=dict(type='str', default='localhost'),
            port=dict(type='int', default=8125),
            protocol=dict(type='str', default='udp', choices=['udp', 'tcp']),
            timeout=dict(type='float', default=1.0),
            metric=dict(type='str', required=True),
            metric_type=dict(type='str', required=True, choices=['counter', 'gauge']),
            metric_prefix=dict(type='str', default=''),
            value=dict(type='int', required=True),
            delta=dict(type='bool', default=False),
        ),
        supports_check_mode=False
    )

    if not HAS_STATSD:
        module.fail_json(msg=missing_required_lib('statsd'))

    host = module.params.get('host')
    port = module.params.get('port')
    protocol = module.params.get('protocol')
    timeout = module.params.get('timeout')
    metric = module.params.get('metric')
    metric_type = module.params.get('metric_type')
    metric_prefix = module.params.get('metric_prefix')
    value = module.params.get('value')
    delta = module.params.get('delta')

    if protocol == 'udp':
        client = udp_statsd_client(host=host, port=port, prefix=metric_prefix, maxudpsize=512, ipv6=False)
    elif protocol == 'tcp':
        client = tcp_statsd_client(host=host, port=port, timeout=timeout, prefix=metric_prefix, ipv6=False)

    metric_name = '%s/%s' % (metric_prefix, metric) if metric_prefix else metric
    metric_display_value = '%s (delta=%s)' % (value, delta) if metric_type == 'gauge' else value

    try:
        if metric_type == 'counter':
            client.incr(metric, value)
        elif metric_type == 'gauge':
            client.gauge(metric, value, delta=delta)

    except Exception as exc:
        module.fail_json(msg='Failed sending to StatsD %s' % str(exc))

    finally:
        if protocol == 'tcp':
            client.close()

    module.exit_json(msg="Sent %s %s -> %s to StatsD" % (metric_type, metric_name, str(metric_display_value)), changed=True)


if __name__ == '__main__':
    main()