Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions debug.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,21 @@ LOG.RDK.FOO=INFO

LOG.RDK.BAR = NONE
#ALL logs will be disabled for this module

##########################################################################
# Duplicate Log Suppression Configuration
#
# These settings control the duplicate log message suppression feature.
# When enabled, consecutive identical log messages are suppressed and
# a summary count is emitted when the suppression ends.
#
# LOG.RDK.DEDUP_ENABLED: 0 = disabled (default), 1 = enabled
# LOG.RDK.DEDUP_WINDOW_SEC: Time window in seconds before auto-flushing
# summary (default: 30)
# LOG.RDK.DEDUP_MAX_SUPPRESS: Maximum consecutive duplicates before
# forced flush (default: 1000)
##########################################################################

#LOG.RDK.DEDUP_ENABLED = 0
#LOG.RDK.DEDUP_WINDOW_SEC = 30
#LOG.RDK.DEDUP_MAX_SUPPRESS = 1000
2 changes: 1 addition & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

AM_CFLAGS = -pthread -Wall -Werror
lib_LTLIBRARIES = librdkloggers.la
librdkloggers_la_SOURCES = rdk_debug.c rdk_debug_priv.c rdk_dynamic_logger.c rdk_logger_init.c rdk_logger_milestone.c rdk_logger_onboard.c
librdkloggers_la_SOURCES = rdk_debug.c rdk_debug_priv.c rdk_dynamic_logger.c rdk_logger_init.c rdk_logger_milestone.c rdk_logger_onboard.c rdk_log_dedup.c
librdkloggers_la_CFLAGS = $(LOG4C_CFLAGS) $(GLIB_CFLAGS) $(SYSTEMD_CFLAGS) -I$(top_srcdir)/include -I$(top_srcdir)/src/include -DDEBUG_CONF_FILE="\"debug.ini\""
librdkloggers_la_LDFLAGS = $(GLIB_LIBS) $(LOG4C_LIBS) $(SYSTEMD_LIBS)

Expand Down
123 changes: 123 additions & 0 deletions src/include/rdk_log_dedup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
* Copyright 2024 RDK Management
*
* 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.
*/

#if !defined(_RDK_LOG_DEDUP_H)
#define _RDK_LOG_DEDUP_H

#include <stdint.h>
#include <stdbool.h>
#include <time.h>

#ifdef __cplusplus
extern "C"
{
#endif

/** Maximum number of tracked category slots for dedup state. */
#define RDK_DEDUP_TABLE_SIZE 256

/** Default dedup window in seconds. */
#define RDK_DEDUP_DEFAULT_WINDOW_SEC 30

/** Default max suppression count before forced flush. */
#define RDK_DEDUP_DEFAULT_MAX_SUPPRESS 1000

/**
* Configuration for the dedup engine.
* Parsed from debug.ini keys:
* LOG.RDK.DEDUP_ENABLED = 0|1
* LOG.RDK.DEDUP_WINDOW_SEC = <seconds>
* LOG.RDK.DEDUP_MAX_SUPPRESS = <count>
*/
typedef struct {
bool enabled; /**< Whether dedup is active */
uint32_t window_sec; /**< Time window before auto-flush of summary */
uint32_t max_suppress; /**< Max consecutive duplicates before forced flush */
} rdk_dedup_config_t;

/**
* Per-category dedup state slot.
*/
typedef struct {
const void *category_key; /**< log4c category pointer (used as hash key) */
uint32_t last_msg_hash; /**< FNV-1a hash of last formatted message */
uint32_t repeat_count; /**< Number of suppressed duplicates */
time_t first_seen; /**< Timestamp when first duplicate was seen */
int last_level; /**< Log level of suppressed message (log4c priority) */
Comment on lines +60 to +62
} rdk_dedup_slot_t;

/**
* Initialize the dedup engine with default configuration.
* Must be called once during logger init (from rdk_dbg_priv_init).
*/
void rdk_dedup_init(void);

/**
* Update dedup configuration. Called when debug.ini is parsed.
* @param config New configuration values.
*/
void rdk_dedup_set_config(const rdk_dedup_config_t *config);

/**
* Get current dedup configuration (read-only).
*/
const rdk_dedup_config_t* rdk_dedup_get_config(void);

/**
* Check if a message should be suppressed.
*
* MUST be called under gLoggingMutex.
*
* @param category_key Opaque pointer identifying the category (log4c_category_t*).
* @param log4c_prio The log4c priority level of the message.
* @param format The format string of the log message.
* @param args The va_list arguments (used for hashing the formatted message).
* @return true if the message should be suppressed (duplicate), false if it should be logged.
*
* Side effects: If returning false after a suppression run, emits a summary
* message via the provided category before returning.
*/
Comment on lines +93 to +95
bool rdk_dedup_check(const void *category_key, int log4c_prio,
const char *format, va_list args);

/**
* Flush any pending dedup summary for a category (e.g., on window expiry).
* MUST be called under gLoggingMutex.
* @param category_key The category to flush.
*/
void rdk_dedup_flush(const void *category_key);

/**
* Flush all pending dedup summaries. Called during deinit.
* MUST be called under gLoggingMutex.
*/
void rdk_dedup_flush_all(void);

/**
* Compute FNV-1a 32-bit hash of a string.
* @param str Null-terminated string to hash.
* @return 32-bit hash value.
*/
uint32_t rdk_dedup_fnv1a_hash(const char *str);

#ifdef __cplusplus
}
#endif

