lib/cmetrics/docs/label-value-handling.md
Before this fix, CMetrics rejected any string longer than 1024 bytes while decoding its internal MessagePack representation. The validation was performed by the generic string decoder, so it applied not only to label values, but also to metric names, namespaces, subsystems, descriptions, and label names.
This behavior caused
fluent/fluent-bit#9297: a
valid Prometheus scrape containing a process_command_line label longer than
1024 bytes was accepted by the Prometheus parser, but failed during the
subsequent CMetrics MessagePack round trip. The failure discarded all metrics
from the scrape without a useful diagnostic.
PR #224 proposed retaining the
first 1024 bytes and appending ... during MessagePack decoding. The issue is
valid, but that behavior should not be implemented in the generic decoder.
Prometheus identifies a time series using its metric name and complete label set. Consider two label values with the same 1024-byte prefix:
process_command_line="<common prefix>A"
process_command_line="<common prefix>B"
Blindly replacing both suffixes with ... gives both samples the same series
identity. This can merge unrelated series and produce incorrect results.
Truncating at a fixed byte offset can also split a multi-byte UTF-8 character. Because the generic MessagePack helper decodes every CMetrics string, the same policy could silently alter metric names, descriptions, and label names.
Presentation requirements must not be implemented by mutating the internal data model during deserialization. An output encoder may abbreviate a value for display, but the stored value must remain unchanged.
There is no universal 1024-byte limit for Prometheus label values:
label_value_length_limit is configured, one violation fails the scrape
instead of silently rewriting the value.error, drop, and truncate
strategies. Its truncation strategy includes a hash of the original value so
that values with a common prefix remain distinct.References:
The internal MessagePack decoder should:
This fix implements those requirements for data-backed CMetrics MessagePack decoding. It verifies that all declared string bytes are present before making an allocation, then copies the complete value into CMetrics-owned storage. A malicious length field therefore cannot trigger an allocation larger than its available input, while valid long strings round-trip without modification.
A configurable safety ceiling may be appropriate for callers that process untrusted MessagePack. Such a ceiling should apply to decoder resources, be documented in bytes, and reject input explicitly. It must not reinterpret an oversized string as valid data with different contents.
If Fluent Bit or another caller needs an ingestion policy, it should be implemented above the MessagePack decoder. Useful policies are:
preserve: retain the complete value; this matches Prometheus defaults.reject: reject the scrape or batch with a diagnostic.drop: discard only the offending series and increment an error counter.truncate_hash: truncate on a valid UTF-8 boundary and append a hash derived
from the complete value to preserve series identity as far as practical.The selected policy and limit should be configurable by the component that owns ingestion, because CMetrics is also used with OTLP and other formats whose requirements differ.
An implementation should include tests for:
Memory-safety validation should include AddressSanitizer, UndefinedBehaviorSanitizer, and Valgrind in addition to the focused unit tests.