]>
git.proxmox.com Git - pve-cluster.git/blob - data/src/logger.c
2 Copyright (C) 2010 Proxmox Server Solutions GmbH
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Affero General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Affero General Public License for more details.
14 You should have received a copy of the GNU Affero General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 Author: Dietmar Maurer <dietmar@proxmox.com>
23 #endif /* HAVE_CONFIG_H */
25 #define _XOPEN_SOURCE /* glibc2 needs this */
26 #include <time.h> /* for strptime */
35 #include <sys/types.h>
40 #define SYSLOG_MAX_LINE_LENGTH 8192
42 #include "cfs-utils.h"
46 * 64 bit FNV-1a non-zero initial basis
48 #define FNV1A_64_INIT ((uint64_t) 0xcbf29ce484222325ULL)
50 * 64 bit Fowler/Noll/Vo FNV-1a hash code
51 * (copied from sheepdog sources)
53 static inline uint64_t fnv_64a_buf(const void *buf
, size_t len
, uint64_t hval
)
55 unsigned char *bp
= (unsigned char *) buf
;
56 unsigned char *be
= bp
+ len
;
58 hval
^= (uint64_t) *bp
++;
59 hval
+= (hval
<< 1) + (hval
<< 4) + (hval
<< 5) +
60 (hval
<< 7) + (hval
<< 8) + (hval
<< 40);
65 static uint32_t uid_counter
= 0;
84 g_return_val_if_fail(clog
!= NULL
, NULL
);
85 g_return_val_if_fail(size
> sizeof(clog_entry_t
), NULL
);
86 g_return_val_if_fail(size
<= CLOG_MAX_ENTRY_SIZE
, NULL
);
88 uint32_t realsize
= ((size
+ 7) & 0xfffffff8);
93 newpos
= sizeof(clog_base_t
);
95 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ clog
->cpos
);
97 if ((newpos
+ realsize
) >= clog
->size
) {
98 newpos
= sizeof(clog_base_t
);
102 clog_entry_t
*entry
= (clog_entry_t
*)((char *)clog
+ newpos
);
104 entry
->prev
= clog
->cpos
;
106 entry
->next
= newpos
+ realsize
;
112 clog_dump_entry(clog_entry_t
*cur
, uint32_t cpos
)
114 g_return_if_fail(cur
!= NULL
);
116 char *node
= cur
->data
;
117 char *ident
= node
+ cur
->node_len
;
118 char *tag
= ident
+ cur
->ident_len
;
119 char *msg
= tag
+ cur
->tag_len
;
121 time_t lt
= cur
->time
;
123 strftime(tbuf
, sizeof(tbuf
), "%F %T", localtime(<
));
124 printf("cpos %05d %08x %s", cpos
, cur
->uid
, tbuf
);
125 printf(" %s{%016" PRIX64
"} %s[%s{%016" PRIX64
"}]: %s\n", node
, cur
->node_digest
, tag
, ident
, cur
->ident_digest
, msg
);
130 clog_dump(clog_base_t
*clog
)
132 g_return_if_fail(clog
!= NULL
);
134 uint32_t cpos
= clog
->cpos
;
136 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
137 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
138 clog_dump_entry(cur
, cpos
);
150 g_return_if_fail(clog
!= NULL
);
151 g_return_if_fail(str
!= NULL
);
153 guint64 ident_digest
= 0;
155 if (ident
&& ident
[0]) {
156 ident_digest
= fnv_64a_buf(ident
, strlen(ident
) + 1, FNV1A_64_INIT
);
159 uint32_t cpos
= clog
->cpos
;
161 g_string_append_printf(str
, "{\n");
163 g_string_append_printf(str
, "\"data\": [\n");
166 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
167 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
170 if (count
>= max_entries
)
173 if (ident_digest
&& ident_digest
!= cur
->ident_digest
)
176 char *node
= cur
->data
;
177 char *ident
= node
+ cur
->node_len
;
178 char *tag
= ident
+ cur
->ident_len
;
179 char *msg
= tag
+ cur
->tag_len
;
182 g_string_append_printf(str
, ",\n");
184 g_string_append_printf(str
, "{\"uid\": %u, \"time\": %u, \"pri\": %d, \"tag\": \"%s\", "
185 "\"pid\": %u, \"node\": \"%s\", \"user\": \"%s\", "
186 "\"msg\": \"%s\"}", cur
->uid
, cur
->time
, cur
->priority
, tag
,
187 cur
->pid
, node
, ident
, msg
);
194 g_string_append_printf(str
, "\n");
196 g_string_append_printf(str
, "]\n");
197 g_string_append_printf(str
, "}\n");
202 clog_entry_size(const clog_entry_t
*entry
)
204 g_return_val_if_fail(entry
!= NULL
, 0);
206 return sizeof(clog_entry_t
) + entry
->node_len
+
207 entry
->ident_len
+ entry
->tag_len
+ entry
->msg_len
;
213 const clog_entry_t
*entry
)
215 g_return_if_fail(clog
!= NULL
);
216 g_return_if_fail(entry
!= NULL
);
218 uint32_t size
= clog_entry_size(entry
);
221 if ((new = clog_alloc_entry(clog
, size
)))
222 memcpy((char *)new + 8, (char *)entry
+ 8, size
- 8);
236 g_return_val_if_fail(entry
!= NULL
, 0);
237 g_return_val_if_fail(ident
!= NULL
, 0);
238 g_return_val_if_fail(tag
!= NULL
, 0);
239 g_return_val_if_fail(msg
!= NULL
, 0);
240 g_return_val_if_fail(priority
>= 0, 0);
241 g_return_val_if_fail(priority
< 8, 0);
243 uint8_t node_len
= CFS_MIN(strlen(node
) + 1, 255);
244 uint8_t ident_len
= CFS_MIN(strlen(ident
) + 1, 255);
245 uint8_t tag_len
= CFS_MIN(strlen(tag
) + 1, 255);
247 char *msg_start
= entry
->data
+ node_len
+ ident_len
+ tag_len
;
250 int buf_len
= CLOG_MAX_ENTRY_SIZE
- (msg_start
- (char *)entry
);
251 utf8_to_ascii(msg_start
, buf_len
, msg
, TRUE
);
253 uint32_t msg_len
= strlen(msg_start
) + 1;
255 uint32_t size
= sizeof(clog_entry_t
) + node_len
+ ident_len
+
258 if (size
> CLOG_MAX_ENTRY_SIZE
) {
259 int diff
= size
- CLOG_MAX_ENTRY_SIZE
;
261 size
= CLOG_MAX_ENTRY_SIZE
;
266 entry
->uid
= ++uid_counter
;
267 entry
->time
= logtime
;
268 entry
->node_digest
= fnv_64a_buf(node
, node_len
, FNV1A_64_INIT
);
269 entry
->ident_digest
= fnv_64a_buf(ident
, ident_len
, FNV1A_64_INIT
);
271 entry
->priority
= priority
;
272 entry
->node_len
= node_len
;
273 entry
->ident_len
= ident_len
;
274 entry
->tag_len
= tag_len
;
275 entry
->msg_len
= msg_len
;
277 char *p
= entry
->data
;
278 g_strlcpy(p
, node
, node_len
);
280 g_strlcpy(p
, ident
, ident_len
);
282 g_strlcpy(p
, tag
, tag_len
);
288 clog_new(uint32_t size
)
290 g_return_val_if_fail(sizeof(clog_base_t
) == 8, NULL
);
293 size
= CLOG_DEFAULT_SIZE
;
295 g_return_val_if_fail(size
>= (CLOG_MAX_ENTRY_SIZE
*10), NULL
);
298 clog_base_t
*clog
= (clog_base_t
*)g_malloc0(size
);
312 clog_entry_t
*entry1
= (clog_entry_t
*)v1
;
313 clog_entry_t
*entry2
= (clog_entry_t
*)v2
;
315 if (entry1
->time
!= entry2
->time
)
316 return entry1
->time
- entry2
->time
;
318 if (entry1
->node_digest
!= entry2
->node_digest
)
319 return entry1
->node_digest
- entry2
->node_digest
;
321 return entry1
->uid
- entry2
->uid
;
325 clog_tree_foreach_fn(
330 clog_entry_t
*entry
= (clog_entry_t
*)value
;
331 clog_base_t
*clog
= (clog_base_t
*)data
;
333 clog_copy(clog
, entry
);
339 clog_sort(clog_base_t
*clog
)
341 g_return_val_if_fail(clog
!= NULL
, NULL
);
342 g_return_val_if_fail(clog
->cpos
!= 0, NULL
);
344 clog_base_t
*res
= clog_new(clog
->size
);
348 GTree
*tree
= g_tree_new_with_data(clog_entry_sort_fn
, NULL
);
354 uint32_t cpos
= clog
->cpos
;
356 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
357 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
359 g_tree_insert(tree
, cur
, cur
);
364 g_tree_foreach(tree
, clog_tree_foreach_fn
, res
);
365 g_tree_destroy(tree
);
371 clog_size(clog_base_t
*clog
)
373 g_return_val_if_fail(clog
!= NULL
, 0);
380 const clog_entry_t
*entry
)
382 g_return_val_if_fail(dedup
!= NULL
, FALSE
);
383 g_return_val_if_fail(entry
!= NULL
, FALSE
);
385 dedup_entry_t
*dd
= g_hash_table_lookup(dedup
, &entry
->node_digest
);
387 if (!(dd
= g_new0(dedup_entry_t
, 1)))
390 dd
->node_digest
= entry
->node_digest
;
391 dd
->time
= entry
->time
;
392 dd
->uid
= entry
->uid
;
394 g_hash_table_insert(dedup
, dd
, dd
);
399 if (entry
->time
> dd
->time
||
400 (entry
->time
== dd
->time
&& entry
->uid
> dd
->uid
)) {
401 dd
->time
= entry
->time
;
402 dd
->uid
= entry
->uid
;
422 g_return_if_fail(cl
!= NULL
);
423 g_return_if_fail(str
!= NULL
);
425 g_mutex_lock(&cl
->mutex
);
426 clog_dump_json(cl
->base
, str
, user
, max_entries
);
427 g_mutex_unlock(&cl
->mutex
);
437 g_return_val_if_fail(cl
!= NULL
, NULL
);
438 g_return_val_if_fail(clog
!= NULL
, NULL
);
439 g_return_val_if_fail(count
>= 2, NULL
);
440 g_return_val_if_fail(local_index
>= 0, NULL
);
441 g_return_val_if_fail(local_index
< count
, NULL
);
443 uint32_t cpos
[count
];
444 uint32_t maxsize
= 0;
447 if (!(dedup
= g_hash_table_new_full(g_int64_hash
, g_int64_equal
, NULL
, g_free
)))
450 GTree
*tree
= g_tree_new_with_data(clog_entry_sort_fn
, NULL
);
452 g_hash_table_destroy(dedup
);
456 clog_base_t
*res
= clog_new(maxsize
);
458 g_hash_table_destroy(dedup
);
459 g_tree_destroy(tree
);
463 g_mutex_lock(&cl
->mutex
);
465 for (int i
= 0; i
< count
; i
++) {
466 if (i
== local_index
)
470 cfs_critical("log pointer is NULL!");
474 cpos
[i
] = clog
[i
]->cpos
;
475 if (clog
[i
]->size
> maxsize
)
476 maxsize
= clog
[i
]->size
;
480 maxsize
= res
->size
- sizeof(clog_base_t
) - CLOG_MAX_ENTRY_SIZE
;
488 /* select entry wit latest time */
489 for (int i
= 0; i
< count
; i
++) {
492 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
[i
] + cpos
[i
]);
493 if (cur
->time
> last
) {
502 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
[found
] + cpos
[found
]);
504 if (!g_tree_lookup(tree
, cur
)) {
505 g_tree_insert(tree
, cur
, cur
);
506 dedup_lookup(dedup
, cur
); /* just to record versions */
507 logsize
+= cur
->next
- cpos
[found
];
508 if (logsize
>= maxsize
)
515 cpos
[found
] = cur
->prev
;
516 if (!(cpos
[found
] <= clog
[found
]->cpos
||
517 cpos
[found
] > (clog
[found
]->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
523 g_tree_foreach(tree
, clog_tree_foreach_fn
, res
);
524 g_tree_destroy(tree
);
526 g_hash_table_destroy(cl
->dedup
);
532 g_mutex_unlock(&cl
->mutex
);
538 clusterlog_destroy(clusterlog_t
*cl
)
540 g_return_if_fail(cl
!= NULL
);
542 g_mutex_clear(&cl
->mutex
);
548 g_hash_table_destroy(cl
->dedup
);
556 clusterlog_t
*cl
= g_new0(clusterlog_t
, 1);
560 g_mutex_init(&cl
->mutex
);
562 if (!(cl
->base
= clog_new(0)))
565 if (!(cl
->dedup
= g_hash_table_new_full(g_int64_hash
, g_int64_equal
, NULL
, g_free
)))
571 clusterlog_destroy(cl
);
576 clusterlog_get_state(
578 unsigned int *res_len
)
580 g_return_val_if_fail(cl
!= NULL
, NULL
);
581 g_return_val_if_fail(res_len
!= NULL
, NULL
);
583 g_mutex_lock(&cl
->mutex
);
586 if ((new = clog_sort(cl
->base
))) {
591 *res_len
= clog_size(cl
->base
);
592 gpointer msg
= g_memdup(cl
->base
, *res_len
);
594 g_mutex_unlock(&cl
->mutex
);
602 const clog_entry_t
*entry
)
604 g_return_if_fail(cl
!= NULL
);
605 g_return_if_fail(entry
!= NULL
);
607 g_mutex_lock(&cl
->mutex
);
609 if (dedup_lookup(cl
->dedup
, entry
)) {
610 clog_copy(cl
->base
, entry
);
612 cfs_message("ignore duplicate"); // fixme remove
615 g_mutex_unlock(&cl
->mutex
);
628 g_return_if_fail(cl
!= NULL
);
629 g_return_if_fail(format
!= NULL
);
632 va_start (args
, format
);
633 char *msg
= g_strdup_vprintf (format
, args
);
636 time_t ctime
= time(NULL
);
637 clog_entry_t
*entry
= (clog_entry_t
*)alloca(CLOG_MAX_ENTRY_SIZE
);
638 uint32_t size
= clog_pack(entry
, cfs
.nodename
, ident
, tag
, pid
, ctime
, priority
, msg
);
644 clusterlog_insert(cl
, entry
);