OPT_FILTER,
OPT_EXCLUDE_NAMES,
OPT_EVENT_NAME,
- OPT_LOGLEVEL,
- OPT_LOGLEVEL_ONLY,
+ OPT_LOG_LEVEL,
OPT_DOMAIN,
OPT_TYPE,
{ OPT_FILTER, 'f', "filter", true },
{ OPT_NAME, 'n', "name", true },
{ OPT_EXCLUDE_NAMES, 'x', "exclude-names", true },
- { OPT_LOGLEVEL, '\0', "loglevel", true },
- { OPT_LOGLEVEL_ONLY, '\0', "loglevel-only", true },
+ { OPT_LOG_LEVEL, 'l', "log-level", true },
{ OPT_EVENT_NAME, 'E', "event-name", true },
{ OPT_DOMAIN, 'd', "domain", true },
char ***exclusion_list);
/*
- * Parse `str` as a log level in domain `domain_type`. Return -1 if the string
- * is not recognized as a valid log level.
+ * Parse `str` as a log level in domain `domain_type`.
+ *
+ * Return the log level in `*log_level`. Return true in `*log_level_only` if
+ * the string specifies exactly this log level, false if it specifies at least
+ * this log level.
+ *
+ * Return true if the string was successfully parsed as a log level string.
*/
-static
-int parse_loglevel_string(const char *str, enum lttng_domain_type domain_type)
+static bool parse_log_level_string(const char *str,
+ enum lttng_domain_type domain_type,
+ int *log_level,
+ bool *log_level_only)
{
+ bool ret;
+
switch (domain_type) {
case LTTNG_DOMAIN_UST:
{
- enum lttng_loglevel loglevel;
- const int ret = loglevel_name_to_value(str, &loglevel);
+ enum lttng_loglevel log_level_min, log_level_max;
+ if (!loglevel_parse_range_string(
+ str, &log_level_min, &log_level_max)) {
+ goto error;
+ }
- return ret == -1 ? ret : (int) loglevel;
+ /* Only support VAL and VAL.. for now. */
+ if (log_level_min != log_level_max &&
+ log_level_max != LTTNG_LOGLEVEL_EMERG) {
+ goto error;
+ }
+
+ *log_level = (int) log_level_min;
+ *log_level_only = log_level_min == log_level_max;
+ break;
}
case LTTNG_DOMAIN_LOG4J:
{
- enum lttng_loglevel_log4j loglevel;
- const int ret = loglevel_log4j_name_to_value(str, &loglevel);
+ enum lttng_loglevel_log4j log_level_min, log_level_max;
+ if (!loglevel_log4j_parse_range_string(
+ str, &log_level_min, &log_level_max)) {
+ goto error;
+ }
- return ret == -1 ? ret : (int) loglevel;
+ /* Only support VAL and VAL.. for now. */
+ if (log_level_min != log_level_max &&
+ log_level_max != LTTNG_LOGLEVEL_LOG4J_FATAL) {
+ goto error;
+ }
+
+ *log_level = (int) log_level_min;
+ *log_level_only = log_level_min == log_level_max;
+ break;
}
case LTTNG_DOMAIN_JUL:
{
- enum lttng_loglevel_jul loglevel;
- const int ret = loglevel_jul_name_to_value(str, &loglevel);
+ enum lttng_loglevel_jul log_level_min, log_level_max;
+ if (!loglevel_jul_parse_range_string(
+ str, &log_level_min, &log_level_max)) {
+ goto error;
+ }
- return ret == -1 ? ret : (int) loglevel;
+ /* Only support VAL and VAL.. for now. */
+ if (log_level_min != log_level_max &&
+ log_level_max != LTTNG_LOGLEVEL_JUL_SEVERE) {
+ goto error;
+ }
+
+ *log_level = (int) log_level_min;
+ *log_level_only = log_level_min == log_level_max;
+ break;
}
case LTTNG_DOMAIN_PYTHON:
{
- enum lttng_loglevel_python loglevel;
- const int ret = loglevel_python_name_to_value(str, &loglevel);
+ enum lttng_loglevel_python log_level_min, log_level_max;
+ if (!loglevel_python_parse_range_string(
+ str, &log_level_min, &log_level_max)) {
+ goto error;
+ }
- return ret == -1 ? ret : (int) loglevel;
+ /* Only support VAL and VAL.. for now. */
+ if (log_level_min != log_level_max &&
+ log_level_max !=
+ LTTNG_LOGLEVEL_PYTHON_CRITICAL) {
+ goto error;
+ }
+
+ *log_level = (int) log_level_min;
+ *log_level_only = log_level_min == log_level_max;
+ break;
}
default:
/* Invalid domain type. */
abort();
}
+
+ ret = true;
+ goto end;
+
+error:
+ ret = false;
+
+end:
+ return ret;
}
static int parse_kernel_probe_opts(const char *source,
char *filter = NULL;
/* Log level. */
- char *loglevel_str = NULL;
- bool loglevel_only = false;
+ char *log_level_str = NULL;
lttng_dynamic_pointer_array_init(&res.capture_descriptors,
destroy_event_expr);
}
break;
- case OPT_LOGLEVEL:
- case OPT_LOGLEVEL_ONLY:
- if (!assign_string(&loglevel_str, item_opt->arg,
- "--loglevel/--loglevel-only")) {
+ case OPT_LOG_LEVEL:
+ if (!assign_string(&log_level_str,
+ item_opt->arg, "--log-level/-l")) {
goto error;
}
- loglevel_only = item_opt->descr->id ==
- OPT_LOGLEVEL_ONLY;
break;
case OPT_CAPTURE:
{
}
}
- if (loglevel_str && event_rule_type != LTTNG_EVENT_RULE_TYPE_TRACEPOINT) {
- ERR("Log levels are only applicable to tracepoint event rules.");
- goto error;
+ if (log_level_str) {
+ if (event_rule_type != LTTNG_EVENT_RULE_TYPE_TRACEPOINT) {
+ ERR("Log levels are only applicable to tracepoint event rules.");
+ goto error;
+ }
+
+ if (domain_type == LTTNG_DOMAIN_KERNEL) {
+ ERR("Log levels are not supported by the kernel tracer.");
+ goto error;
+ }
}
/* Finally, create the event rule object. */
}
}
- if (loglevel_str) {
- int loglevel;
-
- if (domain_type == LTTNG_DOMAIN_KERNEL) {
- ERR("Log levels are not supported by the kernel tracer.");
- goto error;
- }
-
- loglevel = parse_loglevel_string(
- loglevel_str, domain_type);
- if (loglevel < 0) {
- ERR("Failed to parse `%s` as a log level.",
- loglevel_str);
+ /*
+ * ".." is the same as passing no log level option and
+ * correspond the the "ANY" case.
+ */
+ if (log_level_str && strcmp(log_level_str, "..") != 0) {
+ int log_level;
+ bool log_level_only;
+
+ if (!parse_log_level_string(log_level_str, domain_type,
+ &log_level, &log_level_only)) {
+ ERR("Failed to parse log level string `%s`.",
+ log_level_str);
goto error;
}
- if (loglevel_only) {
- log_level_rule = lttng_log_level_rule_exactly_create(loglevel);
+ if (log_level_only) {
+ log_level_rule = lttng_log_level_rule_exactly_create(log_level);
} else {
- log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(loglevel);
+ log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(log_level);
}
if (log_level_rule == NULL) {
free(filter);
free(name);
free(exclude_names);
- free(loglevel_str);
+ free(log_level_str);
free(location);
free(event_name);
return ret;
}
+static bool loglevel_parse_range_string_common(const char *str,
+ const struct loglevel_name_value *nvs,
+ size_t nvs_count,
+ int *min,
+ int *max)
+{
+ bool ret;
+ int i;
+ const struct loglevel_name_value *nv;
+
+ for (i = 0; i < nvs_count; i++) {
+ nv = &nvs[i];
+
+ if (strncmp(str, nv->name, strlen(nv->name)) == 0) {
+ break;
+ }
+ }
+
+ if (i == nvs_count) {
+ goto error;
+ }
+
+ *min = nv->value;
+ str += strlen(nv->name);
+
+ if (*str == '\0') {
+ *max = nv->value;
+ ret = true;
+ goto end;
+ }
+
+ if (strncmp(str, "..", strlen("..")) != 0) {
+ goto error;
+ }
+
+ str += strlen("..");
+
+ if (*str == '\0') {
+ *max = LTTNG_LOGLEVEL_EMERG;
+ ret = true;
+ goto end;
+ }
+
+ for (i = 0; i < nvs_count; i++) {
+ nv = &nvs[i];
+
+ if (strcmp(str, nv->name) == 0) {
+ break;
+ }
+ }
+
+ if (i == nvs_count) {
+ goto error;
+ }
+
+ *max = nv->value;
+
+ ret = true;
+ goto end;
+
+error:
+ ret = false;
+
+end:
+ return ret;
+}
+
LTTNG_HIDDEN
int loglevel_name_to_value(const char *name, enum lttng_loglevel *loglevel)
{
return ret;
}
+LTTNG_HIDDEN
+bool loglevel_parse_range_string(const char *str,
+ enum lttng_loglevel *min,
+ enum lttng_loglevel *max)
+{
+ int min_int, max_int;
+ bool ret = loglevel_parse_range_string_common(str, loglevel_values,
+ ARRAY_SIZE(loglevel_values), &min_int, &max_int);
+
+ *min = min_int;
+ *max = max_int;
+
+ return ret;
+}
+
LTTNG_HIDDEN
int loglevel_log4j_name_to_value(
const char *name, enum lttng_loglevel_log4j *loglevel)
return ret;
}
+LTTNG_HIDDEN
+bool loglevel_log4j_parse_range_string(const char *str,
+ enum lttng_loglevel_log4j *min,
+ enum lttng_loglevel_log4j *max)
+{
+ int min_int, max_int;
+ bool ret = loglevel_parse_range_string_common(str,
+ loglevel_log4j_values,
+ ARRAY_SIZE(loglevel_log4j_values), &min_int, &max_int);
+
+ *min = min_int;
+ *max = max_int;
+
+ return ret;
+}
+
LTTNG_HIDDEN
int loglevel_jul_name_to_value(
const char *name, enum lttng_loglevel_jul *loglevel)
return ret;
}
+LTTNG_HIDDEN
+bool loglevel_jul_parse_range_string(const char *str,
+ enum lttng_loglevel_jul *min,
+ enum lttng_loglevel_jul *max)
+{
+ int min_int, max_int;
+ bool ret = loglevel_parse_range_string_common(str, loglevel_jul_values,
+ ARRAY_SIZE(loglevel_jul_values), &min_int, &max_int);
+
+ *min = min_int;
+ *max = max_int;
+
+ return ret;
+}
+
LTTNG_HIDDEN
int loglevel_python_name_to_value(
const char *name, enum lttng_loglevel_python *loglevel)
return ret;
}
+LTTNG_HIDDEN
+bool loglevel_python_parse_range_string(const char *str,
+ enum lttng_loglevel_python *min,
+ enum lttng_loglevel_python *max)
+{
+ int min_int, max_int;
+ bool ret = loglevel_parse_range_string_common(str,
+ loglevel_python_values,
+ ARRAY_SIZE(loglevel_python_values), &min_int, &max_int);
+
+ *min = min_int;
+ *max = max_int;
+
+ return ret;
+}
+
static
const char *lookup_name_from_value(const struct loglevel_name_value values[],
size_t values_count, int loglevel)
LTTNG_HIDDEN
int loglevel_name_to_value(const char *name, enum lttng_loglevel *loglevel);
+LTTNG_HIDDEN
+bool loglevel_parse_range_string(const char *str,
+ enum lttng_loglevel *min,
+ enum lttng_loglevel *max);
+
LTTNG_HIDDEN
int loglevel_log4j_name_to_value(
const char *name, enum lttng_loglevel_log4j *loglevel);
+LTTNG_HIDDEN
+bool loglevel_log4j_parse_range_string(const char *str,
+ enum lttng_loglevel_log4j *min,
+ enum lttng_loglevel_log4j *max);
+
LTTNG_HIDDEN
int loglevel_jul_name_to_value(
const char *name, enum lttng_loglevel_jul *loglevel);
+LTTNG_HIDDEN
+bool loglevel_jul_parse_range_string(const char *str,
+ enum lttng_loglevel_jul *min,
+ enum lttng_loglevel_jul *max);
+
LTTNG_HIDDEN
int loglevel_python_name_to_value(
const char *name, enum lttng_loglevel_python *loglevel);
+LTTNG_HIDDEN
+bool loglevel_python_parse_range_string(const char *str,
+ enum lttng_loglevel_python *min,
+ enum lttng_loglevel_python *max);
+
LTTNG_HIDDEN
const char *loglevel_value_to_name(int loglevel);
# shellcheck source=../../../utils/utils.sh
source "$TESTDIR/utils/utils.sh"
-
-NUM_TESTS=82
+NUM_TESTS=84
FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
lttng_add_trigger_ok "C" --condition event-rule-matches --domain=user --action notify
lttng_add_trigger_ok "A" --condition event-rule-matches --name=aaa --domain=user --filter 'p == 2' --action notify
lttng_add_trigger_ok "D" --condition event-rule-matches --name='hello*' --domain=user -x 'hello2,hello3,hello4' --action notify
- lttng_add_trigger_ok "B" --condition event-rule-matches --domain=user --name=gerboise --loglevel INFO --action notify
- lttng_add_trigger_ok "E" --condition event-rule-matches --domain=user --name=lemming --loglevel-only WARNING --action notify
+ lttng_add_trigger_ok "B" --condition event-rule-matches --domain=user --name=gerboise --log-level INFO.. --action notify
+ lttng_add_trigger_ok "E" --condition event-rule-matches --domain=user --name=lemming --log-level WARNING --action notify
+ lttng_add_trigger_ok "J" --condition event-rule-matches --domain=user --name=lemming --log-level .. --action notify
lttng_add_trigger_ok "F" --condition event-rule-matches --domain=user --name=capture-payload-field --capture a --action notify
lttng_add_trigger_ok "G" --condition event-rule-matches --domain=user --name=capture-array --capture 'a[2]' --capture '$ctx.tourlou[18]' --action notify
lttng_add_trigger_ok "H" --condition event-rule-matches --domain=user --name=capture-chan-ctx --capture '$ctx.vpid' --action notify
notify
errors: none
errors: none
+ - name: J
+ user id: ${uid}
+ condition: event rule hit
+ rule: lemming (type: tracepoint, domain: ust)
+ actions:
+ notify
+ errors: none
+ errors: none
EOF
list_triggers_matches_ok "event-rule-matches, tracepoint event rule" "${tmp_expected_stdout}"
lttng_remove_trigger_ok "G"
lttng_remove_trigger_ok "H"
lttng_remove_trigger_ok "I"
+ lttng_remove_trigger_ok "J"
}
test_on_event_probe ()