Query
Defines a search query against an object storage container (e.g., AWS S3 bucket) index.
Queries can execute periodically (e.g., k8s CronJob) or ad-demand via the REST API to populate log analytics dashboards, alerts, and ad-hoc queries.
Each query specifies criteria and actions.
Criteria select events to fetch and transform into TenXObjects:
- Target: target app/service whose events to query (e.g., 'myApp').
- Time range: of log/trace events to fetch.
- Terms: query to execute against the underling storage
- Filters: list of JavaScript expressions which allows for more complex filtering of which TenXObjects matching the search terms to select.
Actions specify how to further filter, enrich, aggregate, and stream TenXObjects to log analyzers and metric outputs (e.g., AWS CloudWatch, Prometheus).
Architecture
A distributed Stream Processing Architecture executes queries via parallel scan and stream workers to select, transform and stream TenXObjects to target output(s).
Scan
Scan workers process TenXTemplate Filters to identify blobs matching a target prefix (i.e., app/service name), time frame (e.g., last 10min) and search terms (e.g., ERROR).
Multiple scan workers perform this workload in parallel, submitting matching byte ranges to stream workers via SQS.
Stream
Stream workers read object storage blob byte ranges identified by the scan workers and transform them into TenXObjects on which they perform the actions specified by the query.
Architecture Flow
The following diagram illustrates the complete distributed, parallel architecture for query execution:
graph TD
Client["🔍 Query Request<br/>API /search"] --> S3["☁️ S3 Object Storage<br/>Log Files + Bloom Filters"]
S3 --> ScanLayer
subgraph ScanLayer["⚡ Parallel Scan Functions<br/> "]
Scan1["Scan #1<br/>Time: 00:00-05:00<br/>• Filter prefix<br/>• Test Bloom filters<br/>• Find byte ranges"]
Scan2["Scan #2<br/>Time: 05:00-10:00<br/>• Filter prefix<br/>• Test Bloom filters<br/>• Find byte ranges"]
Scan3["Scan #3<br/>Time: 10:00-15:00<br/>• Filter prefix<br/>• Test Bloom filters<br/>• Find byte ranges"]
ScanN["Scan #N<br/>Time: N+5:00<br/>• Filter prefix<br/>• Test Bloom filters<br/>• Find byte ranges"]
end
ScanLayer --> StreamLayer
subgraph StreamLayer["🌊 Parallel Stream Functions<br/> "]
Stream1["Stream #1<br/>• Fetch ranges<br/>• Parse logs<br/>• Create TenXObjects<br/>• Filter & enrich"]
Stream2["Stream #2<br/>• Fetch ranges<br/>• Parse logs<br/>• Create TenXObjects<br/>• Filter & enrich"]
Stream3["Stream #3<br/>• Fetch ranges<br/>• Parse logs<br/>• Create TenXObjects<br/>• Filter & enrich"]
StreamM["Stream #M<br/>• Fetch ranges<br/>• Parse logs<br/>• Create TenXObjects<br/>• Filter & enrich"]
end
StreamLayer --> OutputLayer
subgraph OutputLayer["📊 Output Targets<br/> "]
Elastic["Elasticsearch<br/>Events & Logs"]
Prometheus["Prometheus<br/>Metrics & Gauges"]
Datadog["Datadog<br/>Custom Metrics"]
Splunk["Splunk<br/>Search Indexes"]
end
%% Elegant dark theme styling
classDef default fill:#2d3748,stroke:#4a5568,stroke-width:2px,color:#e2e8f0
classDef client fill:#2b6cb0,stroke:#3182ce,stroke-width:2px,color:#ffffff
classDef storage fill:#d69e2e,stroke:#ed8936,stroke-width:2px,color:#ffffff
classDef scan fill:#38a169,stroke:#48bb78,stroke-width:2px,color:#ffffff
classDef stream fill:#d53f8c,stroke:#ed64a6,stroke-width:2px,color:#ffffff
classDef output fill:#805ad5,stroke:#9f7aea,stroke-width:2px,color:#ffffff
class Client client
class S3 storage
class Scan1,Scan2,Scan3,ScanN scan
class Stream1,Stream2,Stream3,StreamM stream
class Elastic,Prometheus,Datadog,Splunk output
Benefits
- Scalability: Functions auto-scale based on query complexity and data volume
- Parallelism: Time-based partitioning enables concurrent processing across multiple workers
- Efficiency: Bloom filters minimize unnecessary data reads from object storage
- Flexibility: Multiple output targets support different analytics use cases (logs, metrics, alerts)
- Cost-Effective: SQS-based execution model scales with demand
Configuration
To configure the Object storage query input module, Edit these settings.
Below is the default configuration from: query/config.yaml (* Required Fields).
ewogICJ0eXBlIiA6ICJvYmplY3QiLAogICJwcm9wZXJ0aWVzIiA6IHsKICAgICJpbmNsdWRlIiA6IHsKICAgICAgInR5cGUiIDogImFycmF5IiwKICAgICAgIml0ZW1zIiA6IHsKICAgICAgICAidHlwZSIgOiAic3RyaW5nIgogICAgICB9CiAgICB9LAogICAgInRlbngiIDogewogICAgICAidHlwZSIgOiAic3RyaW5nIgogICAgfSwKICAgICJxdWVyeSIgOiB7CiAgICAgICJ0eXBlIiA6ICJhcnJheSIsCiAgICAgICJpdGVtcyIgOiB7CiAgICAgICAgInR5cGUiIDogIm9iamVjdCIsCiAgICAgICAgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIiA6IGZhbHNlLAogICAgICAgICJwcm9wZXJ0aWVzIiA6IHsKICAgICAgICAgICJuYW1lIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTG9naWNhbCBuYW1lIGZvciB0aGUgcXVlcnlcblxuU3BlY2lmaWVzIGEgbG9naWNhbCBuYW1lIGFzc29jaWF0ZWQgd2l0aCB0aGUgcXVlcnkgKGUuZy4sIGBlcnJvcnNRdWVyeWApIFRoaXMgdmFsdWUgaWRlbnRpZmllcyB0aGlzIHF1ZXJ5IG9wZXJhdGlvbiBpbiBhZ2dyZWdhdGVkIG1ldHJpY3MgcmVwb3J0cy4gSWYgbm90IHNwZWNpZmllZCwgZGVmYXVsdHMgdG8gYSBjb25jYXRlbmF0aW9uIG9mIFtxdWVyeVRhcmdldF0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9xdWVyeS8jcXVlcnl0YXJnZXQpIGFuZCBbcXVlcnlTZWFyY2hdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvcXVlcnkvI3F1ZXJ5c2VhcmNocykiCiAgICAgICAgICB9LAogICAgICAgICAgInJlYWRQcmludFByb2dyZXNzIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJib29sZWFuIiwKICAgICAgICAgICAgICAic3RyaW5nIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiU2V0cyB3aGV0aGVyIHRoaXMgaW5wdXQgcHJpbnRzIHRocm91Z2hwdXQgc3RhdHMgdG8gdGhlIGNvbnNvbGVcblxuU2V0cyB3aGV0aGVyIHRoaXMgaW5wdXQgcHJpbnRzIHRocm91Z2hwdXQgc3RhdHMgdG8gdGhlIGNvbnNvbGUgVGhpcyB2YWx1ZSBpcyBjb21tb25seSB1c2VkIHdoZW4gdGVzdGluZyBhbiBpbnRlZ3JhdGlvbiB0byBhIHJlbW90ZSBlbmRwb2ludC4gKEFjY2VwdHMgYm9vbGVhbiBvciBzdHJpbmcgd2l0aCAkPSBwcmVmaXggZm9yIHJ1bnRpbWUgZXZhbHVhdGlvbikiCiAgICAgICAgICB9LAogICAgICAgICAgInRhcmdldCIgOiB7CiAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAic3RyaW5nIiwKICAgICAgICAgICAgICAibnVsbCIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgIm1hcmtkb3duRGVzY3JpcHRpb24iIDogIkxvZ2ljYWwgcHJlZml4IHRvIGZpbHRlciBpbmRleCBvYmplY3RzIGJ5XG5cblNwZWNpZmllcyBhIGxvZ2ljYWwgbmFtZSBhc3NvY2lhdGVkIHdpdGggdGhlIHNlYXJjaCB0YXJnZXQuIFRoaXMgdmFsdWUgaWRlbnRpZmllcyB0aGUgYXBwIHRoYXQgcHJvZHVjZWQgdGhlIHF1ZXJpZWQgZXZlbnRzIChlLmcuLCBgYWNtZS1jbGllbnRgKS4gIFRoaXMgdmFsdWUgY29ycmVzcG9uZHMgd2l0aCB0aGUgW2luZGV4V3JpdGVUYXJnZXRdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvaW5kZXgvI2luZGV4d3JpdGV0YXJnZXQpIGFyZ3VtZW50LiIKICAgICAgICAgIH0sCiAgICAgICAgICAic2VhcmNoIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTGlzdCBvZiB0ZXJtcyB0byBzZWFyY2ggZm9yXG5cblNwZWNpZmllcyBhIHNlYXJjaCBleHByZXNzaW9uIGFwcGxpZWQgdG8gdGhlIHVuZGVybHlpbmcgc3RvcmFnZSB2aWEgW1RlblhUZW1wbGF0ZSBmaWx0ZXJzXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbnB1dC9vYmplY3RTdG9yYWdlL2luZGV4LyN0ZW54dGVtcGxhdGUtZmlsdGVycykgZm9yIGVmZmljaWVudCBwcmUtZmlsdGVyaW5nLiBTdXBwb3J0cyBvbmx5IGJhc2ljIG9wZXJhdGlvbnM6IGAmJmAgKEFORCksIGB8fGAgKE9SKSwgPT0gKGVxdWFsaXR5KSwgYW5kIFtpbmNsdWRlc10oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9hcGkvanMvI1RlblhTdHJpbmcuaW5jbHVkZXMpIChzdWJzdHJpbmcgbWF0Y2gpLiAgRXhhbXBsZTogICBgYGAganMgKGxldmVsPT1JTkZPIHx8IGxldmVsPT1XQVJOKSAmJiBpbmNsdWRlcyh0ZXh0LCBcIlBPU1RcIikgYGBgICBUaGlzIG5hcnJvd3MgZG93biBkYXRhIGZldGNoZWQgZnJvbSBzdG9yYWdlIGJlZm9yZSBpbi1tZW1vcnkgcHJvY2Vzc2luZy4gIFRvIHBlcmZvcm0gbW9yZSBjb21wbGV4IGluLW1lbW9yeSBmaWx0ZXJpbmcsIHNwZWNpZnkgW3F1ZXJ5RmlsdGVyc10oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9xdWVyeS8jcXVlcnlmaWx0ZXJzKS4iCiAgICAgICAgICB9LAogICAgICAgICAgImZpbHRlcnMiIDogewogICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgImFycmF5IiwKICAgICAgICAgICAgICAibnVsbCIKICAgICAgICAgICAgXSwKICAgICAgICAgICAgIm1hcmtkb3duRGVzY3JpcHRpb24iIDogIkxpc3Qgb2YgdGVybXMgdG8gc2VhcmNoIGZvclxuXG5TcGVjaWZpZXMgSmF2YVNjcmlwdCBleHByZXNzaW9ucyBhcHBsaWVkIGluLW1lbW9yeSB0byBhbGwgVGVuWE9iamVjdHMgdGhhdCBtYXRjaCB0aGUgW3F1ZXJ5U2VhcmNoXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbnB1dC9vYmplY3RTdG9yYWdlL3F1ZXJ5LyNxdWVyeXNlYXJjaCkgZXhwcmVzc2lvbi4gU3VwcG9ydHMgYWxsIHZhbGlkIFtUZW5YIEphdmFTY3JpcHRdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vYXBpL2pzLykgZXhwcmVzc2lvbnMgZm9yIGNvbXBsZXggZmlsdGVyaW5nLCBlbnJpY2htZW50LCBhbmQgcHJvY2Vzc2luZy4gIFRoaXMgcHJvdmlkZXMgcHJlY2lzZSwgZXhhY3QgZmlsdGVyaW5nIGFmdGVyIGRhdGEgaXMgZmV0Y2hlZCBmcm9tIHN0b3JhZ2UuICBgYGAgeWFtbCBxdWVyeUZpbHRlcnM6ICAgLSBMZXZlbFRlbXBsYXRlLmxldmVsID09IFwiRVJST1JcIiAgICAtIE1hdGgubWF4KHRoaXMucHJpY2UsIDEwMCkgYGBgIiwKICAgICAgICAgICAgIml0ZW1zIiA6IHsKICAgICAgICAgICAgICAidHlwZSIgOiAic3RyaW5nIgogICAgICAgICAgICB9CiAgICAgICAgICB9LAogICAgICAgICAgImZyb20iIDogewogICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICAgIm51bGwiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJCZWdpbm5pbmcgb2YgdGhlIHNlYXJjaCB0aW1lIHJhbmdlIChpbmNsdXNpdmUpXG5cbkRlZmluZXMgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2VhcmNoIHRpbWUgcmFuZ2UgKGluY2x1c2l2ZSkgZXhwcmVzc2VkIGFzIGEgVU5JWCBtaWxsaXNlY29uZCBlcG9jaCB2YWx1ZS4gVGhpcyB2YWx1ZSBjb21tb25seSB1c2VzIHRoZSBbbm93XShodHRwczovL2RvYy5sb2cxMHguY29tL2FwaS9qcy8jVGVuWERhdGUubm93KSBmdW5jdGlvbi4gIEZvciBleGFtcGxlLCB0byBleHByZXNzIHRoZSB2YWx1ZSBvZiBvbmUgaG91ciBiZWZvcmUgdGhlIGN1cnJlbnQgbWlsbGlzZWNvbmQgZXBvY2gsIHNwZWNpZnk6ICBgYGAgeWFtbCBxdWVyeUZyb206IG5vdyhcIi0xaFwiKSBgYGAiCiAgICAgICAgICB9LAogICAgICAgICAgInRvIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiRW5kIG9mIHRoZSBzZWFyY2ggdGltZSByYW5nZSAoZXhjbHVzaXZlKVxuXG5EZWZpbmVzIHRoZSBlbmQgb2YgdGhlIHNlYXJjaCB0aW1lIHJhbmdlIGV4cHJlc3NlZCBhcyBhIFVOSVggbWlsbGlzZWNvbmQgZXBvY2ggdmFsdWUgKGV4Y2x1c2l2ZSkuIFRoaXMgdmFsdWUgY29tbW9ubHkgdXNlcyB0aGUgW25vd10oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9hcGkvanMvI1RlblhEYXRlLm5vdykgZnVuY3Rpb24uICBGb3IgZXhhbXBsZSwgdG8gZXhwcmVzcyB0aGUgdmFsdWUgb2YgdGhlIGN1cnJlbnQgbWlsbGlzZWNvbmQgZXBvY2gsIHNwZWNpZnk6ICBgYGAgeWFtbCBxdWVyeVRvOiBub3coKSBgYGAiCiAgICAgICAgICB9LAogICAgICAgICAgIm9iamVjdFN0b3JhZ2VOYW1lIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiT2JqZWN0IHN0b3JhZ2UgbG9naWNhbCBuYW1lXG5cbklkZW50aWZpZXMgdGhlIFtPYmplY3QgU3RvcmFnZV0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS8jb2JqZWN0c3RvcmFnZWNsYXNzbmFtZSkgYWdhaW5zdCB3aGljaCB0aGlzIHF1ZXJ5IGlzIG1hZGUgKGUuZy4sIGBBV1NgKS4iCiAgICAgICAgICB9LAogICAgICAgICAgImluZGV4Q29udGFpbmVyIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiT2JqZWN0IHN0b3JhZ2UgY29udGFpbmVyIGNvbnRhaW5pbmcgaW5kZXggb2JqZWN0c1xuXG5TcGVjaWZpZXMgdGhlIG9iamVjdCBzdG9yYWdlIGNvbnRhaW5lciAoZS5nLiwgQVdTIFMzIGJ1Y2tldCkgbmFtZSBpbiB3aGljaCB0byBzdG9yZSBbVGVuWFRlbXBsYXRlIEZpbHRlcnNdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvaW5kZXgvI3Rlbnh0ZW1wbGF0ZS1maWx0ZXJzKScuIFRoaXMgdmFsdWUgY29ycmVzcG9uZHMgd2l0aCB0aGUgW2luZGV4V3JpdGVDb250YWluZXJdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvaW5kZXgpIgogICAgICAgICAgfSwKICAgICAgICAgICJyZWFkQ29udGFpbmVyIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTG9jYXRpb24gb2YgdGhlIG91dHB1dCBmaWxlIGZvciB3cml0aW5nIFRlblhPYmplY3QgZmllbGQgdmFsdWVzXG5cblNwZWNpZmllcyB0aGUgb2JqZWN0IHN0b3JhZ2UgY29udGFpbmVyIChlLmcuLCBTMyBidWNrZXQpIG5hbWUgd2hlcmUgaW5wdXQgb2JqZWN0cyAoZS5nLiwgbG9nIGZpbGUpIHRvIHNjYW4gYXJlIHN0b3JlZC4gVGhpcyB2YWx1ZSBjb3JyZXNwb25kcyB3aXRoIHRoZSBbaW5kZXhXcml0ZUNvbnRhaW5lcl0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9pbmRleCkiCiAgICAgICAgICB9LAogICAgICAgICAgIm9iamVjdFN0b3JhZ2VBcmdzIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJhcnJheSIsCiAgICAgICAgICAgICAgIm51bGwiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJDdXN0b20gb2JqZWN0IHN0b3JhZ2UgYXJnc1xuXG5DdXN0b20gYXJndW1lbnRzIHBhc3NlZCBhcyBhIG1hcCB0byB0aGUgY29uc3RydWN0b3Igb2YgdGhlIHVuZGVybHlpbmcgW29iamVjdCBzdG9yYWdlXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbnB1dC9vYmplY3RTdG9yYWdlL3F1ZXJ5LyNpbmRleG9iamVjdHN0b3JhZ2VuYW1lKS4gVGhpcyBsaXN0IGlzIGV4cGVjdGVkIHRvIGhvbGQgcGFpcnMgb2Yga2V5IHZhbHVlcyAoZS5nLiwgYXJnczogW2tleTEsIHZhbHVlMSwga2V5MiwgdmFsdWUyXSkiLAogICAgICAgICAgICAiaXRlbXMiIDogewogICAgICAgICAgICAgICJ0eXBlIiA6ICJzdHJpbmciCiAgICAgICAgICAgIH0KICAgICAgICAgIH0sCiAgICAgICAgICAibGltaXQiIDogewogICAgICAgICAgICAidHlwZSIgOiAib2JqZWN0IiwKICAgICAgICAgICAgImFkZGl0aW9uYWxQcm9wZXJ0aWVzIiA6IGZhbHNlLAogICAgICAgICAgICAicHJvcGVydGllcyIgOiB7CiAgICAgICAgICAgICAgInByb2Nlc3NpbmdUaW1lIiA6IHsKICAgICAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJNYXggbWlsbGlzZWNvbmRzIGFsbG90ZWQgZm9yIHRoaXMgcXVlcnlcblxuTWlsbGlzZWNvbmRzIGFsbG90dGVkIGZvciB0aGlzIHF1ZXJ5IHRvIGNvbXBsZXRlLiBPbmNlIHRoaXMgcGVyaW9kIGhhcyBlbGFwc2VkIHRoZSBxdWVyeSB3aWxsIHRlcm1pbmF0ZSByZWdhcmRsZXNzIG9mIHdoZXRoZXIgW3F1ZXJ5TGltaXRSZXN1bHRTaXplXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbnB1dC9vYmplY3RTdG9yYWdlL3F1ZXJ5LyNxdWVyeWxpbWl0cmVzdWx0c2l6ZSkgaGFzIG5vdCBiZWVuIGV4Y2VlZGVkLiIKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJyZXN1bHRTaXplIiA6IHsKICAgICAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJNYXggYnl0ZSB2b2x1bWUgb2YgbWF0Y2hpbmcgZXZlbnRzIHRvIGZldGNoXG5cblZvbHVtZSBpbiBieXRlcyBvZiBldmVudHMgbWF0Y2hpbmcgdGhlIGFwcCBwcmVmaXgsIHRlcm1zIGFuZCB0aW1lIHJhbmdlIHRvIGZldGNoLiBPbmNlIHRoaXMgdm9sdW1lIGhhcyBiZWVuIHJlYWNoZWQgdGhlIHF1ZXJ5IHdpbGwgdGVybWluYXRlLiAgSWYgW3F1ZXJ5TGltaXRQcm9jZXNzaW5nVGltZV0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9xdWVyeS8jcXVlcnlsaW1pdHByb2Nlc3Npbmd0aW1lKSBoYXMgZWxhcHNlZCBiZWZvcmUgdGhlIHJlcXVlc3RlZCByZXN1bHQgdm9sdW1lIGhhcyBiZWVuIGZldGNoZWQsIHRoZSBxdWVyeSB3aWxsIHN0aWxsIHRlcm1pbmF0ZS4iCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAicmVxdWlyZWQiIDogWwogICAgICAgICAgICAgICJwcm9jZXNzaW5nVGltZSIsCiAgICAgICAgICAgICAgInJlc3VsdFNpemUiCiAgICAgICAgICAgIF0KICAgICAgICAgIH0sCiAgICAgICAgICAic2NhbkZ1bmN0aW9uIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogIm9iamVjdCIsCiAgICAgICAgICAgICJhZGRpdGlvbmFsUHJvcGVydGllcyIgOiBmYWxzZSwKICAgICAgICAgICAgInByb3BlcnRpZXMiIDogewogICAgICAgICAgICAgICJwYXJhbGxlbCIgOiB7CiAgICAgICAgICAgICAgICAidHlwZSIgOiAib2JqZWN0IiwKICAgICAgICAgICAgICAgICJhZGRpdGlvbmFsUHJvcGVydGllcyIgOiBmYWxzZSwKICAgICAgICAgICAgICAgICJwcm9wZXJ0aWVzIiA6IHsKICAgICAgICAgICAgICAgICAgInRpbWVzbGljZSIgOiB7CiAgICAgICAgICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAibnVsbCIKICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJNYXggdGltZSByYW5nZSB0byBwcm9jZXNzIGJ5IGEgc2NhbiB3b3JrZXIgaW5zdGFuY2VcblxuU3BlY2lmaWVzIHRoZSBtYXggdGltZSBkdXJhdGlvbiAoZS5nLiwgMW1pbikgYW4gaW5zdGFuY2Ugb2YgdGhlIFtzY2FuXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbnB1dC9vYmplY3RTdG9yYWdlL3F1ZXJ5LyNzY2FuKSB3b3JrZXIgd2lsbCB0cmF2ZXJzZSB3aXRoaW4gdGhlIGluZGV4LiBGb3IgZXhhbXBsZSwgaWYgYSBxdWVyeSBzcGVjaWZpZXMgYSB0aW1lIHJhbmdlIG9mIGAxNW1pbmAgYW5kIHRoaXMgdmFsdWUgaXMgc2V0IHRvIGAxbWAsIDE1IGluc3RhbmNlcyBvZiB0aGUgc2NhbiB3b3JrZXIgd2lsbCBleGVjdXRlIGluIHBhcmFsbGVsIHRvIHNjYW4gdGhyb3VnaCB0aGUgaW5kZXguIElmIHRoaXMgdmFsdWUgaXMgMCwgYSBzaW5nbGUgd29ya2VyIGluc3RhbmNlIHdpbGwgc2VxdWVudGlhbGx5IHNjYW4gdGhyb3VnaCB0aGUgaW5kZXguIgogICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAibWF4SW5zdGFuY2VzIiA6IHsKICAgICAgICAgICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgICAgICAgICAibnVtYmVyIiwKICAgICAgICAgICAgICAgICAgICAgICJzdHJpbmciCiAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTWF4IG51bWJlciBvZiBpbnN0YW5jZXMgb2YgdGhlIHNjYW4gd29ya2VyXG5cblNwZWNpZmllcyB0aGUgbWF4aW11bSBudW1iZXIgb2YgW3NjYW5dKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvcXVlcnkvI3NjYW4pIHdvcmtlciBpbnN0YW5jZXMgdGhhdCB3aWxsIHRyYXZlcnNlIHRoZSBpbmRleC4gaWYgdGhlIHByb3ZpZGVkIHRpbWUgcmFuZ2UgYW5kIFt0aW1lU2xpY2VdKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvcXVlcnkvI3F1ZXJ5c2NhbmZ1bmN0aW9ucGFyYWxsZWx0aW1lc2xpY2UpIHByb3ZpZGVkIHdpbGwgcmVzdWx0IGluIG1vcmUgaW5zdGFuY2VzIHRoYW4gdGhlIHByb3ZpZGVkIHZhbHVlLCB0aGUgdGltZSBzbGljZSB3aWxsIGluY3JlYXNlIGl0cyBzaXplIHVudGlsIHRoZSBhbW91bnQgb2Ygd29ya2VycyBuZWVkZWQgd2lsbCBiZSBsZXNzIHRoYW4gdGhpcyB2YWx1ZS4gIEZvciBleGFtcGxlLCBpZiBhIHF1ZXJ5IHNwZWNpZmllcyBhIHRpbWUgcmFuZ2Ugb2YgYDYwbWluYCBhbmQgYSB0aW1lIHNsaWNlIG9mIGAxbWAsIHdoaWxlIHRoaXMgdmFsdWUgaXMgc2V0IHRvIGAyNWAsIHRoZSB0aW1lIHNsaWNlIHdpbGwgYmUgZWZmZWN0aXZlbHkgaW5jcmVhc2VkIHRvIGAzbWAgdG8gYWNjb21tb2RhdGUgdGhpcy4gIFRoZSBtYXhpbXVtIHZhbHVlIGZvciB0aGlzIG9wdGlvbiBpczogMTAsMDAwIChBY2NlcHRzIG51bWJlciBvciBzdHJpbmcgd2l0aCAkPSBwcmVmaXggZm9yIHJ1bnRpbWUgZXZhbHVhdGlvbikgKERlZmF1bHQ6IDEwMDApIiwKICAgICAgICAgICAgICAgICAgICAiZGVmYXVsdCIgOiAxMDAwCiAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICJ0aHJlYWRzIiA6IHsKICAgICAgICAgICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgICAgICAgICAibnVtYmVyIiwKICAgICAgICAgICAgICAgICAgICAgICJzdHJpbmciCiAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTWF4IG51bWJlciBvZiB0aHJlYWRzIGFsbG9jYXRlZCBwZXIgZWFjaCAnc2Nhbicgd29ya2VyIGluc3RhbmNlXG5cblNldHMgdGhlIG51bWJlciBvZiBKVk0gdGhyZWFkcyB0byBzY2FuIHRocm91Z2ggYSB0aW1lIHNsaWNlIG9mIHRoZSBpbmRleCB3aXRoaW4gYSBbc2Nhbl0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9xdWVyeS8jc2Nhbikgd29ya2VyIGluc3RhbmNlLiBGb3IgZXhhbXBsZSwgaWYgW3RpbWVTbGljZV0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9xdWVyeS8jcXVlcnlzY2FuZnVuY3Rpb25wYXJhbGxlbHRpbWVzbGljZSkgaXMgYDEwbWluYCBhbmQgdGhpcyB2YWx1ZSBpcyBzZXQgdG8gMTAsIHNjYW4gZWFjaCAxbSBpbmRleCB0aW1lIHJhbmdlIHVzaW5nIGEgZGVkaWNhdGVkIHRocmVhZC4gSWYgc2V0IHRvIDEgb3IgMCwgYSBzaW5nbGUgdGhyZWFkIHdpbGwgc2NhbiB0aHJvdWdoIHRoZSBlbnRpcmUgaW5kZXggdGltZSByYW5nZSAoZS5nLiwgMTBtaW4pLiAoQWNjZXB0cyBudW1iZXIgb3Igc3RyaW5nIHdpdGggJD0gcHJlZml4IGZvciBydW50aW1lIGV2YWx1YXRpb24pIgogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAidXJsIiA6IHsKICAgICAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAgICAgInN0cmluZyIsCiAgICAgICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJTY2FuIHdvcmtlciBlbmRwb2ludCBVUkxcblxuU3BlY2lmaWVzIHRoZSBlbmRwb2ludCB1c2VkIHRvIGludm9rZSB0aGUgW3NjYW5dKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvcXVlcnkvI3NjYW4pIHdvcmtlciIKICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJsaW1pdFJlc3VsdFNpemVJbnRlcnZhbCIgOiB7CiAgICAgICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICAgICAibnVsbCIKICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiSW50ZXJ2YWwgYnkgd2hpY2ggdG8gY2hlY2sgd2hldGhlciAncXVlcnlMaW1pdFJlc3VsdFNpemUnIGlzIGV4Y2VlZGVkXG5cbkludGVydmFsIGJ5IHdoaWNoIHRvIGNoZWNrIHdoZXRoZXIgW3F1ZXJ5TGltaXRSZXN1bHRTaXplXShodHRwczovL2RvYy5sb2cxMHguY29tL3J1bi9pbnB1dC9vYmplY3RTdG9yYWdlL3F1ZXJ5LyNxdWVyeWxpbWl0cmVzdWx0c2l6ZSkgdGhhdCBpcyB0aGUgcXVlcnkgaGFzIHJldHVybmVkID49IHRoZSByZXF1ZXN0IHJlc3VsdCB2b2x1bWUuIgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgInJlcXVpcmVkIiA6IFsKICAgICAgICAgICAgICAidXJsIgogICAgICAgICAgICBdCiAgICAgICAgICB9LAogICAgICAgICAgInNjYW5GbHVzaEludGVydmFsIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiSW50ZXJ2YWwgdG8gd2FpdCBiZWZvcmUgcG9zdGluZyBwZW5kaW5nICdzdHJlYW0nIHdvcmtlciByZXF1ZXN0c1xuXG5TcGVjaWZpZXMgYSBtYXhpbXVtIGludGVydmFsIChlLmcuLCBgMnNlY2ApIHdoZW4gc2Nhbm5pbmcgYW4gaW5kZXggdGltZSBzbGljZSB0byB3YWl0IHRvIHN1Ym1pdCBwZW5kaW5nIFtzdHJlYW1dKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvcXVlcnkvI3N0cmVhbSkgd29ya2VyIHJlcXVlc3RzLiBJZiBub3Qgc2V0LCBhbGwgc3RyZWFtIHdvcmtlciByZXF1ZXN0cyBhcmUgc2VudCBhZnRlciB0aGUgaW5kZXggc2Nhbm5pbmcgcHJvY2VzcyBmb3IgYSB0YXJnZXQgaW5kZXggdGltZSBzbGljZSBoYXMgZmluaXNoZWQuIgogICAgICAgICAgfSwKICAgICAgICAgICJzdHJlYW1GdW5jdGlvbiIgOiB7CiAgICAgICAgICAgICJ0eXBlIiA6ICJvYmplY3QiLAogICAgICAgICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiIDogZmFsc2UsCiAgICAgICAgICAgICJwcm9wZXJ0aWVzIiA6IHsKICAgICAgICAgICAgICAicGFyYWxsZWwiIDogewogICAgICAgICAgICAgICAgInR5cGUiIDogIm9iamVjdCIsCiAgICAgICAgICAgICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiIDogZmFsc2UsCiAgICAgICAgICAgICAgICAicHJvcGVydGllcyIgOiB7CiAgICAgICAgICAgICAgICAgICJvYmplY3RzIiA6IHsKICAgICAgICAgICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgICAgICAgICAibnVtYmVyIiwKICAgICAgICAgICAgICAgICAgICAgICJzdHJpbmciCiAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiTWF4IG51bWJlciBvZiBpbnB1dCBvYmplY3QgYnl0ZSByYW5nZXMgdG8gcHJvY2VzcyBpbiBhIHNpbmdsZSAnc3RyZWFtJyBpbnN0YW5jZVxuXG5EZWZpbmVzIHRoZSBtYXhpbXVtIG51bWJlciBvZiBTdG9yYWdlIG9iamVjdHMgdG8gcHJvY2VzcyBieSBhIHNpbmdsZSBpbnN0YW5jZSBvZiB0aGUgW3N0cmVhbV0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9xdWVyeS8jc3RyZWFtKSB3b3JrZXIuICBGb3IgZXhhbXBsZSwgaWYgc2V0IHRvIDUwIGFuZCB0aGUgW3NjYW5dKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvcXVlcnkvI3NjYW4pIHBoYXNlIGhhcyBpZGVudGlmaWVkIDIwMCBwb3RlbnRpYWxseSBtYXRjaGluZyBpbnB1dCBvYmplY3QgYnl0ZSByYW5nZXMsIGZvdXIgaW5zdGFuY2VzIG9mIHRoZSBzdHJlYW0gd29ya2VyIHdpbGwgc3BsaXQgdGhlIHdvcmtsb2FkIGluIHBhcmFsbGVsLiAoQWNjZXB0cyBudW1iZXIgb3Igc3RyaW5nIHdpdGggJD0gcHJlZml4IGZvciBydW50aW1lIGV2YWx1YXRpb24pIgogICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAiYnl0ZVJhbmdlIiA6IHsKICAgICAgICAgICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgICAgICAgICAic3RyaW5nIiwKICAgICAgICAgICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIm1hcmtkb3duRGVzY3JpcHRpb24iIDogIk1heCBpbnB1dCBvYmplY3QgYnl0ZXMgZm9yIGEgc2luZ2xlIGZldGNoIHJlcXVlc3RcblxuRGVmaW5lcyB0aGUgbWF4IGJ5dGUgcmFuZ2Ugd2l0aGluIGFuIGlucHV0IG9iamVjdCAoZS5nLiwgbG9nIGZpbGUpIHRoYXQgY2FuIGZldGNoZWQgdmlhIGEgc2luZ2xlIHJlcXVlc3QuIEZvciBleGFtcGxlLCBpZiB0aGlzIHZhbHVlIGlzIGA1TWJgIGFuZCB0d28gbWF0Y2hpbmcgMU1iIGJ5dGUgcmFuZ2VzIHNwYWNlZCAyTWIgYXBhcnQgYXJlIGlkZW50aWZpZWQgd2l0aGluIGEgdGFyZ2V0IG9iamVjdCBmZXRjaCBib3RoIGZyb20gdGhlIHN0b3JhZ2UgdmlhIGEgc2luZ2xlIG9wZXJhdGlvbi4gSWYgdGhlcmUgaXMgYSAyTWIgZ2FwLCBsYXVuY2ggdHdvIGluc3RhbmNlcyBvZiB0aGUgW3N0cmVhbV0oaHR0cHM6Ly9kb2MubG9nMTB4LmNvbS9ydW4vaW5wdXQvb2JqZWN0U3RvcmFnZS9xdWVyeS8jc3RyZWFtKSB3b3JrZXIuIgogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgInJlcXVpcmVkIiA6IFsKICAgICAgICAgICAgICAgICAgImJ5dGVSYW5nZSIKICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJ1cmwiIDogewogICAgICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICAgICAic3RyaW5nIiwKICAgICAgICAgICAgICAgICAgIm51bGwiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgIm1hcmtkb3duRGVzY3JpcHRpb24iIDogIlN0cmVhbSB3b3JrZXIgZW5kcG9pbnQgVVJMXG5cblNwZWNpZmllcyB0aGUgZW5kcG9pbnQgdXNlZCB0byBpbnZva2UgdGhlIFtzdHJlYW1dKGh0dHBzOi8vZG9jLmxvZzEweC5jb20vcnVuL2lucHV0L29iamVjdFN0b3JhZ2UvcXVlcnkvI3N0cmVhbSkgd29ya2VyIgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgInJlcXVpcmVkIiA6IFsKICAgICAgICAgICAgICAidXJsIgogICAgICAgICAgICBdCiAgICAgICAgICB9LAogICAgICAgICAgImZpbHRlciIgOiB7CiAgICAgICAgICAgICJ0eXBlIiA6ICJvYmplY3QiLAogICAgICAgICAgICAiYWRkaXRpb25hbFByb3BlcnRpZXMiIDogZmFsc2UsCiAgICAgICAgICAgICJwcm9wZXJ0aWVzIiA6IHsKICAgICAgICAgICAgICAidmFycyIgOiB7CiAgICAgICAgICAgICAgICAidHlwZSIgOiBbCiAgICAgICAgICAgICAgICAgICJhcnJheSIsCiAgICAgICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICJtYXJrZG93bkRlc2NyaXB0aW9uIiA6ICJTcGVjaWZpZXMgYSBsaXN0IG9mIHZhcmlhYmxlIHZhbHVlcyB0byBzY2FuIGZvclxuXG5TcGVjaWZpZXMgYSBsaXN0IG9mIHZhcmlhYmxlIHZhbHVlcyB0byBzY2FuIGZvciIsCiAgICAgICAgICAgICAgICAiaXRlbXMiIDogewogICAgICAgICAgICAgICAgICAidHlwZSIgOiAic3RyaW5nIgogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgInRlbXBsYXRlSGFzaGVzIiA6IHsKICAgICAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAgICAgImFycmF5IiwKICAgICAgICAgICAgICAgICAgIm51bGwiCiAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgIm1hcmtkb3duRGVzY3JpcHRpb24iIDogIlNwZWNpZmllcyBhIGxpc3Qgb2YgVGVuWFRlbXBsYXRlIGhhc2ggdmFsdWVzIHRvIHNjYW4gZm9yXG5cblNwZWNpZmllcyBhIGxpc3Qgb2YgVGVuWFRlbXBsYXRlIGhhc2ggdmFsdWVzIHRvIHNjYW4gZm9yIiwKICAgICAgICAgICAgICAgICJpdGVtcyIgOiB7CiAgICAgICAgICAgICAgICAgICJ0eXBlIiA6ICJzdHJpbmciCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9LAogICAgICAgICAgImlEIiA6IHsKICAgICAgICAgICAgInR5cGUiIDogWwogICAgICAgICAgICAgICJzdHJpbmciLAogICAgICAgICAgICAgICJudWxsIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiVW5pcXVlIElEIG9mIGhvc3QgcXVlcnlcblxuVVVJRCBpZGVudGlmeWluZyB0aGlzIHF1ZXJ5LiBUaGlzIHZhbHVlIGlzIGF1dG9tYXRpY2FsbHkgYXNzaWduZWQgaWYgbm90IGV4cGxpY2l0bHkgc2V0LiIKICAgICAgICAgIH0sCiAgICAgICAgICAiZWxhcHNlVGltZSIgOiB7CiAgICAgICAgICAgICJ0eXBlIiA6IFsKICAgICAgICAgICAgICAibnVtYmVyIiwKICAgICAgICAgICAgICAic3RyaW5nIgogICAgICAgICAgICBdLAogICAgICAgICAgICAibWFya2Rvd25EZXNjcmlwdGlvbiIgOiAiRXBvY2ggYWZ0ZXIgd2hpY2ggcHJvY2Vzc2luZyB0aW1lcyBvdXRcblxuRXBvY2ggdmFsdWUgd2hpY2ggaWYgZXhjZWVkcyB0aGUgY3VycmVudCBzeXN0ZW0gdGltZSB3aWxsIHJlc3VsdCBpbiB0aGlzIHJlcXVlc3QgYmVpbmcgY2FuY2VsbGVkIChBY2NlcHRzIG51bWJlciBvciBzdHJpbmcgd2l0aCAkPSBwcmVmaXggZm9yIHJ1bnRpbWUgZXZhbHVhdGlvbikiCiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAicmVxdWlyZWQiIDogWwogICAgICAgICAgInRhcmdldCIsCiAgICAgICAgICAiZnJvbSIsCiAgICAgICAgICAidG8iLAogICAgICAgICAgIm9iamVjdFN0b3JhZ2VOYW1lIiwKICAgICAgICAgICJpbmRleENvbnRhaW5lciIsCiAgICAgICAgICAicmVhZENvbnRhaW5lciIKICAgICAgICBdCiAgICAgIH0KICAgIH0KICB9LAogICJhZGRpdGlvbmFsUHJvcGVydGllcyIgOiBmYWxzZQp9
# 🔟❎ 'run' Object storage query AWS S3 configuration
# Configure query AWS S3 bucket settings
# To learn more see https://doc.log10x.com/run/input/objectStorage/query/
# Set the 10x pipeline to 'run'
tenx: run
# =============================== Dependencies ================================
include:
- run/modules/input/objectStorage/input
- run/modules/input/objectStorage/query
# =============================== Query Options ===============================
query:
# 'name' specifies a logical name associated with this query
- name: my-query
# 'readPrintProgress' sets whether this input prints throughput stats to the console
readPrintProgress: $=!TenXEnv.get("quiet")
# ---------------------------- Storage Options ----------------------------
# 'objectStorage' selects the underlying storage (e.g., S3). To learn more see: https://doc.log10x.com/run/input/objectStorage
# Authentication is made via the default provider credentials chain:
# https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.html
# Region selection is made via the default region provider chain:
# https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/regions/providers/DefaultAwsRegionProviderChain.html
objectStorageName: AWS
# 'readContainer' specifies the container (e.g., S3 bucket) in which to search
readContainer: $=TenXEnv.get("TENX_STREAMER_INPUT_BUCKET", "") # (❗ REQUIRED)
# 'indexContainer' specifies the container (e.g., S3 bucket) in which index objects created by the 'index' module reside.
indexContainer: $=TenXEnv.get("TENX_STREAMER_INDEX_BUCKET", "") # (❗ REQUIRED)
# ----------------------------- Search Options ----------------------------
# 'target' specifies a user app/service name (e.g., 'acme-client') to search in.
target: app # (❗ REQUIRED)
# 'from' sets the query's beginning epoch time range (inclusive).
# The 'now' function returns the current epoch value with an optional positive/negative offset.
from: now("-5m") # (❗ REQUIRED)
# 'to' sets the end epoch time range (exclusive), must be greater than 'from'.
to: now() # (❗ REQUIRED)
# 'search' Specifies a search expression applied to raw events in the underlying storage
# Supports basic operations: `&&` (AND), `||` (OR), == (equality), and includes(field, text) (substring match).
search: (severity_level == "ERROR") || (severity_level == "FATAL")
# 'filters' specify expressions TenXObjects transformed from matching events in storage must meet
# To learn more see https://doc.log10x.com/run/output/regulate/#filter-expressions
filters: []
# ----------------------------- Limit Options ------------------------------
# 'limit' options caps the query's processing time and volume of results it will return
limit:
# 'processingTime' specifies the time in ms allotted for this query to complete.
# Once this period has elapsed the query will terminate regardless of
# whether 'resultSize' has not been exceeded.
processingTime: parseDuration("1m")
# 'resultSize' specifies the volume in bytes of events matching the target app name, terms and time range to fetch.
# Once this volume has been reached the query will terminate.
resultSize: parseBytes("10MB")
Options
Specify the options below to configure multiple Object storage query input:
| Name | Description | Category |
|---|---|---|
| queryName | Logical name for the query | General |
| queryReadPrintProgress | Sets whether this input prints throughput stats to the console | General |
| queryTarget | Logical prefix to filter index objects by | Filter |
| querySearch | List of terms to search for | Filter |
| queryFilters | List of terms to search for | Filter |
| queryFrom | Beginning of the search time range (inclusive) | Filter |
| queryTo | End of the search time range (exclusive) | Filter |
| queryObjectStorageName | Object storage logical name | Access |
| queryIndexContainer | Object storage container containing index objects | Scan |
| queryScanFunctionParallelTimeslice | Max time range to process by a scan worker instance | Scan |
| queryScanFunctionParallelMaxInstances | Max number of instances of the scan worker | Scan |
| queryScanFunctionParallelThreads | Max number of threads allocated per each 'scan' worker instance | Scan |
| queryScanFlushInterval | Interval to wait before posting pending 'stream' worker requests | Scan |
| queryScanFunctionUrl | Scan worker endpoint URL | Scan |
| queryReadContainer | Location of the output file for writing TenXObject field values | Stream |
| queryStreamFunctionParallelObjects | Max number of input object byte ranges to process in a single 'stream' instance | Stream |
| queryStreamFunctionParallelByteRange | Max input object bytes for a single fetch request | Stream |
| queryStreamFunctionUrl | Stream worker endpoint URL | Stream |
| queryObjectStorageArgs | Custom object storage args | Advanced |
| queryFilterVars | Specifies a list of variable values to scan for | Advanced |
| queryFilterTemplateHashes | Specifies a list of TenXTemplate hash values to scan for | Advanced |
| queryID | Unique ID of host query | Advanced |
| queryElapseTime | Epoch after which processing times out | Advanced |
| queryScanFunctionLimitResultSizeInterval | Interval by which to check whether 'queryLimitResultSize' is exceeded | Advanced |
| queryLimitProcessingTime | Max milliseconds alloted for this query | Limit |
| queryLimitResultSize | Max byte volume of matching events to fetch | Limit |
General
queryName
Logical name for the query.
| Type | Default | Category |
|---|---|---|
| String | "" | General |
Specifies a logical name associated with the query (e.g., errorsQuery)
This value identifies this query operation in aggregated metrics reports.
If not specified, defaults to a concatenation of queryTarget and querySearch.
queryReadPrintProgress
Sets whether this input prints throughput stats to the console.
| Type | Default | Category |
|---|---|---|
| Boolean | false | General |
Sets whether this input prints throughput stats to the console This value is commonly used when testing an integration to a remote endpoint.
Filter
queryTarget
Logical prefix to filter index objects by.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Filter |
Specifies a logical name associated with the search target.
This value identifies the app that produced the queried events (e.g., acme-client).
This value corresponds with the indexWriteTarget argument.
querySearch
List of terms to search for.
| Type | Default | Category |
|---|---|---|
| String | "" | Filter |
Specifies a search expression applied to the underlying storage via TenXTemplate filters for efficient pre-filtering.
Supports only basic operations: && (AND), || (OR), == (equality), and includes (substring match).
Example:
This narrows down data fetched from storage before in-memory processing. To perform more complex in-memory filtering, specify queryFilters.
queryFilters
List of terms to search for.
| Type | Default | Category |
|---|---|---|
| List | [] | Filter |
Specifies JavaScript expressions applied in-memory to all TenXObjects that match the querySearch expression.
Supports all valid TenX JavaScript expressions for complex filtering, enrichment, and processing.
This provides precise, exact filtering after data is fetched from storage.
queryFrom
Beginning of the search time range (inclusive).
| Type | Required | Category |
|---|---|---|
| String | ✔ | Filter |
defines the beginning of the search time range (inclusive) expressed as a UNIX millisecond epoch value.
This value commonly uses the now function.
For example, to express the value of one hour before the current millisecond epoch, specify:
queryTo
End of the search time range (exclusive).
| Type | Required | Category |
|---|---|---|
| String | ✔ | Filter |
defines the end of the search time range expressed as a UNIX millisecond epoch value (exclusive).
This value commonly uses the now function.
For example, to express the value of the current millisecond epoch, specify:
Access
queryObjectStorageName
Object storage logical name.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Access |
Identifies the Object Storage against which this query is made (e.g., AWS).
Scan
queryIndexContainer
Object storage container containing index objects.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Scan |
Specifies the object storage container (e.g., AWS S3 bucket) name in which to store TenXTemplate Filters'.
This value corresponds with the indexWriteContainer.
queryScanFunctionParallelTimeslice
Max time range to process by a scan worker instance.
| Type | Default | Category |
|---|---|---|
| String | "" | Scan |
Specifies the max time duration (e.g., 1min) an instance of the scan worker will traverse within the index.
For example, if a query specifies a time range of 15min and this value is set to 1m, 15 instances of the scan
worker will execute in parallel to scan through the index.
If this value is 0, a single worker instance will sequentially scan through the index.
queryScanFunctionParallelMaxInstances
Max number of instances of the scan worker.
| Type | Default | Category |
|---|---|---|
| Number | 1000 | Scan |
Specifies the maximum number of scan worker instances that will traverse the index. if the provided time range and timeSlice provided will result in more instances than the provided value, the time slice will increase its size until the amount of workers needed will be less than this value.
For example, if a query specifies a time range of 60min and a time slice of 1m, while this
value is set to 25, the time slice will be effectively increased to 3m to accommodate this.
The maximum value for this option is: 10,000.
queryScanFunctionParallelThreads
Max number of threads allocated per each 'scan' worker instance.
| Type | Default | Category |
|---|---|---|
| Number | 0 | Scan |
Sets the number of JVM threads to scan through a time slice of the index within a scan worker instance.
For example, if timeSlice is 10min and this value is set to 10,
scan each 1m index time range using a dedicated thread.
If set to 1 or 0, a single thread will scan through the entire index time range (e.g., 10min).
queryScanFlushInterval
Interval to wait before posting pending 'stream' worker requests.
| Type | Default | Category |
|---|---|---|
| String | "" | Scan |
Specifies a maximum interval (e.g., 2sec) when scanning an index time slice to wait
to submit pending stream worker requests.
If not set, all stream worker requests are sent after the index scanning process for a target index time slice has finished.
queryScanFunctionUrl
Scan worker endpoint URL.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Scan |
Specifies the endpoint used to invoke the scan worker.
Stream
queryReadContainer
Location of the output file for writing TenXObject field values.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Stream |
Specifies the object storage container (e.g., S3 bucket) name where input objects (e.g., log file) to scan are stored.
This value corresponds with the indexWriteContainer.
queryStreamFunctionParallelObjects
Max number of input object byte ranges to process in a single 'stream' instance.
| Type | Default | Category |
|---|---|---|
| Number | 0 | Stream |
Defines the maximum number of Storage objects to process by a single instance of the stream worker.
For example, if set to 50 and the scan phase has identified 200 potentially matching input object byte ranges, four instances of the stream worker will split the workload in parallel.
queryStreamFunctionParallelByteRange
Max input object bytes for a single fetch request.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Stream |
Defines the max byte range within an input object (e.g., log file) that can fetched via a single request.
For example, if this value is 5Mb and two matching 1Mb
byte ranges spaced 2Mb apart are identified within a target object
fetch both from the storage via a single operation.
If there is a 2Mb gap, launch two instances of the stream worker.
queryStreamFunctionUrl
Stream worker endpoint URL.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Stream |
Specifies the endpoint used to invoke the stream worker.
Advanced
queryObjectStorageArgs
Custom object storage args.
| Type | Default | Category |
|---|---|---|
| List | [] | Advanced |
Custom arguments passed as a map to the constructor of the underlying object storage. This list is expected to hold pairs of key values (e.g., args: [key1, value1, key2, value2]).
queryFilterVars
Specifies a list of variable values to scan for.
| Type | Default | Category |
|---|---|---|
| List | [] | Advanced |
Specifies a list of variable values to scan for.
queryFilterTemplateHashes
Specifies a list of TenXTemplate hash values to scan for.
| Type | Default | Category |
|---|---|---|
| List | [] | Advanced |
Specifies a list of TenXTemplate hash values to scan for.
queryID
Unique ID of host query.
| Type | Default | Category |
|---|---|---|
| String | "" | Advanced |
UUID identifying this query. This value is automatically assigned if not explicitly set.
queryElapseTime
Epoch after which processing times out.
| Type | Default | Category |
|---|---|---|
| Number | 0 | Advanced |
Epoch value which if exceeds the current system time will result in this request being cancelled.
queryScanFunctionLimitResultSizeInterval
Interval by which to check whether 'queryLimitResultSize' is exceeded.
| Type | Default | Category |
|---|---|---|
| String | "" | Advanced |
Interval by which to check whether queryLimitResultSize that is the query has returned >= the request result volume.
Limit
queryLimitProcessingTime
Max milliseconds alloted for this query.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Limit |
Milliseconds allotted for this query to complete. Once this period has elapsed the query will terminate regardless of whether queryLimitResultSize has not been exceeded.
queryLimitResultSize
Max byte volume of matching events to fetch.
| Type | Required | Category |
|---|---|---|
| String | ✔ | Limit |
Volume in bytes of events matching the app prefix, terms and time range to fetch. Once this volume has been reached the query will terminate.
If queryLimitProcessingTime has elapsed before the requested result volume has been fetched, the query will still terminate.
This module is defined in query/module.yaml.