From: Michael Jeanson Date: Wed, 2 Feb 2022 20:04:09 +0000 (+0000) Subject: Add a Log4j 2.x agent specific domain 'log4j2' X-Git-Url: http://git.lttng.org./?a=commitdiff_plain;h=47abf22b48023960069e1d3e23f42298ce4b3c2a;p=lttng-tools.git Add a Log4j 2.x agent specific domain 'log4j2' The initial version of the new LTTng-UST Log4j 2.x agent only operated in a compatibility mode making use of the existing 'log4j' tracing domain currently implemented in LTTng-Tools. While this is useful when migrating existing Log4j applications using the compatibility bridge it does require converting the log levels from the new Log4j 2.x values to the old Log4j 1.x standard. This results in hiding the actual log level values from the users for applications natively using Log4j 2.x. Exposing the native Log4j 2.x log level values requires a new domain since the changes are significant: * The same list of standard log levels and names * Each standard log level has a new integer value * The log levels scale is reversed and shortened from 'int32_max -> int32_min' to '0 -> int32_max' * The interval between standard log levels has changed This new 'log4j2' domain is basicaly a straight copy of the current 'log4j' domain with minor adjustements for the reversed and shortened scale. Change-Id: I89f9c0a428ffe1d0bd26f7af547e9e21503de653 Signed-off-by: Michael Jeanson Signed-off-by: Jérémie Galarneau --- diff --git a/include/Makefile.am b/include/Makefile.am index a2d6a5cf0..0ce426826 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -160,6 +160,7 @@ lttngeventruleinclude_HEADERS= \ lttng/event-rule/kernel-tracepoint.h \ lttng/event-rule/kernel-uprobe.h \ lttng/event-rule/log4j-logging.h \ + lttng/event-rule/log4j2-logging.h \ lttng/event-rule/python-logging.h \ lttng/event-rule/user-tracepoint.h @@ -193,6 +194,7 @@ noinst_HEADERS = \ lttng/event-rule/kernel-tracepoint-internal.hpp \ lttng/event-rule/kernel-uprobe-internal.hpp \ lttng/event-rule/log4j-logging-internal.hpp \ + lttng/event-rule/log4j2-logging-internal.hpp \ lttng/event-rule/python-logging-internal.hpp \ lttng/event-rule/user-tracepoint-internal.hpp \ lttng/health-internal.hpp \ diff --git a/include/lttng/domain.h b/include/lttng/domain.h index da19ebf1c..0c0335e2e 100644 --- a/include/lttng/domain.h +++ b/include/lttng/domain.h @@ -37,11 +37,14 @@ enum lttng_domain_type { /// java.util.logging (JUL). LTTNG_DOMAIN_JUL = 3, - /// Apache log4j. + /// Apache Log4j 1.x. LTTNG_DOMAIN_LOG4J = 4, /// Python logging. LTTNG_DOMAIN_PYTHON = 5, + + /// Apache Log4j 2. + LTTNG_DOMAIN_LOG4J2 = 6, }; /*! diff --git a/include/lttng/event-rule/event-rule.h b/include/lttng/event-rule/event-rule.h index a75db771e..78a34ab16 100644 --- a/include/lttng/event-rule/event-rule.h +++ b/include/lttng/event-rule/event-rule.h @@ -26,6 +26,7 @@ enum lttng_event_rule_type { LTTNG_EVENT_RULE_TYPE_JUL_LOGGING = 5, LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING = 6, LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING = 7, + LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING = 8, }; enum lttng_event_rule_status { diff --git a/include/lttng/event-rule/jul-logging-internal.hpp b/include/lttng/event-rule/jul-logging-internal.hpp index c84ab7a7f..b6ddc3644 100644 --- a/include/lttng/event-rule/jul-logging-internal.hpp +++ b/include/lttng/event-rule/jul-logging-internal.hpp @@ -17,6 +17,8 @@ #include #include +#define LTTNG_JUL_EVENT_RULE_AT_LEAST_AS_SEVERE_AS_OP ">=" + struct lttng_event_rule_jul_logging { struct lttng_event_rule parent; diff --git a/include/lttng/event-rule/log4j-logging-internal.hpp b/include/lttng/event-rule/log4j-logging-internal.hpp index 239bf98ee..31b2e9e2e 100644 --- a/include/lttng/event-rule/log4j-logging-internal.hpp +++ b/include/lttng/event-rule/log4j-logging-internal.hpp @@ -17,6 +17,8 @@ #include #include +#define LTTNG_LOG4J_EVENT_RULE_AT_LEAST_AS_SEVERE_AS_OP ">=" + struct lttng_event_rule_log4j_logging { struct lttng_event_rule parent; diff --git a/include/lttng/event-rule/log4j2-logging-internal.hpp b/include/lttng/event-rule/log4j2-logging-internal.hpp new file mode 100644 index 000000000..5358ed3dd --- /dev/null +++ b/include/lttng/event-rule/log4j2-logging-internal.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 Michael Jeanson + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_EVENT_RULE_LOG4J2_LOGGING_INTERNAL_H +#define LTTNG_EVENT_RULE_LOG4J2_LOGGING_INTERNAL_H + +#include +#include +#include + +#include +#include +#include +#include + +#define LTTNG_LOG4J2_EVENT_RULE_AT_LEAST_AS_SEVERE_AS_OP "<=" + +struct lttng_event_rule_log4j2_logging { + struct lttng_event_rule parent; + + /* Name pattern. */ + char *pattern; + + /* Filter. */ + char *filter_expression; + + /* Log level. */ + struct lttng_log_level_rule *log_level_rule; + + /* internal use only. */ + struct { + char *filter; + struct lttng_bytecode *bytecode; + } internal_filter; +}; + +struct lttng_event_rule_log4j2_logging_comm { + /* Includes terminator `\0`. */ + uint32_t pattern_len; + /* Includes terminator `\0`. */ + uint32_t filter_expression_len; + /* enum lttng_log_level_rule_comm + payload if any */ + uint32_t log_level_rule_len; + /* + * Payload is composed of, in that order: + * - pattern (null terminated), + * - filter expression (null terminated), + * - log level rule serialized object, + */ + char payload[]; +} LTTNG_PACKED; + +ssize_t lttng_event_rule_log4j2_logging_create_from_payload(struct lttng_payload_view *view, + struct lttng_event_rule **rule); + +#endif /* LTTNG_EVENT_RULE_LOG4J2_LOGGING_INTERNAL_H */ diff --git a/include/lttng/event-rule/log4j2-logging.h b/include/lttng/event-rule/log4j2-logging.h new file mode 100644 index 000000000..fc942c72b --- /dev/null +++ b/include/lttng/event-rule/log4j2-logging.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2024 Michael Jeanson + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_EVENT_RULE_LOG4J2_LOGGING_H +#define LTTNG_EVENT_RULE_LOG4J2_LOGGING_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Create a newly allocated log4j2 logging event rule. + * + * The default name pattern is '*'. + * + * Returns a new event rule on success, NULL on failure. This event rule must be + * destroyed using lttng_event_rule_destroy(). + */ +LTTNG_EXPORT extern struct lttng_event_rule *lttng_event_rule_log4j2_logging_create(void); + +/* + * Set the name pattern of a log4j2 logging event rule. + * + * Pattern can contain wildcard '*'. See man lttng-enable-event. + * + * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID + * if invalid parameters are passed. + */ +LTTNG_EXPORT extern enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_set_name_pattern(struct lttng_event_rule *rule, + const char *pattern); + +/* + * Get the name pattern of a log4j2 logging event rule. + * + * The caller does not assume the ownership of the returned pattern. The + * pattern shall only only be used for the duration of the event rule's + * lifetime, or before a different pattern is set. + * + * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's pattern + * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid + * parameter is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a pattern + * was not set prior to this call. + */ +LTTNG_EXPORT extern enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_get_name_pattern(const struct lttng_event_rule *rule, + const char **pattern); + +/* + * Set the filter expression of a log4j2 logging event rule. + * + * The expression is copied internally. + * + * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID + * if invalid parameters are passed. + */ +LTTNG_EXPORT extern enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_set_filter(struct lttng_event_rule *rule, const char *expression); + +/* + * Get the filter expression of a log4j2 logging event rule. + * + * The caller does not assume the ownership of the returned filter expression. + * The filter expression shall only only be used for the duration of the event + * rule's lifetime, or before a different filter expression is set. + * + * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's filter + * expression on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid + * parameter is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a filter expression + * was not set prior to this call. + */ +LTTNG_EXPORT extern enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_get_filter(const struct lttng_event_rule *rule, + const char **expression); + +/* + * Set the log level rule of a log4j2 logging event rule. + * + * The log level rule is copied internally. + * + * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID + * if invalid parameters are passed. + */ +LTTNG_EXPORT extern enum lttng_event_rule_status lttng_event_rule_log4j2_logging_set_log_level_rule( + struct lttng_event_rule *rule, const struct lttng_log_level_rule *log_level_rule); + +/* + * Get the log level rule of a log4j2 logging event rule. + * + * The caller does not assume the ownership of the returned log level rule. The + * log level rule shall only only be used for the duration of the event rule's + * lifetime, or before a different log level rule is set. + * + * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the log level rule output + * parameter on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter + * is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a log level rule was not set prior + * to this call. + */ +LTTNG_EXPORT extern enum lttng_event_rule_status lttng_event_rule_log4j2_logging_get_log_level_rule( + const struct lttng_event_rule *rule, const struct lttng_log_level_rule **log_level_rule); + +#ifdef __cplusplus +} +#endif + +#endif /* LTTNG_EVENT_RULE_LOG4J2_LOGGING_H */ diff --git a/include/lttng/event.h b/include/lttng/event.h index 64bd2ad23..397ac6344 100644 --- a/include/lttng/event.h +++ b/include/lttng/event.h @@ -202,7 +202,7 @@ enum lttng_loglevel_jul { Value of the \ref api-rer-conds-ll "instrumentation point log level condition" of an - \link #LTTNG_DOMAIN_LOG4J Apache log4j\endlink + \link #LTTNG_DOMAIN_LOG4J Apache Log4j 1.x\endlink recording event rule. @ingroup api_rer @@ -251,6 +251,60 @@ enum lttng_loglevel_log4j { LTTNG_LOGLEVEL_LOG4J_ALL = INT32_MIN, }; +/*! +@brief + Value of the + \ref api-rer-conds-ll "instrumentation point log level condition" + of a + \link #LTTNG_DOMAIN_LOG4J2 Apache Log4j 2\endlink + recording event rule. + +@ingroup api_rer + +@sa #lttng_loglevel_type -- + Operand of the log level condition of a recording event rule. +*/ +enum lttng_loglevel_log4j2 { + /// Logging turned off. + LTTNG_LOGLEVEL_LOG4J2_OFF = 0, + + /*! + Very severe error events that will presumably lead the + application to abort. + */ + LTTNG_LOGLEVEL_LOG4J2_FATAL = 100, + + /*! + Error events that might still allow the application to continue + running. + */ + LTTNG_LOGLEVEL_LOG4J2_ERROR = 200, + + /// Potentially harmful situations. + LTTNG_LOGLEVEL_LOG4J2_WARN = 300, + + /*! + Informational messages that highlight the progress of the + application at coarse-grained level. + */ + LTTNG_LOGLEVEL_LOG4J2_INFO = 400, + + /*! + Fine-grained informational events that are most useful to debug + an application. + */ + LTTNG_LOGLEVEL_LOG4J2_DEBUG = 500, + + /*! + Finer-grained informational events than the + #LTTNG_LOGLEVEL_LOG4J2_DEBUG level. + */ + LTTNG_LOGLEVEL_LOG4J2_TRACE = 600, + + /// All levels, including custom levels. + LTTNG_LOGLEVEL_LOG4J2_ALL = INT32_MAX, +}; + /*! @brief Value of the diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 6ae331bda..7c63e6335 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bin/lttng-sessiond/agent-thread.cpp b/src/bin/lttng-sessiond/agent-thread.cpp index 82c74b10a..9b5a5b569 100644 --- a/src/bin/lttng-sessiond/agent-thread.cpp +++ b/src/bin/lttng-sessiond/agent-thread.cpp @@ -216,6 +216,8 @@ static const char *domain_type_str(enum lttng_domain_type domain_type) return "jul"; case LTTNG_DOMAIN_LOG4J: return "log4j"; + case LTTNG_DOMAIN_LOG4J2: + return "log4j2"; case LTTNG_DOMAIN_PYTHON: return "python"; default: diff --git a/src/bin/lttng-sessiond/agent.cpp b/src/bin/lttng-sessiond/agent.cpp index 4be1c32fc..2beb7e9aa 100644 --- a/src/bin/lttng-sessiond/agent.cpp +++ b/src/bin/lttng-sessiond/agent.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1257,6 +1258,10 @@ struct agent_event *agent_find_event_by_trigger(const struct lttng_trigger *trig logging_get_name_pattern = lttng_event_rule_log4j_logging_get_name_pattern; logging_get_log_level_rule = lttng_event_rule_log4j_logging_get_log_level_rule; break; + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + logging_get_name_pattern = lttng_event_rule_log4j2_logging_get_name_pattern; + logging_get_log_level_rule = lttng_event_rule_log4j2_logging_get_log_level_rule; + break; case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: logging_get_name_pattern = lttng_event_rule_python_logging_get_name_pattern; logging_get_log_level_rule = lttng_event_rule_python_logging_get_log_level_rule; @@ -1268,7 +1273,7 @@ struct agent_event *agent_find_event_by_trigger(const struct lttng_trigger *trig domain = lttng_event_rule_get_domain_type(rule); LTTNG_ASSERT(domain == LTTNG_DOMAIN_JUL || domain == LTTNG_DOMAIN_LOG4J || - domain == LTTNG_DOMAIN_PYTHON); + domain == LTTNG_DOMAIN_LOG4J2 || domain == LTTNG_DOMAIN_PYTHON); /* Get the event's pattern name ('name' in the legacy terminology). */ er_status = logging_get_name_pattern(rule, &name); diff --git a/src/bin/lttng-sessiond/channel.cpp b/src/bin/lttng-sessiond/channel.cpp index 77c073e2c..5bc446701 100644 --- a/src/bin/lttng-sessiond/channel.cpp +++ b/src/bin/lttng-sessiond/channel.cpp @@ -70,6 +70,9 @@ struct lttng_channel *channel_new_default_attr(int dom, enum lttng_buffer_type t case LTTNG_DOMAIN_LOG4J: channel_name = DEFAULT_LOG4J_CHANNEL_NAME; goto common_ust; + case LTTNG_DOMAIN_LOG4J2: + channel_name = DEFAULT_LOG4J2_CHANNEL_NAME; + goto common_ust; case LTTNG_DOMAIN_PYTHON: channel_name = DEFAULT_PYTHON_CHANNEL_NAME; goto common_ust; @@ -346,6 +349,8 @@ enum lttng_error_code channel_ust_create(struct ltt_ust_session *usess, domain = LTTNG_DOMAIN_JUL; } else if (!strcmp(attr->name, DEFAULT_LOG4J_CHANNEL_NAME)) { domain = LTTNG_DOMAIN_LOG4J; + } else if (!strcmp(attr->name, DEFAULT_LOG4J2_CHANNEL_NAME)) { + domain = LTTNG_DOMAIN_LOG4J2; } else if (!strcmp(attr->name, DEFAULT_PYTHON_CHANNEL_NAME)) { domain = LTTNG_DOMAIN_PYTHON; } diff --git a/src/bin/lttng-sessiond/client.cpp b/src/bin/lttng-sessiond/client.cpp index db9442b8e..310b79f8b 100644 --- a/src/bin/lttng-sessiond/client.cpp +++ b/src/bin/lttng-sessiond/client.cpp @@ -448,6 +448,7 @@ static int copy_session_consumer(int domain, const ltt_session::locked_ref& sess break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_UST: DBG3("Copying tracing session consumer output in UST session"); @@ -492,6 +493,7 @@ static int create_ust_session(const ltt_session::locked_ref& session, switch (domain->type) { case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_UST: break; @@ -1180,6 +1182,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, int *sock_ break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_UST: if (!(*target_session)->ust_session) { @@ -1263,6 +1266,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, int *sock_ break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: if (!agent_tracing_is_enabled()) { ret = LTTNG_ERR_AGENT_TRACING_DISABLED; @@ -1368,6 +1372,7 @@ skip_domain: break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_UST: if (uatomic_read(&the_ust_consumerd_state) != CONSUMER_STARTED) { diff --git a/src/bin/lttng-sessiond/cmd.cpp b/src/bin/lttng-sessiond/cmd.cpp index e2f10d2a3..f1b29da9c 100644 --- a/src/bin/lttng-sessiond/cmd.cpp +++ b/src/bin/lttng-sessiond/cmd.cpp @@ -1384,6 +1384,7 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: if (!agent_tracing_is_enabled()) { DBG("Attempted to enable a channel in an agent domain but the agent thread is not running"); @@ -1434,6 +1435,7 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref case LTTNG_DOMAIN_UST: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: { struct ltt_ust_channel *uchan; @@ -1460,6 +1462,13 @@ static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME; goto error; } + } else if (domain->type == LTTNG_DOMAIN_LOG4J2) { + if (strncmp(attr->name, + DEFAULT_LOG4J2_CHANNEL_NAME, + LTTNG_SYMBOL_NAME_LEN - 1) != 0) { + ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME; + goto error; + } } else if (domain->type == LTTNG_DOMAIN_PYTHON) { if (strncmp(attr->name, DEFAULT_PYTHON_CHANNEL_NAME, @@ -1848,6 +1857,7 @@ int cmd_disable_event(struct command_ctx *cmd_ctx, break; } case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_PYTHON: { @@ -1942,6 +1952,7 @@ int cmd_add_context(struct command_ctx *cmd_ctx, break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: { /* * Validate channel name. @@ -1958,6 +1969,10 @@ int cmd_add_context(struct command_ctx *cmd_ctx, strcmp(channel_name, DEFAULT_LOG4J_CHANNEL_NAME) != 0) { ret = LTTNG_ERR_UST_CHAN_NOT_FOUND; goto error; + } else if (domain == LTTNG_DOMAIN_LOG4J2 && *channel_name && + strcmp(channel_name, DEFAULT_LOG4J2_CHANNEL_NAME) != 0) { + ret = LTTNG_ERR_UST_CHAN_NOT_FOUND; + goto error; } } /* fall through */ @@ -2046,6 +2061,7 @@ static int validate_ust_event_name(const char *name) */ if (name_starts_with(name, DEFAULT_JUL_EVENT_COMPONENT) || name_starts_with(name, DEFAULT_LOG4J_EVENT_COMPONENT) || + name_starts_with(name, DEFAULT_LOG4J2_EVENT_COMPONENT) || name_starts_with(name, DEFAULT_PYTHON_EVENT_COMPONENT)) { ret = -1; } @@ -2304,6 +2320,7 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session, break; } case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_PYTHON: { @@ -2356,6 +2373,9 @@ static int _cmd_enable_event(ltt_session::locked_ref& locked_session, case LTTNG_DOMAIN_LOG4J: default_chan_name = DEFAULT_LOG4J_CHANNEL_NAME; break; + case LTTNG_DOMAIN_LOG4J2: + default_chan_name = DEFAULT_LOG4J2_CHANNEL_NAME; + break; case LTTNG_DOMAIN_JUL: default_chan_name = DEFAULT_JUL_CHANNEL_NAME; break; @@ -2547,6 +2567,7 @@ enum lttng_error_code cmd_list_tracepoints(enum lttng_domain_type domain, } break; case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_PYTHON: nb_events = agent_list_events(&events, domain); @@ -3907,6 +3928,7 @@ enum lttng_error_code cmd_list_events(enum lttng_domain_type domain, break; } case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_PYTHON: if (session->ust_session) { @@ -4475,6 +4497,7 @@ synchronize_tracer_notifier_register(struct notification_thread_handle *notifica break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: { /* Agent domains. */ @@ -4630,6 +4653,7 @@ synchronize_tracer_notifier_unregister(const struct lttng_trigger *trigger) break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: { /* Agent domains. */ diff --git a/src/bin/lttng-sessiond/context.cpp b/src/bin/lttng-sessiond/context.cpp index 153465c66..9a098841c 100644 --- a/src/bin/lttng-sessiond/context.cpp +++ b/src/bin/lttng-sessiond/context.cpp @@ -119,6 +119,7 @@ static int add_uctx_to_channel(struct ltt_ust_session *usess, switch (domain) { case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: { struct agent *agt; diff --git a/src/bin/lttng-sessiond/event-notifier-error-accounting.cpp b/src/bin/lttng-sessiond/event-notifier-error-accounting.cpp index 447585f7d..512440c3b 100644 --- a/src/bin/lttng-sessiond/event-notifier-error-accounting.cpp +++ b/src/bin/lttng-sessiond/event-notifier-error-accounting.cpp @@ -1073,6 +1073,7 @@ event_notifier_error_accounting_register_event_notifier(const struct lttng_trigg case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: state = &ust_state; break; default: @@ -1123,6 +1124,7 @@ event_notifier_error_accounting_register_event_notifier(const struct lttng_trigg case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: pthread_mutex_lock(&the_event_notifier_counter.lock); the_event_notifier_counter.count++; if (the_event_notifier_counter.count == 1) { @@ -1211,6 +1213,7 @@ event_notifier_error_accounting_get_count(const struct lttng_trigger *trigger, u case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: #ifdef HAVE_LIBLTTNG_UST_CTL return event_notifier_error_accounting_ust_get_count(trigger, count); #else @@ -1232,6 +1235,7 @@ event_notifier_error_accounting_clear(const struct lttng_trigger *trigger) case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: #ifdef HAVE_LIBLTTNG_UST_CTL return event_notifier_error_accounting_ust_clear(trigger); #else @@ -1276,6 +1280,7 @@ void event_notifier_error_accounting_unregister_event_notifier(const struct lttn case LTTNG_DOMAIN_PYTHON: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: state = &ust_state; pthread_mutex_lock(&the_event_notifier_counter.lock); diff --git a/src/bin/lttng-sessiond/event.cpp b/src/bin/lttng-sessiond/event.cpp index 6d4dd6c26..0371b27b5 100644 --- a/src/bin/lttng-sessiond/event.cpp +++ b/src/bin/lttng-sessiond/event.cpp @@ -598,6 +598,7 @@ int trigger_agent_enable(const struct lttng_trigger *trigger, struct agent *agt) switch (lttng_event_rule_get_type(rule)) { case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: break; default: @@ -663,6 +664,9 @@ const char *event_get_default_agent_ust_name(enum lttng_domain_type domain) case LTTNG_DOMAIN_LOG4J: default_event_name = DEFAULT_LOG4J_EVENT_NAME; break; + case LTTNG_DOMAIN_LOG4J2: + default_event_name = DEFAULT_LOG4J2_EVENT_NAME; + break; case LTTNG_DOMAIN_JUL: default_event_name = DEFAULT_JUL_EVENT_NAME; break; @@ -749,6 +753,8 @@ static int event_agent_disable_one(struct ltt_ust_session *usess, ust_channel_name = DEFAULT_JUL_CHANNEL_NAME; } else if (agt->domain == LTTNG_DOMAIN_LOG4J) { ust_channel_name = DEFAULT_LOG4J_CHANNEL_NAME; + } else if (agt->domain == LTTNG_DOMAIN_LOG4J2) { + ust_channel_name = DEFAULT_LOG4J2_CHANNEL_NAME; } else if (agt->domain == LTTNG_DOMAIN_PYTHON) { ust_channel_name = DEFAULT_PYTHON_CHANNEL_NAME; } else { diff --git a/src/bin/lttng-sessiond/save.cpp b/src/bin/lttng-sessiond/save.cpp index 715325a4a..6c6339c36 100644 --- a/src/bin/lttng-sessiond/save.cpp +++ b/src/bin/lttng-sessiond/save.cpp @@ -1725,6 +1725,9 @@ static const char *get_config_domain_str(enum lttng_domain_type domain) case LTTNG_DOMAIN_LOG4J: str_dom = config_domain_type_log4j; break; + case LTTNG_DOMAIN_LOG4J2: + str_dom = config_domain_type_log4j2; + break; case LTTNG_DOMAIN_PYTHON: str_dom = config_domain_type_python; break; @@ -1798,6 +1801,7 @@ static int save_process_attr_tracker(struct config_writer *writer, } case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: default: ret = LTTNG_ERR_UNSUPPORTED_DOMAIN; @@ -2148,6 +2152,11 @@ static int save_domains(struct config_writer *writer, const ltt_session::locked_ goto end; } + ret = save_ust_domain(writer, session, LTTNG_DOMAIN_LOG4J2); + if (ret != LTTNG_OK) { + goto end; + } + ret = save_ust_domain(writer, session, LTTNG_DOMAIN_PYTHON); if (ret != LTTNG_OK) { goto end; diff --git a/src/bin/lttng-sessiond/trace-ust.hpp b/src/bin/lttng-sessiond/trace-ust.hpp index 778870717..3ae9c09aa 100644 --- a/src/bin/lttng-sessiond/trace-ust.hpp +++ b/src/bin/lttng-sessiond/trace-ust.hpp @@ -61,7 +61,7 @@ struct ltt_ust_channel { bool enabled; /* * A UST channel can be part of a userspace sub-domain such as JUL, - * Log4j, Python. + * Log4j, Log4j2, Python. */ enum lttng_domain_type domain; char name[LTTNG_UST_ABI_SYM_NAME_LEN]; diff --git a/src/bin/lttng-sessiond/ust-app.cpp b/src/bin/lttng-sessiond/ust-app.cpp index 217d5622e..802b593dc 100644 --- a/src/bin/lttng-sessiond/ust-app.cpp +++ b/src/bin/lttng-sessiond/ust-app.cpp @@ -2240,6 +2240,7 @@ static int create_ust_event_notifier(struct ust_app *app, LTTNG_ASSERT(event_rule_type == LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT || event_rule_type == LTTNG_EVENT_RULE_TYPE_JUL_LOGGING || event_rule_type == LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING || + event_rule_type == LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING || event_rule_type == LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING); init_ust_event_notifier_from_event_rule(event_rule, &event_notifier); diff --git a/src/bin/lttng/commands/add_context.cpp b/src/bin/lttng/commands/add_context.cpp index 3a0613bd0..497a12065 100644 --- a/src/bin/lttng/commands/add_context.cpp +++ b/src/bin/lttng/commands/add_context.cpp @@ -29,6 +29,7 @@ static int opt_kernel; static int opt_userspace; static int opt_jul; static int opt_log4j; +static int opt_log4j2; static char *opt_type; #ifdef LTTNG_EMBED_HELP @@ -43,6 +44,7 @@ enum { OPT_USERSPACE, OPT_JUL, OPT_LOG4J, + OPT_LOG4J2, OPT_LIST_OPTIONS, OPT_LIST, }; @@ -175,6 +177,7 @@ static struct poptOption long_options[] = { { "userspace", 'u', POPT_ARG_NONE, nullptr, OPT_USERSPACE, nullptr, nullptr }, { "jul", 'j', POPT_ARG_NONE, nullptr, OPT_JUL, nullptr, nullptr }, { "log4j", 'l', POPT_ARG_NONE, nullptr, OPT_LOG4J, nullptr, nullptr }, + { "log4j2", 0, POPT_ARG_NONE, nullptr, OPT_LOG4J2, nullptr, nullptr }, { "type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, nullptr, nullptr }, { "list", 0, POPT_ARG_NONE, nullptr, OPT_LIST, nullptr, nullptr }, { "list-options", 0, POPT_ARG_NONE, nullptr, OPT_LIST_OPTIONS, nullptr, nullptr }, @@ -514,6 +517,8 @@ static enum lttng_domain_type get_domain() return LTTNG_DOMAIN_JUL; } else if (opt_log4j) { return LTTNG_DOMAIN_LOG4J; + } else if (opt_log4j2) { + return LTTNG_DOMAIN_LOG4J2; } else { abort(); } @@ -1081,6 +1086,9 @@ int cmd_add_context(int argc, const char **argv) case OPT_LOG4J: opt_log4j = 1; break; + case OPT_LOG4J2: + opt_log4j2 = 1; + break; case OPT_LIST_OPTIONS: list_cmd_options(stdout, long_options); goto end; @@ -1097,8 +1105,8 @@ int cmd_add_context(int argc, const char **argv) goto end; } - ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace + opt_jul + opt_log4j, - true); + ret = print_missing_or_multiple_domains( + opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_log4j2, true); if (ret) { ret = CMD_ERROR; goto end; diff --git a/src/bin/lttng/commands/add_trigger.cpp b/src/bin/lttng/commands/add_trigger.cpp index fa20cda61..a733bf57e 100644 --- a/src/bin/lttng/commands/add_trigger.cpp +++ b/src/bin/lttng/commands/add_trigger.cpp @@ -122,6 +122,8 @@ static bool assign_event_rule_type(enum lttng_event_rule_type *dest, const char *dest = LTTNG_EVENT_RULE_TYPE_JUL_LOGGING; } else if (strcmp(arg, "log4j") == 0 || strcmp(arg, "log4j:logging") == 0) { *dest = LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING; + } else if (strcmp(arg, "log4j2") == 0 || strcmp(arg, "log4j2:logging") == 0) { + *dest = LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING; } else if (strcmp(arg, "python") == 0 || strcmp(arg, "python:logging") == 0) { *dest = LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING; } else if (strcmp(arg, "kprobe") == 0 || strcmp(arg, "kernel:kprobe") == 0) { @@ -266,6 +268,23 @@ static bool parse_log_level_string(const char *str, *log_level_only = log_level_min == log_level_max; break; } + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + { + enum lttng_loglevel_log4j2 log_level_min, log_level_max; + if (!loglevel_log4j2_parse_range_string(str, &log_level_min, &log_level_max)) { + goto error; + } + + /* Only support VAL and VAL.. for now. */ + if (log_level_min != log_level_max && + log_level_max != LTTNG_LOGLEVEL_LOG4J2_FATAL) { + goto error; + } + + *log_level = (int) log_level_min; + *log_level_only = log_level_min == log_level_max; + break; + } case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: { enum lttng_loglevel_jul log_level_min, log_level_max; @@ -788,14 +807,15 @@ static struct parse_event_rule_res parse_event_rule(int *argc, const char ***arg /* * Option --name is applicable to event rules of type kernel, user, jul, - * log4j,python and syscall. If --name is omitted, it is implicitly - * "*". + * log4j, log4j2, python and syscall. If --name is omitted, it is + * implicitly "*". */ switch (event_rule_type) { case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT: case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT: case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL: if (!name) { @@ -872,6 +892,7 @@ static struct parse_event_rule_res parse_event_rule(int *argc, const char ***arg case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT: case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL: break; @@ -908,6 +929,7 @@ static struct parse_event_rule_res parse_event_rule(int *argc, const char ***arg case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT: case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: { int log_level; @@ -1117,6 +1139,45 @@ static struct parse_event_rule_res parse_event_rule(int *argc, const char ***arg } break; } + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + { + enum lttng_event_rule_status event_rule_status; + + res.er = lttng_event_rule_log4j2_logging_create(); + if (!res.er) { + ERR("Failed to create log4j2_logging event rule."); + goto error; + } + + /* Set pattern. */ + event_rule_status = lttng_event_rule_log4j2_logging_set_name_pattern(res.er, name); + if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { + ERR("Failed to set log4j2_logging event rule's pattern to '%s'.", name); + goto error; + } + + /* Set filter. */ + if (filter) { + event_rule_status = + lttng_event_rule_log4j2_logging_set_filter(res.er, filter); + if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { + ERR("Failed to set log4j2_logging event rule's filter to '%s'.", + filter); + goto error; + } + } + + if (log_level_rule) { + event_rule_status = lttng_event_rule_log4j2_logging_set_log_level_rule( + res.er, log_level_rule); + + if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) { + ERR("Failed to set log level on event fule."); + goto error; + } + } + break; + } case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: { enum lttng_event_rule_status event_rule_status; diff --git a/src/bin/lttng/commands/disable_events.cpp b/src/bin/lttng/commands/disable_events.cpp index 40e85e7c8..db0b9aaba 100644 --- a/src/bin/lttng/commands/disable_events.cpp +++ b/src/bin/lttng/commands/disable_events.cpp @@ -27,6 +27,7 @@ static int opt_userspace; static int opt_disable_all; static int opt_jul; static int opt_log4j; +static int opt_log4j2; static int opt_python; static int opt_event_type; @@ -57,6 +58,7 @@ static struct poptOption long_options[] = { { "channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, nullptr, nullptr }, { "jul", 'j', POPT_ARG_VAL, &opt_jul, 1, nullptr, nullptr }, { "log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, nullptr, nullptr }, + { "log4j2", 0, POPT_ARG_VAL, &opt_log4j2, 1, nullptr, nullptr }, { "python", 'p', POPT_ARG_VAL, &opt_python, 1, nullptr, nullptr }, { "kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, nullptr, nullptr }, { "userspace", 'u', POPT_ARG_VAL, &opt_userspace, 1, nullptr, nullptr }, @@ -164,6 +166,8 @@ static int disable_events(char *session_name, char *event_list) dom.type = LTTNG_DOMAIN_JUL; } else if (opt_log4j) { dom.type = LTTNG_DOMAIN_LOG4J; + } else if (opt_log4j2) { + dom.type = LTTNG_DOMAIN_LOG4J2; } else if (opt_python) { dom.type = LTTNG_DOMAIN_PYTHON; } else { @@ -371,16 +375,16 @@ int cmd_disable_events(int argc, const char **argv) } ret = print_missing_or_multiple_domains( - opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_python, true); + opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_log4j2 + opt_python, true); if (ret) { ret = CMD_ERROR; goto end; } /* Ust and agent only support ALL event type */ - if ((opt_userspace || opt_jul || opt_log4j || opt_python) && + if ((opt_userspace || opt_jul || opt_log4j || opt_log4j2 || opt_python) && opt_event_type != LTTNG_EVENT_ALL) { - ERR("Disabling userspace and agent (-j | -l | -p) event(s) based on instrumentation type is not supported.\n"); + ERR("Disabling userspace and agent event(s) based on instrumentation type is not supported.\n"); ret = CMD_ERROR; goto end; } diff --git a/src/bin/lttng/commands/enable_events.cpp b/src/bin/lttng/commands/enable_events.cpp index b081adeee..1f1c8b459 100644 --- a/src/bin/lttng/commands/enable_events.cpp +++ b/src/bin/lttng/commands/enable_events.cpp @@ -61,6 +61,7 @@ char *opt_session_name; int opt_userspace; int opt_jul; int opt_log4j; +int opt_log4j2; int opt_python; int opt_enable_all; char *opt_probe; @@ -104,6 +105,7 @@ struct poptOption long_options[] = { { "userspace", 'u', POPT_ARG_NONE, nullptr, OPT_USERSPACE, nullptr, nullptr }, { "jul", 'j', POPT_ARG_VAL, &opt_jul, 1, nullptr, nullptr }, { "log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, nullptr, nullptr }, + { "log4j2", 0, POPT_ARG_VAL, &opt_log4j2, 1, nullptr, nullptr }, { "python", 'p', POPT_ARG_VAL, &opt_python, 1, nullptr, nullptr }, { "tracepoint", 0, POPT_ARG_NONE, nullptr, OPT_TRACEPOINT, nullptr, nullptr }, { "probe", 0, POPT_ARG_STRING, &opt_probe, OPT_PROBE, nullptr, nullptr }, @@ -444,6 +446,10 @@ int enable_events(const std::string& session_name, const event_rule_patterns& pa dom.type = LTTNG_DOMAIN_LOG4J; /* Default. */ dom.buf_type = LTTNG_BUFFER_PER_UID; + } else if (opt_log4j2) { + dom.type = LTTNG_DOMAIN_LOG4J2; + /* Default. */ + dom.buf_type = LTTNG_BUFFER_PER_UID; } else if (opt_python) { dom.type = LTTNG_DOMAIN_PYTHON; /* Default. */ @@ -458,6 +464,7 @@ int enable_events(const std::string& session_name, const event_rule_patterns& pa case LTTNG_DOMAIN_KERNEL: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: ERR("Event name exclusions are not supported for %s event rules", lttng_domain_type_str(dom.type)); @@ -653,7 +660,7 @@ int enable_events(const std::string& session_name, const event_rule_patterns& pa } else { ev->loglevel = -1; } - } else if (opt_jul || opt_log4j || opt_python) { + } else if (opt_jul || opt_log4j || opt_log4j2 || opt_python) { if (opt_event_type != LTTNG_EVENT_ALL && opt_event_type != LTTNG_EVENT_TRACEPOINT) { ERR("Instrumentation point type not supported for the %s domain", @@ -678,6 +685,12 @@ int enable_events(const std::string& session_name, const event_rule_patterns& pa name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, &loglevel); ev->loglevel = (int) loglevel; + } else if (opt_log4j2) { + enum lttng_loglevel_log4j2 loglevel; + + name_search_ret = loglevel_log4j2_name_to_value( + opt_loglevel, &loglevel); + ev->loglevel = (int) loglevel; } else { /* python domain. */ enum lttng_loglevel_python loglevel; @@ -697,6 +710,8 @@ int enable_events(const std::string& session_name, const event_rule_patterns& pa ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL; } else if (opt_log4j) { ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL; + } else if (opt_log4j2) { + ev->loglevel = LTTNG_LOGLEVEL_LOG4J2_ALL; } else if (opt_python) { ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG; } @@ -792,6 +807,7 @@ int enable_events(const std::string& session_name, const event_rule_patterns& pa } case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: /* * Don't print the default channel @@ -1082,7 +1098,7 @@ int cmd_enable_events(int argc, const char **argv) } ret = print_missing_or_multiple_domains( - opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_python, true); + opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_log4j2 + opt_python, true); if (ret) { return CMD_ERROR; } diff --git a/src/bin/lttng/commands/list.cpp b/src/bin/lttng/commands/list.cpp index c4e52b78f..b0cbf0ca1 100644 --- a/src/bin/lttng/commands/list.cpp +++ b/src/bin/lttng/commands/list.cpp @@ -27,6 +27,7 @@ static int opt_userspace; static int opt_kernel; static int opt_jul; static int opt_log4j; +static int opt_log4j2; static int opt_python; static char *opt_channel; static int opt_domain; @@ -61,6 +62,7 @@ static struct poptOption long_options[] = { { "kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, nullptr, nullptr }, { "jul", 'j', POPT_ARG_VAL, &opt_jul, 1, nullptr, nullptr }, { "log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, nullptr, nullptr }, + { "log4j2", 0, POPT_ARG_VAL, &opt_log4j2, 1, nullptr, nullptr }, { "python", 'p', POPT_ARG_VAL, &opt_python, 1, nullptr, nullptr }, { "userspace", 'u', POPT_ARG_NONE, nullptr, OPT_USERSPACE, nullptr, nullptr }, { "channel", 'c', POPT_ARG_STRING, &opt_channel, 0, nullptr, nullptr }, @@ -583,6 +585,8 @@ static int list_agent_events() domain.type = LTTNG_DOMAIN_JUL; } else if (opt_log4j) { domain.type = LTTNG_DOMAIN_LOG4J; + } else if (opt_log4j2) { + domain.type = LTTNG_DOMAIN_LOG4J2; } else if (opt_python) { domain.type = LTTNG_DOMAIN_PYTHON; } else { @@ -2224,10 +2228,13 @@ static int list_domains(const char *session_name) MSG(" - UST global"); break; case LTTNG_DOMAIN_JUL: - MSG(" - JUL (Java Util Logging)"); + MSG(" - JUL (java.util.logging)"); break; case LTTNG_DOMAIN_LOG4J: - MSG(" - LOG4j (Logging for Java)"); + MSG(" - Log4j"); + break; + case LTTNG_DOMAIN_LOG4J2: + MSG(" - Log4j2"); break; case LTTNG_DOMAIN_PYTHON: MSG(" - Python (logging)"); @@ -2327,6 +2334,8 @@ int cmd_list(int argc, const char **argv) domain.type = LTTNG_DOMAIN_JUL; } else if (opt_log4j) { domain.type = LTTNG_DOMAIN_LOG4J; + } else if (opt_log4j2) { + domain.type = LTTNG_DOMAIN_LOG4J2; } else if (opt_python) { domain.type = LTTNG_DOMAIN_PYTHON; } @@ -2337,7 +2346,7 @@ int cmd_list(int argc, const char **argv) goto end; } - if (opt_kernel || opt_userspace || opt_jul || opt_log4j || opt_python) { + if (opt_kernel || opt_userspace || opt_jul || opt_log4j || opt_log4j2 || opt_python) { the_handle = lttng_create_handle(arg_session_name, &domain); if (the_handle == nullptr) { ret = CMD_FATAL; @@ -2346,7 +2355,8 @@ int cmd_list(int argc, const char **argv) } if (arg_session_name == nullptr) { - if (!opt_kernel && !opt_userspace && !opt_jul && !opt_log4j && !opt_python) { + if (!opt_kernel && !opt_userspace && !opt_jul && !opt_log4j && !opt_log4j2 && + !opt_python) { ret = list_sessions(nullptr); if (ret) { goto end; @@ -2375,7 +2385,7 @@ int cmd_list(int argc, const char **argv) goto end; } } - if (opt_jul || opt_log4j || opt_python) { + if (opt_jul || opt_log4j || opt_log4j2 || opt_python) { ret = list_agent_events(); if (ret) { goto end; @@ -2479,10 +2489,13 @@ int cmd_list(int argc, const char **argv) "per-user"); break; case LTTNG_DOMAIN_JUL: - MSG("=== Domain: java.util.logging (JUL) ===\n"); + MSG("=== Domain: JUL (java.util.logging) ===\n"); break; case LTTNG_DOMAIN_LOG4J: - MSG("=== Domain: log4j ===\n"); + MSG("=== Domain: Log4j ===\n"); + break; + case LTTNG_DOMAIN_LOG4J2: + MSG("=== Domain: Log4j2 ===\n"); break; case LTTNG_DOMAIN_PYTHON: MSG("=== Domain: Python logging ===\n"); @@ -2513,6 +2526,7 @@ int cmd_list(int argc, const char **argv) if (domains[i].type == LTTNG_DOMAIN_JUL || domains[i].type == LTTNG_DOMAIN_LOG4J || + domains[i].type == LTTNG_DOMAIN_LOG4J2 || domains[i].type == LTTNG_DOMAIN_PYTHON) { ret = list_session_agent_events(); if (ret) { diff --git a/src/bin/lttng/commands/list_triggers.cpp b/src/bin/lttng/commands/list_triggers.cpp index 0cedb2642..db905bc4f 100644 --- a/src/bin/lttng/commands/list_triggers.cpp +++ b/src/bin/lttng/commands/list_triggers.cpp @@ -135,6 +135,9 @@ static const char *get_pretty_loglevel_name(enum lttng_event_rule_type event_rul case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: name = loglevel_log4j_value_to_name(loglevel); break; + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + name = loglevel_log4j2_value_to_name(loglevel); + break; case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: name = loglevel_jul_value_to_name(loglevel); break; @@ -274,6 +277,12 @@ static void print_event_rule_logging(const struct lttng_event_rule *event_rule) logging_get_log_level_rule = lttng_event_rule_log4j_logging_get_log_level_rule; type_str = "log4j"; break; + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + logging_get_name_pattern = lttng_event_rule_log4j2_logging_get_name_pattern; + logging_get_filter = lttng_event_rule_log4j2_logging_get_filter; + logging_get_log_level_rule = lttng_event_rule_log4j2_logging_get_log_level_rule; + type_str = "log4j2"; + break; case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: logging_get_name_pattern = lttng_event_rule_python_logging_get_name_pattern; logging_get_filter = lttng_event_rule_python_logging_get_filter; @@ -513,6 +522,7 @@ static void print_event_rule(const struct lttng_event_rule *event_rule) break; case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: print_event_rule_logging(event_rule); break; diff --git a/src/bin/lttng/loglevel.cpp b/src/bin/lttng/loglevel.cpp index d266baa44..de19ffed3 100644 --- a/src/bin/lttng/loglevel.cpp +++ b/src/bin/lttng/loglevel.cpp @@ -77,6 +77,25 @@ static const struct loglevel_name_value loglevel_log4j_values[] = { { .name = "LOG4J_ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL }, }; +static const struct loglevel_name_value loglevel_log4j2_values[] = { + { .name = "OFF", .value = LTTNG_LOGLEVEL_LOG4J2_OFF }, + { .name = "LOG4J2_OFF", .value = LTTNG_LOGLEVEL_LOG4J2_OFF }, + { .name = "FATAL", .value = LTTNG_LOGLEVEL_LOG4J2_FATAL }, + { .name = "LOG4J2_FATAL", .value = LTTNG_LOGLEVEL_LOG4J2_FATAL }, + { .name = "ERROR", .value = LTTNG_LOGLEVEL_LOG4J2_ERROR }, + { .name = "LOG4J2_ERROR", .value = LTTNG_LOGLEVEL_LOG4J2_ERROR }, + { .name = "WARN", .value = LTTNG_LOGLEVEL_LOG4J2_WARN }, + { .name = "LOG4J2_WARN", .value = LTTNG_LOGLEVEL_LOG4J2_WARN }, + { .name = "INFO", .value = LTTNG_LOGLEVEL_LOG4J2_INFO }, + { .name = "LOG4J2_INFO", .value = LTTNG_LOGLEVEL_LOG4J2_INFO }, + { .name = "DEBUG", .value = LTTNG_LOGLEVEL_LOG4J2_DEBUG }, + { .name = "LOG4J2_DEBUG", .value = LTTNG_LOGLEVEL_LOG4J2_DEBUG }, + { .name = "TRACE", .value = LTTNG_LOGLEVEL_LOG4J2_TRACE }, + { .name = "LOG4J2_TRACE", .value = LTTNG_LOGLEVEL_LOG4J2_TRACE }, + { .name = "ALL", .value = LTTNG_LOGLEVEL_LOG4J2_ALL }, + { .name = "LOG4J2_ALL", .value = LTTNG_LOGLEVEL_LOG4J2_ALL }, +}; + static const struct loglevel_name_value loglevel_jul_values[] = { { .name = "OFF", .value = LTTNG_LOGLEVEL_JUL_OFF }, { .name = "JUL_OFF", .value = LTTNG_LOGLEVEL_JUL_OFF }, @@ -261,6 +280,36 @@ bool loglevel_log4j_parse_range_string(const char *str, return ret; } +int loglevel_log4j2_name_to_value(const char *name, enum lttng_loglevel_log4j2 *loglevel) +{ + int ret = lookup_value_from_name( + loglevel_log4j2_values, ARRAY_SIZE(loglevel_log4j2_values), name); + + if (ret >= 0) { + *loglevel = (typeof(*loglevel)) ret; + ret = 0; + } + + return ret; +} + +bool loglevel_log4j2_parse_range_string(const char *str, + enum lttng_loglevel_log4j2 *min, + enum lttng_loglevel_log4j2 *max) +{ + int min_int, max_int; + bool ret = loglevel_parse_range_string_common(str, + loglevel_log4j2_values, + ARRAY_SIZE(loglevel_log4j2_values), + &min_int, + &max_int); + + *min = (lttng_loglevel_log4j2) min_int; + *max = (lttng_loglevel_log4j2) max_int; + + return ret; +} + int loglevel_jul_name_to_value(const char *name, enum lttng_loglevel_jul *loglevel) { int ret = @@ -347,6 +396,12 @@ const char *loglevel_log4j_value_to_name(int loglevel) loglevel_log4j_values, ARRAY_SIZE(loglevel_log4j_values), loglevel); } +const char *loglevel_log4j2_value_to_name(int loglevel) +{ + return lookup_name_from_value( + loglevel_log4j2_values, ARRAY_SIZE(loglevel_log4j2_values), loglevel); +} + const char *loglevel_jul_value_to_name(int loglevel) { return lookup_name_from_value( diff --git a/src/bin/lttng/loglevel.hpp b/src/bin/lttng/loglevel.hpp index 76c5ce021..0989ee60f 100644 --- a/src/bin/lttng/loglevel.hpp +++ b/src/bin/lttng/loglevel.hpp @@ -24,6 +24,12 @@ bool loglevel_log4j_parse_range_string(const char *str, enum lttng_loglevel_log4j *min, enum lttng_loglevel_log4j *max); +int loglevel_log4j2_name_to_value(const char *name, enum lttng_loglevel_log4j2 *loglevel); + +bool loglevel_log4j2_parse_range_string(const char *str, + enum lttng_loglevel_log4j2 *min, + enum lttng_loglevel_log4j2 *max); + int loglevel_jul_name_to_value(const char *name, enum lttng_loglevel_jul *loglevel); bool loglevel_jul_parse_range_string(const char *str, @@ -40,6 +46,8 @@ const char *loglevel_value_to_name(int loglevel); const char *loglevel_log4j_value_to_name(int loglevel); +const char *loglevel_log4j2_value_to_name(int loglevel); + const char *loglevel_jul_value_to_name(int loglevel); const char *loglevel_python_value_to_name(int loglevel); diff --git a/src/bin/lttng/utils.cpp b/src/bin/lttng/utils.cpp index 6622d1aa8..7831ae65a 100644 --- a/src/bin/lttng/utils.cpp +++ b/src/bin/lttng/utils.cpp @@ -423,7 +423,7 @@ int print_missing_or_multiple_domains(unsigned int domain_count, bool include_ag if (domain_count == 0) { ERR("Please specify a domain (--kernel/--userspace%s).", - include_agent_domains ? "/--jul/--log4j/--python" : ""); + include_agent_domains ? "/--jul/--log4j/--log4j2/--python" : ""); ret = -1; } else if (domain_count > 1) { ERR("Only one domain must be specified."); diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 68ab02f04..2516a5042 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -84,6 +84,7 @@ libcommon_lgpl_la_SOURCES = \ event-rule/kernel-tracepoint.cpp \ event-rule/user-tracepoint.cpp \ event-rule/log4j-logging.cpp \ + event-rule/log4j2-logging.cpp \ event-rule/jul-logging.cpp \ event-rule/python-logging.cpp \ exception.cpp exception.hpp \ diff --git a/src/common/conditions/event-rule-matches.cpp b/src/common/conditions/event-rule-matches.cpp index 91012f475..64f00859c 100644 --- a/src/common/conditions/event-rule-matches.cpp +++ b/src/common/conditions/event-rule-matches.cpp @@ -822,6 +822,7 @@ lttng_condition_event_rule_matches_append_capture_descriptor(struct lttng_condit case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT: case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING: case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL: /* Supported. */ diff --git a/src/common/config/config-session-abi.hpp b/src/common/config/config-session-abi.hpp index f56b4bd0d..d0b41dbbc 100644 --- a/src/common/config/config-session-abi.hpp +++ b/src/common/config/config-session-abi.hpp @@ -105,6 +105,7 @@ LTTNG_EXPORT extern const char *const config_domain_type_kernel; LTTNG_EXPORT extern const char *const config_domain_type_ust; LTTNG_EXPORT extern const char *const config_domain_type_jul; LTTNG_EXPORT extern const char *const config_domain_type_log4j; +LTTNG_EXPORT extern const char *const config_domain_type_log4j2; LTTNG_EXPORT extern const char *const config_domain_type_python; LTTNG_EXPORT extern const char *const config_buffer_type_per_pid; diff --git a/src/common/config/session-config.cpp b/src/common/config/session-config.cpp index 9af61fa93..6dddbe41e 100644 --- a/src/common/config/session-config.cpp +++ b/src/common/config/session-config.cpp @@ -164,6 +164,7 @@ const char *const config_domain_type_kernel = "KERNEL"; const char *const config_domain_type_ust = "UST"; const char *const config_domain_type_jul = "JUL"; const char *const config_domain_type_log4j = "LOG4J"; +const char *const config_domain_type_log4j2 = "LOG4J2"; const char *const config_domain_type_python = "PYTHON"; const char *const config_buffer_type_per_pid = "PER_PID"; @@ -723,6 +724,8 @@ static int get_domain_type(xmlChar *domain) ret = LTTNG_DOMAIN_JUL; } else if (!strcmp((char *) domain, config_domain_type_log4j)) { ret = LTTNG_DOMAIN_LOG4J; + } else if (!strcmp((char *) domain, config_domain_type_log4j2)) { + ret = LTTNG_DOMAIN_LOG4J2; } else if (!strcmp((char *) domain, config_domain_type_python)) { ret = LTTNG_DOMAIN_PYTHON; } else { @@ -1609,6 +1612,9 @@ static int process_event_node(xmlNodePtr event_node, case LTTNG_DOMAIN_LOG4J: event->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL; break; + case LTTNG_DOMAIN_LOG4J2: + event->loglevel = LTTNG_LOGLEVEL_LOG4J2_ALL; + break; case LTTNG_DOMAIN_PYTHON: event->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG; break; @@ -2821,6 +2827,7 @@ static int process_domain_node(xmlNodePtr domain_node, const char *session_name) switch (domain.type) { case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: domain.type = LTTNG_DOMAIN_UST; default: @@ -3102,6 +3109,7 @@ static int process_session_node(xmlNodePtr session_node, struct lttng_domain *ust_domain = nullptr; struct lttng_domain *jul_domain = nullptr; struct lttng_domain *log4j_domain = nullptr; + struct lttng_domain *log4j2_domain = nullptr; struct lttng_domain *python_domain = nullptr; for (node = xmlFirstElementChild(session_node); node; node = xmlNextElementSibling(node)) { @@ -3257,6 +3265,13 @@ static int process_session_node(xmlNodePtr session_node, } log4j_domain = domain; break; + case LTTNG_DOMAIN_LOG4J2: + if (log4j2_domain) { + /* Same domain seen twice, invalid! */ + goto domain_init_error; + } + log4j2_domain = domain; + break; case LTTNG_DOMAIN_PYTHON: if (python_domain) { /* Same domain seen twice, invalid! */ @@ -3358,6 +3373,7 @@ error: free(ust_domain); free(jul_domain); free(log4j_domain); + free(log4j2_domain); free(python_domain); xmlFree(name); xmlFree(shm_path); diff --git a/src/common/defaults.hpp b/src/common/defaults.hpp index 149c483ec..2be3648cc 100644 --- a/src/common/defaults.hpp +++ b/src/common/defaults.hpp @@ -193,6 +193,12 @@ #define DEFAULT_LOG4J_EVENT_COMPONENT "lttng_log4j" #define DEFAULT_LOG4J_EVENT_NAME DEFAULT_LOG4J_EVENT_COMPONENT ":*" +/* Default log4j2 domain channel name. */ +#define DEFAULT_LOG4J2_CHANNEL_NAME "lttng_log4j2_channel" +/* Default log4j tracepoint name. This is a wildcard for the log4j2 domain. */ +#define DEFAULT_LOG4J2_EVENT_COMPONENT "lttng_log4j2" +#define DEFAULT_LOG4J2_EVENT_NAME DEFAULT_LOG4J2_EVENT_COMPONENT ":*" + /* Default Python domain channel name. */ #define DEFAULT_PYTHON_CHANNEL_NAME "lttng_python_channel" /* Default Python tracepoint name. This is a wildcard for the python domain. */ diff --git a/src/common/domain.cpp b/src/common/domain.cpp index 7b331d049..0ae57d9d0 100644 --- a/src/common/domain.cpp +++ b/src/common/domain.cpp @@ -21,6 +21,8 @@ const char *lttng_domain_type_str(enum lttng_domain_type domain_type) return "java.util.logging (JUL)"; case LTTNG_DOMAIN_LOG4J: return "log4j"; + case LTTNG_DOMAIN_LOG4J2: + return "log4j2"; case LTTNG_DOMAIN_PYTHON: return "Python logging"; default: diff --git a/src/common/event-rule/event-rule.cpp b/src/common/event-rule/event-rule.cpp index 197d4b011..220a99a23 100644 --- a/src/common/event-rule/event-rule.cpp +++ b/src/common/event-rule/event-rule.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,9 @@ enum lttng_domain_type lttng_event_rule_get_domain_type(const struct lttng_event case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: domain_type = LTTNG_DOMAIN_LOG4J; break; + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + domain_type = LTTNG_DOMAIN_LOG4J2; + break; case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: domain_type = LTTNG_DOMAIN_PYTHON; break; @@ -190,6 +194,9 @@ ssize_t lttng_event_rule_create_from_payload(struct lttng_payload_view *view, case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: create_from_payload = lttng_event_rule_log4j_logging_create_from_payload; break; + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + create_from_payload = lttng_event_rule_log4j2_logging_create_from_payload; + break; case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: create_from_payload = lttng_event_rule_python_logging_create_from_payload; break; @@ -288,6 +295,7 @@ bool lttng_event_rule_targets_agent_domain(const struct lttng_event_rule *rule) switch (type) { case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: targets_agent_domain = true; break; @@ -321,6 +329,8 @@ const char *lttng_event_rule_type_str(enum lttng_event_rule_type type) return "jul logging"; case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING: return "log4j logging"; + case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING: + return "log4j2 logging"; case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING: return "python logging"; diff --git a/src/common/event-rule/jul-logging.cpp b/src/common/event-rule/jul-logging.cpp index 97876cd35..289349ca6 100644 --- a/src/common/event-rule/jul-logging.cpp +++ b/src/common/event-rule/jul-logging.cpp @@ -231,7 +231,7 @@ static int generate_agent_filter(const struct lttng_event_rule *rule, char **_ag case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( log_level_rule, &level); - op = ">="; + op = LTTNG_JUL_EVENT_RULE_AT_LEAST_AS_SEVERE_AS_OP; break; default: abort(); @@ -810,8 +810,8 @@ end: static bool log_level_rule_valid(const struct lttng_log_level_rule *rule __attribute__((unused))) { /* - * For both JUL and LOG4J custom log level are possible and can - * span the entire int32 range. + * JUL custom log levels are possible and can span the entire int32 + * range. */ return true; } diff --git a/src/common/event-rule/log4j-logging.cpp b/src/common/event-rule/log4j-logging.cpp index ba440b979..dc0c9f2df 100644 --- a/src/common/event-rule/log4j-logging.cpp +++ b/src/common/event-rule/log4j-logging.cpp @@ -231,7 +231,7 @@ static int generate_agent_filter(const struct lttng_event_rule *rule, char **_ag case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( log_level_rule, &level); - op = ">="; + op = LTTNG_LOG4J_EVENT_RULE_AT_LEAST_AS_SEVERE_AS_OP; break; default: abort(); @@ -809,8 +809,8 @@ end: static bool log_level_rule_valid(const struct lttng_log_level_rule *rule __attribute__((unused))) { /* - * For both LOG4J custom log level are possible and can - * span the entire int32 range. + * LOG4J custom log levels are possible and can span the entire int32 + * range. */ return true; } diff --git a/src/common/event-rule/log4j2-logging.cpp b/src/common/event-rule/log4j2-logging.cpp new file mode 100644 index 000000000..884963907 --- /dev/null +++ b/src/common/event-rule/log4j2-logging.cpp @@ -0,0 +1,874 @@ +/* + * Copyright (C) 2024 Michael Jeanson + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define IS_LOG4J2_LOGGING_EVENT_RULE(rule) \ + (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING) + +static void lttng_event_rule_log4j2_logging_destroy(struct lttng_event_rule *rule) +{ + struct lttng_event_rule_log4j2_logging *log4j2_logging; + + if (rule == nullptr) { + return; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + + lttng_log_level_rule_destroy(log4j2_logging->log_level_rule); + free(log4j2_logging->pattern); + free(log4j2_logging->filter_expression); + free(log4j2_logging->internal_filter.filter); + free(log4j2_logging->internal_filter.bytecode); + free(log4j2_logging); +} + +static bool lttng_event_rule_log4j2_logging_validate(const struct lttng_event_rule *rule) +{ + bool valid = false; + struct lttng_event_rule_log4j2_logging *log4j2_logging; + + if (!rule) { + goto end; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + + /* Required field. */ + if (!log4j2_logging->pattern) { + ERR("Invalid log4j2_logging event rule: a pattern must be set."); + goto end; + } + + valid = true; +end: + return valid; +} + +static int lttng_event_rule_log4j2_logging_serialize(const struct lttng_event_rule *rule, + struct lttng_payload *payload) +{ + int ret; + size_t pattern_len, filter_expression_len, header_offset; + size_t size_before_log_level_rule; + struct lttng_event_rule_log4j2_logging *log4j2_logging; + struct lttng_event_rule_log4j2_logging_comm log4j2_logging_comm; + struct lttng_event_rule_log4j2_logging_comm *header; + + if (!rule || !IS_LOG4J2_LOGGING_EVENT_RULE(rule)) { + ret = -1; + goto end; + } + + header_offset = payload->buffer.size; + + DBG("Serializing log4j2_logging event rule."); + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + + pattern_len = strlen(log4j2_logging->pattern) + 1; + + if (log4j2_logging->filter_expression != nullptr) { + filter_expression_len = strlen(log4j2_logging->filter_expression) + 1; + } else { + filter_expression_len = 0; + } + + log4j2_logging_comm.pattern_len = pattern_len; + log4j2_logging_comm.filter_expression_len = filter_expression_len; + + ret = lttng_dynamic_buffer_append( + &payload->buffer, &log4j2_logging_comm, sizeof(log4j2_logging_comm)); + if (ret) { + goto end; + } + + ret = lttng_dynamic_buffer_append(&payload->buffer, log4j2_logging->pattern, pattern_len); + if (ret) { + goto end; + } + + ret = lttng_dynamic_buffer_append( + &payload->buffer, log4j2_logging->filter_expression, filter_expression_len); + if (ret) { + goto end; + } + + size_before_log_level_rule = payload->buffer.size; + + ret = lttng_log_level_rule_serialize(log4j2_logging->log_level_rule, payload); + if (ret < 0) { + goto end; + } + + header = (typeof(header)) ((char *) payload->buffer.data + header_offset); + header->log_level_rule_len = payload->buffer.size - size_before_log_level_rule; + +end: + return ret; +} + +static bool lttng_event_rule_log4j2_logging_is_equal(const struct lttng_event_rule *_a, + const struct lttng_event_rule *_b) +{ + bool is_equal = false; + struct lttng_event_rule_log4j2_logging *a, *b; + + a = lttng::utils::container_of(_a, <tng_event_rule_log4j2_logging::parent); + b = lttng::utils::container_of(_b, <tng_event_rule_log4j2_logging::parent); + + /* Quick checks. */ + + if (!!a->filter_expression != !!b->filter_expression) { + goto end; + } + + /* Long check. */ + LTTNG_ASSERT(a->pattern); + LTTNG_ASSERT(b->pattern); + if (strcmp(a->pattern, b->pattern) != 0) { + goto end; + } + + if (a->filter_expression && b->filter_expression) { + if (strcmp(a->filter_expression, b->filter_expression) != 0) { + goto end; + } + } else if (!!a->filter_expression != !!b->filter_expression) { + /* One is set; not the other. */ + goto end; + } + + if (!lttng_log_level_rule_is_equal(a->log_level_rule, b->log_level_rule)) { + goto end; + } + + is_equal = true; +end: + return is_equal; +} + +/* + * On success ret is 0; + * + * On error ret is negative. + * + * An event with NO loglevel and the name is * will return NULL. + */ +static int generate_agent_filter(const struct lttng_event_rule *rule, char **_agent_filter) +{ + int err; + int ret = 0; + char *agent_filter = nullptr; + const char *pattern; + const char *filter; + const struct lttng_log_level_rule *log_level_rule = nullptr; + enum lttng_event_rule_status status; + + LTTNG_ASSERT(rule); + LTTNG_ASSERT(_agent_filter); + + status = lttng_event_rule_log4j2_logging_get_name_pattern(rule, &pattern); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ret = -1; + goto end; + } + + status = lttng_event_rule_log4j2_logging_get_filter(rule, &filter); + if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { + filter = nullptr; + } else if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ret = -1; + goto end; + } + + /* Don't add filter for the '*' event. */ + if (strcmp(pattern, "*") != 0) { + if (filter) { + err = asprintf( + &agent_filter, "(%s) && (logger_name == \"%s\")", filter, pattern); + } else { + err = asprintf(&agent_filter, "logger_name == \"%s\"", pattern); + } + + if (err < 0) { + PERROR("Failed to format agent filter string"); + ret = -1; + goto end; + } + } + + status = lttng_event_rule_log4j2_logging_get_log_level_rule(rule, &log_level_rule); + if (status == LTTNG_EVENT_RULE_STATUS_OK) { + enum lttng_log_level_rule_status llr_status; + const char *op; + int level; + + switch (lttng_log_level_rule_get_type(log_level_rule)) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + llr_status = lttng_log_level_rule_exactly_get_level(log_level_rule, &level); + op = "=="; + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( + log_level_rule, &level); + op = LTTNG_LOG4J2_EVENT_RULE_AT_LEAST_AS_SEVERE_AS_OP; + break; + default: + abort(); + } + + if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) { + ret = -1; + goto end; + } + + if (filter || agent_filter) { + char *new_filter; + + err = asprintf(&new_filter, + "(%s) && (int_loglevel %s %d)", + agent_filter ? agent_filter : filter, + op, + level); + if (agent_filter) { + free(agent_filter); + } + agent_filter = new_filter; + } else { + err = asprintf(&agent_filter, "int_loglevel %s %d", op, level); + } + + if (err < 0) { + PERROR("Failed to format agent filter string"); + ret = -1; + goto end; + } + } + + *_agent_filter = agent_filter; + agent_filter = nullptr; + +end: + free(agent_filter); + return ret; +} + +static enum lttng_error_code +lttng_event_rule_log4j2_logging_generate_filter_bytecode(struct lttng_event_rule *rule, + const struct lttng_credentials *creds) +{ + int ret; + enum lttng_error_code ret_code; + struct lttng_event_rule_log4j2_logging *log4j2_logging; + enum lttng_event_rule_status status; + const char *filter; + struct lttng_bytecode *bytecode = nullptr; + char *agent_filter; + + LTTNG_ASSERT(rule); + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + + status = lttng_event_rule_log4j2_logging_get_filter(rule, &filter); + if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { + filter = nullptr; + } else if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ret_code = LTTNG_ERR_FILTER_INVAL; + goto end; + } + + if (filter && filter[0] == '\0') { + ret_code = LTTNG_ERR_FILTER_INVAL; + goto error; + } + + ret = generate_agent_filter(rule, &agent_filter); + if (ret) { + ret_code = LTTNG_ERR_FILTER_INVAL; + goto error; + } + + log4j2_logging->internal_filter.filter = agent_filter; + + if (log4j2_logging->internal_filter.filter == nullptr) { + ret_code = LTTNG_OK; + goto end; + } + + ret = run_as_generate_filter_bytecode( + log4j2_logging->internal_filter.filter, creds, &bytecode); + if (ret) { + ret_code = LTTNG_ERR_FILTER_INVAL; + goto end; + } + + log4j2_logging->internal_filter.bytecode = bytecode; + bytecode = nullptr; + ret_code = LTTNG_OK; + +error: +end: + free(bytecode); + return ret_code; +} + +static const char * +lttng_event_rule_log4j2_logging_get_internal_filter(const struct lttng_event_rule *rule) +{ + struct lttng_event_rule_log4j2_logging *log4j2_logging; + + LTTNG_ASSERT(rule); + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + return log4j2_logging->internal_filter.filter; +} + +static const struct lttng_bytecode * +lttng_event_rule_log4j2_logging_get_internal_filter_bytecode(const struct lttng_event_rule *rule) +{ + struct lttng_event_rule_log4j2_logging *log4j2_logging; + + LTTNG_ASSERT(rule); + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + return log4j2_logging->internal_filter.bytecode; +} + +static enum lttng_event_rule_generate_exclusions_status +lttng_event_rule_log4j2_logging_generate_exclusions(const struct lttng_event_rule *rule + __attribute__((unused)), + struct lttng_event_exclusion **_exclusions) +{ + /* Unsupported. */ + *_exclusions = nullptr; + return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE; +} + +static unsigned long lttng_event_rule_log4j2_logging_hash(const struct lttng_event_rule *rule) +{ + unsigned long hash; + struct lttng_event_rule_log4j2_logging *tp_rule = + lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + + hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING, lttng_ht_seed); + hash ^= hash_key_str(tp_rule->pattern, lttng_ht_seed); + + if (tp_rule->filter_expression) { + hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed); + } + + if (tp_rule->log_level_rule) { + hash ^= lttng_log_level_rule_hash(tp_rule->log_level_rule); + } + + return hash; +} + +static struct lttng_event * +lttng_event_rule_log4j2_logging_generate_lttng_event(const struct lttng_event_rule *rule) +{ + int ret; + const struct lttng_event_rule_log4j2_logging *log4j2_logging; + struct lttng_event *local_event = nullptr; + struct lttng_event *event = nullptr; + enum lttng_loglevel_type loglevel_type; + int loglevel_value = 0; + enum lttng_event_rule_status status; + const struct lttng_log_level_rule *log_level_rule; + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + + local_event = zmalloc(); + if (!local_event) { + goto error; + } + + local_event->type = LTTNG_EVENT_TRACEPOINT; + ret = lttng_strncpy(local_event->name, log4j2_logging->pattern, sizeof(local_event->name)); + if (ret) { + ERR("Truncation occurred when copying event rule pattern to `lttng_event` structure: pattern = '%s'", + log4j2_logging->pattern); + goto error; + } + + /* Map the log level rule to an equivalent lttng_loglevel. */ + status = lttng_event_rule_log4j2_logging_get_log_level_rule(rule, &log_level_rule); + if (status == LTTNG_EVENT_RULE_STATUS_UNSET) { + loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL; + loglevel_value = LTTNG_LOGLEVEL_LOG4J2_ALL; + } else if (status == LTTNG_EVENT_RULE_STATUS_OK) { + enum lttng_log_level_rule_status llr_status; + + switch (lttng_log_level_rule_get_type(log_level_rule)) { + case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY: + llr_status = lttng_log_level_rule_exactly_get_level(log_level_rule, + &loglevel_value); + loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE; + break; + case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS: + llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level( + log_level_rule, &loglevel_value); + loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE; + break; + default: + abort(); + break; + } + + if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) { + goto error; + } + } else { + goto error; + } + + local_event->loglevel_type = loglevel_type; + local_event->loglevel = loglevel_value; + + event = local_event; + local_event = nullptr; +error: + free(local_event); + return event; +} + +static enum lttng_error_code +lttng_event_rule_log4j2_logging_mi_serialize(const struct lttng_event_rule *rule, + struct mi_writer *writer) +{ + int ret; + enum lttng_error_code ret_code; + enum lttng_event_rule_status status; + const char *filter = nullptr; + const char *name_pattern = nullptr; + const struct lttng_log_level_rule *log_level_rule = nullptr; + + LTTNG_ASSERT(rule); + LTTNG_ASSERT(writer); + LTTNG_ASSERT(IS_LOG4J2_LOGGING_EVENT_RULE(rule)); + + status = lttng_event_rule_log4j2_logging_get_name_pattern(rule, &name_pattern); + LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK); + LTTNG_ASSERT(name_pattern); + + status = lttng_event_rule_log4j2_logging_get_filter(rule, &filter); + LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || + status == LTTNG_EVENT_RULE_STATUS_UNSET); + + status = lttng_event_rule_log4j2_logging_get_log_level_rule(rule, &log_level_rule); + LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK || + status == LTTNG_EVENT_RULE_STATUS_UNSET); + + /* Open event rule log4j2 logging element. */ + ret = mi_lttng_writer_open_element(writer, mi_lttng_element_event_rule_log4j2_logging); + if (ret) { + goto mi_error; + } + + /* Name pattern. */ + ret = mi_lttng_writer_write_element_string( + writer, mi_lttng_element_event_rule_name_pattern, name_pattern); + if (ret) { + goto mi_error; + } + + /* Filter expression. */ + if (filter != nullptr) { + ret = mi_lttng_writer_write_element_string( + writer, mi_lttng_element_event_rule_filter_expression, filter); + if (ret) { + goto mi_error; + } + } + + /* Log level rule. */ + if (log_level_rule) { + ret_code = lttng_log_level_rule_mi_serialize(log_level_rule, writer); + if (ret_code != LTTNG_OK) { + goto end; + } + } + + /* Close event rule log4j2 logging element. */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto mi_error; + } + + ret_code = LTTNG_OK; + goto end; + +mi_error: + ret_code = LTTNG_ERR_MI_IO_FAIL; +end: + return ret_code; +} + +struct lttng_event_rule *lttng_event_rule_log4j2_logging_create(void) +{ + struct lttng_event_rule *rule = nullptr; + struct lttng_event_rule_log4j2_logging *tp_rule; + enum lttng_event_rule_status status; + + tp_rule = zmalloc(); + if (!tp_rule) { + goto end; + } + + rule = &tp_rule->parent; + lttng_event_rule_init(&tp_rule->parent, LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING); + tp_rule->parent.validate = lttng_event_rule_log4j2_logging_validate; + tp_rule->parent.serialize = lttng_event_rule_log4j2_logging_serialize; + tp_rule->parent.equal = lttng_event_rule_log4j2_logging_is_equal; + tp_rule->parent.destroy = lttng_event_rule_log4j2_logging_destroy; + tp_rule->parent.generate_filter_bytecode = + lttng_event_rule_log4j2_logging_generate_filter_bytecode; + tp_rule->parent.get_filter = lttng_event_rule_log4j2_logging_get_internal_filter; + tp_rule->parent.get_filter_bytecode = + lttng_event_rule_log4j2_logging_get_internal_filter_bytecode; + tp_rule->parent.generate_exclusions = lttng_event_rule_log4j2_logging_generate_exclusions; + tp_rule->parent.hash = lttng_event_rule_log4j2_logging_hash; + tp_rule->parent.generate_lttng_event = lttng_event_rule_log4j2_logging_generate_lttng_event; + tp_rule->parent.mi_serialize = lttng_event_rule_log4j2_logging_mi_serialize; + + tp_rule->log_level_rule = nullptr; + + /* Default pattern is '*'. */ + status = lttng_event_rule_log4j2_logging_set_name_pattern(rule, "*"); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + lttng_event_rule_destroy(rule); + rule = nullptr; + } + +end: + return rule; +} + +ssize_t lttng_event_rule_log4j2_logging_create_from_payload(struct lttng_payload_view *view, + struct lttng_event_rule **_event_rule) +{ + ssize_t ret, offset = 0; + enum lttng_event_rule_status status; + const struct lttng_event_rule_log4j2_logging_comm *log4j2_logging_comm; + const char *pattern; + const char *filter_expression = nullptr; + struct lttng_buffer_view current_buffer_view; + struct lttng_event_rule *rule = nullptr; + struct lttng_log_level_rule *log_level_rule = nullptr; + + if (!_event_rule) { + ret = -1; + goto end; + } + + current_buffer_view = + lttng_buffer_view_from_view(&view->buffer, offset, sizeof(*log4j2_logging_comm)); + if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { + ERR("Failed to initialize from malformed event rule log4j2_logging: buffer too short to contain header."); + ret = -1; + goto end; + } + + log4j2_logging_comm = (typeof(log4j2_logging_comm)) current_buffer_view.data; + + rule = lttng_event_rule_log4j2_logging_create(); + if (!rule) { + ERR("Failed to create event rule log4j2_logging."); + ret = -1; + goto end; + } + + /* Skip to payload. */ + offset += current_buffer_view.size; + + /* Map the pattern. */ + current_buffer_view = lttng_buffer_view_from_view( + &view->buffer, offset, log4j2_logging_comm->pattern_len); + + if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { + ret = -1; + goto end; + } + + pattern = current_buffer_view.data; + if (!lttng_buffer_view_contains_string( + ¤t_buffer_view, pattern, log4j2_logging_comm->pattern_len)) { + ret = -1; + goto end; + } + + /* Skip after the pattern. */ + offset += log4j2_logging_comm->pattern_len; + + if (!log4j2_logging_comm->filter_expression_len) { + goto skip_filter_expression; + } + + /* Map the filter_expression. */ + current_buffer_view = lttng_buffer_view_from_view( + &view->buffer, offset, log4j2_logging_comm->filter_expression_len); + if (!lttng_buffer_view_is_valid(¤t_buffer_view)) { + ret = -1; + goto end; + } + + filter_expression = current_buffer_view.data; + if (!lttng_buffer_view_contains_string(¤t_buffer_view, + filter_expression, + log4j2_logging_comm->filter_expression_len)) { + ret = -1; + goto end; + } + + /* Skip after the pattern. */ + offset += log4j2_logging_comm->filter_expression_len; + +skip_filter_expression: + if (!log4j2_logging_comm->log_level_rule_len) { + goto skip_log_level_rule; + } + + { + /* Map the log level rule. */ + struct lttng_payload_view current_payload_view = lttng_payload_view_from_view( + view, offset, log4j2_logging_comm->log_level_rule_len); + + ret = lttng_log_level_rule_create_from_payload(¤t_payload_view, + &log_level_rule); + if (ret < 0) { + ret = -1; + goto end; + } + + LTTNG_ASSERT(ret == log4j2_logging_comm->log_level_rule_len); + } + + /* Skip after the log level rule. */ + offset += log4j2_logging_comm->log_level_rule_len; + +skip_log_level_rule: + + status = lttng_event_rule_log4j2_logging_set_name_pattern(rule, pattern); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ERR("Failed to set event rule log4j2_logging pattern."); + ret = -1; + goto end; + } + + if (filter_expression) { + status = lttng_event_rule_log4j2_logging_set_filter(rule, filter_expression); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ERR("Failed to set event rule log4j2_logging pattern."); + ret = -1; + goto end; + } + } + + if (log_level_rule) { + status = lttng_event_rule_log4j2_logging_set_log_level_rule(rule, log_level_rule); + if (status != LTTNG_EVENT_RULE_STATUS_OK) { + ERR("Failed to set event rule log4j2_logging log level rule."); + ret = -1; + goto end; + } + } + + *_event_rule = rule; + rule = nullptr; + ret = offset; +end: + lttng_log_level_rule_destroy(log_level_rule); + lttng_event_rule_destroy(rule); + return ret; +} + +enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_set_name_pattern(struct lttng_event_rule *rule, const char *pattern) +{ + char *pattern_copy = nullptr; + struct lttng_event_rule_log4j2_logging *log4j2_logging; + enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + + if (!rule || !IS_LOG4J2_LOGGING_EVENT_RULE(rule) || !pattern || strlen(pattern) == 0) { + status = LTTNG_EVENT_RULE_STATUS_INVALID; + goto end; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + pattern_copy = strdup(pattern); + if (!pattern_copy) { + status = LTTNG_EVENT_RULE_STATUS_ERROR; + goto end; + } + + /* Normalize the pattern. */ + strutils_normalize_star_glob_pattern(pattern_copy); + + free(log4j2_logging->pattern); + + log4j2_logging->pattern = pattern_copy; + pattern_copy = nullptr; +end: + return status; +} + +enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_get_name_pattern(const struct lttng_event_rule *rule, + const char **pattern) +{ + struct lttng_event_rule_log4j2_logging *log4j2_logging; + enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + + if (!rule || !IS_LOG4J2_LOGGING_EVENT_RULE(rule) || !pattern) { + status = LTTNG_EVENT_RULE_STATUS_INVALID; + goto end; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + if (!log4j2_logging->pattern) { + status = LTTNG_EVENT_RULE_STATUS_UNSET; + goto end; + } + + *pattern = log4j2_logging->pattern; +end: + return status; +} + +enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_set_filter(struct lttng_event_rule *rule, const char *expression) +{ + char *expression_copy = nullptr; + struct lttng_event_rule_log4j2_logging *log4j2_logging; + enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + + if (!rule || !IS_LOG4J2_LOGGING_EVENT_RULE(rule) || !expression || + strlen(expression) == 0) { + status = LTTNG_EVENT_RULE_STATUS_INVALID; + goto end; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + expression_copy = strdup(expression); + if (!expression_copy) { + PERROR("Failed to copy filter expression"); + status = LTTNG_EVENT_RULE_STATUS_ERROR; + goto end; + } + + if (log4j2_logging->filter_expression) { + free(log4j2_logging->filter_expression); + } + + log4j2_logging->filter_expression = expression_copy; + expression_copy = nullptr; +end: + return status; +} + +enum lttng_event_rule_status +lttng_event_rule_log4j2_logging_get_filter(const struct lttng_event_rule *rule, + const char **expression) +{ + struct lttng_event_rule_log4j2_logging *log4j2_logging; + enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + + if (!rule || !IS_LOG4J2_LOGGING_EVENT_RULE(rule) || !expression) { + status = LTTNG_EVENT_RULE_STATUS_INVALID; + goto end; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + if (!log4j2_logging->filter_expression) { + status = LTTNG_EVENT_RULE_STATUS_UNSET; + goto end; + } + + *expression = log4j2_logging->filter_expression; +end: + return status; +} + +static bool log_level_rule_valid(const struct lttng_log_level_rule *rule) +{ + /* + * LOG4J2 custom log levels are possible and can range from 0 to + * int32_max. + */ + return (rule->level >= 0); +} + +enum lttng_event_rule_status lttng_event_rule_log4j2_logging_set_log_level_rule( + struct lttng_event_rule *rule, const struct lttng_log_level_rule *log_level_rule) +{ + struct lttng_event_rule_log4j2_logging *log4j2_logging; + enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + struct lttng_log_level_rule *copy = nullptr; + + if (!rule || !IS_LOG4J2_LOGGING_EVENT_RULE(rule)) { + status = LTTNG_EVENT_RULE_STATUS_INVALID; + goto end; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + + if (!log_level_rule_valid(log_level_rule)) { + status = LTTNG_EVENT_RULE_STATUS_INVALID; + goto end; + } + + copy = lttng_log_level_rule_copy(log_level_rule); + if (copy == nullptr) { + status = LTTNG_EVENT_RULE_STATUS_ERROR; + goto end; + } + + if (log4j2_logging->log_level_rule) { + lttng_log_level_rule_destroy(log4j2_logging->log_level_rule); + } + + log4j2_logging->log_level_rule = copy; + +end: + return status; +} + +enum lttng_event_rule_status lttng_event_rule_log4j2_logging_get_log_level_rule( + const struct lttng_event_rule *rule, const struct lttng_log_level_rule **log_level_rule) +{ + struct lttng_event_rule_log4j2_logging *log4j2_logging; + enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK; + + if (!rule || !IS_LOG4J2_LOGGING_EVENT_RULE(rule) || !log_level_rule) { + status = LTTNG_EVENT_RULE_STATUS_INVALID; + goto end; + } + + log4j2_logging = lttng::utils::container_of(rule, <tng_event_rule_log4j2_logging::parent); + if (log4j2_logging->log_level_rule == nullptr) { + status = LTTNG_EVENT_RULE_STATUS_UNSET; + goto end; + } + + *log_level_rule = log4j2_logging->log_level_rule; +end: + return status; +} diff --git a/src/common/mi-lttng-4.1.xsd b/src/common/mi-lttng-4.1.xsd index 7d68b2e8e..4ebb2574d 100644 --- a/src/common/mi-lttng-4.1.xsd +++ b/src/common/mi-lttng-4.1.xsd @@ -170,6 +170,14 @@ SPDX-License-Identifier: MIT + + + + + + + + @@ -305,6 +313,7 @@ SPDX-License-Identifier: MIT + @@ -1068,6 +1077,7 @@ SPDX-License-Identifier: MIT + diff --git a/src/common/mi-lttng.cpp b/src/common/mi-lttng.cpp index d7833fcd5..c82b3ee98 100644 --- a/src/common/mi-lttng.cpp +++ b/src/common/mi-lttng.cpp @@ -151,6 +151,16 @@ const char *const mi_lttng_loglevel_str_log4j_debug = "LOG4J_DEBUG"; const char *const mi_lttng_loglevel_str_log4j_trace = "LOG4J_TRACE"; const char *const mi_lttng_loglevel_str_log4j_all = "LOG4J_ALL"; +/* String related to loglevel LOG4J2 */ +const char *const mi_lttng_loglevel_str_log4j2_off = "LOG4J2_OFF"; +const char *const mi_lttng_loglevel_str_log4j2_fatal = "LOG4J2_FATAL"; +const char *const mi_lttng_loglevel_str_log4j2_error = "LOG4J2_ERROR"; +const char *const mi_lttng_loglevel_str_log4j2_warn = "LOG4J2_WARN"; +const char *const mi_lttng_loglevel_str_log4j2_info = "LOG4J2_INFO"; +const char *const mi_lttng_loglevel_str_log4j2_debug = "LOG4J2_DEBUG"; +const char *const mi_lttng_loglevel_str_log4j2_trace = "LOG4J2_TRACE"; +const char *const mi_lttng_loglevel_str_log4j2_all = "LOG4J2_ALL"; + /* String related to loglevel Python */ const char *const mi_lttng_loglevel_str_python_critical = "PYTHON_CRITICAL"; const char *const mi_lttng_loglevel_str_python_error = "PYTHON_ERROR"; @@ -275,6 +285,7 @@ const char *const mi_lttng_element_event_rule_kernel_syscall = "event_rule_kerne const char *const mi_lttng_element_event_rule_kernel_tracepoint = "event_rule_kernel_tracepoint"; const char *const mi_lttng_element_event_rule_kernel_uprobe = "event_rule_kernel_uprobe"; const char *const mi_lttng_element_event_rule_log4j_logging = "event_rule_log4j_logging"; +const char *const mi_lttng_element_event_rule_log4j2_logging = "event_rule_log4j2_logging"; const char *const mi_lttng_element_event_rule_python_logging = "event_rule_python_logging"; const char *const mi_lttng_element_event_rule_user_tracepoint = "event_rule_user_tracepoint"; @@ -432,6 +443,30 @@ const char *mi_lttng_loglevel_string(int value, enum lttng_domain_type domain) return mi_lttng_loglevel_str_unknown; } break; + case LTTNG_DOMAIN_LOG4J2: + switch (value) { + case -1: + return mi_lttng_element_empty; + case LTTNG_LOGLEVEL_LOG4J2_OFF: + return mi_lttng_loglevel_str_log4j2_off; + case LTTNG_LOGLEVEL_LOG4J2_FATAL: + return mi_lttng_loglevel_str_log4j2_fatal; + case LTTNG_LOGLEVEL_LOG4J2_ERROR: + return mi_lttng_loglevel_str_log4j2_error; + case LTTNG_LOGLEVEL_LOG4J2_WARN: + return mi_lttng_loglevel_str_log4j2_warn; + case LTTNG_LOGLEVEL_LOG4J2_INFO: + return mi_lttng_loglevel_str_log4j2_info; + case LTTNG_LOGLEVEL_LOG4J2_DEBUG: + return mi_lttng_loglevel_str_log4j2_debug; + case LTTNG_LOGLEVEL_LOG4J2_TRACE: + return mi_lttng_loglevel_str_log4j2_trace; + case LTTNG_LOGLEVEL_LOG4J2_ALL: + return mi_lttng_loglevel_str_log4j2_all; + default: + return mi_lttng_loglevel_str_unknown; + } + break; case LTTNG_DOMAIN_JUL: switch (value) { case -1: @@ -630,6 +665,8 @@ const char *mi_lttng_domaintype_string(enum lttng_domain_type value) return config_domain_type_jul; case LTTNG_DOMAIN_LOG4J: return config_domain_type_log4j; + case LTTNG_DOMAIN_LOG4J2: + return config_domain_type_log4j2; case LTTNG_DOMAIN_PYTHON: return config_domain_type_python; default: diff --git a/src/common/mi-lttng.hpp b/src/common/mi-lttng.hpp index 10a3e13f5..0ab5abc1b 100644 --- a/src/common/mi-lttng.hpp +++ b/src/common/mi-lttng.hpp @@ -173,6 +173,16 @@ LTTNG_EXPORT extern const char *const mi_lttng_loglevel_str_log4j_debug; LTTNG_EXPORT extern const char *const mi_lttng_loglevel_str_log4j_trace; LTTNG_EXPORT extern const char *const mi_lttng_loglevel_str_log4j_all; +/* String related to loglevel Log4j2 */ +extern const char *const mi_lttng_loglevel_str_log4j2_off; +extern const char *const mi_lttng_loglevel_str_log4j2_fatal; +extern const char *const mi_lttng_loglevel_str_log4j2_error; +extern const char *const mi_lttng_loglevel_str_log4j2_warn; +extern const char *const mi_lttng_loglevel_str_log4j2_info; +extern const char *const mi_lttng_loglevel_str_log4j2_debug; +extern const char *const mi_lttng_loglevel_str_log4j2_trace; +extern const char *const mi_lttng_loglevel_str_log4j2_all; + /* String related to loglevel Python */ LTTNG_EXPORT extern const char *const mi_lttng_loglevel_str_python_critical; LTTNG_EXPORT extern const char *const mi_lttng_loglevel_str_python_error; @@ -290,6 +300,7 @@ extern const char *const mi_lttng_element_event_rule_kernel_syscall; extern const char *const mi_lttng_element_event_rule_kernel_tracepoint; extern const char *const mi_lttng_element_event_rule_kernel_uprobe; extern const char *const mi_lttng_element_event_rule_log4j_logging; +extern const char *const mi_lttng_element_event_rule_log4j2_logging; extern const char *const mi_lttng_element_event_rule_python_logging; extern const char *const mi_lttng_element_event_rule_user_tracepoint; diff --git a/src/common/session.xsd b/src/common/session.xsd index 986fb2dda..20e4cfe54 100644 --- a/src/common/session.xsd +++ b/src/common/session.xsd @@ -235,6 +235,7 @@ by its signed 32-bit representation when converted to msec. + diff --git a/src/lib/lttng-ctl/liblttng-ctl.sym b/src/lib/lttng-ctl/liblttng-ctl.sym index 3bd9efb76..ff1aa823d 100644 --- a/src/lib/lttng-ctl/liblttng-ctl.sym +++ b/src/lib/lttng-ctl/liblttng-ctl.sym @@ -4,6 +4,7 @@ config_buffer_type_per_uid config_domain_type_jul config_domain_type_kernel config_domain_type_log4j +config_domain_type_log4j2 config_domain_type_python config_domain_type_ust config_element_address @@ -293,6 +294,13 @@ lttng_event_rule_log4j_logging_get_name_pattern lttng_event_rule_log4j_logging_set_filter lttng_event_rule_log4j_logging_set_log_level_rule lttng_event_rule_log4j_logging_set_name_pattern +lttng_event_rule_log4j2_logging_create +lttng_event_rule_log4j2_logging_get_filter +lttng_event_rule_log4j2_logging_get_log_level_rule +lttng_event_rule_log4j2_logging_get_name_pattern +lttng_event_rule_log4j2_logging_set_filter +lttng_event_rule_log4j2_logging_set_log_level_rule +lttng_event_rule_log4j2_logging_set_name_pattern lttng_event_rule_python_logging_create lttng_event_rule_python_logging_get_filter lttng_event_rule_python_logging_get_log_level_rule diff --git a/src/lib/lttng-ctl/lttng-ctl.cpp b/src/lib/lttng-ctl/lttng-ctl.cpp index 5057b75ef..c5c04c262 100644 --- a/src/lib/lttng-ctl/lttng-ctl.cpp +++ b/src/lib/lttng-ctl/lttng-ctl.cpp @@ -93,6 +93,7 @@ void lttng_ctl_copy_lttng_domain(struct lttng_domain *dst, struct lttng_domain * case LTTNG_DOMAIN_UST: case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: + case LTTNG_DOMAIN_LOG4J2: case LTTNG_DOMAIN_PYTHON: memcpy(dst, src, sizeof(struct lttng_domain)); break; @@ -1011,12 +1012,14 @@ int lttng_enable_event_with_filter(struct lttng_handle *handle, * * An event with NO loglevel and the name is * will return NULL. */ -static char *set_agent_filter(const char *filter, struct lttng_event *ev) +static char * +set_agent_filter(const char *filter, struct lttng_event *ev, struct lttng_domain *domain) { int err; char *agent_filter = nullptr; LTTNG_ASSERT(ev); + LTTNG_ASSERT(domain); /* Don't add filter for the '*' event. */ if (strcmp(ev->name, "*") != 0) { @@ -1032,12 +1035,20 @@ static char *set_agent_filter(const char *filter, struct lttng_event *ev) } } - /* Add loglevel filtering if any for the JUL domain. */ + /* Add loglevel filtering if any for the agent domains. */ if (ev->loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) { const char *op; if (ev->loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) { - op = ">="; + /* + * Log4j2 is the only agent domain for which more severe + * logging levels have a lower numerical value. + */ + if (domain->type == LTTNG_DOMAIN_LOG4J2) { + op = "<="; + } else { + op = ">="; + } } else { op = "=="; } @@ -1134,18 +1145,20 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, /* Parse filter expression. */ if (filter_expression != nullptr || handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J || + handle->domain.type == LTTNG_DOMAIN_LOG4J2 || handle->domain.type == LTTNG_DOMAIN_PYTHON) { if (handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J || + handle->domain.type == LTTNG_DOMAIN_LOG4J2 || handle->domain.type == LTTNG_DOMAIN_PYTHON) { char *agent_filter; /* Setup agent filter if needed. */ - agent_filter = set_agent_filter(filter_expression, ev); + agent_filter = set_agent_filter(filter_expression, ev, &handle->domain); if (!agent_filter) { if (!filter_expression) { /* - * No JUL and no filter, just skip + * No agent and no filter, just skip * everything below. */ goto serialize; @@ -1317,14 +1330,16 @@ int lttng_disable_event_ext(struct lttng_handle *handle, /* Parse filter expression. */ if (filter_expression != nullptr || handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J || + handle->domain.type == LTTNG_DOMAIN_LOG4J2 || handle->domain.type == LTTNG_DOMAIN_PYTHON) { if (handle->domain.type == LTTNG_DOMAIN_JUL || handle->domain.type == LTTNG_DOMAIN_LOG4J || + handle->domain.type == LTTNG_DOMAIN_LOG4J2 || handle->domain.type == LTTNG_DOMAIN_PYTHON) { char *agent_filter; /* Setup agent filter if needed. */ - agent_filter = set_agent_filter(filter_expression, ev); + agent_filter = set_agent_filter(filter_expression, ev, &handle->domain); if (!agent_filter) { if (!filter_expression) { /*