Group Sequencer
Groups TenXObjects for filtering, aggregation, and output as single units.
Log events read from an input stream can serve as a part of a larger logical group. A typical example of events spanning multiple sub-events are stack traces where each line within the stack trace may be logged as a separate line.
Grouping enables:
- Identify groups consuming the most storage and analytics resources using aggregators. This is especially valuable when storing stack traces than span 100s of lines and consume a significant amount of resources.
- Filter unnecessary groups such as 'noisy' stack traces via group filters and output regulators.
- Optimize storage of multi-line events by losslessly compacting them as a composite instances to reduce storage footprint by > 75% when compared to storing individual events.
Group Heads
tenXObjects which evaluate as truthy against groupExpressions are marked as starting of a new group (i.e. a group head).
All subsequent TenXObjects read from the same input will join the current group until either:
- Another group is started marked by a subsequent instance which evaluates as truthy against
groupExpressions. - The number of TenXObjects in the current group exceeds groupMaxSize.
- The groupFlushTimeout elapses.
At that point the group is sealed as new composite TenXObject and flushed forward for aggregation and output. Each composite TenXObject returns the number of instances grouped within it via the groupSize member.
Example #1 - timestamps + negators (default)
The TenXObject constructor below marks an instance as the head of a group if:
- its text field starts with an indicator value.
- its timestamped field is true.
export class GroupTemplate extends TenXTemplate {
static get isGroup() {
// https://doc.log10x.com/run/initialize/group/#groupindicators
if (this.startsWith(TenXEnv.get("groupIndicators"))) {
return true;
}
return this.timestamped;
}
// This constructor is invoked by the engine once for each unique TenXTemplate discovered
// at runtime based on log event structures
constructor() {
GroupTemplate.isGroup = this.isGroup();
}
}
Example #2 - Group ISO_8601 events
The TenXObject below marks an instance as the head of a group if it has an ISO_8601 timestamp:
export class IsoTemplate extends TenXTemplate {
constructor() {
IsoTemplate.isGroup = this.timestampFormat() == "yyyy-MM-dd'T'HH:mm'Z'";
}
}
Example #3 - Group Linux Call Traces
The constructor below groups Linux Call Traces (see example)
by folding lines that are part of a trace (e.g., an
class NixTemplate extends TenXTemplate {
constructor() {
// is event is call trace interrupt marker
if (this.contains("<IRQ>")) {
NixTemplate.isGroup = false;
} else
// does event end in a '/'' + hex memory address (e.g., 0x16d0) ?
// use the token() function to access the last + penultimate instance values
if (this.token(-2) == "/") && (startsWith(this.token(-1), "0x")) {
NixTemplate.isGroup = false;
}
}
}
Group Filters
The groupFilters option provides a mechanism for filtering TenXObject groups based on conditions that relate to the entire group (e.g., filter entire stack traces vs. individual lines).
The YAML config below places a limit of a maximum of 'SocketException' 1000 groups per minute using a cyclical counter:
group:
filters: 'this.includes("SocketException") && (this.groupSize > 1) ? (TenXCounter.incAndGet("socketException", 1, "1m") > 1000) : true'
A filter may also be set to a function loaded from a JavaScript config file. For example:
Where the JavaScript file would contain:
// @loader: tenx
public class MyFilter extends TenXObject {
function socketExceptionFilter() {
return this.includes("SocketException") && (this.groupSize > 1) ?
(TenXCounter.incAndGet("socketException", 1, "1m") > 1000) :
true
}
}
Event Source
Input streams that read data from multiple locations (e.g., log files, pods, hosts) can utilize source patterns and fields to assign each event a logical origin (e.g., log file, host address).
This value ensure each TenXObject is grouped alongside instances from the same source and is accessible via the source member.
Configuration
To configure the Group sequencer unit, Edit these settings.
Below is the default configuration from: group/config.yaml.
ewogICJ0eXBlIiA6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIiA6IHsKICAgICJ0ZW54IiA6IHsKICAgICAgInR5cGUiIDogInN0cmluZyIKICAgIH0sCiAgICAiZ3JvdXAiIDogewogICAgICAidHlwZSIgOiAib2JqZWN0IiwKICAgICAgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIiA6IGZhbHNlLAogICAgICAicHJvcGVydGllcyIgOiB7CiAgICAgICAgIm1heFNpemUiIDogewogICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAibnVtYmVyIiwKICAgICAgICAgICAgInN0cmluZyIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTWF4IG51bWJlciBvZiBvYmplY3RzIHRvIHBsYWNlIGluIGEgZ3JvdXBcblxuU2V0cyB0aGUgbWF4aW11bSBudW1iZXIgb2Ygb2JqZWN0cyB0byBwbGFjZSB1bmRlciBvbmUgZ3JvdXAgYmVmb3JlIHN0YXJ0aW5nIGEgbmV3IGdyb3VwLiBTZXQgMCB0byB1bmxpbWl0ZWQuIChBY2NlcHRzIG51bWJlciBvciBzdHJpbmcgd2l0aCAkPSBwcmVmaXggZm9yIHJ1bnRpbWUgZXZhbHVhdGlvbikgKERlZmF1bHQ6IDIwMDAwKSIsCiAgICAgICAgICAiZGVmYXVsdCIgOiAyMDAwMAogICAgICAgIH0sCiAgICAgICAgImZsdXNoVGltZW91dCIgOiB7CiAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAibnVsbCIKICAgICAgICAgIF0sCiAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiSW50ZXJ2YWwgdG8gZmx1c2ggYSBwZW5kaW5nIFRlblhPYmplY3RzIGdyb3VwXG5cblNldHMgdGhlIG1heCBpbnRlcnZhbCBhZnRlciB3aGljaCB0byBmbHVzaCBwZW5kaW5nIFRlblhPYmplY3RzIGludG8gdGhlIHBpcGVsaW5lLiBUaGlzIG9wdGlvbiBwcm92aWRlcyBhIHRpbWVvdXQgcGVyaW9kIHRvIGZsdXNoIHRoZSBjdXJyZW50IGdyb3VwIGhlYWQgYW5kIGNvbXBvc2VkICBUZW5YT2JqZWN0cyBpbnRvIHRoZSBwaXBlbGluZSBmb3IgYWdncmVnYXRpb24sIGZpbHRlcmluZywgYW5kIGVuY29kaW5nIHRvIG91dHB1dC4gKERlZmF1bHQ6IDVzZWMpIiwKICAgICAgICAgICJkZWZhdWx0IiA6ICI1c2VjIgogICAgICAgIH0sCiAgICAgICAgImV4cHJlc3Npb25zIiA6IHsKICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICJudWxsIgogICAgICAgICAgXSwKICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJKYXZhU2NyaXB0IGV4cHJlc3Npb25zIFRlblhPYmplY3QgaW5zdGFuY2UvZ3JvdXAgbXVzdCBldmFsdWF0ZSBhcyB0cnV0aHkgYWdhaW5zdCB0byBiZSBzZXQgYXMgZ3JvdXAgaGVhZFxuXG5TcGVjaWZpZXMgYSBsaXN0IG9mIEphdmFTY3JpcHQgZXhwcmVzc2lvbnMgdGhhdCBtdXN0IGFsbCBldmFsdWF0ZSBhcyB0cnV0aHkgZm9yIHRoZSB0YXJnZXQgVGVuWE9iamVjdCB0byBiZSBjbGFzc2lmaWVkIGFzIFtncm91cCBoZWFkXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi90cmFuc2Zvcm0vZ3JvdXAvI2dyb3VwLWhlYWRzKS4gIEZvciBleGFtcGxlLCB0aGUgW2dyb3VwIGluaXRpYWxpemVyXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbml0aWFsaXplL2dyb3VwLykgbW9kdWxlIGNhbGN1bGF0ZXMgYSBbVGVueFRlbXBsYXRlIHZhcmlhYmxlXShodHRwczovL2RvYy5sb2cxMHguY29tL2FwaS9qcy8jVGVuWFRlbXBsYXRlLnNldCkgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgaW5zdGFuY2VzIG9mIGEgdGFyZ2V0IGBUZW5YVGVtcGxhdGVgIHJlcHJlc2VudCBncm91cCBoZWFkcyBiYXNlZCBvbiBhIG51bWJlciBvZiBoZXVyaXN0aWMgaW5kaWNhdG9ycyBhbmQgc2V0cyB0aGUgY2FsY3VsYXRlZCBmaWVsZCBuYW1lIChlLmcuLCBgR3JvdXBUZW1wbGF0ZS5pc0dyb3VwYCkgaG9sZGluZyB0aGUgcmVzdWx0aW5nIHZhbHVlIGludG8gdGhpcyBhcnJheS4gICBVc2luZyBUZW5YVGVtcGxhdGUgdmFyaWFibGVzIGFsbG93cyBmb3IgY29tcHV0aW5nIHRoaXMgc3RhdGUgb25jZSBmb3IgYWxsIGluc3RhbmNlcyBvZiBhIHRhcmdldCBldmVudC4iCiAgICAgICAgfSwKICAgICAgICAiZmlsdGVycyIgOiB7CiAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICJhcnJheSIsCiAgICAgICAgICAgICJudWxsIgogICAgICAgICAgXSwKICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJKYXZhU2NyaXB0IGV4cHJlc3Npb25zIFRlblhPYmplY3QgaW5zdGFuY2UvZ3JvdXAgbXVzdCBldmFsdWF0ZSBhcyB0cnV0aHkgYWdhaW5zdFxuXG5TcGVjaWZpZXMgYSBsaXN0IG9mIEphdmFTY3JpcHQgZXhwcmVzc2lvbnMgdGhhdCBtdXN0IGFsbCBldmFsdWF0ZSBhcyB0cnV0aHkgZm9yIHRoZSB0YXJnZXQgb2JqZWN0L2dyb3VwIHRvIGJlIHBhcnQgb2YgYSBzZXF1ZW5jZSBhZ2dyZWdhdGVkL3dyaXR0ZW4gdG8gb3V0cHV0LiAgVG8gbGVhcm4gbW9yZSBzZWUgW2dyb3VwIGZpbHRlcnNdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL3RyYW5zZm9ybS9ncm91cC8jZ3JvdXAtZmlsdGVycykuIiwKICAgICAgICAgICJpdGVtcyIgOiB7CiAgICAgICAgICAgICJ0eXBlIiA6ICJzdHJpbmciCiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAiYXN5bmMiIDogewogICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAiYm9vbGVhbiIsCiAgICAgICAgICAgICJzdHJpbmciCiAgICAgICAgICBdLAogICAgICAgICAgIm1hcmtkb3duRGVzY3JpcHRpb24iIDogIkdyb3VwIFRlblhPYmplY3RzIGluIGEgZGVkaWNhdGVkIHRocmVhZFxuXG5TcGVjaWZpZXMgd2hldGhlciB0byBwZXJmb3JtIFRlblhPYmplY3QgZ3JvdXBpbmcgbG9naWMgaW4gYSBkZWRpY2F0ZWQgdGhyZWFkIChBY2NlcHRzIGJvb2xlYW4gb3Igc3RyaW5nIHdpdGggJD0gcHJlZml4IGZvciBydW50aW1lIGV2YWx1YXRpb24pIChEZWZhdWx0OiB0cnVlKSIsCiAgICAgICAgICAiZGVmYXVsdCIgOiB0cnVlCiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfSwKICAiYWRkaXRpb25hbFByb3BlcnRpZXMiIDogZmFsc2UKfQ==
# 🔟❎ 'run' event grouping configuration
# Group sequences of TenXObjects to filter, aggregate and output as a single logical unit.
# To learn more see https://doc.log10x.com/run/transform/group/
# Set the 10x pipeline to 'run'
tenx: run
# =============================== Group Options ===============================
group:
# 'filters' specify JavaScript expressions an TenXObject instance/group must
# evaluate as truthy against to be written to output
filters: []
# 'maxSize' defines the maximum number of TenXObjects to group
# before the group is sealed and forwarded into the pipeline.
# Subsequent TenXObjects can form a new group.
maxSize: 20000
# 'flushTimeout' defines the max interval (e.g., 10s) to wait for
# new events to be read from an input stream before it flushes any
# pending TenXObjects group into the pipeline.
# This mechanism is designed to avoid latencies in dispatching pending event
# groups to output destinations.
flushTimeout: $=parseDuration("5s")
# 'async' specifies whether to sequence and group TenXObjects in a dedicated thread
async: true
Options
Specify the options below to configure the Group sequencer:
| Name | Description |
|---|---|
| groupMaxSize | Max number of objects to place in a group |
| groupMaxSize | Max number of objects to place in a group |
| groupFlushTimeout | Interval to flush a pending TenXObjects group |
| groupExpressions | JavaScript expressions TenXObject instance/group must evaluate as truthy against to be set as group head |
| groupFilters | JavaScript expressions TenXObject instance/group must evaluate as truthy against |
| groupAsync | Group TenXObjects in a dedicated thread |
groupMaxSize
Max number of objects to place in a group.
| Type | Default |
|---|---|
| Number | 20000 |
Sets the maximum number of objects to place under one group before starting a new group. Set 0 to unlimited.
groupMaxSize
Max number of objects to place in a group.
| Type | Default |
|---|---|
| Number | 20000 |
Sets the maximum number of objects to place under one group before starting a new group. Set 0 to unlimited.
groupFlushTimeout
Interval to flush a pending TenXObjects group.
| Type | Default |
|---|---|
| String | 5sec |
Sets the max interval after which to flush pending TenXObjects into the pipeline. This option provides a timeout period to flush the current group head and composed TenXObjects into the pipeline for aggregation, filtering, and encoding to output.
groupExpressions
JavaScript expressions TenXObject instance/group must evaluate as truthy against to be set as group head.
| Type | Default |
|---|---|
| String | "" |
Specifies a list of JavaScript expressions that must all evaluate as truthy for the target TenXObject to be classified as group head.
For example, the group initializer module calculates a TenxTemplate variable to determine whether instances of a target TenXTemplate represent group heads based on a number of heuristic indicators and sets the calculated field name (e.g., GroupTemplate.isGroup) holding the resulting value into this array.
Using TenXTemplate variables allows for computing this state once for all instances of a target event.
groupFilters
JavaScript expressions TenXObject instance/group must evaluate as truthy against.
| Type | Default |
|---|---|
| List | [] |
Specifies a list of JavaScript expressions that must all evaluate as truthy for the target object/group to be part of a sequence aggregated/written to output.
To learn more see group filters.
groupAsync
Group TenXObjects in a dedicated thread.
| Type | Default |
|---|---|
| Boolean | true |
Specifies whether to perform TenXObject grouping logic in a dedicated thread.
This unit is defined in group/unit.yaml.