@sa lttng_channel_set_monitor_timer_interval() --
Sets the monitor timer period property of a channel summary.
*/
-LTTNG_EXPORT extern int lttng_channel_get_monitor_timer_interval(struct lttng_channel *channel,
- uint64_t *period);
+LTTNG_EXPORT extern int
+lttng_channel_get_monitor_timer_interval(const struct lttng_channel *channel, uint64_t *period);
/*!
@brief
@sa lttng_channel_set_blocking_timeout() --
Sets the blocking timeout property of a channel summary.
*/
-LTTNG_EXPORT extern int lttng_channel_get_blocking_timeout(struct lttng_channel *channel,
+LTTNG_EXPORT extern int lttng_channel_get_blocking_timeout(const struct lttng_channel *channel,
int64_t *timeout);
/*!
#include <lttng/event.h>
#include <lttng/lttng-error.h>
+#include <functional>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
using event_rule_mi_serialize_cb = enum lttng_error_code (*)(const struct lttng_event_rule *,
struct mi_writer *);
+struct lttng_event_rule;
+
+bool lttng_event_rule_is_equal(const struct lttng_event_rule *a, const struct lttng_event_rule *b);
+
+unsigned long lttng_event_rule_hash(const struct lttng_event_rule *rule);
+
struct lttng_event_rule {
struct urcu_ref ref;
enum lttng_event_rule_type type;
event_rule_hash_cb hash;
event_rule_generate_lttng_event_cb generate_lttng_event;
event_rule_mi_serialize_cb mi_serialize;
+
+ bool operator==(const lttng_event_rule& other) const
+ {
+ return lttng_event_rule_is_equal(this, &other);
+ }
};
struct lttng_event_rule_comm {
char payload[];
};
+/* Specialize std::hash for lttng_event_rule (by reference) */
+namespace std {
+template <>
+struct hash<std::reference_wrapper<const lttng_event_rule>> {
+ std::size_t
+ operator()(const std::reference_wrapper<const lttng_event_rule> rule) const noexcept
+ {
+ return lttng_event_rule_hash(&rule.get());
+ }
+};
+} /* namespace std */
+
+/* Implement equality comparison for std::reference_wrapper of lttng_event_rule */
+struct lttng_event_rule_ref_equal {
+ bool operator()(const std::reference_wrapper<const lttng_event_rule> lhs,
+ const std::reference_wrapper<const lttng_event_rule> rhs) const
+ {
+ /* Use the operator== defined for lttng_event_rule. */
+ return lhs.get() == rhs.get();
+ }
+};
+
void lttng_event_rule_init(struct lttng_event_rule *event_rule, enum lttng_event_rule_type type);
bool lttng_event_rule_validate(const struct lttng_event_rule *event_rule);
int lttng_event_rule_serialize(const struct lttng_event_rule *event_rule,
struct lttng_payload *payload);
-bool lttng_event_rule_is_equal(const struct lttng_event_rule *a, const struct lttng_event_rule *b);
-
bool lttng_event_rule_get(struct lttng_event_rule *rule);
void lttng_event_rule_put(struct lttng_event_rule *rule);
const char *lttng_event_rule_type_str(enum lttng_event_rule_type type);
-unsigned long lttng_event_rule_hash(const struct lttng_event_rule *rule);
-
/*
* This is a compatibility helper allowing us to generate a sessiond-side (not
* communication) `struct lttng_event` object from an event rule.
trace-class.hpp trace-class.cpp \
consumer-destination-type.hpp \
consumer-output.hpp \
- snapshot-output.hpp
+ snapshot-output.hpp \
+ recording-channel-configuration.hpp recording-channel-configuration.cpp \
+ event-rule-configuration.hpp event-rule-configuration.cpp \
+ domain.hpp domain.cpp
if HAVE_LIBLTTNG_UST_CTL
liblttng_sessiond_common_la_SOURCES += trace-ust.cpp ust-registry.cpp ust-app.cpp \
#include <common/buffer-view.hpp>
#include <common/compat/getenv.hpp>
#include <common/compat/socket.hpp>
+#include <common/ctl/format.hpp>
+#include <common/ctl/memory.hpp>
#include <common/dynamic-array.hpp>
#include <common/dynamic-buffer.hpp>
#include <common/exception.hpp>
#include <lttng/error-query-internal.hpp>
#include <lttng/event-internal.hpp>
+#include <lttng/event-rule/event-rule-internal.hpp>
#include <lttng/lttng.h>
#include <lttng/session-descriptor-internal.hpp>
#include <lttng/session-internal.hpp>
struct lttng_event **out_event,
char **out_filter_expression,
struct lttng_bytecode **out_bytecode,
- struct lttng_event_exclusion **out_exclusion)
+ struct lttng_event_exclusion **out_exclusion,
+ lttng::event_rule_uptr& event_rule)
{
int ret;
size_t event_len;
/* Deserialize event. */
{
ssize_t len;
- struct lttng_payload_view event_view =
+ lttng_payload_view event_view =
lttng_payload_view_from_payload(&event_payload, 0, -1);
len = lttng_event_create_from_payload(&event_view,
goto end;
}
- if (len != event_len) {
- ERR("Userspace probe location from the received buffer is not the advertised length: header length = %zu" PRIu32
- ", payload length = %zd",
- event_len,
- len);
- ret_code = LTTNG_ERR_INVALID_PROTOCOL;
- goto end;
+ lttng_payload_view event_rule_view =
+ lttng_payload_view_from_payload(&event_payload, len, -1);
+
+ /*
+ * The disable event command, when issued with LTTNG_EVENT_ALL,
+ * does not provide an event rule.
+ *
+ * The semantics of LTTNG_EVENT_ALL vary between enable and disable
+ * event commands:
+ * - enable: means enable all tracepoints and syscalls (if kernel domain).
+ * - disable: disable any enabled event regardless of instrumentation type.
+ */
+ if (event_rule_view.buffer.size > 0) {
+ lttng_event_rule *raw_event_rule;
+ ret = lttng_event_rule_create_from_payload(&event_rule_view,
+ &raw_event_rule);
+ if (ret < 0) {
+ ERR("Failed to create an event rule from the received buffer");
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+
+ event_rule.reset(raw_event_rule);
}
}
}
case LTTCOMM_SESSIOND_COMMAND_DISABLE_CHANNEL:
{
- ret = cmd_disable_channel(*target_session,
- cmd_ctx->lsm.domain.type,
- cmd_ctx->lsm.u.disable.channel_name);
+ try {
+ ret = cmd_disable_channel(*target_session,
+ cmd_ctx->lsm.domain.type,
+ cmd_ctx->lsm.u.disable.channel_name);
+ } catch (const std::out_of_range& oor_ex) {
+ const auto channel_name = cmd_ctx->lsm.u.disable.channel_name;
+ const auto domain_type = cmd_ctx->lsm.domain.type;
+
+ ERR_FMT("Failed to disable channel: session_name=`{}`, channel_name=`{}`, domain={}",
+ (*target_session)->name,
+ channel_name,
+ domain_type);
+ ret = LTTNG_ERR_CHAN_NOT_FOUND;
+ }
+
break;
}
case LTTCOMM_SESSIOND_COMMAND_ENABLE_CHANNEL:
char *filter_expression;
struct lttng_event_exclusion *exclusions;
struct lttng_bytecode *bytecode;
+ lttng::event_rule_uptr event_rule;
const enum lttng_error_code ret_code = receive_lttng_event(cmd_ctx,
*sock,
sock_error,
&event,
&filter_expression,
&bytecode,
- &exclusions);
+ &exclusions,
+ event_rule);
if (ret_code != LTTNG_OK) {
ret = (int) ret_code;
filter_expression,
exclusions,
bytecode,
- the_kernel_poll_pipe[1]) :
+ the_kernel_poll_pipe[1],
+ std::move(event_rule)) :
cmd_disable_event(cmd_ctx,
*target_session,
event,
filter_expression,
bytecode,
- exclusions);
+ exclusions,
+ std::move(event_rule));
lttng_event_destroy(event);
break;
}
} catch (const lttng::sessiond::exceptions::session_not_found_error& ex) {
log_nested_exceptions(ex);
ret = LTTNG_ERR_SESS_NOT_FOUND;
+ } catch (const lttng::sessiond::exceptions::channel_not_found_error& ex) {
+ log_nested_exceptions(ex);
+ ret = LTTNG_ERR_CHAN_NOT_FOUND;
} catch (const lttng::runtime_error& ex) {
log_nested_exceptions(ex);
ret = LTTNG_ERR_UNK;
#include "lttng-syscall.hpp"
#include "notification-thread-commands.hpp"
#include "notification-thread.hpp"
+#include "recording-channel-configuration.hpp"
#include "rotation-thread.hpp"
#include "session.hpp"
#include "timer.hpp"
#include <common/buffer-view.hpp>
#include <common/common.hpp>
#include <common/compat/string.hpp>
+#include <common/ctl/format.hpp>
#include <common/defaults.hpp>
#include <common/dynamic-buffer.hpp>
+#include <common/exception.hpp>
#include <common/kernel-ctl/kernel-ctl.hpp>
+#include <common/make-unique-wrapper.hpp>
+#include <common/math.hpp>
#include <common/payload-view.hpp>
#include <common/payload.hpp>
#include <common/relayd/relayd.hpp>
+#include <common/scope-exit.hpp>
#include <common/sessiond-comm/sessiond-comm.hpp>
#include <common/string-utils/string-utils.hpp>
#include <common/trace-chunk.hpp>
/* Sleep for 100ms between each check for the shm path's deletion. */
#define SESSION_DESTROY_SHM_PATH_CHECK_DELAY_US 100000
+namespace ls = lttng::sessiond;
namespace lsu = lttng::sessiond::ust;
static enum lttng_error_code wait_on_path(void *path);
char *filter_expression,
struct lttng_bytecode *filter,
struct lttng_event_exclusion *exclusion,
- int wpipe);
+ int wpipe,
+ lttng::event_rule_uptr event_rule);
static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref& session,
const struct lttng_domain *domain,
- const struct lttng_channel *_attr,
+ const struct lttng_channel& channel_attr,
int wpipe);
/*
return ret;
}
+namespace {
+lttng::sessiond::domain_class
+get_domain_class_from_ctl_domain_type(enum lttng_domain_type domain_type)
+{
+ switch (domain_type) {
+ case LTTNG_DOMAIN_KERNEL:
+ return lttng::sessiond::domain_class::KERNEL_SPACE;
+ case LTTNG_DOMAIN_UST:
+ return lttng::sessiond::domain_class::USER_SPACE;
+ case LTTNG_DOMAIN_JUL:
+ return lttng::sessiond::domain_class::JAVA_UTIL_LOGGING;
+ case LTTNG_DOMAIN_LOG4J:
+ return lttng::sessiond::domain_class::LOG4J;
+ case LTTNG_DOMAIN_PYTHON:
+ return lttng::sessiond::domain_class::PYTHON_LOGGING;
+ case LTTNG_DOMAIN_LOG4J2:
+ return lttng::sessiond::domain_class::LOG4J2;
+ default:
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "No suitable conversion exists from lttng_domain_type enum to lttng::sessiond::domain_class: domain={}",
+ domain_type));
+ }
+}
+} /* namespace */
+
/*
* Command LTTNG_DISABLE_CHANNEL processed by the client thread.
*/
enum lttng_domain_type domain,
char *channel_name)
{
- int ret;
- struct ltt_ust_session *usess;
+ ls::domain& target_domain =
+ session->get_domain(get_domain_class_from_ctl_domain_type(domain));
- usess = session->ust_session;
+ /* Throws if not found. */
+ auto& channel_config = target_domain.get_channel(channel_name);
const lttng::urcu::read_lock_guard read_lock;
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
{
- ret = channel_kernel_disable(session->kernel_session, channel_name);
- if (ret != LTTNG_OK) {
- goto error;
+ const auto disable_ret =
+ channel_kernel_disable(session->kernel_session, channel_name);
+ if (disable_ret != LTTNG_OK) {
+ return disable_ret;
}
kernel_wait_quiescent();
}
case LTTNG_DOMAIN_UST:
{
- struct ltt_ust_channel *uchan;
- struct lttng_ht *chan_ht;
-
- chan_ht = usess->domain_global.channels;
+ const auto usess = session->ust_session;
+ const auto chan_ht = usess->domain_global.channels;
+ const auto uchan = trace_ust_find_channel_by_name(chan_ht, channel_name);
- uchan = trace_ust_find_channel_by_name(chan_ht, channel_name);
if (uchan == nullptr) {
- ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
- goto error;
+ return LTTNG_ERR_UST_CHAN_NOT_FOUND;
}
- ret = channel_ust_disable(usess, uchan);
- if (ret != LTTNG_OK) {
- goto error;
+ const auto disable_ret = channel_ust_disable(usess, uchan);
+ if (disable_ret != LTTNG_OK) {
+ return disable_ret;
}
+
break;
}
default:
- ret = LTTNG_ERR_UNKNOWN_DOMAIN;
- goto error;
+ return LTTNG_ERR_UNKNOWN_DOMAIN;
}
- ret = LTTNG_OK;
+ channel_config.disable();
-error:
- return ret;
+ return LTTNG_OK;
}
/*
*/
int cmd_enable_channel(command_ctx *cmd_ctx, ltt_session::locked_ref& session, int sock, int wpipe)
{
- int ret;
- size_t channel_len;
- ssize_t sock_recv_len;
- struct lttng_channel *channel = nullptr;
- struct lttng_buffer_view view;
- struct lttng_dynamic_buffer channel_buffer;
const struct lttng_domain command_domain = cmd_ctx->lsm.domain;
+ if (command_domain.type == LTTNG_DOMAIN_NONE) {
+ return LTTNG_ERR_INVALID;
+ }
+
+ /* Free buffer contents on function exit using a scope_exit. */
+ lttng_dynamic_buffer channel_buffer;
lttng_dynamic_buffer_init(&channel_buffer);
- channel_len = (size_t) cmd_ctx->lsm.u.channel.length;
- ret = lttng_dynamic_buffer_set_size(&channel_buffer, channel_len);
- if (ret) {
- ret = LTTNG_ERR_NOMEM;
- goto end;
+ auto destroy_buffer = lttng::make_scope_exit(
+ [&channel_buffer]() noexcept { lttng_dynamic_buffer_reset(&channel_buffer); });
+
+ const size_t channel_len = (size_t) cmd_ctx->lsm.u.channel.length;
+
+ const int buffer_alloc_ret = lttng_dynamic_buffer_set_size(&channel_buffer, channel_len);
+ if (buffer_alloc_ret) {
+ return LTTNG_ERR_NOMEM;
}
- sock_recv_len = lttcomm_recv_unix_sock(sock, channel_buffer.data, channel_len);
+ const auto sock_recv_len = lttcomm_recv_unix_sock(sock, channel_buffer.data, channel_len);
if (sock_recv_len < 0 || sock_recv_len != channel_len) {
ERR("Failed to receive \"enable channel\" command payload");
- ret = LTTNG_ERR_INVALID;
- goto end;
+ return LTTNG_ERR_INVALID;
}
- view = lttng_buffer_view_from_dynamic_buffer(&channel_buffer, 0, channel_len);
+ auto view = lttng_buffer_view_from_dynamic_buffer(&channel_buffer, 0, channel_len);
if (!lttng_buffer_view_is_valid(&view)) {
- ret = LTTNG_ERR_INVALID;
- goto end;
+ /* lttng_buffer_view_from_dynamic_buffer already logs on error. */
+ return LTTNG_ERR_INVALID;
}
- if (lttng_channel_create_from_buffer(&view, &channel) != channel_len) {
- ERR("Invalid channel payload received in \"enable channel\" command");
- ret = LTTNG_ERR_INVALID;
- goto end;
- }
+ auto channel = lttng::make_unique_wrapper<lttng_channel,
+ lttng_channel_destroy>([&view, channel_len]() {
+ lttng_channel *raw_channel = nullptr;
+
+ if (lttng_channel_create_from_buffer(&view, &raw_channel) != channel_len) {
+ LTTNG_THROW_PROTOCOL_ERROR(
+ "Invalid channel payload received in \"enable channel\" command");
+ }
- ret = cmd_enable_channel_internal(session, &command_domain, channel, wpipe);
+ return raw_channel;
+ }());
-end:
- lttng_dynamic_buffer_reset(&channel_buffer);
- lttng_channel_destroy(channel);
- return ret;
+ const auto cmd_ret = cmd_enable_channel_internal(session, &command_domain, *channel, wpipe);
+ if (cmd_ret != LTTNG_OK) {
+ return cmd_ret;
+ }
+
+ return LTTNG_OK;
}
static enum lttng_error_code cmd_enable_channel_internal(ltt_session::locked_ref& session,
const struct lttng_domain *domain,
- const struct lttng_channel *_attr,
+ const struct lttng_channel& channel_attr,
int wpipe)
{
enum lttng_error_code ret_code;
struct ltt_ust_session *usess = session->ust_session;
struct lttng_ht *chan_ht;
size_t len;
- struct lttng_channel *attr = nullptr;
- LTTNG_ASSERT(_attr);
LTTNG_ASSERT(domain);
const lttng::urcu::read_lock_guard read_lock;
- attr = lttng_channel_copy(_attr);
- if (!attr) {
- ret_code = LTTNG_ERR_NOMEM;
- goto end;
+ auto new_channel_attr = lttng::make_unique_wrapper<lttng_channel, lttng_channel_destroy>(
+ lttng_channel_copy(&channel_attr));
+ if (!new_channel_attr) {
+ return LTTNG_ERR_NOMEM;
}
- len = lttng_strnlen(attr->name, sizeof(attr->name));
+ len = lttng_strnlen(new_channel_attr->name, sizeof(new_channel_attr->name));
/* Validate channel name */
- if (attr->name[0] == '.' || memchr(attr->name, '/', len) != nullptr) {
- ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
- goto end;
+ if (new_channel_attr->name[0] == '.' ||
+ memchr(new_channel_attr->name, '/', len) != nullptr) {
+ return LTTNG_ERR_INVALID_CHANNEL_NAME;
}
- DBG("Enabling channel %s for session %s", attr->name, session->name);
+ DBG("Enabling channel %s for session %s", new_channel_attr->name, session->name);
/*
* If the session is a live session, remove the switch timer, the
* beacons for inactive streams.
*/
if (session->live_timer > 0) {
- attr->attr.live_timer_interval = session->live_timer;
- attr->attr.switch_timer_interval = 0;
+ new_channel_attr->attr.live_timer_interval = session->live_timer;
+ new_channel_attr->attr.switch_timer_interval = 0;
}
/* Check for feature support */
WARN("Kernel tracer does not support buffer monitoring. "
"Setting the monitor interval timer to 0 "
"(disabled) for channel '%s' of session '%s'",
- attr->name,
+ new_channel_attr->name,
session->name);
- lttng_channel_set_monitor_timer_interval(attr, 0);
+ lttng_channel_set_monitor_timer_interval(new_channel_attr.get(), 0);
}
+
break;
}
case LTTNG_DOMAIN_UST:
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");
- ret_code = LTTNG_ERR_AGENT_TRACING_DISABLED;
- goto error;
+ return LTTNG_ERR_AGENT_TRACING_DISABLED;
}
+
break;
default:
- ret_code = LTTNG_ERR_UNKNOWN_DOMAIN;
- goto error;
+ return LTTNG_ERR_UNKNOWN_DOMAIN;
}
switch (domain->type) {
{
struct ltt_kernel_channel *kchan;
- kchan = trace_kernel_get_channel_by_name(attr->name, session->kernel_session);
+ kchan = trace_kernel_get_channel_by_name(new_channel_attr->name,
+ session->kernel_session);
if (kchan == nullptr) {
/*
* Don't try to create a channel if the session has been started at
* some point in time before. The tracer does not allow it.
*/
if (session->has_been_started) {
- ret_code = LTTNG_ERR_TRACE_ALREADY_STARTED;
- goto error;
+ return LTTNG_ERR_TRACE_ALREADY_STARTED;
}
if (session->snapshot.nb_output > 0 || session->snapshot_mode) {
/* Enforce mmap output for snapshot sessions. */
- attr->attr.output = LTTNG_EVENT_MMAP;
+ new_channel_attr->attr.output = LTTNG_EVENT_MMAP;
}
- ret_code = channel_kernel_create(session->kernel_session, attr, wpipe);
- if (attr->name[0] != '\0') {
+
+ ret_code = channel_kernel_create(
+ session->kernel_session, new_channel_attr.get(), wpipe);
+ if (new_channel_attr->name[0] != '\0') {
session->kernel_session->has_non_default_channel = 1;
}
} else {
}
if (ret_code != LTTNG_OK) {
- goto error;
+ return ret_code;
}
kernel_wait_quiescent();
* adhered to.
*/
if (domain->type == LTTNG_DOMAIN_JUL) {
- if (strncmp(attr->name,
+ if (strncmp(new_channel_attr->name,
DEFAULT_JUL_CHANNEL_NAME,
LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
- ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
- goto error;
+ return LTTNG_ERR_INVALID_CHANNEL_NAME;
}
} else if (domain->type == LTTNG_DOMAIN_LOG4J) {
- if (strncmp(attr->name,
+ if (strncmp(new_channel_attr->name,
DEFAULT_LOG4J_CHANNEL_NAME,
LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
- ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
- goto error;
+ return LTTNG_ERR_INVALID_CHANNEL_NAME;
}
} else if (domain->type == LTTNG_DOMAIN_LOG4J2) {
- if (strncmp(attr->name,
+ if (strncmp(new_channel_attr->name,
DEFAULT_LOG4J2_CHANNEL_NAME,
LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
- ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
- goto error;
+ return LTTNG_ERR_INVALID_CHANNEL_NAME;
}
} else if (domain->type == LTTNG_DOMAIN_PYTHON) {
- if (strncmp(attr->name,
+ if (strncmp(new_channel_attr->name,
DEFAULT_PYTHON_CHANNEL_NAME,
LTTNG_SYMBOL_NAME_LEN - 1) != 0) {
- ret_code = LTTNG_ERR_INVALID_CHANNEL_NAME;
- goto error;
+ return LTTNG_ERR_INVALID_CHANNEL_NAME;
}
}
chan_ht = usess->domain_global.channels;
- uchan = trace_ust_find_channel_by_name(chan_ht, attr->name);
+ uchan = trace_ust_find_channel_by_name(chan_ht, new_channel_attr->name);
if (uchan == nullptr) {
/*
* Don't try to create a channel if the session has been started at
* some point in time before. The tracer does not allow it.
*/
if (session->has_been_started) {
- ret_code = LTTNG_ERR_TRACE_ALREADY_STARTED;
- goto error;
+ return LTTNG_ERR_TRACE_ALREADY_STARTED;
}
- ret_code = channel_ust_create(usess, attr, domain->buf_type);
- if (attr->name[0] != '\0') {
+ ret_code =
+ channel_ust_create(usess, new_channel_attr.get(), domain->buf_type);
+ if (new_channel_attr->name[0] != '\0') {
usess->has_non_default_channel = 1;
}
} else {
ret_code = channel_ust_enable(usess, uchan);
}
+
break;
}
default:
- ret_code = LTTNG_ERR_UNKNOWN_DOMAIN;
- goto error;
+ return LTTNG_ERR_UNKNOWN_DOMAIN;
}
- if (ret_code == LTTNG_OK && attr->attr.output != LTTNG_EVENT_MMAP) {
+ if (ret_code == LTTNG_OK && new_channel_attr->attr.output != LTTNG_EVENT_MMAP) {
session->has_non_mmap_channel = true;
}
-error:
-end:
- lttng_channel_destroy(attr);
+
+ const auto subbuffer_count = channel_attr.attr.num_subbuf;
+
+ const auto switch_timer_period_us = [&channel_attr]() {
+ return channel_attr.attr.switch_timer_interval > 0 ?
+ decltype(ls::recording_channel_configuration::switch_timer_period_us)(
+ channel_attr.attr.switch_timer_interval) :
+ nonstd::nullopt;
+ }();
+
+ const auto read_timer_period_us = [&channel_attr]() {
+ return channel_attr.attr.read_timer_interval > 0 ?
+ decltype(ls::recording_channel_configuration::read_timer_period_us)(
+ channel_attr.attr.read_timer_interval) :
+ nonstd::nullopt;
+ }();
+
+ const auto live_timer_period_us = [&channel_attr]() {
+ return channel_attr.attr.live_timer_interval > 0 ?
+ decltype(ls::recording_channel_configuration::live_timer_period_us)(
+ channel_attr.attr.live_timer_interval) :
+ nonstd::nullopt;
+ }();
+
+ const auto monitor_timer_period_us = [&channel_attr]() {
+ std::uint64_t period;
+ const int ret = lttng_channel_get_monitor_timer_interval(&channel_attr, &period);
+
+ if (ret) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to retrieve monitor timer period from channel: channel_name=`{}`",
+ channel_attr.name));
+ }
+
+ return period > 0 ?
+ decltype(ls::recording_channel_configuration::monitor_timer_period_us)(
+ period) :
+ nonstd::nullopt;
+ }();
+
+ auto blocking_policy = [&channel_attr]() {
+ std::int64_t timeout_us;
+ const int ret = lttng_channel_get_blocking_timeout(&channel_attr, &timeout_us);
+
+ if (ret) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to retrieve blocking timeout from channel: channel_name=`{}`",
+ channel_attr.name));
+ }
+
+ switch (timeout_us) {
+ case 0:
+ return ls::recording_channel_configuration::consumption_blocking_policy(
+ ls::recording_channel_configuration::consumption_blocking_policy::
+ mode::NONE);
+ case -1:
+ return ls::recording_channel_configuration::consumption_blocking_policy(
+ ls::recording_channel_configuration::consumption_blocking_policy::
+ mode::UNBOUNDED);
+ default:
+ if (timeout_us < 0) {
+ /*Negative, but not -1. */
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Invalid buffer consumption blocking policy timeout value: timeout_us={}",
+ timeout_us));
+ }
+
+ return ls::recording_channel_configuration::consumption_blocking_policy(
+ ls::recording_channel_configuration::consumption_blocking_policy::
+ mode::TIMED,
+ timeout_us);
+ }
+ }();
+
+ ls::domain& target_domain =
+ session->get_domain(get_domain_class_from_ctl_domain_type(domain->type));
+
+ /* Extract all channel properties needed to initialize the channel. */
+ auto name = std::string(channel_attr.name[0] ? channel_attr.name : DEFAULT_CHANNEL_NAME);
+ const auto is_enabled = !!channel_attr.enabled;
+ const auto buffer_full_policy = [&session](int overwrite_value) {
+ switch (overwrite_value) {
+ case -1:
+ /* Session default. */
+ return session->snapshot_mode ?
+ ls::recording_channel_configuration::buffer_full_policy_t::
+ OVERWRITE_OLDEST_PACKET :
+ ls::recording_channel_configuration::buffer_full_policy_t::
+ DISCARD_EVENT;
+ case 0:
+ return ls::recording_channel_configuration::buffer_full_policy_t::
+ DISCARD_EVENT;
+ case 1:
+ return ls::recording_channel_configuration::buffer_full_policy_t::
+ OVERWRITE_OLDEST_PACKET;
+ default:
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Invalid channel overwrite property value received: value={}",
+ overwrite_value));
+ }
+ }(channel_attr.attr.overwrite);
+ const auto trace_file_size_limit_bytes = channel_attr.attr.tracefile_size ?
+ decltype(ls::recording_channel_configuration::trace_file_size_limit_bytes)(
+ channel_attr.attr.tracefile_size) :
+ nonstd::nullopt;
+
+ const auto trace_file_count_limit = channel_attr.attr.tracefile_count ?
+ decltype(ls::recording_channel_configuration::trace_file_count_limit)(
+ channel_attr.attr.tracefile_count) :
+ nonstd::nullopt;
+
+ /* Validate consumption backend (mmap or splice). */
+ if (target_domain.domain_class_ != ls::domain_class::KERNEL_SPACE &&
+ channel_attr.attr.output != LTTNG_EVENT_MMAP) {
+ LTTNG_THROW_UNSUPPORTED_ERROR(fmt::format(
+ "Buffer consumption back-end is unsupported by this domain: domain={}, backend=SPLICE",
+ target_domain.domain_class_));
+ }
+
+ const auto buffer_consumption_backend = channel_attr.attr.output == LTTNG_EVENT_MMAP ?
+ ls::recording_channel_configuration::buffer_consumption_backend_t::MMAP :
+ ls::recording_channel_configuration::buffer_consumption_backend_t::SPLICE;
+
+ /* Validate sub-buffer size. */
+ if (!lttng::math::is_power_of_two(channel_attr.attr.subbuf_size) ||
+ channel_attr.attr.subbuf_size < the_page_size) {
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Invalid subbuffer size (must be a power of two and equal or larger than the page size): subbuffer_size={}, page_size={}",
+ channel_attr.attr.subbuf_size,
+ the_page_size));
+ }
+
+ const auto subbuffer_size_bytes = channel_attr.attr.subbuf_size;
+
+ /* Validate sub-buffer count. */
+ if (!lttng::math::is_power_of_two(channel_attr.attr.num_subbuf)) {
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Invalid subbuffer count (must be a power of two): subbuffer_count={}",
+ channel_attr.attr.num_subbuf));
+ }
+
+ try {
+ target_domain.get_channel(name).enable();
+ } catch (const lttng::sessiond::exceptions::channel_not_found_error& ex) {
+ /* Channel doesn't exist, create it. */
+ target_domain.add_channel(is_enabled,
+ std::move(name),
+ buffer_full_policy,
+ buffer_consumption_backend,
+ subbuffer_size_bytes,
+ subbuffer_count,
+ switch_timer_period_us,
+ read_timer_period_us,
+ live_timer_period_us,
+ monitor_timer_period_us,
+ std::move(blocking_policy),
+ trace_file_size_limit_bytes,
+ trace_file_count_limit);
+ }
+
return ret_code;
}
return ret_code;
}
+namespace {
+/* An unset value means 'match all'. */
+nonstd::optional<lttng::c_string_view>
+get_event_rule_pattern_or_name(const lttng_event_rule& event_rule)
+{
+ lttng_event_rule_status status;
+ const char *pattern_or_name;
+
+ switch (lttng_event_rule_get_type(&event_rule)) {
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+ status = lttng_event_rule_kernel_syscall_get_name_pattern(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
+ status = lttng_event_rule_kernel_kprobe_get_event_name(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+ status = lttng_event_rule_kernel_tracepoint_get_name_pattern(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
+ status = lttng_event_rule_kernel_uprobe_get_event_name(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+ status = lttng_event_rule_user_tracepoint_get_name_pattern(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+ status = lttng_event_rule_jul_logging_get_name_pattern(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+ status = lttng_event_rule_log4j_logging_get_name_pattern(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+ status = lttng_event_rule_python_logging_get_name_pattern(&event_rule,
+ &pattern_or_name);
+ break;
+ case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
+ status = lttng_event_rule_log4j2_logging_get_name_pattern(&event_rule,
+ &pattern_or_name);
+ break;
+ default:
+ std::abort();
+ }
+
+ if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
+ return nonstd::nullopt;
+ }
+
+ LTTNG_ASSERT(status == LTTNG_EVENT_RULE_STATUS_OK);
+ LTTNG_ASSERT(pattern_or_name);
+
+ return pattern_or_name;
+}
+} /* namespace */
+
/*
* Command LTTNG_DISABLE_EVENT processed by the client thread.
+ *
+ * Filter and exclusions are simply not handled by the disable event command
+ * at this time.
*/
-int cmd_disable_event(struct command_ctx *cmd_ctx,
- ltt_session::locked_ref& locked_session,
- struct lttng_event *event,
- char *filter_expression,
- struct lttng_bytecode *bytecode,
- struct lttng_event_exclusion *exclusion)
+lttng_error_code cmd_disable_event(struct command_ctx *cmd_ctx,
+ ltt_session::locked_ref& locked_session,
+ struct lttng_event *event,
+ char *raw_filter_expression,
+ struct lttng_bytecode *raw_bytecode,
+ struct lttng_event_exclusion *raw_exclusion,
+ lttng::event_rule_uptr event_rule)
{
int ret;
const ltt_session& session = *locked_session;
- const char *event_name;
+ const char *event_name = event->name;
const char *channel_name = cmd_ctx->lsm.u.disable.channel_name;
const enum lttng_domain_type domain = cmd_ctx->lsm.domain.type;
DBG("Disable event command for event \'%s\'", event->name);
- /*
- * Filter and exclusions are simply not handled by the
- * disable event command at this time.
- *
- * FIXME
- */
- (void) filter_expression;
- (void) exclusion;
+ const auto filter_expression =
+ lttng::make_unique_wrapper<char, lttng::memory::free>(raw_filter_expression);
+ const auto bytecode =
+ lttng::make_unique_wrapper<lttng_bytecode, lttng::memory::free>(raw_bytecode);
+ const auto exclusion =
+ lttng::make_unique_wrapper<lttng_event_exclusion, lttng::memory::free>(
+ raw_exclusion);
+
+ if (!event_rule && event->type != LTTNG_EVENT_ALL) {
+ /* LTTNG_EVENT_ALL is the only case where we don't expect an event rule. */
+ return LTTNG_ERR_INVALID_PROTOCOL;
+ }
/* Ignore the presence of filter or exclusion for the event */
event->filter = 0;
event->exclusion = 0;
- event_name = event->name;
+ if (channel_name[0] == '\0') {
+ switch (cmd_ctx->lsm.domain.type) {
+ case LTTNG_DOMAIN_LOG4J:
+ channel_name = DEFAULT_LOG4J_CHANNEL_NAME;
+ break;
+ case LTTNG_DOMAIN_LOG4J2:
+ channel_name = DEFAULT_LOG4J2_CHANNEL_NAME;
+ break;
+ case LTTNG_DOMAIN_JUL:
+ channel_name = DEFAULT_JUL_CHANNEL_NAME;
+ break;
+ case LTTNG_DOMAIN_PYTHON:
+ channel_name = DEFAULT_PYTHON_CHANNEL_NAME;
+ break;
+ default:
+ channel_name = DEFAULT_CHANNEL_NAME;
+ break;
+ }
+ }
const lttng::urcu::read_lock_guard read_lock;
/* Error out on unhandled search criteria */
if (event->loglevel_type || event->loglevel != -1 || event->enabled || event->pid ||
event->filter || event->exclusion) {
- ret = LTTNG_ERR_UNK;
- goto error;
+ return LTTNG_ERR_UNK;
}
+ const bool pattern_disables_all = lttng::c_string_view(event_name) == "";
+
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
{
* to be provided.
*/
if (ksess->has_non_default_channel && channel_name[0] == '\0') {
- ret = LTTNG_ERR_NEED_CHANNEL_NAME;
- goto error_unlock;
+ return LTTNG_ERR_NEED_CHANNEL_NAME;
}
kchan = trace_kernel_get_channel_by_name(channel_name, ksess);
if (kchan == nullptr) {
- ret = LTTNG_ERR_KERN_CHAN_NOT_FOUND;
- goto error_unlock;
+ return LTTNG_ERR_KERN_CHAN_NOT_FOUND;
}
switch (event->type) {
case LTTNG_EVENT_PROBE:
case LTTNG_EVENT_FUNCTION:
case LTTNG_EVENT_FUNCTION_ENTRY: /* fall-through */
- if (event_name[0] == '\0') {
+ if (pattern_disables_all) {
ret = event_kernel_disable_event(kchan, nullptr, event->type);
} else {
ret = event_kernel_disable_event(kchan, event_name, event->type);
}
if (ret != LTTNG_OK) {
- goto error_unlock;
+ return static_cast<lttng_error_code>(ret);
}
break;
default:
- ret = LTTNG_ERR_UNK;
- goto error_unlock;
+ return LTTNG_ERR_UNK;
}
kernel_wait_quiescent();
usess = session.ust_session;
if (validate_ust_event_name(event_name)) {
- ret = LTTNG_ERR_INVALID_EVENT_NAME;
- goto error_unlock;
+ return LTTNG_ERR_INVALID_EVENT_NAME;
}
/*
* to be provided.
*/
if (usess->has_non_default_channel && channel_name[0] == '\0') {
- ret = LTTNG_ERR_NEED_CHANNEL_NAME;
- goto error_unlock;
+ return LTTNG_ERR_NEED_CHANNEL_NAME;
}
uchan = trace_ust_find_channel_by_name(usess->domain_global.channels, channel_name);
if (uchan == nullptr) {
- ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
- goto error_unlock;
+ return LTTNG_ERR_UST_CHAN_NOT_FOUND;
}
switch (event->type) {
case LTTNG_EVENT_ALL:
- /*
- * An empty event name means that everything
- * should be disabled.
- */
- if (event->name[0] == '\0') {
+ if (pattern_disables_all) {
ret = event_ust_disable_all_tracepoints(usess, uchan);
} else {
ret = event_ust_disable_tracepoint(usess, uchan, event_name);
}
+
if (ret != LTTNG_OK) {
- goto error_unlock;
+ return static_cast<lttng_error_code>(ret);
}
break;
default:
- ret = LTTNG_ERR_UNK;
- goto error_unlock;
+ return LTTNG_ERR_UNK;
}
DBG3("Disable UST event %s in channel %s completed", event_name, channel_name);
case LTTNG_EVENT_ALL:
break;
default:
- ret = LTTNG_ERR_UNK;
- goto error_unlock;
+ return LTTNG_ERR_UNK;
}
agt = trace_ust_find_agent(usess, domain);
if (!agt) {
- ret = -LTTNG_ERR_UST_EVENT_NOT_FOUND;
- goto error_unlock;
+ return LTTNG_ERR_UST_EVENT_NOT_FOUND;
}
- /*
- * An empty event name means that everything
- * should be disabled.
- */
- if (event->name[0] == '\0') {
+
+ if (pattern_disables_all) {
ret = event_agent_disable_all(usess, agt);
} else {
ret = event_agent_disable(usess, agt, event_name);
}
+
if (ret != LTTNG_OK) {
- goto error_unlock;
+ return static_cast<lttng_error_code>(ret);
}
break;
}
default:
- ret = LTTNG_ERR_UND;
- goto error_unlock;
+ return LTTNG_ERR_UND;
}
- ret = LTTNG_OK;
+ for (const auto& pair : session.get_domain(get_domain_class_from_ctl_domain_type(domain))
+ .get_channel(channel_name)
+ .event_rules) {
+ auto& event_rule_cfg = *pair.second;
-error_unlock:
-error:
- free(exclusion);
- free(bytecode);
- free(filter_expression);
- return ret;
+ const auto this_pattern_or_name =
+ get_event_rule_pattern_or_name(*event_rule_cfg.event_rule);
+ if (pattern_disables_all || (*this_pattern_or_name == event_name)) {
+ event_rule_cfg.disable();
+ }
+ }
+
+ return LTTNG_OK;
}
/*
return ret;
}
+namespace {
+lttng::event_rule_uptr create_agent_internal_event_rule(lttng_domain_type agent_domain,
+ lttng::c_string_view filter_expression)
+{
+ lttng::event_rule_uptr event_rule(lttng_event_rule_user_tracepoint_create());
+
+ if (!event_rule) {
+ LTTNG_THROW_POSIX("Failed to allocate agent internal user space tracer event rule",
+ ENOMEM);
+ }
+
+ const auto set_pattern_ret = lttng_event_rule_user_tracepoint_set_name_pattern(
+ event_rule.get(), event_get_default_agent_ust_name(agent_domain));
+ if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Failed to set agent LTTng-UST event name as event-rule name pattern: domain={}",
+ agent_domain));
+ }
+
+ if (filter_expression) {
+ const auto set_filter_ret = lttng_event_rule_user_tracepoint_set_filter(
+ event_rule.get(), filter_expression.data());
+ if (set_filter_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Failed to set agent LTTng-UST event filter expression as event-rule filter: domain={}",
+ filter_expression));
+ }
+ }
+
+ return event_rule;
+}
+} /* namespace */
+
/*
* Internal version of cmd_enable_event() with a supplemental
* "internal_event" flag which is used to enable internal events which should
* be hidden from clients. Such events are used in the agent implementation to
* enable the events through which all "agent" events are funeled.
*/
-static int _cmd_enable_event(ltt_session::locked_ref& locked_session,
- const struct lttng_domain *domain,
- char *channel_name,
- struct lttng_event *event,
- char *filter_expression,
- struct lttng_bytecode *filter,
- struct lttng_event_exclusion *exclusion,
- int wpipe,
- bool internal_event)
+static lttng_error_code _cmd_enable_event(ltt_session::locked_ref& locked_session,
+ const struct lttng_domain *domain,
+ char *channel_name,
+ struct lttng_event *event,
+ char *raw_filter_expression,
+ struct lttng_bytecode *raw_bytecode,
+ struct lttng_event_exclusion *raw_exclusion,
+ int wpipe,
+ bool internal_event,
+ lttng::event_rule_uptr event_rule)
{
+ if (!event_rule) {
+ return LTTNG_ERR_INVALID_PROTOCOL;
+ }
+
int ret = 0, channel_created = 0;
struct lttng_channel *attr = nullptr;
- const ltt_session& session = *locked_session;
+ ltt_session& session = *locked_session;
+
+ auto filter_expression =
+ lttng::make_unique_wrapper<char, lttng::memory::free>(raw_filter_expression);
+ auto bytecode =
+ lttng::make_unique_wrapper<lttng_bytecode, lttng::memory::free>(raw_bytecode);
+ auto exclusion = lttng::make_unique_wrapper<lttng_event_exclusion, lttng::memory::free>(
+ raw_exclusion);
LTTNG_ASSERT(event);
LTTNG_ASSERT(channel_name);
}
const lttng::urcu::read_lock_guard read_lock;
+ const auto *user_visible_channel_name = channel_name[0] == '\0' ? DEFAULT_CHANNEL_NAME :
+ channel_name;
/* If we have a filter, we must have its filter expression. */
- if (!!filter_expression ^ !!filter) {
+ if (!!filter_expression ^ !!bytecode) {
DBG("Refusing to enable recording event rule as it has an inconsistent filter expression and bytecode specification");
- ret = LTTNG_ERR_INVALID;
- goto error;
+ return LTTNG_ERR_INVALID;
}
switch (domain->type) {
* to be provided.
*/
if (session.kernel_session->has_non_default_channel && channel_name[0] == '\0') {
- ret = LTTNG_ERR_NEED_CHANNEL_NAME;
- goto error;
+ return LTTNG_ERR_NEED_CHANNEL_NAME;
}
kchan = trace_kernel_get_channel_by_name(channel_name, session.kernel_session);
if (kchan == nullptr) {
attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL, LTTNG_BUFFER_GLOBAL);
if (attr == nullptr) {
- ret = LTTNG_ERR_FATAL;
- goto error;
+ return LTTNG_ERR_FATAL;
}
+
if (lttng_strncpy(attr->name, channel_name, sizeof(attr->name))) {
- ret = LTTNG_ERR_INVALID;
- goto error;
+ return LTTNG_ERR_INVALID;
}
- ret = cmd_enable_channel_internal(locked_session, domain, attr, wpipe);
+ ret = cmd_enable_channel_internal(locked_session, domain, *attr, wpipe);
if (ret != LTTNG_OK) {
- goto error;
+ return static_cast<lttng_error_code>(ret);
}
+
channel_created = 1;
}
kchan = trace_kernel_get_channel_by_name(channel_name, session.kernel_session);
if (kchan == nullptr) {
/* This sould not happen... */
- ret = LTTNG_ERR_FATAL;
- goto error;
+ return LTTNG_ERR_FATAL;
}
switch (event->type) {
* event.
*/
if (filter_expression) {
- filter_expression_a = strdup(filter_expression);
+ filter_expression_a = strdup(filter_expression.get());
if (!filter_expression_a) {
- ret = LTTNG_ERR_FATAL;
- goto error;
+ return LTTNG_ERR_FATAL;
}
}
- if (filter) {
- filter_a = zmalloc<lttng_bytecode>(sizeof(*filter_a) + filter->len);
+
+ if (bytecode) {
+ filter_a =
+ zmalloc<lttng_bytecode>(sizeof(*filter_a) + bytecode->len);
if (!filter_a) {
free(filter_expression_a);
- ret = LTTNG_ERR_FATAL;
- goto error;
+ return LTTNG_ERR_FATAL;
}
- memcpy(filter_a, filter, sizeof(*filter_a) + filter->len);
+
+ memcpy(filter_a, bytecode.get(), sizeof(*filter_a) + bytecode->len);
}
+
event->type = LTTNG_EVENT_TRACEPOINT; /* Hack */
- ret = event_kernel_enable_event(kchan, event, filter_expression, filter);
- /* We have passed ownership */
- filter_expression = nullptr;
- filter = nullptr;
+ ret = event_kernel_enable_event(
+ kchan, event, filter_expression.release(), bytecode.release());
if (ret != LTTNG_OK) {
if (channel_created) {
/* Let's not leak a useless channel. */
kernel_destroy_channel(kchan);
}
+
free(filter_expression_a);
free(filter_a);
- goto error;
+ return static_cast<lttng_error_code>(ret);
}
+
event->type = LTTNG_EVENT_SYSCALL; /* Hack */
ret = event_kernel_enable_event(
kchan, event, filter_expression_a, filter_a);
filter_expression_a = nullptr;
filter_a = nullptr;
if (ret != LTTNG_OK) {
- goto error;
+ return static_cast<lttng_error_code>(ret);
}
+
break;
}
case LTTNG_EVENT_PROBE:
case LTTNG_EVENT_FUNCTION:
case LTTNG_EVENT_FUNCTION_ENTRY:
case LTTNG_EVENT_TRACEPOINT:
- ret = event_kernel_enable_event(kchan, event, filter_expression, filter);
- /* We have passed ownership */
- filter_expression = nullptr;
- filter = nullptr;
+ ret = event_kernel_enable_event(
+ kchan, event, filter_expression.release(), bytecode.release());
if (ret != LTTNG_OK) {
if (channel_created) {
/* Let's not leak a useless channel. */
kernel_destroy_channel(kchan);
}
- goto error;
+
+ return static_cast<lttng_error_code>(ret);
}
+
break;
case LTTNG_EVENT_SYSCALL:
- ret = event_kernel_enable_event(kchan, event, filter_expression, filter);
- /* We have passed ownership */
- filter_expression = nullptr;
- filter = nullptr;
+ ret = event_kernel_enable_event(
+ kchan, event, filter_expression.release(), bytecode.release());
if (ret != LTTNG_OK) {
- goto error;
+ return static_cast<lttng_error_code>(ret);
}
+
break;
default:
- ret = LTTNG_ERR_UNK;
- goto error;
+ return LTTNG_ERR_UNK;
}
kernel_wait_quiescent();
* to be provided.
*/
if (usess->has_non_default_channel && channel_name[0] == '\0') {
- ret = LTTNG_ERR_NEED_CHANNEL_NAME;
- goto error;
+ return LTTNG_ERR_NEED_CHANNEL_NAME;
}
/* Get channel from global UST domain */
/* Create default channel */
attr = channel_new_default_attr(LTTNG_DOMAIN_UST, usess->buffer_type);
if (attr == nullptr) {
- ret = LTTNG_ERR_FATAL;
- goto error;
+ return LTTNG_ERR_FATAL;
}
+
if (lttng_strncpy(attr->name, channel_name, sizeof(attr->name))) {
- ret = LTTNG_ERR_INVALID;
- goto error;
+ return LTTNG_ERR_INVALID;
}
- ret = cmd_enable_channel_internal(locked_session, domain, attr, wpipe);
+ ret = cmd_enable_channel_internal(locked_session, domain, *attr, wpipe);
if (ret != LTTNG_OK) {
- goto error;
+ return static_cast<lttng_error_code>(ret);
}
/* Get the newly created channel reference back */
* are assigned to a userspace subdomain (JUL, Log4J,
* Python, etc.).
*/
- ret = LTTNG_ERR_INVALID_CHANNEL_DOMAIN;
- goto error;
+ return LTTNG_ERR_INVALID_CHANNEL_DOMAIN;
}
if (!internal_event) {
ret = validate_ust_event_name(event->name);
if (ret) {
WARN("Userspace event name %s failed validation.", event->name);
- ret = LTTNG_ERR_INVALID_EVENT_NAME;
- goto error;
+ return LTTNG_ERR_INVALID_EVENT_NAME;
}
}
/* At this point, the session and channel exist on the tracer */
- ret = event_ust_enable_tracepoint(
- usess, uchan, event, filter_expression, filter, exclusion, internal_event);
- /* We have passed ownership */
- filter_expression = nullptr;
- filter = nullptr;
- exclusion = nullptr;
- if (ret == LTTNG_ERR_UST_EVENT_ENABLED) {
- goto already_enabled;
- } else if (ret != LTTNG_OK) {
- goto error;
+ ret = event_ust_enable_tracepoint(usess,
+ uchan,
+ event,
+ filter_expression.release(),
+ bytecode.release(),
+ exclusion.release(),
+ internal_event);
+ if (ret != LTTNG_OK) {
+ return static_cast<lttng_error_code>(ret);
}
+
break;
}
case LTTNG_DOMAIN_LOG4J:
struct lttng_domain tmp_dom;
struct ltt_ust_session *usess = session.ust_session;
+ lttng::event_rule_uptr internal_event_rule =
+ create_agent_internal_event_rule(domain->type, filter_expression.get());
+
LTTNG_ASSERT(usess);
if (!agent_tracing_is_enabled()) {
DBG("Attempted to enable an event in an agent domain but the agent thread is not running");
- ret = LTTNG_ERR_AGENT_TRACING_DISABLED;
- goto error;
+ return LTTNG_ERR_AGENT_TRACING_DISABLED;
}
agt = trace_ust_find_agent(usess, domain->type);
if (!agt) {
agt = agent_create(domain->type);
if (!agt) {
- ret = LTTNG_ERR_NOMEM;
- goto error;
+ return LTTNG_ERR_NOMEM;
}
+
agent_add(agt, usess->agents);
}
uevent.loglevel = -1;
default_event_name = event_get_default_agent_ust_name(domain->type);
if (!default_event_name) {
- ret = LTTNG_ERR_FATAL;
- goto error;
+ return LTTNG_ERR_FATAL;
}
+
strncpy(uevent.name, default_event_name, sizeof(uevent.name));
uevent.name[sizeof(uevent.name) - 1] = '\0';
abort();
}
+ user_visible_channel_name = default_chan_name;
+
{
char *filter_expression_copy = nullptr;
- struct lttng_bytecode *filter_copy = nullptr;
+ struct lttng_bytecode *bytecode_copy = nullptr;
- if (filter) {
+ if (bytecode) {
const size_t filter_size =
- sizeof(struct lttng_bytecode) + filter->len;
+ sizeof(struct lttng_bytecode) + bytecode->len;
- filter_copy = zmalloc<lttng_bytecode>(filter_size);
- if (!filter_copy) {
- ret = LTTNG_ERR_NOMEM;
- goto error;
+ bytecode_copy = zmalloc<lttng_bytecode>(filter_size);
+ if (!bytecode_copy) {
+ return LTTNG_ERR_NOMEM;
}
- memcpy(filter_copy, filter, filter_size);
- filter_expression_copy = strdup(filter_expression);
- if (!filter_expression) {
- ret = LTTNG_ERR_NOMEM;
- }
+ memcpy(bytecode_copy, bytecode.get(), filter_size);
- if (!filter_expression_copy || !filter_copy) {
- free(filter_expression_copy);
- free(filter_copy);
- goto error;
+ filter_expression_copy = strdup(filter_expression.get());
+ if (!filter_expression_copy) {
+ free(bytecode_copy);
+ return LTTNG_ERR_NOMEM;
}
}
(char *) default_chan_name,
&uevent,
filter_expression_copy,
- filter_copy,
+ bytecode_copy,
nullptr,
- wpipe);
+ wpipe,
+ std::move(internal_event_rule));
}
- if (ret == LTTNG_ERR_UST_EVENT_ENABLED) {
- goto already_enabled;
- } else if (ret != LTTNG_OK) {
- goto error;
+ if (ret != LTTNG_OK) {
+ return static_cast<lttng_error_code>(ret);
}
/* The wild card * means that everything should be enabled. */
if (strncmp(event->name, "*", 1) == 0 && strlen(event->name) == 1) {
- ret = event_agent_enable_all(usess, agt, event, filter, filter_expression);
+ ret = event_agent_enable_all(
+ usess, agt, event, bytecode.release(), filter_expression.release());
} else {
- ret = event_agent_enable(usess, agt, event, filter, filter_expression);
+ ret = event_agent_enable(
+ usess, agt, event, bytecode.release(), filter_expression.release());
}
- filter = nullptr;
- filter_expression = nullptr;
+
if (ret != LTTNG_OK) {
- goto error;
+ return static_cast<lttng_error_code>(ret);
}
break;
}
default:
- ret = LTTNG_ERR_UND;
- goto error;
+ return LTTNG_ERR_UND;
}
- ret = LTTNG_OK;
+ auto& channel_cfg = session.get_domain(get_domain_class_from_ctl_domain_type(domain->type))
+ .get_channel(user_visible_channel_name);
+ try {
+ channel_cfg.get_event_rule_configuration(*event_rule).enable();
+ } catch (const lttng::sessiond::exceptions::event_rule_configuration_not_found_error& ex) {
+ DBG("%s", ex.what());
+ channel_cfg.add_event_rule_configuration(true, std::move(event_rule));
+ }
-already_enabled:
-error:
- free(filter_expression);
- free(filter);
- free(exclusion);
- channel_attr_destroy(attr);
- return ret;
+ return LTTNG_OK;
}
/*
char *filter_expression,
struct lttng_event_exclusion *exclusion,
struct lttng_bytecode *bytecode,
- int wpipe)
+ int wpipe,
+ lttng::event_rule_uptr event_rule)
{
int ret;
/*
bytecode,
exclusion,
wpipe,
- false);
+ false,
+ std::move(event_rule));
filter_expression = nullptr;
bytecode = nullptr;
exclusion = nullptr;
char *filter_expression,
struct lttng_bytecode *filter,
struct lttng_event_exclusion *exclusion,
- int wpipe)
+ int wpipe,
+ lttng::event_rule_uptr event_rule)
{
return _cmd_enable_event(locked_session,
domain,
filter,
exclusion,
wpipe,
- true);
+ true,
+ std::move(event_rule));
}
/*
* Make sure to set the session in output mode after we set URI since a
* session can be created without URL (thus flagged in no output mode).
*/
- session->output_traces = 1;
+ session->output_traces = true;
if (ksess) {
ksess->output_traces = 1;
}
switch (lttng_session_descriptor_get_type(descriptor)) {
case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
- new_session->snapshot_mode = 1;
+ new_session->snapshot_mode = true;
break;
case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
new_session->live_timer =
#include "session.hpp"
#include "snapshot-output.hpp"
+#include <common/ctl/memory.hpp>
#include <common/tracker.hpp>
#include <lttng/kernel.h>
struct lttng_process_attr_values **values);
/* Event commands */
-int cmd_disable_event(struct command_ctx *cmd_ctx,
- ltt_session::locked_ref& locked_session,
- struct lttng_event *event,
- char *filter_expression,
- struct lttng_bytecode *filter,
- struct lttng_event_exclusion *exclusion);
+lttng_error_code cmd_disable_event(struct command_ctx *cmd_ctx,
+ ltt_session::locked_ref& locked_session,
+ struct lttng_event *event,
+ char *filter_expression,
+ struct lttng_bytecode *filter,
+ struct lttng_event_exclusion *exclusion,
+ lttng::event_rule_uptr event_rule);
int cmd_add_context(struct command_ctx *cmd_ctx,
ltt_session::locked_ref& locked_session,
const struct lttng_event_context *event_context,
char *filter_expression,
struct lttng_event_exclusion *exclusion,
struct lttng_bytecode *bytecode,
- int wpipe);
+ int wpipe,
+ lttng::event_rule_uptr event_rule);
/* Trace session action commands */
int cmd_start_trace(const ltt_session::locked_ref& session);
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "domain.hpp"
+
+lttng::sessiond::exceptions::channel_not_found_error::channel_not_found_error(
+ std::string channel_name_, const lttng::source_location& source_location_) :
+ lttng::runtime_error(
+ fmt::format("No channel with the given name in domain: channel_name=`{}`",
+ channel_name_),
+ source_location_),
+ channel_name{ std::move(channel_name_) }
+{
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_SESSIOND_DOMAIN_HPP
+#define LTTNG_SESSIOND_DOMAIN_HPP
+
+#include "recording-channel-configuration.hpp"
+
+#include <common/exception.hpp>
+#include <common/format.hpp>
+#include <common/make-unique.hpp>
+#include <common/string-utils/c-string-view.hpp>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+namespace lttng {
+namespace sessiond {
+
+enum class domain_class {
+ USER_SPACE,
+ KERNEL_SPACE,
+ LOG4J,
+ LOG4J2,
+ JAVA_UTIL_LOGGING,
+ PYTHON_LOGGING,
+};
+
+#define LTTNG_THROW_CHANNEL_NOT_FOUND_BY_NAME_ERROR(channel_name) \
+ throw lttng::sessiond::exceptions::channel_not_found_error(channel_name, \
+ LTTNG_SOURCE_LOCATION())
+
+namespace exceptions {
+/*
+ * @class channel_not_found_error
+ * @brief Represents a channel-not-found error and provides the name of the channel looked-up
+ * for use by error-reporting code.
+ */
+class channel_not_found_error : public lttng::runtime_error {
+public:
+ explicit channel_not_found_error(std::string channel_name,
+ const lttng::source_location& source_location);
+
+ const std::string channel_name;
+};
+} /* namespace exceptions */
+
+/*
+ * A channel configuration represents the configuration of a recording session's
+ * channel at a given point in time. It belongs to a single recording session.
+ */
+class domain {
+public:
+ explicit domain(lttng::sessiond::domain_class domain_class) : domain_class_(domain_class)
+ {
+ }
+
+ virtual ~domain() = default;
+
+ domain(const domain&) = delete;
+ domain(domain&&) = delete;
+ domain& operator=(const domain&) = delete;
+ domain& operator=(domain&&) = delete;
+
+ /* Add a channel to the domain by constructing it in place. */
+ template <typename... Args>
+ recording_channel_configuration& add_channel(Args&&...args)
+ {
+ return _add_channel(lttng::make_unique<recording_channel_configuration>(
+ std::forward<Args>(args)...));
+ }
+
+ /* Lookup by name, get non-const reference. */
+ virtual recording_channel_configuration& get_channel(const lttng::c_string_view& name) = 0;
+
+ /* Lookup by name, get const reference. */
+ const recording_channel_configuration& get_channel(const lttng::c_string_view& name) const
+ {
+ /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
+ return const_cast<domain *>(this)->get_channel(name);
+ }
+
+ const lttng::sessiond::domain_class domain_class_;
+
+private:
+ virtual recording_channel_configuration&
+ _add_channel(recording_channel_configuration::uptr new_channel) = 0;
+};
+
+class multi_channel_domain : public domain {
+ using channels_t = std::unordered_map<std::string, recording_channel_configuration::uptr>;
+
+public:
+ explicit multi_channel_domain(domain_class domain_class) : domain(domain_class)
+ {
+ }
+
+ ~multi_channel_domain() override = default;
+ multi_channel_domain(multi_channel_domain&& other) noexcept :
+ domain(other.domain_class_), channels(std::move(other.channels))
+ {
+ }
+
+ multi_channel_domain(const multi_channel_domain&) = delete;
+ multi_channel_domain& operator=(const multi_channel_domain&) = delete;
+ multi_channel_domain& operator=(multi_channel_domain&&) = delete;
+
+ /* Lookup by name, get non-const reference. */
+ recording_channel_configuration& get_channel(const lttng::c_string_view& name) override
+ {
+ const auto it = channels.find(name.data());
+ if (it == channels.end()) {
+ LTTNG_THROW_CHANNEL_NOT_FOUND_BY_NAME_ERROR(name);
+ }
+
+ return *(it->second);
+ }
+
+ /* Iterate over channels (non-const) */
+ channels_t::iterator begin()
+ {
+ return channels.begin();
+ }
+
+ channels_t::iterator end()
+ {
+ return channels.end();
+ }
+
+ /* Iterate over channels (const) */
+ channels_t::const_iterator begin() const
+ {
+ return channels.begin();
+ }
+
+ channels_t::const_iterator end() const
+ {
+ return channels.end();
+ }
+
+private:
+ recording_channel_configuration&
+ _add_channel(recording_channel_configuration::uptr new_channel) override
+ {
+ const auto& name = new_channel->name;
+
+ auto result = channels.emplace(name, std::move(new_channel));
+ if (!result.second) {
+ throw std::runtime_error(fmt::format(
+ "Failed to add channel to domain, name already in use: channel_name=`{}`",
+ name));
+ }
+
+ return *(result.first->second);
+ }
+
+ channels_t channels;
+};
+
+} /* namespace sessiond */
+} /* namespace lttng */
+
+/*
+ * Specialize fmt::formatter for domain_class.
+ *
+ * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace,
+ * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480.
+ */
+namespace fmt {
+template <>
+struct formatter<lttng::sessiond::domain_class> : formatter<std::string> {
+ /* Format function to convert enum to string. */
+ template <typename FormatContextType>
+ typename FormatContextType::iterator format(lttng::sessiond::domain_class domain,
+ FormatContextType& ctx) const
+ {
+ auto name = "UNKNOWN";
+
+ switch (domain) {
+ case lttng::sessiond::domain_class::USER_SPACE:
+ name = "USER_SPACE";
+ break;
+ case lttng::sessiond::domain_class::KERNEL_SPACE:
+ name = "KERNEL_SPACE";
+ break;
+ case lttng::sessiond::domain_class::LOG4J:
+ name = "LOG4J";
+ break;
+ case lttng::sessiond::domain_class::LOG4J2:
+ name = "LOG4J2";
+ break;
+ case lttng::sessiond::domain_class::JAVA_UTIL_LOGGING:
+ name = "JAVA_UTIL_LOGGING";
+ break;
+ case lttng::sessiond::domain_class::PYTHON_LOGGING:
+ name = "PYTHON_LOGGING";
+ break;
+ }
+
+ /* Write the string representation to the format context output iterator. */
+ return format_to(ctx.out(), name);
+ }
+};
+} /* namespace fmt */
+
+#endif /* LTTNG_SESSIOND_DOMAIN_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "event-rule-configuration.hpp"
+
+namespace ls = lttng::sessiond;
+
+ls::event_rule_configuration::event_rule_configuration(bool is_enabled_,
+ lttng::event_rule_uptr&& event_rule_) :
+ is_enabled(is_enabled_), event_rule(std::move(event_rule_))
+{
+}
+
+void ls::event_rule_configuration::set_enabled(bool enable) noexcept
+{
+ is_enabled = enable;
+}
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_SESSIOND_EVENT_RULE_CONFIGURATION_HPP
+#define LTTNG_SESSIOND_EVENT_RULE_CONFIGURATION_HPP
+
+#include <common/ctl/memory.hpp>
+#include <common/format.hpp>
+
+#include <vendor/optional.hpp>
+
+#include <cstdint>
+#include <string>
+
+namespace lttng {
+namespace sessiond {
+
+/*
+ * An event rule configuration represents the configuration of a channel or map's
+ * event rule at a given point in time. It belongs to a single channel or map.
+ */
+class event_rule_configuration final {
+public:
+ using uptr = std::unique_ptr<event_rule_configuration>;
+
+ event_rule_configuration(bool is_enabled, lttng::event_rule_uptr&& event_rule);
+
+ ~event_rule_configuration() = default;
+ event_rule_configuration(event_rule_configuration&&) = delete;
+ event_rule_configuration(const event_rule_configuration&) = delete;
+ event_rule_configuration& operator=(const event_rule_configuration&) = delete;
+ event_rule_configuration& operator=(event_rule_configuration&&) = delete;
+
+ void enable() noexcept
+ {
+ set_enabled(true);
+ }
+
+ void disable() noexcept
+ {
+ set_enabled(false);
+ }
+
+ void set_enabled(bool enable) noexcept;
+
+ bool is_enabled;
+ const lttng::event_rule_uptr event_rule;
+};
+
+} /* namespace sessiond */
+} /* namespace lttng */
+
+#endif /* LTTNG_SESSIOND_EVENT_RULE_CONFIGURATION_HPP */
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "recording-channel-configuration.hpp"
+
+#include <common/ctl/format.hpp>
+#include <common/error.hpp>
+#include <common/exception.hpp>
+#include <common/format.hpp>
+
+#include <lttng/event-rule/event-rule-internal.hpp>
+
+namespace ls = lttng::sessiond;
+
+ls::exceptions::event_rule_configuration_not_found_error::event_rule_configuration_not_found_error(
+ const lttng_event_rule& event_rule_, const lttng::source_location& source_location_) :
+ lttng::runtime_error(
+ fmt::format("No matching event-rule in channel configuration: event_rule=`{}`",
+ event_rule_),
+ source_location_)
+{
+}
+
+ls::recording_channel_configuration::recording_channel_configuration(
+ bool is_enabled_,
+ std::string name_,
+ buffer_full_policy_t buffer_full_policy_,
+ buffer_consumption_backend_t buffer_consumption_backend_,
+ std::uint64_t subbuffer_size_bytes_,
+ unsigned int subbuffer_count_,
+ const nonstd::optional<timer_period_us>& switch_timer_period_us_,
+ const nonstd::optional<timer_period_us>& read_timer_period_us_,
+ const nonstd::optional<timer_period_us>& live_timer_period_us_,
+ const nonstd::optional<timer_period_us>& monitor_timer_period_us_,
+ consumption_blocking_policy blocking_policy,
+ const nonstd::optional<std::uint64_t>& trace_file_size_limit_bytes_,
+ const nonstd::optional<unsigned int>& trace_file_count_limit_) :
+ name(std::move(name_)),
+ buffer_full_policy(buffer_full_policy_),
+ buffer_consumption_backend(buffer_consumption_backend_),
+ subbuffer_size_bytes(subbuffer_size_bytes_),
+ subbuffer_count(subbuffer_count_),
+ switch_timer_period_us(switch_timer_period_us_),
+ read_timer_period_us(read_timer_period_us_),
+ live_timer_period_us(live_timer_period_us_),
+ monitor_timer_period_us(monitor_timer_period_us_),
+ consumption_blocking_policy_(std::move(blocking_policy)),
+ trace_file_size_limit_bytes(trace_file_size_limit_bytes_),
+ trace_file_count_limit(trace_file_count_limit_),
+ is_enabled(is_enabled_)
+{
+}
+
+ls::recording_channel_configuration::consumption_blocking_policy::consumption_blocking_policy(
+ ls::recording_channel_configuration::consumption_blocking_policy::mode policy_mode,
+ const nonstd::optional<timer_period_us>& blocking_timeout_us) :
+ mode_(policy_mode), timeout_us(blocking_timeout_us)
+{
+ if (blocking_timeout_us.has_value() !=
+ (policy_mode ==
+ ls::recording_channel_configuration::consumption_blocking_policy::mode::TIMED)) {
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Invalid timeout argument specified for consumption blocking policy: policy_mode={}, timeout={}",
+ mode_,
+ timeout_us));
+ }
+}
+
+void ls::recording_channel_configuration::set_enabled(bool enable) noexcept
+{
+ is_enabled = enable;
+}
+
+const ls::event_rule_configuration&
+ls::recording_channel_configuration::get_event_rule_configuration(
+ const lttng_event_rule& matching_event_rule_to_lookup) const
+{
+ /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
+ return const_cast<recording_channel_configuration *>(this)->get_event_rule_configuration(
+ matching_event_rule_to_lookup);
+}
+
+ls::event_rule_configuration& ls::recording_channel_configuration::get_event_rule_configuration(
+ const lttng_event_rule& matching_event_rule_to_lookup)
+{
+ const auto it = event_rules.find(std::ref(matching_event_rule_to_lookup));
+ if (it == event_rules.end()) {
+ LTTNG_THROW_EVENT_RULE_CONFIGURATION_NOT_FOUND_ERROR(matching_event_rule_to_lookup);
+ }
+
+ return *(it->second);
+}
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_SESSIOND_RECORDING_CHANNEL_CONFIGURATION_HPP
+#define LTTNG_SESSIOND_RECORDING_CHANNEL_CONFIGURATION_HPP
+
+#include "event-rule-configuration.hpp"
+
+#include <common/ctl/memory.hpp>
+#include <common/exception.hpp>
+#include <common/format.hpp>
+#include <common/make-unique.hpp>
+
+#include <lttng/event-rule/event-rule-internal.hpp>
+
+#include <vendor/optional.hpp>
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+namespace lttng {
+namespace sessiond {
+
+#define LTTNG_THROW_EVENT_RULE_CONFIGURATION_NOT_FOUND_ERROR(event_rule) \
+ throw lttng::sessiond::exceptions::event_rule_configuration_not_found_error( \
+ event_rule, LTTNG_SOURCE_LOCATION())
+
+namespace exceptions {
+/*
+ * @class event_rule_configuration_not_found_error
+ * @brief Represents a event-rule-configuration-not-found error and provides the
+ * name of the channel looked-up for use by error-reporting code.
+ */
+class event_rule_configuration_not_found_error : public lttng::runtime_error {
+public:
+ explicit event_rule_configuration_not_found_error(
+ const lttng_event_rule& event_rule, const lttng::source_location& source_location);
+};
+} /* namespace exceptions */
+
+/*
+ * A recording channel configuration represents the configuration of a recording session's
+ * channel at a given point in time. It belongs to a single recording session.
+ */
+class recording_channel_configuration final {
+public:
+ using uptr = std::unique_ptr<recording_channel_configuration>;
+ using timer_period_us = std::uint64_t;
+
+ enum class buffer_full_policy_t {
+ DISCARD_EVENT,
+ OVERWRITE_OLDEST_PACKET,
+ };
+
+ enum class buffer_consumption_backend_t {
+ MMAP,
+ SPLICE,
+ };
+
+ struct consumption_blocking_policy {
+ enum class mode {
+ NONE,
+ TIMED,
+ UNBOUNDED,
+ };
+
+ explicit consumption_blocking_policy(
+ mode mode,
+ const nonstd::optional<timer_period_us>& timeout_us = nonstd::nullopt);
+
+ const mode mode_;
+ /* Only set in TIMED mode. */
+ const nonstd::optional<timer_period_us> timeout_us;
+ };
+
+ recording_channel_configuration(
+ bool is_enabled,
+ std::string name,
+ buffer_full_policy_t buffer_full_policy,
+ buffer_consumption_backend_t buffer_consumption_backend,
+ std::uint64_t subbuffer_size_bytes,
+ unsigned int subbuffer_count,
+ const nonstd::optional<timer_period_us>& switch_timer_period_us,
+ const nonstd::optional<timer_period_us>& read_timer_period_us,
+ const nonstd::optional<timer_period_us>& live_timer_period_us,
+ const nonstd::optional<timer_period_us>& monitor_timer_period_us,
+ consumption_blocking_policy consumption_blocking_policy,
+ const nonstd::optional<std::uint64_t>& trace_file_size_limit_bytes,
+ const nonstd::optional<unsigned int>& trace_file_count_limit);
+
+ ~recording_channel_configuration() = default;
+ recording_channel_configuration(recording_channel_configuration&&) = delete;
+ recording_channel_configuration(const recording_channel_configuration&) = delete;
+ recording_channel_configuration& operator=(const recording_channel_configuration&) = delete;
+ recording_channel_configuration& operator=(recording_channel_configuration&&) = delete;
+
+ void enable() noexcept
+ {
+ set_enabled(true);
+ }
+
+ void disable() noexcept
+ {
+ set_enabled(false);
+ }
+
+ void set_enabled(bool enable) noexcept;
+
+ template <typename... Args>
+ void add_event_rule_configuration(Args&&...args)
+ {
+ auto config =
+ lttng::make_unique<event_rule_configuration>(std::forward<Args>(args)...);
+
+ event_rules.emplace(std::cref(*config->event_rule), std::move(config));
+ }
+
+ const lttng::sessiond::event_rule_configuration&
+ get_event_rule_configuration(const lttng_event_rule& matching_event_rule_to_lookup) const;
+ lttng::sessiond::event_rule_configuration&
+ get_event_rule_configuration(const lttng_event_rule& matching_event_rule_to_lookup);
+
+ const std::string name;
+ const buffer_full_policy_t buffer_full_policy;
+ const buffer_consumption_backend_t buffer_consumption_backend;
+ const std::uint64_t subbuffer_size_bytes;
+ const unsigned int subbuffer_count;
+ const nonstd::optional<timer_period_us> switch_timer_period_us;
+ const nonstd::optional<timer_period_us> read_timer_period_us;
+ const nonstd::optional<timer_period_us> live_timer_period_us;
+ const nonstd::optional<timer_period_us> monitor_timer_period_us;
+ const consumption_blocking_policy consumption_blocking_policy_;
+ const nonstd::optional<std::uint64_t> trace_file_size_limit_bytes;
+ const nonstd::optional<unsigned int> trace_file_count_limit;
+
+ bool is_enabled;
+
+ std::unordered_map<std::reference_wrapper<const lttng_event_rule>,
+ event_rule_configuration::uptr,
+ std::hash<std::reference_wrapper<const lttng_event_rule>>,
+ lttng_event_rule_ref_equal>
+ event_rules;
+};
+
+} /* namespace sessiond */
+} /* namespace lttng */
+
+/*
+ * Specialize fmt::formatter for consumption_blocking_policy's mode.
+ *
+ * Due to a bug in g++ < 7.1, this specialization must be enclosed in the fmt namespace,
+ * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480.
+ */
+namespace fmt {
+template <>
+struct formatter<lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::mode>
+ : formatter<std::string> {
+ /* Format function to convert enum to string. */
+ template <typename FormatContextType>
+ typename FormatContextType::iterator
+ format(lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::mode
+ mode,
+ FormatContextType& ctx) const
+ {
+ auto name = "UNKNOWN";
+
+ switch (mode) {
+ case lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::
+ mode::NONE:
+ name = "NONE";
+ break;
+ case lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::
+ mode::UNBOUNDED:
+ name = "UNBOUNDED";
+ break;
+ case lttng::sessiond::recording_channel_configuration::consumption_blocking_policy::
+ mode::TIMED:
+ name = "TIMED";
+ break;
+ }
+
+ /* Write the string representation to the format context output iterator. */
+ return format_to(ctx.out(), name);
+ }
+};
+} /* namespace fmt */
+
+#endif /* LTTNG_SESSIOND_RECORDING_CHANNEL_CONFIGURATION_HPP */
ltt_session::_const_session_unlock(*this);
}
+ls::domain& ltt_session::get_domain(ls::domain_class domain)
+{
+ switch (domain) {
+ case ls::domain_class::LOG4J:
+ case ls::domain_class::LOG4J2:
+ case ls::domain_class::JAVA_UTIL_LOGGING:
+ case ls::domain_class::PYTHON_LOGGING:
+ case ls::domain_class::USER_SPACE:
+ return user_space_domain;
+ case ls::domain_class::KERNEL_SPACE:
+ return kernel_space_domain;
+ }
+
+ std::abort();
+}
+
+const ls::domain& ltt_session::get_domain(ls::domain_class domain) const
+{
+ /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
+ return const_cast<ltt_session *>(this)->get_domain(domain);
+}
+
/*
* Release session lock
*/
ls::user_space_consumer_channel_keys::iterator::_get_registry_session_per_uid()
{
return _position._per_uid.current_registry->registry->reg.ust;
-}
\ No newline at end of file
+}
#define _LTT_SESSION_H
#include "consumer.hpp"
+#include "domain.hpp"
#include "snapshot.hpp"
#include "trace-kernel.hpp"
#include "trace-ust.hpp"
void lock() const noexcept;
void unlock() const noexcept;
+ lttng::sessiond::domain& get_domain(lttng::sessiond::domain_class domain);
+ const lttng::sessiond::domain& get_domain(lttng::sessiond::domain_class domain) const;
+
lttng::sessiond::user_space_consumer_channel_keys user_space_consumer_channel_keys() const;
/*
struct lttng_dynamic_array clear_notifiers = {};
/* Session base path override. Set non-null. */
char *base_path = nullptr;
+
+ lttng::sessiond::multi_channel_domain user_space_domain =
+ lttng::sessiond::multi_channel_domain(lttng::sessiond::domain_class::USER_SPACE);
+ lttng::sessiond::multi_channel_domain kernel_space_domain =
+ lttng::sessiond::multi_channel_domain(lttng::sessiond::domain_class::KERNEL_SPACE);
};
/*
query_parameter query_parameter;
};
-} // namespace exceptions
+} /* namespace exceptions */
} /* namespace sessiond */
} /* namespace lttng */
buffer-view.hpp buffer-view.cpp \
channel.cpp \
ctl/format.hpp \
+ ctl/memory.hpp \
compiler.hpp \
conditions/buffer-usage.cpp \
conditions/condition.cpp \
log-level-rule.cpp \
make-unique.hpp \
make-unique-wrapper.hpp \
+ math.hpp \
meta-helpers.hpp \
mi-lttng.cpp mi-lttng.hpp \
notification.cpp \
return format_to(ctx.out(), name);
}
};
+
+template <>
+struct formatter<lttng_domain_type> : formatter<std::string> {
+ template <typename FormatContextType>
+ typename FormatContextType::iterator format(lttng_domain_type domain_type,
+ FormatContextType& ctx) const
+ {
+ auto name = "unknown";
+
+ switch (domain_type) {
+ case LTTNG_DOMAIN_NONE:
+ name = "none";
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ name = "kernel";
+ break;
+ case LTTNG_DOMAIN_UST:
+ name = "user space";
+ break;
+ case LTTNG_DOMAIN_JUL:
+ name = "java.util.logging (JUL)";
+ break;
+ case LTTNG_DOMAIN_LOG4J:
+ name = "log4j";
+ break;
+ case LTTNG_DOMAIN_LOG4J2:
+ name = "log4j2";
+ break;
+ case LTTNG_DOMAIN_PYTHON:
+ name = "Python logging";
+ break;
+ }
+
+ return format_to(ctx.out(), name);
+ }
+};
+
+template <>
+struct formatter<lttng_loglevel_type> : formatter<std::string> {
+ template <typename FormatContextType>
+ typename FormatContextType::iterator format(lttng_loglevel_type loglevel_type,
+ FormatContextType& ctx) const
+ {
+ auto name = "unknown";
+
+ switch (loglevel_type) {
+ case LTTNG_EVENT_LOGLEVEL_ALL:
+ name = "all";
+ break;
+ case LTTNG_EVENT_LOGLEVEL_RANGE:
+ name = "range";
+ break;
+ case LTTNG_EVENT_LOGLEVEL_SINGLE:
+ name = "single";
+ break;
+ }
+
+ return format_to(ctx.out(), name);
+ }
+};
+
+template <>
+struct formatter<lttng_log_level_rule_type> : formatter<std::string> {
+ template <typename FormatContextType>
+ typename FormatContextType::iterator format(lttng_log_level_rule_type rule_type,
+ FormatContextType& ctx) const
+ {
+ auto name = "unknown";
+
+ switch (rule_type) {
+ case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+ name = "exactly";
+ break;
+ case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+ name = "\"at least as severe as\"";
+ break;
+ case LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN:
+ break;
+ }
+
+ return format_to(ctx.out(), name);
+ }
+};
+
+template <>
+struct formatter<lttng_event_rule> : formatter<std::string> {
+ template <typename FormatContextType>
+ typename FormatContextType::iterator format(const lttng_event_rule& rule,
+ FormatContextType& ctx) const
+ {
+ const auto rule_type = lttng_event_rule_get_type(&rule);
+ const char *rule_type_name;
+
+ switch (rule_type) {
+ case LTTNG_EVENT_RULE_TYPE_UNKNOWN:
+ rule_type_name = "UNKNOWN";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+ rule_type_name = "KERNEL_SYSCALL";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
+ rule_type_name = "KERNEL_KPROBE";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+ rule_type_name = "KERNEL_TRACEPOINT";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
+ rule_type_name = "KERNEL_UPROBE";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+ rule_type_name = "USER_TRACEPOINT";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+ rule_type_name = "JUL_LOGGING";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+ rule_type_name = "LOG4J_LOGGING";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+ rule_type_name = "PYTHON_LOGGING";
+ break;
+ case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
+ rule_type_name = "LOG4J2_LOGGING";
+ break;
+ default:
+ std::abort();
+ }
+
+ return format_to(ctx.out(), "{{type={}}}", rule_type_name);
+ }
+};
+
} /* namespace fmt */
-#endif /* LTTNG_COMMON_CTL_FORMAT_H */
\ No newline at end of file
+#endif /* LTTNG_COMMON_CTL_FORMAT_H */
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_COMMON_CTL_MEMORY_HPP
+#define LTTNG_COMMON_CTL_MEMORY_HPP
+
+#include <common/meta-helpers.hpp>
+
+#include <lttng/lttng.h>
+
+#include <memory>
+#include <vector>
+
+namespace lttng {
+
+using event_rule_uptr = std::unique_ptr<
+ lttng_event_rule,
+ lttng::memory::create_deleter_class<lttng_event_rule, lttng_event_rule_destroy>>;
+
+using kernel_location_uptr =
+ std::unique_ptr<lttng_kernel_probe_location,
+ lttng::memory::create_deleter_class<lttng_kernel_probe_location,
+ lttng_kernel_probe_location_destroy>>;
+
+} /* namespace lttng */
+
+#endif /* LTTNG_COMMON_CTL_MEMORY_HPP */
#include <common/macros.hpp>
#include <common/make-unique.hpp>
+#include <vendor/optional.hpp>
+
#include <cxxabi.h>
#include <string>
#include <utility>
return it;
}
};
+
+template <typename WrappedType>
+struct formatter<nonstd::optional<WrappedType>> : formatter<WrappedType> {
+ template <typename FormatContextType>
+ typename FormatContextType::iterator format(const nonstd::optional<WrappedType>& opt,
+ FormatContextType& ctx) const
+ {
+ if (opt) {
+ /* Defer formatting to the base formatter for WrappedType. */
+ return formatter<WrappedType>::format(*opt, ctx);
+ } else {
+ /* Print "unset" when the optional has no value. */
+ return format_to(ctx.out(), "unset");
+ }
+ }
+};
} /* namespace fmt */
namespace lttng {
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_MATH_HPP
+#define LTTNG_MATH_HPP
+
+#include <type_traits>
+
+namespace lttng {
+namespace math {
+template <typename IntegralType>
+bool is_power_of_two(IntegralType value)
+{
+ static_assert(std::is_integral<IntegralType>::value,
+ "IntegralType must be an integral type.");
+ if (value < 0) {
+ return false;
+ }
+
+ return __builtin_popcount(value) == 1;
+}
+} /* namespace math */
+} /* namespace lttng */
+
+#endif /* LTTNG_MATH_HPP */
*/
operator bool() const noexcept /* NOLINT(google-explicit-constructor) */
{
- return *this->data();
+ return this->data() && *this->data();
}
/*
const auto raw_lhs = internal::as_const_char_ptr(lhs);
const auto raw_rhs = internal::as_const_char_ptr(rhs);
+ if (raw_lhs == raw_rhs) {
+ return true;
+ } else if (!raw_lhs || !raw_rhs) {
+ /* Only one of the strings is null, not equal. */
+ return false;
+ }
+
return std::strcmp(raw_lhs, raw_rhs) == 0;
}
deprecated-symbols.cpp \
destruction-handle.cpp \
event.cpp \
+ event-rule-convert.cpp \
+ event-rule-convert.hpp \
load.cpp \
lttng-ctl.cpp \
lttng-ctl-health.cpp \
CDS_INIT_LIST_HEAD(&channel->pending_notifications.list);
{
- const auto length = std::snprintf(
- nullptr, 0, DEFAULT_NOTIFICATION_CHANNEL_UNIX_SOCK, rundir_path.get()) + 1;
+ const auto length = std::snprintf(nullptr,
+ 0,
+ DEFAULT_NOTIFICATION_CHANNEL_UNIX_SOCK,
+ rundir_path.get()) +
+ 1;
std::vector<char> sock_path;
sock_path.reserve(length);
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "event-rule-convert.hpp"
+
+#include <common/ctl/format.hpp>
+#include <common/exception.hpp>
+
+using log_level_rule_uptr = std::unique_ptr<
+ lttng_log_level_rule,
+ lttng::memory::create_deleter_class<lttng_log_level_rule, lttng_log_level_rule_destroy>>;
+
+using EventRuleCreateFunctionType = lttng_event_rule *(*) ();
+using EventRuleSetNamePatternFunctionType = lttng_event_rule_status (*)(lttng_event_rule *,
+ const char *);
+using EventRuleSetLogLevelRuleFunctionType =
+ lttng_event_rule_status (*)(lttng_event_rule *, const lttng_log_level_rule *);
+using EventRuleSetFilterExpressionFunctionType = lttng_event_rule_status (*)(lttng_event_rule *,
+ const char *);
+
+namespace {
+log_level_rule_uptr create_log_level_rule_from_lttng_event(const lttng_event& event)
+{
+ log_level_rule_uptr rule;
+ lttng_log_level_rule_type log_level_rule_type;
+
+ switch (event.loglevel_type) {
+ case LTTNG_EVENT_LOGLEVEL_ALL:
+ return nullptr;
+ case LTTNG_EVENT_LOGLEVEL_RANGE:
+ rule.reset(lttng_log_level_rule_exactly_create(event.loglevel));
+ log_level_rule_type = LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS;
+ break;
+ case LTTNG_EVENT_LOGLEVEL_SINGLE:
+ rule.reset(lttng_log_level_rule_at_least_as_severe_as_create(event.loglevel));
+ log_level_rule_type = LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY;
+ break;
+ default:
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(
+ fmt::format("Invalid log level type: type={}", event.loglevel_type));
+ }
+
+ if (!rule) {
+ LTTNG_THROW_ERROR(
+ fmt::format("Failed to allocate log level rule: rule_type={}, level={}",
+ log_level_rule_type,
+ event.loglevel));
+ }
+
+ return rule;
+}
+
+template <EventRuleCreateFunctionType EventRuleCreateFunction,
+ EventRuleSetNamePatternFunctionType EventRuleSetNamePatternFunction,
+ EventRuleSetLogLevelRuleFunctionType EventRuleSetLogLevelRuleFunction,
+ EventRuleSetFilterExpressionFunctionType EventRuleSetFilterExpressionFunction>
+lttng::event_rule_uptr create_user_or_agent_event_rule_from_lttng_event(
+ const lttng_event& event,
+ lttng_domain_type domain,
+ const log_level_rule_uptr& log_level_rule,
+ nonstd::optional<lttng::c_string_view> filter_expression)
+{
+ lttng::event_rule_uptr rule{ EventRuleCreateFunction() };
+
+ if (!rule) {
+ LTTNG_THROW_ERROR(fmt::format("Failed to allocate event rule: domain={}", domain));
+ }
+
+ const auto pattern = event.name[0] == '\0' ? "*" : event.name;
+ const auto set_pattern_ret = EventRuleSetNamePatternFunction(rule.get(), pattern);
+ if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set name pattern on event rule: domain={}, pattern=`{}`",
+ domain,
+ pattern));
+ }
+
+ if (log_level_rule) {
+ const auto set_log_level_rule_ret =
+ EventRuleSetLogLevelRuleFunction(rule.get(), log_level_rule.get());
+ if (set_log_level_rule_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ if (set_log_level_rule_ret == LTTNG_EVENT_RULE_STATUS_INVALID) {
+ LTTNG_THROW_CTL("Invalid log level specified for domain",
+ LTTNG_ERR_INVALID);
+ } else {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set log level rule on event rule: domain=\"{}\"",
+ domain));
+ }
+ }
+ }
+
+ if (filter_expression) {
+ const auto set_filter_expression_ret =
+ EventRuleSetFilterExpressionFunction(rule.get(), filter_expression->data());
+ if (set_filter_expression_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set filter expression on event rule: domain={}, filter_expression=`{}`",
+ domain,
+ *filter_expression));
+ }
+ }
+
+ return rule;
+}
+
+lttng::event_rule_uptr
+create_kernel_event_rule_from_lttng_event(const lttng_event& event,
+ nonstd::optional<lttng::c_string_view> filter_expression)
+{
+ lttng::event_rule_uptr rule;
+
+ switch (event.type) {
+ case LTTNG_EVENT_ALL:
+ /* Caller should enable all syscalls and all tracepoints explicitly/separately. */
+ LTTNG_THROW_UNSUPPORTED_ERROR(
+ "'All' instrumentation type is unsupported by the event rule interface");
+ case LTTNG_EVENT_TRACEPOINT:
+ {
+ const auto pattern = event.name[0] == '\0' ? "*" : event.name;
+ rule.reset(lttng_event_rule_kernel_tracepoint_create());
+ if (!rule) {
+ LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+ "Failed to create kernel tracepoint event rule");
+ }
+
+ const auto set_pattern_ret =
+ lttng_event_rule_kernel_tracepoint_set_name_pattern(rule.get(), pattern);
+ if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set name pattern on kernel tracepoint event rule: pattern=`{}`",
+ pattern));
+ };
+
+ if (filter_expression) {
+ const auto set_filter_ret = lttng_event_rule_kernel_tracepoint_set_filter(
+ rule.get(), filter_expression->data());
+ if (set_filter_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set filter expression on kernel tracepoint event rule: filter_expression=`{}`",
+ filter_expression->data()));
+ };
+ }
+ break;
+ }
+ case LTTNG_EVENT_PROBE:
+ case LTTNG_EVENT_FUNCTION:
+ {
+ lttng::kernel_location_uptr location;
+
+ if (event.attr.probe.symbol_name[0]) {
+ /* Specified by name. */
+ location.reset(lttng_kernel_probe_location_symbol_create(
+ event.attr.probe.symbol_name, event.attr.probe.offset));
+ } else {
+ /* Specified by address. */
+ location.reset(
+ lttng_kernel_probe_location_address_create(event.attr.probe.addr));
+ }
+
+ if (!location) {
+ LTTNG_THROW_ERROR(
+ "Failed to create kernel probe location from lttng_event");
+ }
+
+ rule.reset(lttng_event_rule_kernel_kprobe_create(location.get()));
+ if (!rule) {
+ LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+ "Failed to create kernel kprobe event rule");
+ }
+
+ const auto set_name_ret =
+ lttng_event_rule_kernel_kprobe_set_event_name(rule.get(), event.name);
+ if (set_name_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set name on kernel tracepoint event rule: name=`{}`",
+ event.name));
+ }
+
+ break;
+ }
+ case LTTNG_EVENT_SYSCALL:
+ {
+ const auto pattern = event.name[0] == '\0' ? "*" : event.name;
+
+ /* Entry + exit is currently the only mode exposed for recording event rules. */
+ rule.reset(lttng_event_rule_kernel_syscall_create(
+ LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY_EXIT));
+ if (!rule) {
+ LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+ "Failed to create kernel syscall event rule");
+ }
+
+ const auto set_pattern_ret =
+ lttng_event_rule_kernel_syscall_set_name_pattern(rule.get(), pattern);
+ if (set_pattern_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set name pattern on kernel syscall event rule: pattern=`{}`",
+ pattern));
+ };
+
+ if (filter_expression) {
+ const auto set_filter_ret = lttng_event_rule_kernel_syscall_set_filter(
+ rule.get(), filter_expression->data());
+ if (set_filter_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set filter expression on kernel syscall event rule: filter_expression=`{}`",
+ filter_expression->data()));
+ };
+ }
+
+ break;
+ }
+ case LTTNG_EVENT_USERSPACE_PROBE:
+ {
+ const auto location = lttng_event_get_userspace_probe_location(&event);
+
+ rule.reset(lttng_event_rule_kernel_uprobe_create(location));
+ if (!rule) {
+ LTTNG_THROW_ALLOCATION_FAILURE_ERROR(
+ "Failed to create kernel user space probe event rule");
+ }
+
+ const auto set_name_ret =
+ lttng_event_rule_kernel_uprobe_set_event_name(rule.get(), event.name);
+ if (set_name_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to set name on kernel uprobe event rule: name=`{}`",
+ event.name));
+ }
+
+ break;
+ }
+ default:
+ LTTNG_THROW_UNSUPPORTED_ERROR(
+ "Unsupported instrumentation type encountered while creating kernel event rule from lttng_event");
+ }
+
+ return rule;
+}
+} /* namespace */
+
+lttng::event_rule_uptr lttng::ctl::create_event_rule_from_lttng_event(
+ const lttng_event& event,
+ lttng_domain_type domain,
+ const nonstd::optional<lttng::c_string_view>& filter_expression,
+ const std::vector<lttng::c_string_view>& exclusions)
+{
+ lttng::event_rule_uptr rule;
+ const auto log_level_rule = [&event, domain]() {
+ switch (domain) {
+ case LTTNG_DOMAIN_UST:
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_LOG4J2:
+ case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_PYTHON:
+ return create_log_level_rule_from_lttng_event(event);
+ default:
+ return log_level_rule_uptr();
+ }
+ }();
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ rule = create_kernel_event_rule_from_lttng_event(event, filter_expression);
+ break;
+ case LTTNG_DOMAIN_UST:
+ rule = create_user_or_agent_event_rule_from_lttng_event<
+ lttng_event_rule_user_tracepoint_create,
+ lttng_event_rule_user_tracepoint_set_name_pattern,
+ lttng_event_rule_user_tracepoint_set_log_level_rule,
+ lttng_event_rule_user_tracepoint_set_filter>(
+ event, domain, log_level_rule, filter_expression);
+ break;
+ case LTTNG_DOMAIN_LOG4J:
+ rule = create_user_or_agent_event_rule_from_lttng_event<
+ lttng_event_rule_log4j_logging_create,
+ lttng_event_rule_log4j_logging_set_name_pattern,
+ lttng_event_rule_log4j_logging_set_log_level_rule,
+ lttng_event_rule_log4j_logging_set_filter>(
+ event, domain, log_level_rule, filter_expression);
+ break;
+ case LTTNG_DOMAIN_LOG4J2:
+ rule = create_user_or_agent_event_rule_from_lttng_event<
+ lttng_event_rule_log4j2_logging_create,
+ lttng_event_rule_log4j2_logging_set_name_pattern,
+ lttng_event_rule_log4j2_logging_set_log_level_rule,
+ lttng_event_rule_log4j2_logging_set_filter>(
+ event, domain, log_level_rule, filter_expression);
+ break;
+ case LTTNG_DOMAIN_JUL:
+ rule = create_user_or_agent_event_rule_from_lttng_event<
+ lttng_event_rule_jul_logging_create,
+ lttng_event_rule_jul_logging_set_name_pattern,
+ lttng_event_rule_jul_logging_set_log_level_rule,
+ lttng_event_rule_jul_logging_set_filter>(
+ event, domain, log_level_rule, filter_expression);
+ break;
+ case LTTNG_DOMAIN_PYTHON:
+ rule = create_user_or_agent_event_rule_from_lttng_event<
+ lttng_event_rule_python_logging_create,
+ lttng_event_rule_python_logging_set_name_pattern,
+ lttng_event_rule_python_logging_set_log_level_rule,
+ lttng_event_rule_python_logging_set_filter>(
+ event, domain, log_level_rule, filter_expression);
+ break;
+ default:
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
+ "Invalid domain specified during event-rule creation: domain={}", domain));
+ }
+
+ if (!exclusions.empty()) {
+ if (domain != LTTNG_DOMAIN_UST) {
+ LTTNG_THROW_UNSUPPORTED_ERROR(
+ "Pattern exclusions are only supported by the user space domain");
+ }
+
+ for (const auto& exclusion : exclusions) {
+ const auto set_exclusions_ret =
+ lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
+ rule.get(), exclusion.data());
+
+ if (set_exclusions_ret != LTTNG_EVENT_RULE_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to add name pattern exclusion to event rule: pattern=`{}`",
+ exclusion));
+ }
+ }
+ }
+
+ return rule;
+}
--- /dev/null
+/*
+ * Copyright (C) 2024 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_CTL_EVENT_RULE_CONVERT_HPP
+#define LTTNG_CTL_EVENT_RULE_CONVERT_HPP
+
+#include "lttng/event-rule/event-rule-internal.hpp"
+
+#include <common/ctl/memory.hpp>
+#include <common/string-utils/c-string-view.hpp>
+
+#include <lttng/lttng.h>
+
+#include <vendor/optional.hpp>
+
+#include <memory>
+#include <vector>
+
+namespace lttng {
+namespace ctl {
+event_rule_uptr
+create_event_rule_from_lttng_event(const lttng_event& event,
+ lttng_domain_type domain,
+ const nonstd::optional<lttng::c_string_view>& filter_expression,
+ const std::vector<lttng::c_string_view>& exclusions);
+} /* namespace ctl */
+} /* namespace lttng */
+
+#endif /* LTTNG_CTL_EVENT_RULE_CONVERT_HPP */
*/
#define _LGPL_SOURCE
+#include "event-rule-convert.hpp"
#include "lttng-ctl-helper.hpp"
#include <common/align.hpp>
#include <common/defaults.hpp>
#include <common/dynamic-array.hpp>
#include <common/dynamic-buffer.hpp>
+#include <common/exception.hpp>
#include <common/filter/filter-ast.hpp>
+/* NOLINTNEXTLINE */
#include <common/filter/filter-parser.hpp>
#include <common/filter/memstream.hpp>
#include <common/make-unique-wrapper.hpp>
#include <common/payload-view.hpp>
#include <common/payload.hpp>
+#include <common/scope-exit.hpp>
#include <common/sessiond-comm/sessiond-comm.hpp>
#include <common/tracker.hpp>
#include <common/unix.hpp>
}
/*
- * Depending on the event, return a newly allocated agent filter expression or
- * NULL if not applicable.
+ * Depending on the event, return a new agent filter expression or
+ * an empty string if not applicable.
*
- * An event with NO loglevel and the name is * will return NULL.
+ * An event with NO loglevel and the name is * will return an empty string.
*/
-static char *
-set_agent_filter(const char *filter, struct lttng_event *ev, struct lttng_domain *domain)
+static std::string build_agent_filter_expression(const char *original_filter_expression,
+ const lttng_event& ev,
+ const lttng_domain& domain)
{
- int err;
- char *agent_filter = nullptr;
+ std::string agent_filter;
- LTTNG_ASSERT(ev);
- LTTNG_ASSERT(domain);
+ try {
+ /* Don't add filter for the '*' event. */
+ std::string logger_name_filter;
- /* Don't add filter for the '*' event. */
- if (strcmp(ev->name, "*") != 0) {
- if (filter) {
- err = asprintf(
- &agent_filter, "(%s) && (logger_name == \"%s\")", filter, ev->name);
- } else {
- err = asprintf(&agent_filter, "logger_name == \"%s\"", ev->name);
+ if (lttng::c_string_view(ev.name) != "*" &&
+ lttng::c_string_view(ev.name).len() != 0) {
+ logger_name_filter = fmt::format("logger_name == \"{}\"", ev.name);
}
- if (err < 0) {
- PERROR("asprintf");
- goto error;
+
+ if (original_filter_expression == nullptr) {
+ agent_filter = std::move(logger_name_filter);
+ } else {
+ if (logger_name_filter.size() > 0) {
+ agent_filter = fmt::format("({}) && ({})",
+ original_filter_expression,
+ logger_name_filter);
+ } else {
+ agent_filter.append(original_filter_expression);
+ }
}
- }
- /* Add loglevel filtering if any for the agent domains. */
- if (ev->loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
- const char *op;
+ /* Add loglevel filtering if any for the agent domains. */
+ if (ev.loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+ std::string op;
- if (ev->loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) {
- /*
- * Log4j2 is the only agent domain for which more severe
- * logging levels have a lower numerical value.
- */
- if (domain->type == LTTNG_DOMAIN_LOG4J2) {
- op = "<=";
+ if (ev.loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) {
+ /*
+ * 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 = ">=";
+ op = "==";
}
- } else {
- op = "==";
- }
- if (filter || agent_filter) {
- char *new_filter;
+ if (original_filter_expression != nullptr || !agent_filter.empty()) {
+ std::string existing_filter = !agent_filter.empty() ?
+ agent_filter :
+ std::string(original_filter_expression);
- err = asprintf(&new_filter,
- "(%s) && (int_loglevel %s %d)",
- agent_filter ? agent_filter : filter,
- op,
- ev->loglevel);
- if (agent_filter) {
- free(agent_filter);
+ agent_filter = fmt::format("({}) && (int_loglevel {} {})",
+ existing_filter,
+ op,
+ ev.loglevel);
+ } else {
+ agent_filter = fmt::format("int_loglevel {} {}", op, ev.loglevel);
}
- agent_filter = new_filter;
- } else {
- err = asprintf(&agent_filter, "int_loglevel %s %d", op, ev->loglevel);
- }
- if (err < 0) {
- PERROR("asprintf");
- goto error;
}
+ } catch (const std::exception& e) {
+ return std::string();
}
return agent_filter;
-error:
- free(agent_filter);
- return nullptr;
}
/*
int exclusion_count,
char **exclusion_list)
{
- struct lttcomm_session_msg lsm = {
+ lttcomm_session_msg lsm = {
.cmd_type = LTTCOMM_SESSIOND_COMMAND_ENABLE_EVENT,
.session = {},
.domain = {},
.u = {},
.fd_count = 0,
};
- struct lttng_payload payload;
+ lttng_payload payload;
int ret = 0;
- unsigned int free_filter_expression = 0;
- struct filter_parser_ctx *ctx = nullptr;
- size_t bytecode_len = 0;
- /*
- * We have either a filter or some exclusions, so we need to set up
- * a variable-length payload from where to send the data.
- */
- lttng_payload_init(&payload);
-
- /*
- * Cast as non-const since we may replace the filter expression
- * by a dynamically allocated string. Otherwise, the original
- * string is not modified.
- */
- char *filter_expression = (char *) original_filter_expression;
+ if (ev->type == LTTNG_EVENT_ALL) {
+ /*
+ * Since we modify the user's parameter, ensure it is set back to its original value
+ * on exit.
+ */
+ const auto restore_event_type_value =
+ lttng::make_scope_exit([&ev]() noexcept { ev->type = LTTNG_EVENT_ALL; });
+
+ ev->type = LTTNG_EVENT_TRACEPOINT;
+ const auto tp_ret = lttng_enable_event_with_exclusions(handle,
+ ev,
+ channel_name,
+ original_filter_expression,
+ exclusion_count,
+ exclusion_list);
+ if (tp_ret < 0 || handle->domain.type != LTTNG_DOMAIN_KERNEL) {
+ return tp_ret;
+ }
+
+ ev->type = LTTNG_EVENT_SYSCALL;
+ const auto syscall_ret =
+ lttng_enable_event_with_exclusions(handle,
+ ev,
+ channel_name,
+ original_filter_expression,
+ exclusion_count,
+ exclusion_list);
+ return syscall_ret;
+ }
if (handle == nullptr || ev == nullptr) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
}
/*
* anyway, so treat this corner-case early to eliminate
* lttng_fmemopen error for 0-byte allocation.
*/
- if (filter_expression && filter_expression[0] == '\0') {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ if (original_filter_expression && strlen(original_filter_expression) == 0) {
+ return -LTTNG_ERR_INVALID;
}
+ /*
+ * We have either a filter or some exclusions, so we need to set up
+ * a variable-length payload from where to send the data.
+ */
+ lttng_payload_init(&payload);
+ /* Clean-up payload when returning. */
+ auto cleanup_payload =
+ lttng::make_scope_exit([&payload]() noexcept { lttng_payload_reset(&payload); });
+
+ /* The filter expression may be modified below in the case of agent domains. */
+ std::string filter_expression(original_filter_expression ?: "");
+
if (ev->name[0] == '\0') {
/* Enable all events. */
ret = lttng_strncpy(ev->name, "*", sizeof(ev->name));
LTTNG_ASSERT(ret == 0);
}
- /* Parse filter expression. */
- if (filter_expression != nullptr || handle->domain.type == LTTNG_DOMAIN_JUL ||
- handle->domain.type == LTTNG_DOMAIN_LOG4J ||
+ 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) {
- 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, &handle->domain);
- if (!agent_filter) {
- if (!filter_expression) {
- /*
- * No agent and no filter, just skip
- * everything below.
- */
- goto serialize;
- }
- } else {
- /*
- * With an agent filter, the original filter has
- * been added to it thus replace the filter
- * expression.
- */
- filter_expression = agent_filter;
- free_filter_expression = 1;
- }
+ /* Setup agent filter if needed. */
+ try {
+ filter_expression = build_agent_filter_expression(
+ original_filter_expression, *ev, handle->domain);
+ } catch (const std::bad_alloc& bad_alloc_ex) {
+ return -LTTNG_ERR_NOMEM;
+ } catch (...) {
+ return -LTTNG_ERR_UNK;
}
+ }
- if (strnlen(filter_expression, LTTNG_FILTER_MAX_LEN) == LTTNG_FILTER_MAX_LEN) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto error;
+ if (handle->domain.type == LTTNG_DOMAIN_KERNEL && ev->type == LTTNG_EVENT_ALL) {
+ /*
+ * Syscall and tracepoints are different instrumentation types that must be
+ * enabled by separate event rules.
+ */
+ ev->type = LTTNG_EVENT_SYSCALL;
+ ret = lttng_enable_event_with_exclusions(handle,
+ ev,
+ channel_name,
+ original_filter_expression,
+ exclusion_count,
+ exclusion_list);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ev->type = LTTNG_EVENT_TRACEPOINT;
+ ret = lttng_enable_event_with_exclusions(handle,
+ ev,
+ channel_name,
+ original_filter_expression,
+ exclusion_count,
+ exclusion_list);
+ if (ret < 0) {
+ return ret;
}
- ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
+ return ret;
+ }
+
+ std::vector<lttng::c_string_view> exclusions_vec;
+ if (exclusion_count > 0) {
+ exclusions_vec.reserve(exclusion_count);
+
+ for (unsigned int i = 0; i < exclusion_count; i++) {
+ exclusions_vec.emplace_back(exclusion_list[i]);
+ }
+ }
+
+ lttng::event_rule_uptr event_rule;
+ try {
+ event_rule = lttng::ctl::create_event_rule_from_lttng_event(
+ *ev,
+ handle->domain.type,
+ original_filter_expression ?
+ nonstd::make_optional(original_filter_expression) :
+ nonstd::nullopt,
+ exclusions_vec);
+ } catch (const lttng::ctl::error& ctl_error) {
+ DBG("%s", ctl_error.what());
+ return -LTTNG_ERR_INVALID;
+ } catch (const std::exception& ex) {
+ DBG("%s", ex.what());
+ return -LTTNG_ERR_UNK;
+ }
+
+ filter_parser_ctx *ctx = nullptr;
+
+ if (filter_expression.size() > 0) {
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression.c_str(),
+ &ctx);
if (ret) {
- goto error;
+ return -LTTNG_ERR_INVALID;
}
+ }
- bytecode_len = bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b);
- if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto error;
+ const auto free_bytecode_ir_and_parser_context = lttng::make_scope_exit([ctx]() noexcept {
+ if (!ctx) {
+ return;
}
+
+ filter_bytecode_free(ctx);
+ filter_ir_free(ctx);
+ filter_parser_ctx_free(ctx);
+ });
+
+ const auto bytecode_len =
+ ctx ? (bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b)) : 0;
+ if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
+ return -LTTNG_ERR_INVALID;
}
-serialize:
ret = lttng_event_serialize(ev,
exclusion_count,
exclusion_list,
- filter_expression,
+ filter_expression.size() > 0 ? filter_expression.c_str() :
+ nullptr,
bytecode_len,
(ctx && bytecode_len) ? &ctx->bytecode->b : nullptr,
&payload);
if (ret) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
+ }
+
+ if (!lttng_event_rule_validate(event_rule.get())) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ ret = lttng_event_rule_serialize(event_rule.get(), &payload);
+ if (ret) {
+ return -LTTNG_ERR_INVALID;
}
/* If no channel name, send empty string. */
ret = lttng_strncpy(
lsm.u.enable.channel_name, channel_name ?: "", sizeof(lsm.u.enable.channel_name));
if (ret) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
}
/* Domain */
/* Session name */
ret = lttng_strncpy(lsm.session.name, handle->session_name, sizeof(lsm.session.name));
if (ret) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
}
- /* Length of the serialized event. */
+ /* Length of the serialized event rule. */
lsm.u.enable.length = (uint32_t) payload.buffer.size;
- {
- struct lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
- const int fd_count = lttng_payload_view_get_fd_handle_count(&view);
- int fd_to_send;
+ lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
+ const auto fd_count = lttng_payload_view_get_fd_handle_count(&view);
- if (fd_count < 0) {
- goto error;
- }
+ if (fd_count < 0) {
+ return -LTTNG_ERR_UNK;
+ }
- LTTNG_ASSERT(fd_count == 0 || fd_count == 1);
- if (fd_count == 1) {
- struct fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
+ LTTNG_ASSERT(fd_count == 0 || fd_count == 2);
- if (!h) {
- goto error;
- }
+ std::vector<int> fds_to_send;
- fd_to_send = fd_handle_get_fd(h);
- fd_handle_put(h);
- }
+ fds_to_send.reserve(fd_count);
+ for (auto i = 0; i < fd_count; i++) {
+ fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
- lsm.fd_count = fd_count;
+ if (!h) {
+ return -LTTNG_ERR_UNK;
+ }
- ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm,
- fd_count ? &fd_to_send : nullptr,
- fd_count,
- view.buffer.size ? view.buffer.data :
- nullptr,
- view.buffer.size,
- nullptr,
- nullptr,
- nullptr);
+ const auto fd_to_send = fd_handle_get_fd(h);
+ fds_to_send.push_back(fd_to_send);
+ fd_handle_put(h);
}
-error:
- if (filter_expression && ctx) {
- filter_bytecode_free(ctx);
- filter_ir_free(ctx);
- filter_parser_ctx_free(ctx);
- }
- if (free_filter_expression) {
- /*
- * The filter expression has been replaced and must be freed as
- * it is not the original filter expression received as a
- * parameter.
- */
- free(filter_expression);
- }
- /*
- * Return directly to the caller and don't ask the sessiond since
- * something went wrong in the parsing of data above.
- */
- lttng_payload_reset(&payload);
- return ret;
+ lsm.fd_count = fd_count;
+
+ return lttng_ctl_ask_sessiond_fds_varlen(&lsm,
+ fd_count ? fds_to_send.data() : nullptr,
+ fd_count,
+ view.buffer.size ? view.buffer.data : nullptr,
+ view.buffer.size,
+ nullptr,
+ nullptr,
+ nullptr);
}
int lttng_disable_event_ext(struct lttng_handle *handle,
const char *channel_name,
const char *original_filter_expression)
{
- struct lttcomm_session_msg lsm = {
+ lttcomm_session_msg lsm = {
.cmd_type = LTTCOMM_SESSIOND_COMMAND_DISABLE_EVENT,
.session = {},
.domain = {},
.u = {},
.fd_count = 0,
};
- struct lttng_payload payload;
+ lttng_payload payload;
int ret = 0;
- unsigned int free_filter_expression = 0;
- struct filter_parser_ctx *ctx = nullptr;
- size_t bytecode_len = 0;
-
- /*
- * We have either a filter or some exclusions, so we need to set up
- * a variable-length payload from where to send the data.
- */
- lttng_payload_init(&payload);
-
- /*
- * Cast as non-const since we may replace the filter expression
- * by a dynamically allocated string. Otherwise, the original
- * string is not modified.
- */
- char *filter_expression = (char *) original_filter_expression;
if (handle == nullptr || ev == nullptr) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
}
/*
* anyway, so treat this corner-case early to eliminate
* lttng_fmemopen error for 0-byte allocation.
*/
- if (filter_expression && filter_expression[0] == '\0') {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ if (original_filter_expression && strlen(original_filter_expression) == 0) {
+ return -LTTNG_ERR_INVALID;
}
- /* Parse filter expression. */
- if (filter_expression != nullptr || handle->domain.type == LTTNG_DOMAIN_JUL ||
- handle->domain.type == LTTNG_DOMAIN_LOG4J ||
+ /*
+ * We have either a filter or some exclusions, so we need to set up
+ * a variable-length payload from where to send the data.
+ */
+ lttng_payload_init(&payload);
+ /* Clean-up payload when returning. */
+ auto cleanup_payload =
+ lttng::make_scope_exit([&payload]() noexcept { lttng_payload_reset(&payload); });
+
+ /* The filter expression may be modified below in the case of agent domains. */
+ std::string filter_expression(original_filter_expression ?: "");
+
+ 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) {
- 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, &handle->domain);
- if (!agent_filter) {
- if (!filter_expression) {
- /*
- * No JUL and no filter, just skip
- * everything below.
- */
- goto serialize;
- }
- } else {
- /*
- * With an agent filter, the original filter has
- * been added to it thus replace the filter
- * expression.
- */
- filter_expression = agent_filter;
- free_filter_expression = 1;
- }
+ /* Setup agent filter if needed. */
+ try {
+ filter_expression = build_agent_filter_expression(
+ original_filter_expression, *ev, handle->domain);
+ } catch (const std::bad_alloc& bad_alloc_ex) {
+ return -LTTNG_ERR_NOMEM;
+ } catch (...) {
+ return -LTTNG_ERR_UNK;
+ }
+ }
+
+ const std::vector<lttng::c_string_view> exclusions_vec;
+ lttng::event_rule_uptr event_rule;
+ if (ev->type != LTTNG_EVENT_ALL) {
+ try {
+ event_rule = lttng::ctl::create_event_rule_from_lttng_event(
+ *ev,
+ handle->domain.type,
+ original_filter_expression ?
+ nonstd::make_optional(original_filter_expression) :
+ nonstd::nullopt,
+ exclusions_vec);
+ } catch (const lttng::ctl::error& ctl_error) {
+ DBG("%s", ctl_error.what());
+ return -LTTNG_ERR_INVALID;
+ } catch (const std::exception& ex) {
+ DBG("%s", ex.what());
+ return -LTTNG_ERR_UNK;
+ }
+ }
+
+ filter_parser_ctx *ctx = nullptr;
+ if (filter_expression.size() > 0) {
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression.c_str(),
+ &ctx);
+ if (ret) {
+ return -LTTNG_ERR_INVALID;
}
+ }
- if (strnlen(filter_expression, LTTNG_FILTER_MAX_LEN) == LTTNG_FILTER_MAX_LEN) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto error;
+ const auto free_bytecode_ir_and_parser_context = lttng::make_scope_exit([ctx]() noexcept {
+ if (!ctx) {
+ return;
}
- ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
- if (ret) {
- goto error;
- }
+ filter_bytecode_free(ctx);
+ filter_ir_free(ctx);
+ filter_parser_ctx_free(ctx);
+ });
- bytecode_len = bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b);
- if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto error;
- }
+ const auto bytecode_len =
+ ctx ? (bytecode_get_len(&ctx->bytecode->b) + sizeof(ctx->bytecode->b)) : 0;
+ if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
+ return -LTTNG_ERR_INVALID;
}
-serialize:
ret = lttng_event_serialize(ev,
0,
nullptr,
- filter_expression,
+ filter_expression.size() > 0 ? filter_expression.c_str() :
+ nullptr,
bytecode_len,
(ctx && bytecode_len) ? &ctx->bytecode->b : nullptr,
&payload);
if (ret) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
+ }
+
+ if (event_rule) {
+ ret = lttng_event_rule_serialize(event_rule.get(), &payload);
+ if (ret) {
+ return -LTTNG_ERR_INVALID;
+ }
}
/* If no channel name, send empty string. */
ret = lttng_strncpy(
lsm.u.disable.channel_name, channel_name ?: "", sizeof(lsm.u.disable.channel_name));
if (ret) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
}
/* Domain */
/* Session name */
ret = lttng_strncpy(lsm.session.name, handle->session_name, sizeof(lsm.session.name));
if (ret) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ return -LTTNG_ERR_INVALID;
}
- /* Length of the serialized event. */
+ /* Length of the serialized event rule. */
lsm.u.disable.length = (uint32_t) payload.buffer.size;
- {
- struct lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
- const int fd_count = lttng_payload_view_get_fd_handle_count(&view);
- int fd_to_send;
+ lttng_payload_view view = lttng_payload_view_from_payload(&payload, 0, -1);
+ const auto fd_count = lttng_payload_view_get_fd_handle_count(&view);
- if (fd_count < 0) {
- goto error;
- }
+ if (fd_count < 0) {
+ return -LTTNG_ERR_UNK;
+ }
- LTTNG_ASSERT(fd_count == 0 || fd_count == 1);
- if (fd_count == 1) {
- struct fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
+ LTTNG_ASSERT(fd_count == 0 || fd_count == 2);
- if (!h) {
- goto error;
- }
+ std::vector<int> fds_to_send;
- fd_to_send = fd_handle_get_fd(h);
- fd_handle_put(h);
+ fds_to_send.reserve(fd_count);
+ for (auto i = 0; i < fd_count; i++) {
+ fd_handle *h = lttng_payload_view_pop_fd_handle(&view);
+
+ if (!h) {
+ return -LTTNG_ERR_UNK;
}
- ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm,
- fd_count ? &fd_to_send : nullptr,
- fd_count,
- view.buffer.size ? view.buffer.data :
- nullptr,
- view.buffer.size,
- nullptr,
- nullptr,
- nullptr);
+ const auto fd_to_send = fd_handle_get_fd(h);
+ fds_to_send.push_back(fd_to_send);
+ fd_handle_put(h);
}
-error:
- if (filter_expression && ctx) {
- filter_bytecode_free(ctx);
- filter_ir_free(ctx);
- filter_parser_ctx_free(ctx);
- }
- if (free_filter_expression) {
- /*
- * The filter expression has been replaced and must be freed as
- * it is not the original filter expression received as a
- * parameter.
- */
- free(filter_expression);
- }
- /*
- * Return directly to the caller and don't ask the sessiond since
- * something went wrong in the parsing of data above.
- */
- lttng_payload_reset(&payload);
- return ret;
+ lsm.fd_count = fd_count;
+
+ return lttng_ctl_ask_sessiond_fds_varlen(&lsm,
+ fd_count ? fds_to_send.data() : nullptr,
+ fd_count,
+ view.buffer.size ? view.buffer.data : nullptr,
+ view.buffer.size,
+ nullptr,
+ nullptr,
+ nullptr);
}
/*
return ret;
}
-int lttng_channel_get_monitor_timer_interval(struct lttng_channel *chan,
+int lttng_channel_get_monitor_timer_interval(const struct lttng_channel *chan,
uint64_t *monitor_timer_interval)
{
int ret = 0;
return ret;
}
-int lttng_channel_get_blocking_timeout(struct lttng_channel *chan, int64_t *blocking_timeout)
+int lttng_channel_get_blocking_timeout(const struct lttng_channel *chan, int64_t *blocking_timeout)
{
int ret = 0;
<enabled>false</enabled>
<type>TRACEPOINT</type>
<loglevel_type>RANGE</loglevel_type>
- <loglevel>-1</loglevel>
+ <loglevel>5</loglevel>
</event>
<event>
<name>uevent_disabled</name>