#endif /* _RDK_LOG_DEDUP_H */
38 changes: 37 additions & 1 deletion src/rdk_debug_priv.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

#include "rdk_debug_priv.h"
#include "rdk_dynamic_logger.h"
#include "rdk_log_dedup.h"
#include "log4c.h"
#include <log4c/appender_type_rollingfile.h>
#include <log4c/rollingpolicy.h>
Expand Down Expand Up @@ -307,6 +308,34 @@ rdk_Error rdk_logger_parse_config( const char * path)
}
}
}

/* Parse dedup configuration keys */
Comment on lines 308 to +312
if (strcmp("LOG.RDK.DEDUP_ENABLED", trimname) == 0)
{
rdk_dedup_config_t cfg = *rdk_dedup_get_config();
cfg.enabled = (atoi(trimvalue) != 0);
rdk_dedup_set_config(&cfg);
}
else if (strcmp("LOG.RDK.DEDUP_WINDOW_SEC", trimname) == 0)
{
rdk_dedup_config_t cfg = *rdk_dedup_get_config();
int val = atoi(trimvalue);
if (val > 0)
{
cfg.window_sec = (uint32_t)val;
rdk_dedup_set_config(&cfg);
}
}
else if (strcmp("LOG.RDK.DEDUP_MAX_SUPPRESS", trimname) == 0)
{
rdk_dedup_config_t cfg = *rdk_dedup_get_config();
int val = atoi(trimvalue);
if (val > 0)
{
cfg.max_suppress = (uint32_t)val;
rdk_dedup_set_config(&cfg);
}
}
}

fclose( f);
Expand Down Expand Up @@ -345,6 +374,9 @@ void rdk_dbg_priv_init(void)
if (NULL != legacy)
(void) log4c_layout_set_type(legacy, &log4c_layout_type_comcast_dated);

/* Initialize the duplicate log suppression engine */
rdk_dedup_init();

isInited = true;
}

Expand Down Expand Up @@ -649,7 +681,11 @@ void rdk_dbg_priv_log_msg(rdk_LogLevel level, const char *module_name, const cha
int log4cPriority = rdk_logLevel_to_log4c_priority(level);
if (log4c_category_is_priority_enabled(cat, log4cPriority))
{
log4c_category_vlog(cat, log4cPriority, format, args);
/* Check for duplicate suppression before dispatching */
if (!rdk_dedup_check((const void *)cat, log4cPriority, format, args))
{
log4c_category_vlog(cat, log4cPriority, format, args);
}
}
}
pthread_mutex_unlock(&gLoggingMutex);
Expand Down
Loading
Loading