{"id":13581684,"url":"https://github.com/grafana/xk6-loki","last_synced_at":"2025-04-09T21:19:05.187Z","repository":{"id":36963183,"uuid":"428559978","full_name":"grafana/xk6-loki","owner":"grafana","description":"k6 extension for Loki","archived":false,"fork":false,"pushed_at":"2025-03-12T09:44:20.000Z","size":198,"stargazers_count":45,"open_issues_count":9,"forks_count":20,"subscribers_count":144,"default_branch":"main","last_synced_at":"2025-04-09T21:18:59.819Z","etag":null,"topics":["k6","loki","xk6"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grafana.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-16T07:34:13.000Z","updated_at":"2025-04-04T04:12:22.000Z","dependencies_parsed_at":"2024-09-03T14:01:05.538Z","dependency_job_id":"244c821a-da34-473e-9628-31cd891aec4f","html_url":"https://github.com/grafana/xk6-loki","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fxk6-loki","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fxk6-loki/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fxk6-loki/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafana%2Fxk6-loki/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grafana","download_url":"https://codeload.github.com/grafana/xk6-loki/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248111973,"owners_count":21049578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["k6","loki","xk6"],"created_at":"2024-08-01T15:02:10.552Z","updated_at":"2025-04-09T21:19:05.144Z","avatar_url":"https://github.com/grafana.png","language":"Go","funding_links":[],"categories":["Go","Extensions"],"sub_categories":["Official"],"readme":"# xk6-loki\n\n**A k6 extension for pushing logs to Loki.**\n\n\n## Getting started\n\n1. Install `xk6`\n\n   ```bash\n   go install go.k6.io/xk6/cmd/xk6@latest\n   ```\n\n1. Checkout `grafana/xk6-loki`\n\n   ```bash\n   git clone https://github.com/grafana/xk6-loki\n   cd xk6-loki\n   ```\n\n1. Build the extension\n\n   ```bash\n   make k6\n   ```\n\n## Javascript API\n\n### Module `k6/x/loki`\n\nThe `k6/x/loki` module contains the Loki extension to interact with the Loki API.\nTo import the module add\n\n```js\nimport loki from 'k6/x/loki';\n```\n\non top of your test file.\n\n### Class `Config(url, [timeout, ratio, cardinality, labels])`\n\nThe class `Config` holds configuration for the Loki client. The constructor\ntakes the following arguments:\n\n| argument    | type    | description | default |\n| ----------- | ------- | ----------- | ------- |\n| url         | string  | The full URL to Loki in format `[${scheme}://][${tenant}[:${token}]]@${host}[:${port}]` | - |\n| timeout     | integer | Request timeout in milliseconds, e.g. `10000` for 10s | 10000 |\n| ratio       | float   | The ratio between JSON and Protobuf encoded batch requests for pushing logs\u003cbr\u003eMust be a number between (including) 0 (100% JSON) and 1 (100% Protobuf)\u003cbr\u003eThis is only relevant for write scenarios.| 0.9 |\n| cardinality | object  | The cardinality (unique values) for [labels](#labels), where the object key is the name of the label and the value is the maximum amount of different values it may have. | null |\n| labels      | Labels  | A Labels object that contains custom label definitions. | null |\n\n**Example:**\n\n```js\nimport loki from 'k6/x/loki';\nlet conf = loki.Config(\"localhost:3100\");\n```\n\n### Class `Labels(labels)`\n\nThe class `Labels` allows the definition of custom labels that can be used\ninstead of the built-in labels. An instance of this class can be passed as\nfifth argument to the `loki.Config` constructor.\n\n| argument | type   | description | default |\n| -------- | ------ | ----------- | ------- |\n| labels   | object | An object of type string (label name) to list of strings (possibel label values). | - |\n\n**Example:**\n\n```js\nimport loki from 'k6/x/loki';\nlet labels = loki.Labels({\n  \"format\": [\"json\", \"logfmt\"], // must contain at least one of the supported log formats\n  \"cluster\": [\"prod-us-east-0\", \"prod-eu-west-1\"],\n  \"namespace\": [\"dev\", \"staging\", \"prod\"],\n  \"container\": [\"nginx\", \"app-1\", \"app-2\", \"app-3\"]\n});\n```\n\n### Class `Client(config)`\n\nThe class `Client` is a Loki client that can read from and write to a Loki instance.\nThe constructor takes the following arguments:\n\n| argument | type   | description | default |\n| -------- | ------ | ----------- | ------- |\n| config   | object |  An instance of `Config` which holds the configuration for the client. | - |\n\n**Example:**\n\n```js\nimport loki from 'k6/x/loki';\nlet conf = loki.Config(\"localhost:3100\");\nlet client = loki.Client(conf);\n```\n\n#### Method `client.push()`\n\nThis function is a shortcut for `client.pushParameterized(5, 800*1024, 1024*1024)`.\n\n#### Method `client.pushParameterized(streams, minSize, maxSize)`\n\nExecute a push request ([POST /loki/api/v1/push](https://grafana.com/docs/loki/latest/api/#post-lokiapiv1push)).\n\nThe function `pushParameterized` generates batch of logs and pushes it to the Loki instance.\nA batch consists of one or more streams which hold multiple log lines.\nA stream is a set of log lines with a unique set of labels.\n\n| argument | type | description | default |\n| -------- | ---- | ----------- | ------- |\n| streams | integer | The amount of streams the pushed batch should contain. | - |\n| minSize | integer | Minimum size in bytes of the raw log lines of the batch. | - |\n| maxSize | integer | Maximum size in bytes of the raw log lines of the batch. | - |\n\n`minSize` and `maxSize` define the boundaries for a random value of the actual batch size.\n\n#### Method `client.instantQuery(query, limit)`\n\nThis function is a shortcut for `client.instantQueryAt(query, limit, time.Now())` where `time.Now()` is the current nanosecond.\n\n#### Method `client.instantQueryAt(query, limit, instant)`\n\nExecute an instant query ([GET /loki/api/v1/query](https://grafana.com/docs/loki/latest/api/#get-lokiapiv1query)).\n\n| argument | type    | description                           | default |\n|----------|---------|---------------------------------------|---------|\n| query    | string  | The LogQL query to perform.           | -       |\n| limit    | integer | Maxiumum number of entries to return. | -       |\n| instant  | integer | Nanosecond at which to execute query. | -       |\n\n#### Method `client.rangeQuery(query, duration, limit)`\n\nThis function is a shortcut for `client.rangeQueryAt(query, duration, limit, time.Now())` where `time.Now()` is the current nanosecond.\n\n#### Method `client.rangeQueryAt(query, duration, limit, instant)`\n\nExecute a range query ([GET /loki/api/v1/query_range](https://grafana.com/docs/loki/latest/api/#get-lokiapiv1query_range)).\n\n| argument | type    | description                                            | default |\n|----------|---------|--------------------------------------------------------|---------|\n| query    | string  | The LogQL query to perform.                            | -       |\n| duration | string  | The time span of the range, e.g. `15m`, `1h`, or `7d`. | -       |\n| limit    | integer | Maxiumum number of entries to return.                  | -       |\n| instant  | integer | Nanosecond at which to execute query.                  | -       |\n\n`duration` defines the range for the query and uses the current timestamp as end and current timestamp - duration as start.\n\n#### Method `client.labelsQuery(duration)`\n\nThis function is a shortcut for `client.labelsQueryAt(duration, time.Now())` where `time.Now()` is the current nanosecond.\n\n#### Method `client.labelsQueryAt(duration, instant)`\n\nExecute a labels query ([GET /loki/api/v1/labels](https://grafana.com/docs/loki/latest/api/#get-lokiapiv1labels)).\n\n| argument | type    | description                                                                   | default |\n|----------|---------|-------------------------------------------------------------------------------|---------|\n| duration | string  | The time span for which labels should be returned, e.g. `15m`, `1h`, or `7d`. | -       |\n| instant  | integer | Nanosecond at which to execute query.                                         | -       |\n\n`duration` defines the range for the query and uses the current timestamp as end and current timestamp - duration as start.\n\n#### Method `client.labelValuesQuery(label, duration)`\n\nThis function is a shortcut for `client.labelValuesQueryAt(label, duration, time.Now())` where `time.Now()` is the current nanosecond.\n\n#### Method `client.labelValuesQueryAt(label, duration, instant)`\n\nExecute a label values query ([GET /loki/api/v1/label/\u003cname\u003e/values](https://grafana.com/docs/loki/latest/api/#get-lokiapiv1labelnamevalues)).\n\n| argument | type    | description                                                                         | default |\n|----------|---------|-------------------------------------------------------------------------------------|---------|\n| label    | string  | The label name for which to query the values.                                       | -       |\n| duration | string  | The time span for which label values should be returned, e.g. `15m`, `1h`, or `7d`. | -       |\n| instant  | integer | Nanosecond at which to execute query.                                               | -       |\n\n`duration` defines the range for the query and uses the current timestamp as end and current timestamp - duration as start.\n\n#### Method `client.seriesQuery(matchers, duration)`\n\nThis function is a shortcut for `client.seriesQueryAt(matchers, duration, time.Now())` where `time.Now()` is the current nanosecond.\n\n#### Method `client.seriesQueryAt(matchers, duration, instant)`\n\nExecute a series query ([GET /loki/api/v1/series](https://grafana.com/docs/loki/latest/api/#series)).\n\n| argument | type    | description                                                                                | default |\n|----------|---------|--------------------------------------------------------------------------------------------|---------|\n| matchers | list    | A list of label matchers used for the query.                                               | -       |\n| duration | string  | The time span for which the matching series should be returned, e.g. `15m`, `1h`, or `7d`. | -       |\n| instant  | integer | Nanosecond at which to execute query.                                                      | -       |\n\n`duration` defines the range for the query and uses the current timestamp as end and current timestamp - duration as start.\n\n## Labels\n\n`xk6-loki` uses the following built-in label names for generating streams:\n\n| name | values | notes |\n| ---- | ------ | ----- |\n| instance | fixed: 1 per k6 worker | |\n| format | fixed: apache_common, apache_combined, apache_error, rfc3164, rfc5424, json, logfmt | This label defines how the log lines of a stream are formatted. |\n| os | fixed: darwin, linux, windows | - |\n| namespace | variable | [^1] |\n| app | variable | [^1] |\n| pod | variable | [^1] |\n| language | variable | [^1] |\n| word | variable | [^1] |\n\n[^1]: The amount of values can be defined in `cardinality` argument of the client configuration.\n\nThe total amount of different streams is defined by the carthesian product of all label values. Keep in mind that high cardinality impacts the performance of the Loki instance.\n\n### Custom labels\n\nAdditionally, `xk6-loki` also supports custom labels that can be used instead\nof the built-in labels.\n\nSee [examples/custom-labels.js](examples/custom-labels.js) for a full example with custom labels.\n\n## Metrics\n\nThe extension collects metrics that are printed in the\n[end-of-test summary](https://k6.io/docs/results-visualization/end-of-test-summary/) in addition to the built-in metrics.\n\n### Query metrics\n\nThese metrics are collected only for instant and range queries.\n\n| name                              | description                                  |\n|-----------------------------------|----------------------------------------------|\n| `loki_bytes_processed_per_second` | amount of bytes processed by Loki per second |\n| `loki_bytes_processed_total`      | total amount of bytes processed by Loki      |\n| `loki_lines_processed_per_second` | amount of lines processed by Loki per second |\n| `loki_lines_processed_total`      | total amount of lines processed by Loki      |\n\n### Write metrics\n\n| name | description |\n| ---- | ----------- |\n| `loki_client_uncompressed_bytes` | the quantity of uncompressed log data pushed to Loki, in bytes |\n| `loki_client_lines` | the number of log lines pushed to Loki |\n\n## Example\n\n```js\nimport sleep from 'k6';\nimport loki from 'k6/x/loki';\n\n/**\n * URL used for push and query requests\n * Path is automatically appended by the client\n * @constant {string}\n */\nconst BASE_URL = `http://localhost:3100`;\n\n/**\n * Client timeout for read and write in milliseconds\n * @constant {number}\n */\nconst timeout = 5000;\n\n/**\n * Ratio between Protobuf and JSON encoded payloads when pushing logs to Loki\n * @constant {number}\n */\nconst ratio = 0.5;\n\n/**\n * Cardinality for labels\n * @constant {object}\n */\nconst cardinality = {\n  \"app\": 5,\n  \"namespace\": 5\n};\n\n/**\n * Execution options\n */\nexport const options = {\n  vus: 10,\n  iterations: 10,\n};\n\n/**\n * Create configuration object\n */\nconst conf = new loki.Config(BASE_URL, timeout, ratio, cardinality);\n\n/**\n * Create Loki client\n */\nconst client = new loki.Client(conf);\n\nexport default () =\u003e {\n  // Push a batch of 2 streams with a payload size between 500KB and 1MB\n  let res = client.pushParameterized(2, 512 * 1024, 1024 * 1024);\n  // A successful push request returns HTTP status 204\n  check(res, { 'successful write': (res) =\u003e res.status == 204 });\n  sleep(1);\n}\n```\n\n```bash\n./k6 run examples/simple.js\n```\n\nYou can find more examples in the [examples/](./examples) folder.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafana%2Fxk6-loki","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrafana%2Fxk6-loki","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafana%2Fxk6-loki/lists"}