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
180
181
182
183
184
185
186
187
188
189
190
191
|
/*
* Copyright (c) 2013 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* Handler for per-process metrics
*
* proc:28896 stat 28896 (bash) S 3574 28896 28896 34844 28896 4202496 2286 23473 1 21 4 2 486 129 20 0 1 0 125421198 119214080 85 18446744073709551615 4194304 5080360 140737040162832 140737040157848 212270400064 0 0 3686404 1266761467 18446744071582594345 0 0 17 2 0 0 0 0 0 9310744 9344396 14004224
*
*/
#include "metrics.h"
#define ticks_to_msec(ticks) (1000ULL * strtoull(ticks, NULL, 0) / kernel_all_hz)
/* /proc/PID/stat fields (starting at fields[2]) */
#define PROC_PID_STAT_PID 0
#define PROC_PID_STAT_CMD 1
#define PROC_PID_STAT_STATE 2
#define PROC_PID_STAT_PPID 3
#define PROC_PID_STAT_PGRP 4
#define PROC_PID_STAT_SESSION 5
#define PROC_PID_STAT_TTY 6
#define PROC_PID_STAT_TTY_PGRP 7
#define PROC_PID_STAT_FLAGS 8
#define PROC_PID_STAT_MINFLT 9
#define PROC_PID_STAT_CMIN_FLT 10
#define PROC_PID_STAT_MAJ_FLT 11
#define PROC_PID_STAT_CMAJ_FLT 12
#define PROC_PID_STAT_UTIME 13
#define PROC_PID_STAT_STIME 14
#define PROC_PID_STAT_CUTIME 15
#define PROC_PID_STAT_CSTIME 16
#define PROC_PID_STAT_PRIORITY 17
#define PROC_PID_STAT_NICE 18
#define PROC_PID_STAT_REMOVED 19
#define PROC_PID_STAT_IT_REAL_VALUE 20
#define PROC_PID_STAT_START_TIME 21
#define PROC_PID_STAT_VSIZE 22
#define PROC_PID_STAT_RSS 23
#define PROC_PID_STAT_RSS_RLIM 24
#define PROC_PID_STAT_START_CODE 25
#define PROC_PID_STAT_END_CODE 26
#define PROC_PID_STAT_START_STACK 27
#define PROC_PID_STAT_ESP 28
#define PROC_PID_STAT_EIP 29
#define PROC_PID_STAT_SIGNAL 30
#define PROC_PID_STAT_BLOCKED 31
#define PROC_PID_STAT_SIGIGNORE 32
#define PROC_PID_STAT_SIGCATCH 33
#define PROC_PID_STAT_WCHAN 34
#define PROC_PID_STAT_NSWAP 35
#define PROC_PID_STAT_CNSWAP 36
#define PROC_PID_STAT_EXIT_SIGNAL 37
#define PROC_PID_STAT_PROCESSOR 38
#define PROC_PID_STAT_TTYNAME 39
#define PROC_PID_STAT_WCHAN_SYMBOL 40
#define PROC_PID_STAT_PSARGS 41
static char *inst;
static fields_t *proc_stat;
static int
find_command_start(const char *buf, size_t len)
{
int i;
/* skip over (minimal) leading "proc:N cmd " */
for (i = 7; i < len - 4; i++)
if (strncmp(&buf[i], "cmd", 4) == 0)
return i + 4;
return -1; /* wha? cannot find the "cmd" component */
}
static void
inst_command_clean(char *command, size_t size)
{
int i;
/* command contains nulls - replace 'em */
for (i = 0; i < size; i++) {
if (!isprint(command[i]))
command[i] = ' ';
}
/* and trailing whitespace - clean that */
while (--size) {
if (isspace(command[size]))
command[size] = '\0';
else
break;
}
}
void
base_command_name(const char *command, char *base, size_t size)
{
char *p, *start, *end;
int kernel = (command[0] == '('); /* kernel daemons heuristic */
/* moral equivalent of basename, dealing with args stripping too */
for (p = end = start = (char *)command; *p; end = ++p) {
if (kernel)
continue;
else if (*p == '/')
start = end = p+1;
else if (isspace(*p))
break;
}
size--; /* allow for a null */
if (size > (end - start))
size = (end - start);
memcpy(base, start, size);
base[size] = '\0';
}
int
proc_handler(handler_t *h, fields_t *f)
{
int pid, off, bytes;
char *command;
size_t size;
if (f->nfields < 2 || f->fieldlen[0] < 6)
return 0;
if (strcmp(f->fields[1], "cmd") == 0) {
/*
* e.g. :
* proc:27041 cmd /bin/sh /usr/prod/mts/common/bin/dblogin_gateway_reader
*/
if ((off = find_command_start(f->buf, f->len)) < 0)
return 0;
size = f->len - off + 16; /* +16 for the "%06d " pid */
if ((inst = (char *)malloc(size)) == NULL)
return 0;
sscanf(f->buf, "proc:%d", &pid);
bytes = snprintf(inst, size, "%06d ", pid);
/* f->buf contains nulls - so memcpy it then replace 'em */
size = f->len - off - 1;
command = inst + bytes;
memcpy(command, f->buf + off, size);
command[size] = '\0';
inst_command_clean(command, size);
}
if (inst == NULL && strcmp(f->fields[1], "stat") == 0) {
/* no instance yet, so stash it for later */
proc_stat = fields_dup(f);
return 0;
}
if (inst) {
pmInDom indom = pmInDom_build(PROC_DOMAIN, PROC_PROC_INDOM);
if ((command = strchr(inst, ' ')) != NULL) {
char cmdname[MAXPATHLEN];
command++;
base_command_name(command, &cmdname[0], sizeof(cmdname));
put_str_value("proc.psinfo.cmd", indom, inst, cmdname);
put_str_value("proc.psinfo.psargs", indom, inst, command);
}
/* emit the stashed proc_stat fields */
put_ull_value("proc.psinfo.utime", indom, inst, ticks_to_msec(proc_stat->fields[PROC_PID_STAT_UTIME+2]));
put_ull_value("proc.psinfo.stime", indom, inst, ticks_to_msec(proc_stat->fields[PROC_PID_STAT_STIME+2]));
put_str_value("proc.psinfo.processor", indom, inst, proc_stat->fields[PROC_PID_STAT_PROCESSOR+2]);
put_str_value("proc.psinfo.rss", indom, inst, proc_stat->fields[PROC_PID_STAT_RSS+2]);
put_str_value("proc.psinfo.vsize", indom, inst, proc_stat->fields[PROC_PID_STAT_VSIZE+2]);
put_str_value("proc.psinfo.sname", indom, inst, proc_stat->fields[PROC_PID_STAT_STATE+2]);
/* and the rest .. */
fields_free(proc_stat);
proc_stat = NULL;
/* TODO emit other stashed stuff .. */
free(inst);
inst = NULL;
}
return 0;
}
|