mirror of
https://github.com/haproxy/haproxy.git
synced 2026-04-13 12:56:20 -04:00
MINOR: otel: changed log-record attr to use sample expressions
Replaced the static key-value attribute storage in log-record with sample-evaluated attributes. The 'attr' keyword now accepts a key and a HAProxy sample expression evaluated at runtime, instead of a static string value. The struct (conf.h) changed from otelc_kv/attr_len to a list of flt_otel_conf_sample entries. The parser (parser.c) calls flt_otel_parse_cfg_sample() with n=1 per attr keyword. At runtime (event.c) each attribute is evaluated via flt_otel_sample_eval() and added via flt_otel_sample_add_kv() to a bare flt_otel_scope_data_kv, which is passed to logger->log_span(). Updated documentation, debug macro and test configurations.
This commit is contained in:
parent
d96ce16cef
commit
651e9fd8a7
11 changed files with 86 additions and 43 deletions
|
|
@ -669,15 +669,15 @@ instrument { update <name> [<attr>] | <type> <name> [<aggr>] [<desc>] [<unit>] <
|
|||
attr - attribute key-value pairs (update form only)
|
||||
|
||||
|
||||
log-record <severity> [id <integer>] [event <name>] [span <span-name>] [attr <key> <value>] ... <sample> ...
|
||||
log-record <severity> [id <integer>] [event <name>] [span <span-name>] [attr <key> <sample>] ... <sample> ...
|
||||
This keyword emits an OpenTelemetry log record within the scope. The first
|
||||
argument is a required severity level. Optional keywords follow in any order
|
||||
before the trailing sample expressions that form the log record body:
|
||||
|
||||
id <integer> - numeric event identifier
|
||||
event <name> - event name string
|
||||
span <span-name> - associate the log record with an open span
|
||||
attr <key> <value> - add a key-value attribute (repeatable)
|
||||
id <integer> - numeric event identifier
|
||||
event <name> - event name string
|
||||
span <span-name> - associate the log record with an open span
|
||||
attr <key> <sample> - add an attribute evaluated at runtime (repeatable)
|
||||
|
||||
The remaining arguments at the end are sample fetch expressions. A single
|
||||
sample preserves its native type; multiple samples are concatenated as a
|
||||
|
|
@ -694,8 +694,8 @@ log-record <severity> [id <integer>] [event <name>] [span <span-name>] [attr <ke
|
|||
|
||||
For example:
|
||||
log-record info str("heartbeat")
|
||||
log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" "GET" method url
|
||||
log-record trace id 1000 event "session-start" span "Client session" attr "attr_1_key" "attr_1_value" src str(":") src_port
|
||||
log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
|
||||
log-record trace id 1000 event "session-start" span "Client session" attr "src_ip" src src str(":") src_port
|
||||
log-record warn event "server-unavailable" str("503 Service Unavailable")
|
||||
|
||||
Arguments :
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ The complete ownership tree, from root to leaves:
|
|||
| +-- flt_otel_conf_sample (samples list)
|
||||
| +-- flt_otel_conf_sample_expr (exprs list)
|
||||
+-- flt_otel_conf_log_record (log_records list)
|
||||
+-- flt_otel_conf_sample (attributes list)
|
||||
| +-- flt_otel_conf_sample_expr (exprs list)
|
||||
+-- flt_otel_conf_sample (samples list)
|
||||
+-- flt_otel_conf_sample_expr (exprs list)
|
||||
|
||||
|
|
@ -217,14 +219,14 @@ an existing instrument via the ref pointer).
|
|||
event_id Optional event identifier.
|
||||
event_name Optional event name.
|
||||
span Optional span reference.
|
||||
attr Log record attributes.
|
||||
attr_len Number of log record attributes.
|
||||
attributes Log record attributes (flt_otel_conf_sample list).
|
||||
samples Sample expressions for the body.
|
||||
|
||||
Log records are emitted via the OTel logger at the configured severity. The
|
||||
optional span reference associates the log record with an open span at runtime.
|
||||
Attributes are stored as key-value pairs added via the 'attr' keyword, which
|
||||
can be repeated.
|
||||
Attributes are stored as flt_otel_conf_sample entries added via the 'attr'
|
||||
keyword, which can be repeated. Attribute values are HAProxy sample expressions
|
||||
evaluated at runtime.
|
||||
|
||||
4.8 flt_otel_conf_context
|
||||
|
||||
|
|
|
|||
|
|
@ -361,14 +361,19 @@ Supported keywords:
|
|||
instrument update "name_cnt_int" attr "attr_1_key" "attr_1_value"
|
||||
|
||||
|
||||
log-record <severity> [id <integer>] [event <name>] [span <span-name>] [attr <key> <value>] ... <sample> ...
|
||||
log-record <severity> [id <integer>] [event <name>] [span <span-name>] [attr <key> <sample>] ... <sample> ...
|
||||
Emit an OpenTelemetry log record. The first argument is a required
|
||||
severity level. Optional keywords follow in any order:
|
||||
|
||||
id <integer> - numeric event identifier
|
||||
event <name> - event name string
|
||||
span <span-name> - associate the log record with an open span
|
||||
attr <key> <value> - add a key-value attribute (repeatable)
|
||||
id <integer> - numeric event identifier
|
||||
event <name> - event name string
|
||||
span <span-name> - associate the log record with an open span
|
||||
attr <key> <sample> - add an attribute evaluated at runtime (repeatable)
|
||||
|
||||
The 'attr' keyword takes an attribute name and a single HAProxy sample
|
||||
expression. The expression is evaluated at runtime, following the same
|
||||
rules as span attributes: a bare sample fetch (e.g. src) or a log-format
|
||||
string (e.g. "%[src]:%[src_port]").
|
||||
|
||||
The remaining arguments at the end are sample fetch expressions that form
|
||||
the log record body. A single sample preserves its native type; multiple
|
||||
|
|
@ -389,8 +394,8 @@ Supported keywords:
|
|||
|
||||
Examples:
|
||||
log-record info str("heartbeat")
|
||||
log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" "GET" method url
|
||||
log-record trace id 1000 event "session-start" span "Client session" attr "attr_1_key" "attr_1_value" attr "attr_2_key" "attr_2_value" src str(":") src_port
|
||||
log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
|
||||
log-record trace id 1000 event "session-start" span "Client session" attr "src_ip" src attr "src_port" src_port src str(":") src_port
|
||||
log-record warn event "server-unavailable" str("503 Service Unavailable")
|
||||
log-record info event "session-stop" str("stream stopped")
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ executes all referenced scopes when the rule fires.
|
|||
inject <name-prefix> [use-headers] [use-vars]
|
||||
finish <name> ...
|
||||
instrument <type> <name> ... / instrument update <name> ...
|
||||
log-record <severity> [id <int>] [event <name>] [span <ref>] [attr <k> <v>] ... <sample> ...
|
||||
log-record <severity> [id <int>] [event <name>] [span <ref>] [attr <key> <sample>] ... <sample> ...
|
||||
acl <name> <criterion> ...
|
||||
|
||||
Each scope ties to a single HAProxy analyzer event (or none, if used only
|
||||
|
|
@ -1157,10 +1157,14 @@ The flt_otel_conf_log_record structure (conf.h) holds:
|
|||
event_id Optional numeric event identifier (int64).
|
||||
event_name Optional event name string.
|
||||
span Optional span reference name (resolved at runtime).
|
||||
attr Key-value attribute array (from "attr" keywords).
|
||||
attr_len Number of attributes.
|
||||
attributes List of flt_otel_conf_sample entries for attributes.
|
||||
samples List of sample expressions for the body.
|
||||
|
||||
The attributes list contains flt_otel_conf_sample entries, one per "attr"
|
||||
keyword. Each entry's key field holds the attribute name and its sample
|
||||
expressions are evaluated at runtime, following the same two-path model
|
||||
(bare sample or log-format) as span attributes.
|
||||
|
||||
The samples list contains exactly one flt_otel_conf_sample entry, which
|
||||
in turn holds either a list of bare sample expressions or a single
|
||||
log-format expression (when the value contains "%[").
|
||||
|
|
@ -1178,7 +1182,12 @@ For each configured log record the function performs:
|
|||
skipped. The threshold is controlled by the "min_severity" option
|
||||
in the YAML logs signal configuration.
|
||||
|
||||
2. Body evaluation: the single sample entry is evaluated using one of
|
||||
2. Attribute evaluation: each entry in the attributes list is evaluated via
|
||||
flt_otel_sample_add() into a temporary flt_otel_scope_data structure.
|
||||
The evaluated key-value array is passed to logger->log_span() and freed
|
||||
after emission.
|
||||
|
||||
3. Body evaluation: the single sample entry is evaluated using one of
|
||||
two paths:
|
||||
|
||||
Log-format path (sample->lf_used is true):
|
||||
|
|
@ -1191,14 +1200,14 @@ For each configured log record the function performs:
|
|||
flt_otel_sample_to_str(). Results are concatenated into a
|
||||
single buffer.
|
||||
|
||||
3. Span resolution: if conf_log->span is non-NULL, the runtime
|
||||
4. Span resolution: if conf_log->span is non-NULL, the runtime
|
||||
context's spans list is searched for a scope_span with a matching
|
||||
name. If found, the OTel span pointer is captured for correlation.
|
||||
A missing span is non-fatal -- a NOTICE warning is logged and the
|
||||
record is emitted without span correlation.
|
||||
|
||||
4. Emission: logger->log_span() is called with the severity, event_id,
|
||||
event_name, resolved span (or NULL), wall-clock timestamp,
|
||||
5. Emission: logger->log_span() is called with the severity, event_id,
|
||||
event_name, resolved span (or NULL), wall-clock timestamp, the evaluated
|
||||
attributes and the evaluated body string.
|
||||
|
||||
18.6.3 Logger Lifecycle Summary
|
||||
|
|
|
|||
|
|
@ -91,9 +91,9 @@
|
|||
(p)->bounds_num, (p)->bounds)
|
||||
|
||||
#define FLT_OTEL_DBG_CONF_LOG_RECORD(h,p) \
|
||||
OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%d %" PRId64 " '%s' '%s' %p %zu %p }", (p), \
|
||||
OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%d %" PRId64 " '%s' '%s' %s %s }", (p), \
|
||||
FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->severity, (p)->event_id, OTELC_STR_ARG((p)->event_name), \
|
||||
OTELC_STR_ARG((p)->span), (p)->attr, (p)->attr_len, flt_otel_list_dump(&((p)->samples)))
|
||||
OTELC_STR_ARG((p)->span), flt_otel_list_dump(&((p)->attributes)), flt_otel_list_dump(&((p)->samples)))
|
||||
|
||||
#define FLT_OTEL_DBG_CONF(h,p) \
|
||||
OTELC_DBG(DEBUG, h "%p:{ %p '%s' '%s' %p %s %s }", (p), \
|
||||
|
|
@ -212,8 +212,7 @@ struct flt_otel_conf_log_record {
|
|||
int64_t event_id; /* Optional event identifier. */
|
||||
char *event_name; /* Optional event name. */
|
||||
char *span; /* Optional span reference. */
|
||||
struct otelc_kv *attr; /* Log record attributes. */
|
||||
size_t attr_len; /* Number of log record attributes. */
|
||||
struct list attributes; /* Log record attributes (flt_otel_conf_sample). */
|
||||
struct list samples; /* Sample expressions for the body. */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@
|
|||
FLT_OTEL_PARSE_SCOPE_DEF( STATUS, 1, NONE, 2, 0, "status", " <code> [<sample> ...]") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( FINISH, 0, NONE, 2, 0, "finish", " <name> ...") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( INSTRUMENT, 0, NONE, 3, 0, "instrument", " { update <name> [<attr> ...] | <type> <name> [<aggr>] [<desc>] [<unit>] <value> [<bounds>] }") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( LOG_RECORD, 0, NONE, 3, 0, "log-record", " <severity> [<id>] [<event>] [<span>] [<attr>] <sample>") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( LOG_RECORD, 0, NONE, 3, 0, "log-record", " <severity> [<id>] [<event>] [<span>] [<attr>] <sample> ...") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF(IDLE_TIMEOUT, 0, NONE, 2, 2, "idle-timeout", " <time>") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( ACL, 0, CHAR, 3, 0, "acl", " <name> <criterion> [flags] [operator] <value> ...") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( ON_EVENT, 0, NONE, 2, 0, "otel-event", " <name> [{ if | unless } <condition>]")
|
||||
|
|
|
|||
|
|
@ -559,14 +559,15 @@ FLT_OTEL_CONF_FUNC_FREE(instrument, id,
|
|||
*
|
||||
* DESCRIPTION
|
||||
* Allocates and initializes a conf_log_record structure. Initializes the
|
||||
* sample expressions list. The <id> string is required by the macro but is
|
||||
* not used directly; the severity level is stored separately. If <head> is
|
||||
* non-NULL, the structure is appended to the list.
|
||||
* attributes and sample expressions lists. The <id> string is required by
|
||||
* the macro but is not used directly; the severity level is stored
|
||||
* separately. If <head> is non-NULL, the structure is appended to the list.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns a pointer to the initialized structure, or NULL on failure.
|
||||
*/
|
||||
FLT_OTEL_CONF_FUNC_INIT(log_record, id,
|
||||
LIST_INIT(&(retptr->attributes));
|
||||
LIST_INIT(&(retptr->samples));
|
||||
)
|
||||
|
||||
|
|
@ -593,7 +594,7 @@ FLT_OTEL_CONF_FUNC_FREE(log_record, id,
|
|||
|
||||
OTELC_SFREE((*ptr)->event_name);
|
||||
OTELC_SFREE((*ptr)->span);
|
||||
otelc_kv_destroy(&((*ptr)->attr), (*ptr)->attr_len);
|
||||
FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->attributes));
|
||||
FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->samples));
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ static int flt_otel_scope_run_log_record(struct stream *s, struct filter *f, uin
|
|||
struct flt_otel_conf_sample_expr *expr;
|
||||
struct sample smp;
|
||||
struct otelc_span *otel_span = NULL;
|
||||
struct flt_otel_scope_data_kv log_attr;
|
||||
struct buffer buffer;
|
||||
int rc;
|
||||
|
||||
|
|
@ -267,6 +268,28 @@ static int flt_otel_scope_run_log_record(struct stream *s, struct filter *f, uin
|
|||
if (OTELC_OPS(logger, enabled, conf_log->severity) == 0)
|
||||
continue;
|
||||
|
||||
/* Evaluate log record attributes from sample expressions. */
|
||||
(void)memset(&log_attr, 0, sizeof(log_attr));
|
||||
|
||||
list_for_each_entry(sample, &(conf_log->attributes), list) {
|
||||
struct otelc_value attr_value;
|
||||
|
||||
OTELC_DBG(DEBUG, "adding log-record attribute '%s' -> '%s'", sample->key, sample->fmt_string);
|
||||
|
||||
if (flt_otel_sample_eval(s, dir, sample, true, &attr_value, err) == FLT_OTEL_RET_ERROR) {
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flt_otel_sample_add_kv(&log_attr, sample->key, &attr_value) == FLT_OTEL_RET_ERROR) {
|
||||
if (attr_value.u_type == OTELC_VALUE_DATA)
|
||||
OTELC_SFREE(attr_value.u.value_data);
|
||||
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* The samples list has exactly one entry. */
|
||||
sample = LIST_NEXT(&(conf_log->samples), typeof(sample), list);
|
||||
|
||||
|
|
@ -318,6 +341,8 @@ static int flt_otel_scope_run_log_record(struct stream *s, struct filter *f, uin
|
|||
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
otelc_kv_destroy(&(log_attr.attr), log_attr.cnt);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -341,9 +366,10 @@ static int flt_otel_scope_run_log_record(struct stream *s, struct filter *f, uin
|
|||
OTELC_DBG(NOTICE, "WARNING: cannot find span '%s' for log-record", conf_log->span);
|
||||
}
|
||||
|
||||
if (OTELC_OPS(logger, log_span, conf_log->severity, conf_log->event_id, conf_log->event_name, otel_span, ts, conf_log->attr, conf_log->attr_len, "%s", buffer.area) == OTELC_RET_ERROR)
|
||||
if (OTELC_OPS(logger, log_span, conf_log->severity, conf_log->event_id, conf_log->event_name, otel_span, ts, log_attr.attr, log_attr.cnt, "%s", buffer.area) == OTELC_RET_ERROR)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
otelc_kv_destroy(&(log_attr.attr), log_attr.cnt);
|
||||
OTELC_SFREE(buffer.area);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1224,10 +1224,11 @@ static int flt_otel_parse_cfg_log_record(const char *file, int line, char **args
|
|||
else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_LOG_RECORD_ATTR)) {
|
||||
if (!FLT_OTEL_ARG_ISVALID(i + 1) || !FLT_OTEL_ARG_ISVALID(i + 2))
|
||||
FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
|
||||
else if (otelc_kv_add(&(log->attr), &(log->attr_len), args[i + 1], args[i + 2], strlen(args[i + 2])) == OTELC_RET_ERROR)
|
||||
FLT_OTEL_PARSE_ERR(err, "'%s' : out of memory", args[0]);
|
||||
else
|
||||
i += 2;
|
||||
else {
|
||||
retval = flt_otel_parse_cfg_sample(file, line, args, i + 2, 1, NULL, &(log->attributes), err);
|
||||
if (!(retval & ERR_CODE))
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
event "event_be" "be" be_id str(" ") be_name
|
||||
event "event_ip" "dst" dst str(":") dst_port
|
||||
event "event_fe" "fe" fe_id str(" ") fe_name
|
||||
log-record trace id 1000 event "session-start" span "HAProxy session" attr "attr_1_key" "attr_1_value" attr "attr_2_key" "attr_2_value" src str(":") src_port
|
||||
log-record trace id 1000 event "session-start" span "HAProxy session" attr "attr_1_key" src attr "attr_2_key" src_port src str(":") src_port
|
||||
acl acl-test-src-ip src 127.0.0.1
|
||||
otel-event on-stream-start if acl-test-src-ip
|
||||
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
attribute "http.url" url
|
||||
attribute "http.version" str("HTTP/") req.ver
|
||||
finish "HTTP body request"
|
||||
log-record info id 1002 event "http-request" span "Frontend HTTP request" attr "http.method" "GET" method url
|
||||
log-record info id 1002 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
|
||||
otel-event on-frontend-http-request
|
||||
|
||||
otel-scope switching_rules_request
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
event "event_be" "be" be_id str(" ") be_name
|
||||
event "event_ip" "dst" dst str(":") dst_port
|
||||
event "event_fe" "fe" fe_id str(" ") fe_name
|
||||
log-record trace id 1000 event "session-start" span "Client session" attr "attr_1_key" "attr_1_value" attr "attr_2_key" "attr_2_value" src str(":") src_port
|
||||
log-record trace id 1000 event "session-start" span "Client session" attr "attr_1_key" src attr "attr_2_key" src_port src str(":") src_port
|
||||
acl acl-test-src-ip src 127.0.0.1
|
||||
otel-event on-stream-start if acl-test-src-ip
|
||||
|
||||
|
|
@ -109,7 +109,7 @@
|
|||
attribute "http.url" url
|
||||
attribute "http.version" str("HTTP/") req.ver
|
||||
finish "HTTP body request"
|
||||
log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" "GET" method url
|
||||
log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
|
||||
otel-event on-frontend-http-request
|
||||
|
||||
otel-scope switching_rules_request
|
||||
|
|
|
|||
Loading…
Reference in a new issue