]>
git.proxmox.com Git - pve-cluster.git/blob - data/src/logger.c
bc7466bae0bb0100f85da9f72c9eb1c5c7277778
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 */
34 #include <sys/types.h>
39 #define SYSLOG_MAX_LINE_LENGTH 8192
41 #include "cfs-utils.h"
45 * 64 bit FNV-1a non-zero initial basis
47 #define FNV1A_64_INIT ((uint64_t) 0xcbf29ce484222325ULL)
49 * 64 bit Fowler/Noll/Vo FNV-1a hash code
50 * (copied from sheepdog sources)
52 static inline uint64_t fnv_64a_buf(const void *buf
, size_t len
, uint64_t hval
)
54 unsigned char *bp
= (unsigned char *) buf
;
55 unsigned char *be
= bp
+ len
;
57 hval
^= (uint64_t) *bp
++;
58 hval
+= (hval
<< 1) + (hval
<< 4) + (hval
<< 5) +
59 (hval
<< 7) + (hval
<< 8) + (hval
<< 40);
64 static uint32_t uid_counter
= 0;
83 g_return_val_if_fail(clog
!= NULL
, NULL
);
84 g_return_val_if_fail(size
> sizeof(clog_entry_t
), NULL
);
85 g_return_val_if_fail(size
<= CLOG_MAX_ENTRY_SIZE
, NULL
);
87 uint32_t realsize
= ((size
+ 7) & 0xfffffff8);
92 newpos
= sizeof(clog_base_t
);
94 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ clog
->cpos
);
96 if ((newpos
+ realsize
) >= clog
->size
) {
97 newpos
= sizeof(clog_base_t
);
101 clog_entry_t
*entry
= (clog_entry_t
*)((char *)clog
+ newpos
);
103 entry
->prev
= clog
->cpos
;
105 entry
->next
= newpos
+ realsize
;
111 clog_dump_entry(clog_entry_t
*cur
, uint32_t cpos
)
113 g_return_if_fail(cur
!= NULL
);
115 char *node
= cur
->data
;
116 char *ident
= node
+ cur
->node_len
;
117 char *tag
= ident
+ cur
->ident_len
;
118 char *msg
= tag
+ cur
->tag_len
;
120 time_t lt
= cur
->time
;
122 strftime(tbuf
, sizeof(tbuf
), "%F %T", localtime(<
));
123 printf("cpos %05d %08x %s", cpos
, cur
->uid
, tbuf
);
124 printf(" %s{%016zX} %s[%s{%016zX}]: %s\n", node
, cur
->node_digest
, tag
, ident
, cur
->ident_digest
, msg
);
129 clog_dump(clog_base_t
*clog
)
131 g_return_if_fail(clog
!= NULL
);
133 uint32_t cpos
= clog
->cpos
;
135 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
136 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
137 clog_dump_entry(cur
, cpos
);
149 g_return_if_fail(clog
!= NULL
);
150 g_return_if_fail(str
!= NULL
);
152 guint64 ident_digest
= 0;
154 if (ident
&& ident
[0]) {
155 ident_digest
= fnv_64a_buf(ident
, strlen(ident
) + 1, FNV1A_64_INIT
);
158 uint32_t cpos
= clog
->cpos
;
160 g_string_append_printf(str
, "{\n");
162 g_string_append_printf(str
, "\"data\": [\n");
165 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
166 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
169 if (count
>= max_entries
)
172 if (ident_digest
&& ident_digest
!= cur
->ident_digest
)
175 char *node
= cur
->data
;
176 char *ident
= node
+ cur
->node_len
;
177 char *tag
= ident
+ cur
->ident_len
;
178 char *msg
= tag
+ cur
->tag_len
;
181 g_string_append_printf(str
, ",\n");
183 g_string_append_printf(str
, "{\"uid\": %u, \"time\": %u, \"pri\": %d, \"tag\": \"%s\", "
184 "\"pid\": %u, \"node\": \"%s\", \"user\": \"%s\", "
185 "\"msg\": \"%s\"}", cur
->uid
, cur
->time
, cur
->priority
, tag
,
186 cur
->pid
, node
, ident
, msg
);
193 g_string_append_printf(str
, "\n");
195 g_string_append_printf(str
, "]\n");
196 g_string_append_printf(str
, "}\n");
201 clog_entry_size(const clog_entry_t
*entry
)
203 g_return_val_if_fail(entry
!= NULL
, 0);
205 return sizeof(clog_entry_t
) + entry
->node_len
+
206 entry
->ident_len
+ entry
->tag_len
+ entry
->msg_len
;
212 const clog_entry_t
*entry
)
214 g_return_if_fail(clog
!= NULL
);
215 g_return_if_fail(entry
!= NULL
);
217 uint32_t size
= clog_entry_size(entry
);
220 if ((new = clog_alloc_entry(clog
, size
)))
221 memcpy((char *)new + 8, (char *)entry
+ 8, size
- 8);
235 g_return_val_if_fail(entry
!= NULL
, 0);
236 g_return_val_if_fail(ident
!= NULL
, 0);
237 g_return_val_if_fail(tag
!= NULL
, 0);
238 g_return_val_if_fail(msg
!= NULL
, 0);
239 g_return_val_if_fail(priority
>= 0, 0);
240 g_return_val_if_fail(priority
< 8, 0);
242 uint8_t node_len
= CFS_MIN(strlen(node
) + 1, 255);
243 uint8_t ident_len
= CFS_MIN(strlen(ident
) + 1, 255);
244 uint8_t tag_len
= CFS_MIN(strlen(tag
) + 1, 255);
246 char *msg_start
= entry
->data
+ node_len
+ ident_len
+ tag_len
;
249 int buf_len
= CLOG_MAX_ENTRY_SIZE
- (msg_start
- (char *)entry
);
250 utf8_to_ascii(msg_start
, buf_len
, msg
, TRUE
);
252 uint32_t msg_len
= strlen(msg_start
) + 1;
254 uint32_t size
= sizeof(clog_entry_t
) + node_len
+ ident_len
+
257 if (size
> CLOG_MAX_ENTRY_SIZE
) {
258 int diff
= size
- CLOG_MAX_ENTRY_SIZE
;
260 size
= CLOG_MAX_ENTRY_SIZE
;
265 entry
->uid
= ++uid_counter
;
266 entry
->time
= logtime
;
267 entry
->node_digest
= fnv_64a_buf(node
, node_len
, FNV1A_64_INIT
);
268 entry
->ident_digest
= fnv_64a_buf(ident
, ident_len
, FNV1A_64_INIT
);
270 entry
->priority
= priority
;
271 entry
->node_len
= node_len
;
272 entry
->ident_len
= ident_len
;
273 entry
->tag_len
= tag_len
;
274 entry
->msg_len
= msg_len
;
276 char *p
= entry
->data
;
277 g_strlcpy(p
, node
, node_len
);
279 g_strlcpy(p
, ident
, ident_len
);
281 g_strlcpy(p
, tag
, tag_len
);
287 clog_new(uint32_t size
)
289 g_return_val_if_fail(sizeof(clog_base_t
) == 8, NULL
);
292 size
= CLOG_DEFAULT_SIZE
;
294 g_return_val_if_fail(size
>= (CLOG_MAX_ENTRY_SIZE
*10), NULL
);
297 clog_base_t
*clog
= (clog_base_t
*)g_malloc0(size
);
311 clog_entry_t
*entry1
= (clog_entry_t
*)v1
;
312 clog_entry_t
*entry2
= (clog_entry_t
*)v2
;
314 if (entry1
->time
!= entry2
->time
)
315 return entry1
->time
- entry2
->time
;
317 if (entry1
->node_digest
!= entry2
->node_digest
)
318 return entry1
->node_digest
- entry2
->node_digest
;
320 return entry1
->uid
- entry2
->uid
;
324 clog_tree_foreach_fn(
329 clog_entry_t
*entry
= (clog_entry_t
*)value
;
330 clog_base_t
*clog
= (clog_base_t
*)data
;
332 clog_copy(clog
, entry
);
338 clog_sort(clog_base_t
*clog
)
340 g_return_val_if_fail(clog
!= NULL
, NULL
);
341 g_return_val_if_fail(clog
->cpos
!= 0, NULL
);
343 clog_base_t
*res
= clog_new(clog
->size
);
347 GTree
*tree
= g_tree_new_with_data(clog_entry_sort_fn
, NULL
);
353 uint32_t cpos
= clog
->cpos
;
355 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
356 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
358 g_tree_insert(tree
, cur
, cur
);
363 g_tree_foreach(tree
, clog_tree_foreach_fn
, res
);
364 g_tree_destroy(tree
);
370 clog_size(clog_base_t
*clog
)
372 g_return_val_if_fail(clog
!= NULL
, 0);
379 const clog_entry_t
*entry
)
381 g_return_val_if_fail(dedup
!= NULL
, FALSE
);
382 g_return_val_if_fail(entry
!= NULL
, FALSE
);
384 dedup_entry_t
*dd
= g_hash_table_lookup(dedup
, &entry
->node_digest
);
386 if (!(dd
= g_new0(dedup_entry_t
, 1)))
389 dd
->node_digest
= entry
->node_digest
;
390 dd
->time
= entry
->time
;
391 dd
->uid
= entry
->uid
;
393 g_hash_table_insert(dedup
, dd
, dd
);
398 if (entry
->time
> dd
->time
||
399 (entry
->time
== dd
->time
&& entry
->uid
> dd
->uid
)) {
400 dd
->time
= entry
->time
;
401 dd
->uid
= entry
->uid
;
421 g_return_if_fail(cl
!= NULL
);
422 g_return_if_fail(str
!= NULL
);
424 g_mutex_lock(cl
->mutex
);
425 clog_dump_json(cl
->base
, str
, user
, max_entries
);
426 g_mutex_unlock(cl
->mutex
);
436 g_return_val_if_fail(cl
!= NULL
, NULL
);
437 g_return_val_if_fail(clog
!= NULL
, NULL
);
438 g_return_val_if_fail(count
>= 2, NULL
);
439 g_return_val_if_fail(local_index
>= 0, NULL
);
440 g_return_val_if_fail(local_index
< count
, NULL
);
442 uint32_t cpos
[count
];
443 uint32_t maxsize
= 0;
446 if (!(dedup
= g_hash_table_new_full(g_int64_hash
, g_int64_equal
, NULL
, g_free
)))
449 GTree
*tree
= g_tree_new_with_data(clog_entry_sort_fn
, NULL
);
451 g_hash_table_destroy(dedup
);
455 clog_base_t
*res
= clog_new(maxsize
);
457 g_hash_table_destroy(dedup
);
458 g_tree_destroy(tree
);
462 g_mutex_lock(cl
->mutex
);
464 for (int i
= 0; i
< count
; i
++) {
465 if (i
== local_index
)
469 cfs_critical("log pointer is NULL!");
473 cpos
[i
] = clog
[i
]->cpos
;
474 if (clog
[i
]->size
> maxsize
)
475 maxsize
= clog
[i
]->size
;
479 maxsize
= res
->size
- sizeof(clog_base_t
) - CLOG_MAX_ENTRY_SIZE
;
487 /* select entry wit latest time */
488 for (int i
= 0; i
< count
; i
++) {
491 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
[i
] + cpos
[i
]);
492 if (cur
->time
> last
) {
501 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
[found
] + cpos
[found
]);
503 if (!g_tree_lookup(tree
, cur
)) {
504 g_tree_insert(tree
, cur
, cur
);
505 dedup_lookup(dedup
, cur
); /* just to record versions */
506 logsize
+= cur
->next
- cpos
[found
];
507 if (logsize
>= maxsize
)
514 cpos
[found
] = cur
->prev
;
515 if (!(cpos
[found
] <= clog
[found
]->cpos
||
516 cpos
[found
] > (clog
[found
]->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
522 g_tree_foreach(tree
, clog_tree_foreach_fn
, res
);
523 g_tree_destroy(tree
);
525 g_hash_table_destroy(cl
->dedup
);
531 g_mutex_unlock(cl
->mutex
);
537 clusterlog_destroy(clusterlog_t
*cl
)
539 g_return_if_fail(cl
!= NULL
);
542 g_mutex_free(cl
->mutex
);
548 g_hash_table_destroy(cl
->dedup
);
556 clusterlog_t
*cl
= g_new0(clusterlog_t
, 1);
560 if (!(cl
->mutex
= g_mutex_new()))
563 if (!(cl
->base
= clog_new(0)))
566 if (!(cl
->dedup
= g_hash_table_new_full(g_int64_hash
, g_int64_equal
, NULL
, g_free
)))
572 clusterlog_destroy(cl
);
577 clusterlog_get_state(
579 unsigned int *res_len
)
581 g_return_val_if_fail(cl
!= NULL
, NULL
);
582 g_return_val_if_fail(res_len
!= NULL
, NULL
);
584 g_mutex_lock(cl
->mutex
);
587 if ((new = clog_sort(cl
->base
))) {
592 *res_len
= clog_size(cl
->base
);
593 gpointer msg
= g_memdup(cl
->base
, *res_len
);
595 g_mutex_unlock(cl
->mutex
);
603 const clog_entry_t
*entry
)
605 g_return_if_fail(cl
!= NULL
);
606 g_return_if_fail(entry
!= NULL
);
608 g_mutex_lock(cl
->mutex
);
610 if (dedup_lookup(cl
->dedup
, entry
)) {
611 clog_copy(cl
->base
, entry
);
613 cfs_message("ignore duplicate"); // fixme remove
616 g_mutex_unlock(cl
->mutex
);
629 g_return_if_fail(cl
!= NULL
);
630 g_return_if_fail(format
!= NULL
);
633 va_start (args
, format
);
634 char *msg
= g_strdup_vprintf (format
, args
);
637 time_t ctime
= time(NULL
);
638 clog_entry_t
*entry
= (clog_entry_t
*)alloca(CLOG_MAX_ENTRY_SIZE
);
639 uint32_t size
= clog_pack(entry
, cfs
.nodename
, ident
, tag
, pid
, ctime
, priority
, msg
);
645 clusterlog_insert(cl
, entry
);