src/n_nodup_log.c
generic no duplicate logging system More...
Functions
| Name | |
|---|---|
| char * | get_nodup_key(const char * file, const char * func, int line) internal, get a key for a log entry |
| char * | get_nodup_indexed_key(const char * file, const char * func, const char * prefix, int line) internal, get a key for an indexed log entry |
| int | check_n_log_dup_indexed(const char * log, const char * file, const char * func, int line, const char * prefix) check if a log was already done or not at the given line, func, file |
| int | check_n_log_dup(const char * log, const char * file, const char * func, int line) check if a log was already done or not at the given line, func, file |
Attributes
| Name | |
|---|---|
| HASH_TABLE * | _n_nodup_table internal: no dup hash_table log save |
Defines
| Name | |
|---|---|
| _GNU_SOURCE_WAS_NOT_DEFINED flag to detect if gnu source was set from our source file |
|
| _GNU_SOURCE Feature test macro. |
Detailed Description
generic no duplicate logging system
Author: Castagnier Mickael
Date: 2015-09-21
Functions Documentation
function get_nodup_key
static char * get_nodup_key(
const char * file,
const char * func,
int line
)
internal, get a key for a log entry
Parameters:
- file log source file
- func log source
- line log source
Return: The key for the the log entry
function get_nodup_indexed_key
static char * get_nodup_indexed_key(
const char * file,
const char * func,
const char * prefix,
int line
)
internal, get a key for an indexed log entry
Parameters:
- file log source file
- func log source
- line log source
- prefix prefix for log entry
Return: The key for the the log entry
function check_n_log_dup_indexed
int check_n_log_dup_indexed(
const char * log,
const char * file,
const char * func,
int line,
const char * prefix
)
check if a log was already done or not at the given line, func, file
Parameters:
- log the line of log
- file the file containing the log
- func the name of calling func
- line the line of the log
- prefix prefix to subgroup logs
Return: 0 if not existing 1 if existing with the same value , 2 if key exist and value is different
function check_n_log_dup
int check_n_log_dup(
const char * log,
const char * file,
const char * func,
int line
)
check if a log was already done or not at the given line, func, file
Parameters:
- log the line of log
- file the file containing the log
- func the name of calling func
- line the line of the log
Return: 0 if not existing 1 if existing with the same value , 2 if key exist and value is different
Attributes Documentation
variable _n_nodup_table
static HASH_TABLE * _n_nodup_table = NULL;
internal: no dup hash_table log save
Macros Documentation
define _GNU_SOURCE_WAS_NOT_DEFINED
#define _GNU_SOURCE_WAS_NOT_DEFINED
flag to detect if gnu source was set from our source file
define _GNU_SOURCE
#define _GNU_SOURCE
Feature test macro.
GNU source
Source code
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#define _GNU_SOURCE_WAS_NOT_DEFINED
#endif
#include <stdio.h>
#include <stdarg.h>
#ifdef _GNU_SOURCE_WAS_NOT_DEFINED
#undef _GNU_SOURCE
#endif
#include "nilorea/n_common.h"
#include "nilorea/n_log.h"
#include "nilorea/n_str.h"
#include "nilorea/n_list.h"
#include "nilorea/n_hash.h"
#include "nilorea/n_nodup_log.h"
static HASH_TABLE* _n_nodup_table = NULL;
int init_nodup_log(size_t max) {
if (_n_nodup_table != NULL) {
n_log(LOG_ERR, "Could not allocate the internal hash table because it's already done");
return FALSE;
}
if (max == 0)
max = 1024;
_n_nodup_table = new_ht(max);
if (_n_nodup_table == NULL) {
n_log(LOG_ERR, "Could not allocate the internal hash with size %zu", max);
return FALSE;
} else {
n_log(LOG_DEBUG, "LOGGING: nodup system activated with a hash table of %zu cells", max);
}
return TRUE;
} /* init_nodup_log() */
int empty_nodup_table() {
__n_assert(_n_nodup_table, return FALSE);
return empty_ht(_n_nodup_table);
} /* empty_nodup_table() */
int close_nodup_log() {
__n_assert(_n_nodup_table, return FALSE);
return destroy_ht(&_n_nodup_table);
} /* close_nodup_log() */
static char* get_nodup_key(const char* file, const char* func, int line) {
N_STR* nstr = NULL;
char* ptr = NULL;
nstrprintf(nstr, "%s%s%d", file, func, line);
__n_assert(nstr, return NULL);
ptr = nstr->data;
Free(nstr);
return ptr;
} /* get_nodup_key */
static char* get_nodup_indexed_key(const char* file, const char* func, const char* prefix, int line) {
N_STR* nstr = NULL;
char* ptr = NULL;
nstrprintf(nstr, "%s%s%s%d", file, func, prefix, line);
__n_assert(nstr, return NULL);
ptr = nstr->data;
Free(nstr);
return ptr;
} /* get_nodup_indexed_key */
int check_n_log_dup(const char* log, const char* file, const char* func, int line) {
const HASH_NODE* node = NULL;
char* key = NULL;
/* check if the nopdup session is on, else do a normal n_log */
if (!_n_nodup_table) {
return 3;
}
key = get_nodup_key(file, func, line);
__n_assert(key, return FALSE);
node = ht_get_node(_n_nodup_table, key);
Free(key);
if (node) {
if (strcmp(log, node->data.string) == 0) {
return 1;
}
return 2;
}
return 0;
} /* check_n_log_dup(...) */
int check_n_log_dup_indexed(const char* log, const char* file, const char* func, int line, const char* prefix) {
const HASH_NODE* node = NULL;
char* key = NULL;
/* check if the nopdup session is on, else do a normal n_log */
if (!_n_nodup_table) {
return 3;
}
key = get_nodup_indexed_key(file, func, prefix, line);
__n_assert(key, return FALSE);
node = ht_get_node(_n_nodup_table, key);
Free(key);
if (node) {
if (strcmp(log, node->data.string) == 0) {
return 1;
}
return 2;
}
return 0;
} /* check_nolog_dup_indexed() */
void _n_nodup_log(int LEVEL, const char* file, const char* func, int line, const char* format, ...) {
__n_assert(file, return);
__n_assert(func, return);
__n_assert(format, return);
HASH_NODE* node = NULL;
va_list args;
char* syslogbuffer = NULL;
va_start(args, format);
if (vasprintf(&syslogbuffer, format, args) == -1) {
int error = errno;
n_log(LOG_ERR, "=>%s:%s:%d unable to parse '%s', %s", file, func, line, format, strerror(error));
va_end(args);
syslogbuffer = NULL;
return;
}
va_end(args);
char* key = get_nodup_key(file, func, line);
int is_dup = check_n_log_dup(syslogbuffer, file, func, line);
switch (is_dup) {
/* new log entry for file,func,line */
case 0:
if (_n_nodup_table) {
ht_put_string(_n_nodup_table, key, syslogbuffer);
}
_n_log(LEVEL, file, func, line, "%s", syslogbuffer);
break;
/* exising and same log entry, do nothing (maybe latter we will add a timeout to repeat logging) */
case 1:
break;
/* existing but different entry. We have to refresh and log it one time*/
case 2:
node = ht_get_node(_n_nodup_table, key);
if (node) {
Free(node->data.string);
node->data.string = syslogbuffer;
syslogbuffer = NULL;
}
_n_log(LEVEL, file, func, line, "%s", node ? node->data.string : "");
break;
/* no nodup session started, normal loggin */
case 3:
default:
_n_log(LEVEL, file, func, line, "%s", syslogbuffer);
break;
}
Free(syslogbuffer);
Free(key);
} /* _n_nodup_log() */
void _n_nodup_log_indexed(int LEVEL, const char* prefix, const char* file, const char* func, int line, const char* format, ...) {
HASH_NODE* node = NULL;
va_list args;
char* syslogbuffer = NULL;
va_start(args, format);
if (vasprintf(&syslogbuffer, format, args) == -1) {
int error = errno;
n_log(LOG_ERR, "=>%s:%s:%d unable to parse '%s:%s', %s", file, func, line, prefix, format, strerror(error));
va_end(args);
syslogbuffer = NULL;
return;
}
va_end(args);
char* key = get_nodup_indexed_key(file, func, prefix, line);
int is_dup = check_n_log_dup_indexed(syslogbuffer, file, func, line, prefix);
switch (is_dup) {
/* new log entry for file,func,line */
case 0:
if (_n_nodup_table) {
ht_put_string(_n_nodup_table, key, syslogbuffer);
}
_n_log(LEVEL, file, func, line, "%s", syslogbuffer);
break;
/* exising and same log entry, do nothing (maybe latter we will add a timeout to repeat logging) */
case 1:
break;
/* existing but different entry. We have to refresh and log it one time*/
case 2:
node = ht_get_node(_n_nodup_table, key);
if (node) {
Free(node->data.string);
node->data.string = syslogbuffer;
syslogbuffer = NULL;
}
_n_log(LEVEL, file, func, line, "%s", node ? node->data.string : "");
break;
/* no nodup session started, normal loggin */
case 3:
default:
_n_log(LEVEL, file, func, line, "%s", syslogbuffer);
break;
}
Free(syslogbuffer);
Free(key);
} /* _n_nodup_log_indexed() */
int dump_nodup_log(char* file) {
FILE* out = NULL;
__n_assert(file, return FALSE);
__n_assert(_n_nodup_table, return FALSE);
char* tmpfile = NULL;
n_log(LOG_DEBUG, "outfile:%s", file);
strprintf(tmpfile, "%s.tmp", file);
if (!tmpfile) {
n_log(LOG_ERR, "could not create tmp file name from filename %s", _str(file));
return FALSE;
}
int fd = open(tmpfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd < 0) {
n_log(LOG_ERR, "could not create file %s with 0644 permissions", _str(tmpfile));
Free(tmpfile);
return FALSE;
}
out = fdopen(fd, "wb");
__n_assert(out, close(fd); Free(tmpfile); return FALSE);
if (_n_nodup_table) {
for (unsigned long int it = 0; it < _n_nodup_table->size; it++) {
list_foreach(list_node, _n_nodup_table->hash_table[it]) {
const HASH_NODE* hash_node = (const HASH_NODE*)list_node->ptr;
fprintf(out, "%s\n", hash_node->data.string);
}
}
}
fclose(out);
if (rename(tmpfile, file) != 0) {
int error = errno;
n_log(LOG_ERR, "could not rename '%s' to '%s' , %s", tmpfile, file,
strerror(error));
}
Free(tmpfile);
return TRUE;
} /* dump_nodup_log() */
Modules
- AABB3D
- ACCEPT_POOL
- ALLEGRO4
- ALLEGRO5
- ANIM_LIB
- ASTAR
- ATLAS_LIB
- AVRO
- CLOCK_SYNC
- COMMONS
- CONFIGFILE
- CYPHER_BASE64
- CYPHER_VIGENERE
- DEAD_RECKONING
- ENUMS
- EXCEPTIONS
- GAME_ENV
- GIT
- GUI
- HASH_TABLE
- ISOMETRIC_ENGINE
- LIST
- LOG
- LOGNODUP
- LZ4
- NETWORKING
- NETWORK_MSG
- N_COOKIES
- N_DIFF
- N_DIGEST
- N_DISK_CACHE
- N_DNS
- N_ECC
- N_ENTROPY
- N_FILES
- N_FLUIDS
- N_GUI_COLOR
- N_GUI_COLORWHEEL
- N_GUI_CURVE
- N_GUI_GRID
- N_GUI_POPUP
- N_HEX
- N_HTTP3
- N_HTTP_COOKIE
- N_HTTP_FORM
- N_HTTP_MIME
- N_HTTP_REQ
- N_HTTP_RESP
- N_HTTP_ROUTER
- N_HTTP_SERVER
- N_ICC
- N_JSON
- N_KAFKA
- N_LINALG
- N_MODULE
- N_OPENSSL_COMPAT
- N_PRETTY
- N_PTH
- N_QUERY
- N_RANDOM
- N_SHA256
- N_STR
- N_TIFF
- N_TIME
- N_USER
- N_X509
- N_ZIP
- PARTICLES
- PCRE
- PHYSICS
- SIGNALS
- STACK
- THREADS
- TRAJECTORY
- TREE
- ZLIB