Projet

Général

Profil

Révision e6c47a3a

IDe6c47a3a4e1e4d2aac998a0198f6d476b30c042e
Parent c6590b67
Enfant d7c353b9

Ajouté par Kim B. Heino il y a environ 4 ans

unit: add new plugin to monitor nginx unit app server

This multigraph plugin does basic monitoring of unit's applications.
See: https://unit.nginx.org/

Voir les différences:

plugins/unit/unit
1
#!/usr/bin/env python3
2

  
3
"""Munin plugin to monitor NGINX Unit applications.
4

  
5
=head1 NAME
6

  
7
unit - monitor NGINX Unit applications
8

  
9
=head1 APPLICABLE SYSTEMS
10

  
11
Systems with NGINX Unit running.
12

  
13
=head1 CONFIGURATION
14

  
15
No configuration is required for this plugin.
16

  
17
=head1 AUTHOR
18

  
19
Kim B. Heino <b@bbbs.net>
20

  
21
=head1 LICENSE
22

  
23
GPLv2
24

  
25
=head1 MAGIC MARKERS
26

  
27
 #%# family=auto
28
 #%# capabilities=autoconf
29

  
30
=cut
31
"""
32

  
33
import re
34
import subprocess
35
import sys
36
import unicodedata
37

  
38

  
39
def safename(name):
40
    """Return safe variable name."""
41
    # Convert ä->a as isalpha('ä') is true
42
    value = unicodedata.normalize('NFKD', name)
43
    value = value.encode('ASCII', 'ignore').decode('utf-8')
44

  
45
    # Remove non-alphanumeric chars
46
    return ''.join(char.lower() if char.isalnum() else '_' for char in value)
47

  
48

  
49
def run_binary(arg):
50
    """Run binary and return output."""
51
    try:
52
        return subprocess.run(arg, stdout=subprocess.PIPE, check=False,
53
                              encoding='utf-8', errors='ignore').stdout
54
    except FileNotFoundError:
55
        return ''
56

  
57

  
58
def parse_time(value):
59
    """Parse "dd-hh:mm:ss", "hh:mm:ss" and "mm:ss" to seconds."""
60
    days = hours = '0'
61
    if '-' in value:
62
        days, value = value.split('-', 1)
63
    if value.count(':') == 2:
64
        hours, value = value.split(':', 1)
65
    minutes, seconds = value.split(':')
66
    return (int(days) * 86400 + int(hours) * 3600 + int(minutes) * 60 +
67
            int(seconds))
68

  
69

  
70
def find_apps():
71
    """Return dict of found unit applications."""
72
    apps = {}
73
    ps_lines = run_binary(['ps', '-eo', '%cpu,etime,rss,command']).splitlines()
74
    for line in ps_lines:
75
        appmatch = re.match(r' *([.0-9]+) +([-:0-9]+) +([0-9]+) '
76
                            r'unit: "(.*)" application', line)
77
        if not appmatch:
78
            continue
79
        cpu = float(appmatch.group(1))
80
        age = parse_time(appmatch.group(2))
81
        memory = int(appmatch.group(3))  # KiB
82
        appname = appmatch.group(4)
83
        if appname in apps:
84
            apps[appname]['count'] += 1
85
            apps[appname]['cpu'] += cpu
86
            apps[appname]['age'] += age
87
            apps[appname]['memory'] += memory
88
        else:
89
            apps[appname] = {
90
                'count': 1,
91
                'cpu': cpu,
92
                'age': age,
93
                'memory': memory,
94
            }
95
    return apps
96

  
97

  
98
def config(apps):
99
    """Print plugin config."""
100
    print('multigraph unit_process')
101
    print('graph_title Unit application processes')
102
    print('graph_info NGINX Unit application process counts.')
103
    print('graph_category appserver')
104
    print('graph_vlabel processes')
105
    print('graph_args --lower-limit 0')
106
    print('graph_scale no')
107
    for app in sorted(apps):
108
        safe = safename(app)
109
        print(f'{safe}.label {app} processes')
110
        print(f'{safe}.draw AREASTACK')
111

  
112
    print('multigraph unit_cpu')
113
    print('graph_title Unit application average CPU usage')
114
    print('graph_info NGINX Unit application average CPU usage per process.')
115
    print('graph_category appserver')
116
    print('graph_vlabel %')
117
    print('graph_args --lower-limit 0')
118
    print('graph_scale no')
119
    for app in sorted(apps):
120
        safe = safename(app)
121
        print(f'{safe}.label {app} CPU')
122

  
123
    print('multigraph unit_age')
124
    print('graph_title Unit application average age')
125
    print('graph_info NGINX Unit application average age per process.')
126
    print('graph_category appserver')
127
    print('graph_vlabel seconds')
128
    print('graph_args --lower-limit 0')
129
    print('graph_scale no')
130
    for app in sorted(apps):
131
        safe = safename(app)
132
        print(f'{safe}.label {app} age')
133

  
134
    print('multigraph unit_memory')
135
    print('graph_title Unit application average memory')
136
    print('graph_info NGINX Unit application average memory per process.')
137
    print('graph_category appserver')
138
    print('graph_vlabel MiB')
139
    print('graph_args --lower-limit 0 --base 1024')
140
    print('graph_scale no')
141
    for app in sorted(apps):
142
        safe = safename(app)
143
        print(f'{safe}.label {app} memory')
144

  
145
    print('multigraph unit_total_memory')
146
    print('graph_title Unit application total memory')
147
    print('graph_info NGINX Unit application total memory.')
148
    print('graph_category appserver')
149
    print('graph_vlabel MiB')
150
    print('graph_args --lower-limit 0 --base 1024')
151
    print('graph_scale no')
152
    for app in sorted(apps):
153
        safe = safename(app)
154
        print(f'{safe}.label {app} memory')
155
        print(f'{safe}.draw AREASTACK')
156

  
157

  
158
def fetch(apps):
159
    """Print values."""
160
    print('multigraph unit_process')
161
    for app, values in apps.items():
162
        safe = safename(app)
163
        print(f'{safe}.value {values["count"]}')
164

  
165
    print('multigraph unit_cpu')
166
    for app, values in apps.items():
167
        safe = safename(app)
168
        print(f'{safe}.value {values["cpu"] / values["count"]}')
169

  
170
    print('multigraph unit_age')
171
    for app, values in apps.items():
172
        safe = safename(app)
173
        print(f'{safe}.value {values["age"] / values["count"]}')
174

  
175
    print('multigraph unit_memory')
176
    for app, values in apps.items():
177
        safe = safename(app)
178
        print(f'{safe}.value {values["memory"] / values["count"] / 1024}')
179

  
180
    print('multigraph unit_total_memory')
181
    for app, values in apps.items():
182
        safe = safename(app)
183
        print(f'{safe}.value {values["memory"] / 1024}')
184

  
185

  
186
if __name__ == '__main__':
187
    if len(sys.argv) > 1 and sys.argv[1] == 'autoconf':
188
        print('yes' if find_apps() else 'no (NGINX Unit is not running)')
189
    elif len(sys.argv) > 1 and sys.argv[1] == 'config':
190
        config(find_apps())
191
    else:
192
        fetch(find_apps())

Formats disponibles : Unified diff