Skip to content

Commit a0881c4

Browse files
committed
in_prometheus_textfile: add Windows support (glob)
Signed-off-by: Eduardo Silva <[email protected]>
1 parent 6814e1f commit a0881c4

File tree

1 file changed

+205
-18
lines changed

1 file changed

+205
-18
lines changed

plugins/in_prometheus_textfile/prometheus_textfile.c

Lines changed: 205 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717
* limitations under the License.
1818
*/
1919

20-
#include <glob.h>
21-
#include <sys/stat.h>
22-
2320
#include <fluent-bit/flb_info.h>
2421
#include <fluent-bit/flb_input.h>
2522
#include <fluent-bit/flb_input_plugin.h>
@@ -29,21 +26,203 @@
2926
#include <fluent-bit/flb_time.h>
3027

3128
#include <cmetrics/cmt_decode_prometheus.h>
32-
3329
#include "prometheus_textfile.h"
3430

31+
#include <sys/stat.h>
32+
/* Glob support */
33+
#ifndef _MSC_VER
34+
#include <glob.h>
35+
#endif
36+
37+
#ifdef _WIN32
38+
#include <Windows.h>
39+
#include <strsafe.h>
40+
#define PATH_MAX MAX_PATH
41+
#endif
42+
43+
#ifndef _WIN32
44+
static struct cfl_array *read_glob(const char *path)
45+
{
46+
int ret = -1;
47+
int ret_glb = -1;
48+
glob_t glb;
49+
size_t idx;
50+
struct cfl_array *list;
51+
52+
ret_glb = glob(path, GLOB_NOSORT, NULL, &glb);
53+
54+
if (ret_glb != 0) {
55+
switch(ret_glb){
56+
case GLOB_NOSPACE:
57+
flb_warn("[%s] glob: [%s] no space", __FUNCTION__, path);
58+
break;
59+
case GLOB_NOMATCH:
60+
flb_warn("[%s] glob: [%s] no match", __FUNCTION__, path);
61+
break;
62+
case GLOB_ABORTED:
63+
flb_warn("[%s] glob: [%s] aborted", __FUNCTION__, path);
64+
break;
65+
default:
66+
flb_warn("[%s] glob: [%s] other error", __FUNCTION__, path);
67+
}
68+
return NULL;
69+
}
70+
71+
list = cfl_array_create(glb.gl_pathc);
72+
for (idx = 0; idx < glb.gl_pathc; idx++) {
73+
ret = cfl_array_append_string(list, glb.gl_pathv[idx]);
74+
if (ret < 0) {
75+
cfl_array_destroy(list);
76+
globfree(&glb);
77+
return NULL;
78+
}
79+
}
80+
81+
globfree(&glb);
82+
return list;
83+
}
84+
#else
85+
static char *dirname(char *path)
86+
{
87+
char *ptr;
88+
89+
ptr = strrchr(path, '\\');
90+
91+
if (ptr == NULL) {
92+
return path;
93+
}
94+
*ptr++='\0';
95+
return path;
96+
}
97+
98+
static struct cfl_array *read_glob_win(const char *path, struct cfl_array *list)
99+
{
100+
char *star, *p0, *p1;
101+
char pattern[MAX_PATH];
102+
char buf[MAX_PATH];
103+
int ret;
104+
struct stat st;
105+
HANDLE hnd;
106+
WIN32_FIND_DATA data;
107+
108+
if (strlen(path) > MAX_PATH - 1) {
109+
flb_error("path too long: %s", path);
110+
return NULL;
111+
}
112+
113+
star = strchr(path, '*');
114+
if (star == NULL) {
115+
flb_error("path has no wild card: %s", path);
116+
return NULL;
117+
}
118+
119+
/*
120+
* C:\data\tmp\input_*.conf
121+
* 0<-----|
122+
*/
123+
p0 = star;
124+
while (path <= p0 && *p0 != '\\') {
125+
p0--;
126+
}
127+
128+
/*
129+
* C:\data\tmp\input_*.conf
130+
* |---->1
131+
*/
132+
p1 = star;
133+
while (*p1 && *p1 != '\\') {
134+
p1++;
135+
}
136+
137+
memcpy(pattern, path, (p1 - path));
138+
pattern[p1 - path] = '\0';
139+
140+
hnd = FindFirstFileA(pattern, &data);
141+
142+
if (hnd == INVALID_HANDLE_VALUE) {
143+
flb_error("unable to open valid handle for: %s", path);
144+
return NULL;
145+
}
146+
147+
if (list == NULL) {
148+
list = cfl_array_create(3);
149+
150+
if (list == NULL) {
151+
flb_error("unable to allocate array");
152+
FindClose(hnd);
153+
return NULL;
154+
}
155+
156+
/* cfl_array_resizable is hardcoded to return 0. */
157+
if (cfl_array_resizable(list, FLB_TRUE) != 0) {
158+
flb_error("unable to make array resizable");
159+
FindClose(hnd);
160+
cfl_array_destroy(list);
161+
return NULL;
162+
}
163+
}
164+
165+
do {
166+
/* Ignore the current and parent dirs */
167+
if (!strcmp(".", data.cFileName) || !strcmp("..", data.cFileName)) {
168+
continue;
169+
}
170+
171+
/* Avoid an infinite loop */
172+
if (strchr(data.cFileName, '*')) {
173+
continue;
174+
}
175+
176+
/* Create a path (prefix + filename + suffix) */
177+
memcpy(buf, path, p0 - path + 1);
178+
buf[p0 - path + 1] = '\0';
179+
180+
if (FAILED(StringCchCatA(buf, MAX_PATH, data.cFileName))) {
181+
continue;
182+
}
183+
184+
if (FAILED(StringCchCatA(buf, MAX_PATH, p1))) {
185+
continue;
186+
}
187+
188+
if (strchr(p1, '*')) {
189+
if (read_glob_win(path, list) == NULL) {
190+
cfl_array_destroy(list);
191+
FindClose(hnd);
192+
return NULL;
193+
}
194+
continue;
195+
}
196+
197+
ret = stat(buf, &st);
198+
199+
if (ret == 0 && (st.st_mode & S_IFMT) == S_IFREG) {
200+
cfl_array_append_string(list, buf);
201+
}
202+
} while (FindNextFileA(hnd, &data) != 0);
203+
204+
FindClose(hnd);
205+
return list;
206+
}
207+
208+
static struct cfl_array *read_glob(const char *path)
209+
{
210+
return read_glob_win(path, NULL);
211+
}
212+
#endif
213+
35214
static int collect_metrics(struct prom_textfile *ctx)
36215
{
37216
int i;
38217
int ret;
39-
glob_t globbuf;
40218
char errbuf[256];
41219
struct stat st;
42220
struct mk_list *head;
43221
struct flb_slist_entry *entry;
44222
struct cmt *cmt = NULL;
45223
struct cmt_decode_prometheus_parse_opts opts = {0};
46224
flb_sds_t content;
225+
struct cfl_array *files;
47226

48227
/* cmetrics prometheus decoder options */
49228
opts.default_timestamp = cfl_time_now();
@@ -54,23 +233,26 @@ static int collect_metrics(struct prom_textfile *ctx)
54233
mk_list_foreach(head, ctx->path_list) {
55234
entry = mk_list_entry(head, struct flb_slist_entry, _head);
56235

57-
globbuf.gl_pathc = 0;
58-
globbuf.gl_pathv = NULL;
59-
60-
ret = glob(entry->str, 0, NULL, &globbuf);
61-
if (ret != 0) {
62-
globfree(&globbuf);
236+
files = read_glob(entry->str);
237+
if (!files) {
238+
flb_plg_error(ctx->ins, "error reading glob pattern: %s", entry->str);
239+
continue;
240+
}
241+
if (files->entry_count == 0) {
242+
flb_plg_debug(ctx->ins, "no files found for glob pattern: %s", entry->str);
243+
cfl_array_destroy(files);
63244
continue;
64245
}
65246

66-
for (i = 0; i < globbuf.gl_pathc; i++) {
67-
ret = stat(globbuf.gl_pathv[i], &st);
247+
/* iterate files */
248+
for (i = 0; i < files->entry_count; i++) {
249+
ret = stat(files->entries[i]->data.as_string, &st);
68250

69251
/* only process regular files */
70252
if (ret == 0 && S_ISREG(st.st_mode)) {
71-
content = flb_file_read(globbuf.gl_pathv[i]);
253+
content = flb_file_read(files->entries[i]->data.as_string);
72254
if (!content) {
73-
flb_plg_debug(ctx->ins, "cannot read %s", globbuf.gl_pathv[i]);
255+
flb_plg_debug(ctx->ins, "cannot read %s", files->entries[i]->data.as_string);
74256
continue;
75257
}
76258

@@ -80,6 +262,7 @@ static int collect_metrics(struct prom_textfile *ctx)
80262
}
81263

82264
cmt = NULL;
265+
memset(errbuf, 0, sizeof(errbuf));
83266
ret = cmt_decode_prometheus_create(&cmt,
84267
content,
85268
flb_sds_len(content),
@@ -90,14 +273,18 @@ static int collect_metrics(struct prom_textfile *ctx)
90273
flb_input_metrics_append(ctx->ins, NULL, 0, cmt);
91274
cmt_decode_prometheus_destroy(cmt);
92275
}
276+
else {
277+
flb_plg_error(ctx->ins, "error parsing file %s: '%s'",
278+
files->entries[i]->data.as_string, errbuf);
279+
continue;
280+
}
93281
}
94282
else if (ret != 0) {
95-
flb_plg_error(ctx->ins, "error parsing %s: %s",
96-
globbuf.gl_pathv[i], errbuf);
283+
flb_plg_error(ctx->ins, "cannot read '%s'", files->entries[i]->data.as_string);
97284
continue;
98285
}
99286
}
100-
globfree(&globbuf);
287+
cfl_array_destroy(files);
101288
}
102289

103290
return 0;

0 commit comments

Comments
 (0)