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
|
#define _GNU_SOURCE
#include <fcntl.h>
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "scrape.h"
#include "util.h"
// size of input buffer for paths and lines
#define BUF_SIZE 256
static void mdstat_collect(scrape_req *req, void *ctx);
const struct collector mdstat_collector = {
.name = "mdstat",
.collect = mdstat_collect,
};
void
scrape_write_md_label(scrape_req *req, char *name, char *md, char *label, char *value, double d) {
struct label labels[] = {
{ .key = "device", .value = md },
{ .key = label, .value = value },
LABEL_END,
};
scrape_write(req, name, labels, d);
}
static void mdstat_collect_dir(scrape_req *req, char *dir) {
char buf[BUF_SIZE];
char md[32] = { 0 };
memcpy(md, dir + 11 /* "/sys/block/" */, strlen(dir) - 11 - 3 /* "/md" */);
int dirfd = open(dir, O_PATH);
if (dirfd < 0)
return;
struct label md_label[] = {
{ .key = "device", .value = md },
LABEL_END,
};
if (read_file_at(dirfd, "level", buf, sizeof buf) > 0)
scrape_write_md_label(req, "node_md_level", md, "level", buf, 1);
if (read_file_at(dirfd, "raid_disks", buf, sizeof buf) > 0)
scrape_write(req, "node_md_disks", md_label, atof(buf));
if (read_file_at(dirfd, "metadata_version", buf, sizeof buf) > 0)
scrape_write_md_label(req, "node_md_metadata_version", md, "version", buf, 1);
if (read_file_at(dirfd, "array_state", buf, sizeof buf) > 0)
scrape_write_md_label(req, "node_md_state", md, "state", buf, 1);
// uuid
if (read_file_at(dirfd, "chunk_size", buf, sizeof buf) > 0)
scrape_write(req, "node_md_chunk_size", md_label, atof(buf));
if (read_file_at(dirfd, "degraded", buf, sizeof buf) > 0)
scrape_write(req, "node_md_degraded_disks", md_label, atof(buf));
if (read_file_at(dirfd, "sync_action", buf, sizeof buf) > 0)
scrape_write_md_label(req, "node_md_sync_action", md, "action", buf, 1);
if (read_file_at(dirfd, "sync_completed", buf, sizeof buf) > 0) {
if (strcmp(buf, "none") != 0) {
double a, b;
if (sscanf(buf, "%lf / %lf", &a, &b) == 2)
scrape_write(req, "node_md_sync_completed", md_label, a / b);
if (read_file_at(dirfd, "sync_speed", buf, sizeof buf) > 0)
scrape_write(req, "node_md_sync_speed", md_label, atof(buf));
}
}
close(dirfd);
char stateglob[BUF_SIZE];
strcpy(stateglob, dir);
strcat(stateglob, "/dev-*/state");
glob_t globbuf = { 0 };
if (glob(stateglob, GLOB_NOSORT, 0, &globbuf) != 0)
return;
for (size_t i = 0; i < globbuf.gl_pathc; i++) {
char dev[16] = { 0 };
memcpy(dev, globbuf.gl_pathv[i] + strlen(dir) + 5 /* "/dev-" */,
strlen(globbuf.gl_pathv[i]) - strlen(dir) - 5 - 6 /* "/state" */);
if (read_file_at(AT_FDCWD, globbuf.gl_pathv[i], buf, sizeof buf)) {
struct label labels[] = {
{ .key = "device", .value = md },
{ .key = "disk", .value = dev },
{ .key = "state", .value = buf },
LABEL_END,
};
scrape_write(req, "node_md_disk_state", labels, 1);
}
}
globfree(&globbuf);
}
static void mdstat_collect(scrape_req *req, void *ctx) {
(void) ctx;
// scan /sys/block/md*/md/ for metrics
if (access("/proc/mdstat", F_OK) != 0)
return;
glob_t globbuf = { 0 };
if (glob("/sys/block/md*/md", GLOB_NOSORT | GLOB_ONLYDIR, 0, &globbuf) != 0)
return;
for (size_t i = 0; i < globbuf.gl_pathc; i++)
mdstat_collect_dir(req, globbuf.gl_pathv[i]);
globfree(&globbuf);
}
|