]>
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 */
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 if (cpos
> (clog
->size
- sizeof(clog_entry_t
))) {
137 cfs_critical("log pointer out of range!");
140 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
141 clog_dump_entry(cur
, cpos
);
153 g_return_if_fail(clog
!= NULL
);
154 g_return_if_fail(str
!= NULL
);
156 guint64 ident_digest
= 0;
158 if (ident
&& ident
[0]) {
159 ident_digest
= fnv_64a_buf(ident
, strlen(ident
) + 1, FNV1A_64_INIT
);
162 uint32_t cpos
= clog
->cpos
;
164 g_string_append_printf(str
, "{\n");
166 g_string_append_printf(str
, "\"data\": [\n");
169 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
170 if (cpos
> (clog
->size
- sizeof(clog_entry_t
))) {
171 cfs_critical("log pointer out of range!");
174 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
178 if (count
>= max_entries
)
181 if (ident_digest
&& ident_digest
!= cur
->ident_digest
)
184 char *node
= cur
->data
;
185 char *ident
= node
+ cur
->node_len
;
186 char *tag
= ident
+ cur
->ident_len
;
187 char *msg
= tag
+ cur
->tag_len
;
190 g_string_append_printf(str
, ",\n");
192 g_string_append_printf(str
, "{\"uid\": %u, \"time\": %u, \"pri\": %d, \"tag\": \"%s\", "
193 "\"pid\": %u, \"node\": \"%s\", \"user\": \"%s\", "
194 "\"msg\": \"%s\"}", cur
->uid
, cur
->time
, cur
->priority
, tag
,
195 cur
->pid
, node
, ident
, msg
);
202 g_string_append_printf(str
, "\n");
204 g_string_append_printf(str
, "]\n");
205 g_string_append_printf(str
, "}\n");
210 clog_entry_size(const clog_entry_t
*entry
)
212 g_return_val_if_fail(entry
!= NULL
, 0);
214 return sizeof(clog_entry_t
) + entry
->node_len
+
215 entry
->ident_len
+ entry
->tag_len
+ entry
->msg_len
;
221 const clog_entry_t
*entry
)
223 g_return_if_fail(clog
!= NULL
);
224 g_return_if_fail(entry
!= NULL
);
226 uint32_t size
= clog_entry_size(entry
);
229 if ((new = clog_alloc_entry(clog
, size
)))
230 memcpy((char *)new + 8, (char *)entry
+ 8, size
- 8);
244 g_return_val_if_fail(entry
!= NULL
, 0);
245 g_return_val_if_fail(ident
!= NULL
, 0);
246 g_return_val_if_fail(tag
!= NULL
, 0);
247 g_return_val_if_fail(msg
!= NULL
, 0);
248 g_return_val_if_fail(priority
>= 0, 0);
249 g_return_val_if_fail(priority
< 8, 0);
251 uint8_t node_len
= CFS_MIN(strlen(node
) + 1, 255);
252 uint8_t ident_len
= CFS_MIN(strlen(ident
) + 1, 255);
253 uint8_t tag_len
= CFS_MIN(strlen(tag
) + 1, 255);
255 char *msg_start
= entry
->data
+ node_len
+ ident_len
+ tag_len
;
258 int buf_len
= CLOG_MAX_ENTRY_SIZE
- (msg_start
- (char *)entry
);
259 utf8_to_ascii(msg_start
, buf_len
, msg
, TRUE
);
261 uint32_t msg_len
= strlen(msg_start
) + 1;
263 uint32_t size
= sizeof(clog_entry_t
) + node_len
+ ident_len
+
266 if (size
> CLOG_MAX_ENTRY_SIZE
) {
267 int diff
= size
- CLOG_MAX_ENTRY_SIZE
;
269 size
= CLOG_MAX_ENTRY_SIZE
;
274 entry
->uid
= ++uid_counter
;
275 entry
->time
= logtime
;
276 entry
->node_digest
= fnv_64a_buf(node
, node_len
, FNV1A_64_INIT
);
277 entry
->ident_digest
= fnv_64a_buf(ident
, ident_len
, FNV1A_64_INIT
);
279 entry
->priority
= priority
;
280 entry
->node_len
= node_len
;
281 entry
->ident_len
= ident_len
;
282 entry
->tag_len
= tag_len
;
283 entry
->msg_len
= msg_len
;
285 char *p
= entry
->data
;
286 g_strlcpy(p
, node
, node_len
);
288 g_strlcpy(p
, ident
, ident_len
);
290 g_strlcpy(p
, tag
, tag_len
);
296 clog_new(uint32_t size
)
298 g_return_val_if_fail(sizeof(clog_base_t
) == 8, NULL
);
301 size
= CLOG_DEFAULT_SIZE
;
303 g_return_val_if_fail(size
>= (CLOG_MAX_ENTRY_SIZE
*10), NULL
);
306 clog_base_t
*clog
= (clog_base_t
*)g_malloc0(size
);
320 clog_entry_t
*entry1
= (clog_entry_t
*)v1
;
321 clog_entry_t
*entry2
= (clog_entry_t
*)v2
;
323 if (entry1
->time
!= entry2
->time
)
324 return entry1
->time
- entry2
->time
;
326 if (entry1
->node_digest
!= entry2
->node_digest
)
327 return entry1
->node_digest
- entry2
->node_digest
;
329 return entry1
->uid
- entry2
->uid
;
333 clog_tree_foreach_fn(
338 clog_entry_t
*entry
= (clog_entry_t
*)value
;
339 clog_base_t
*clog
= (clog_base_t
*)data
;
341 clog_copy(clog
, entry
);
347 clog_sort(clog_base_t
*clog
)
349 g_return_val_if_fail(clog
!= NULL
, NULL
);
350 g_return_val_if_fail(clog
->cpos
!= 0, NULL
);
352 clog_base_t
*res
= clog_new(clog
->size
);
356 GTree
*tree
= g_tree_new_with_data(clog_entry_sort_fn
, NULL
);
362 uint32_t cpos
= clog
->cpos
;
364 while (cpos
&& (cpos
<= clog
->cpos
|| cpos
> (clog
->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
365 if (cpos
> (clog
->size
- sizeof(clog_entry_t
))) {
366 cfs_critical("log pointer out of range!");
369 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
+ cpos
);
371 g_tree_insert(tree
, cur
, cur
);
376 g_tree_foreach(tree
, clog_tree_foreach_fn
, res
);
377 g_tree_destroy(tree
);
383 clog_size(clog_base_t
*clog
)
385 g_return_val_if_fail(clog
!= NULL
, 0);
392 const clog_entry_t
*entry
)
394 g_return_val_if_fail(dedup
!= NULL
, FALSE
);
395 g_return_val_if_fail(entry
!= NULL
, FALSE
);
397 dedup_entry_t
*dd
= g_hash_table_lookup(dedup
, &entry
->node_digest
);
399 if (!(dd
= g_new0(dedup_entry_t
, 1)))
402 dd
->node_digest
= entry
->node_digest
;
403 dd
->time
= entry
->time
;
404 dd
->uid
= entry
->uid
;
406 g_hash_table_insert(dedup
, dd
, dd
);
411 if (entry
->time
> dd
->time
||
412 (entry
->time
== dd
->time
&& entry
->uid
> dd
->uid
)) {
413 dd
->time
= entry
->time
;
414 dd
->uid
= entry
->uid
;
434 g_return_if_fail(cl
!= NULL
);
435 g_return_if_fail(str
!= NULL
);
437 g_mutex_lock(cl
->mutex
);
438 clog_dump_json(cl
->base
, str
, user
, max_entries
);
439 g_mutex_unlock(cl
->mutex
);
449 g_return_val_if_fail(cl
!= NULL
, NULL
);
450 g_return_val_if_fail(clog
!= NULL
, NULL
);
451 g_return_val_if_fail(count
>= 2, NULL
);
452 g_return_val_if_fail(local_index
>= 0, NULL
);
453 g_return_val_if_fail(local_index
< count
, NULL
);
455 uint32_t cpos
[count
];
456 uint32_t maxsize
= 0;
459 if (!(dedup
= g_hash_table_new_full(g_int64_hash
, g_int64_equal
, NULL
, g_free
)))
462 GTree
*tree
= g_tree_new_with_data(clog_entry_sort_fn
, NULL
);
464 g_hash_table_destroy(dedup
);
468 clog_base_t
*res
= clog_new(maxsize
);
470 g_hash_table_destroy(dedup
);
471 g_tree_destroy(tree
);
475 g_mutex_lock(cl
->mutex
);
477 for (int i
= 0; i
< count
; i
++) {
478 if (i
== local_index
)
482 cfs_critical("log pointer is NULL!");
486 cpos
[i
] = clog
[i
]->cpos
;
487 if (clog
[i
]->size
> maxsize
)
488 maxsize
= clog
[i
]->size
;
492 maxsize
= res
->size
- sizeof(clog_base_t
) - CLOG_MAX_ENTRY_SIZE
;
500 /* select entry wit latest time */
501 for (int i
= 0; i
< count
; i
++) {
504 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
[i
] + cpos
[i
]);
505 if (cur
->time
> last
) {
514 clog_entry_t
*cur
= (clog_entry_t
*)((char *)clog
[found
] + cpos
[found
]);
516 if (!g_tree_lookup(tree
, cur
)) {
517 g_tree_insert(tree
, cur
, cur
);
518 dedup_lookup(dedup
, cur
); /* just to record versions */
519 logsize
+= cur
->next
- cpos
[found
];
520 if (logsize
>= maxsize
)
527 cpos
[found
] = cur
->prev
;
528 if (!(cpos
[found
] <= clog
[found
]->cpos
||
529 cpos
[found
] > (clog
[found
]->cpos
+ CLOG_MAX_ENTRY_SIZE
))) {
535 g_tree_foreach(tree
, clog_tree_foreach_fn
, res
);
536 g_tree_destroy(tree
);
538 g_hash_table_destroy(cl
->dedup
);
544 g_mutex_unlock(cl
->mutex
);
550 clusterlog_destroy(clusterlog_t
*cl
)
552 g_return_if_fail(cl
!= NULL
);
555 g_mutex_free(cl
->mutex
);
561 g_hash_table_destroy(cl
->dedup
);
569 clusterlog_t
*cl
= g_new0(clusterlog_t
, 1);
573 if (!(cl
->mutex
= g_mutex_new()))
576 if (!(cl
->base
= clog_new(0)))
579 if (!(cl
->dedup
= g_hash_table_new_full(g_int64_hash
, g_int64_equal
, NULL
, g_free
)))
585 clusterlog_destroy(cl
);
590 clusterlog_get_state(
592 unsigned int *res_len
)
594 g_return_val_if_fail(cl
!= NULL
, NULL
);
595 g_return_val_if_fail(res_len
!= NULL
, NULL
);
597 g_mutex_lock(cl
->mutex
);
600 if ((new = clog_sort(cl
->base
))) {
605 *res_len
= clog_size(cl
->base
);
606 gpointer msg
= g_memdup(cl
->base
, *res_len
);
608 g_mutex_unlock(cl
->mutex
);
616 const clog_entry_t
*entry
)
618 g_return_if_fail(cl
!= NULL
);
619 g_return_if_fail(entry
!= NULL
);
621 g_mutex_lock(cl
->mutex
);
623 if (dedup_lookup(cl
->dedup
, entry
)) {
624 clog_copy(cl
->base
, entry
);
626 cfs_message("ignore duplicate"); // fixme remove
629 g_mutex_unlock(cl
->mutex
);
642 g_return_if_fail(cl
!= NULL
);
643 g_return_if_fail(format
!= NULL
);
646 va_start (args
, format
);
647 char *msg
= g_strdup_vprintf (format
, args
);
650 time_t ctime
= time(NULL
);
651 clog_entry_t
*entry
= (clog_entry_t
*)alloca(CLOG_MAX_ENTRY_SIZE
);
652 uint32_t size
= clog_pack(entry
, cfs
.nodename
, ident
, tag
, pid
, ctime
, priority
, msg
);
658 clusterlog_insert(cl
, entry
);