### Build and Start All Services Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/CONTRIBUTING.md Execute this script to build the project and start all necessary services for development. ```shell ./build_and_start.sh ``` -------------------------------- ### Install Frontend Dependencies and Build Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/CONTRIBUTING.md Install frontend dependencies using npm and build the frontend application. Use `npm run dev` for active development. ```bash $ npm install $ npm run build ``` -------------------------------- ### Install Quickwit Data Source via Grafana CLI Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/src/README.md Use the Grafana CLI to install the Quickwit data source plugin. Ensure you have the CLI installed and configured. ```bash grafana-cli plugins install quickwit-quickwit-datasource ``` -------------------------------- ### Start Storybook Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/CONTRIBUTING.md Launch Storybook to develop and visualize UI components in isolation. This command starts the Storybook development server. ```bash $ npm run storybook ``` -------------------------------- ### Start Grafana Service Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/CONTRIBUTING.md Start only the Grafana service using Docker Compose. Ensure Docker Compose is installed and configured. ```bash $ docker compose up grafana ``` -------------------------------- ### Install Quickwit Datasource v0.3.2 for Quickwit 0.7 Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Install the Quickwit datasource plugin version 0.3.2, compatible with Quickwit 0.7, using the GF_INSTALL_PLUGINS environment variable with the grafana/grafana-oss image. ```bash docker run -p 3000:3000 -e GF_INSTALL_PLUGINS="https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.3.2/quickwit-quickwit-datasource-0.3.2.zip;quickwit-quickwit-datasource" grafana/grafana-oss run ``` -------------------------------- ### Manual Install Quickwit Datasource v0.3.2 for Quickwit 0.7 Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Manually download and unzip the Quickwit datasource plugin version 0.3.2 into the plugins directory. This method is for installations with Quickwit 0.7. ```bash wget https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.3.2/quickwit-quickwit-datasource-0.3.2.zip mkdir -p plugins unzip quickwit-quickwit-datasource-0.3.2.zip -d plugins/quickwit-quickwit-datasource-0.3.2 docker run -p 3000:3000 -e GF_PATHS_PLUGINS=/data/plugins -v ${PWD}/plugins:/data/plugins grafana/grafana-oss run ``` -------------------------------- ### Local Development with Docker Compose Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Starts Quickwit and Grafana with the plugin pre-mounted for local development using Docker Compose. Allows overriding Quickwit and Grafana versions. ```bash # Start Quickwit (port 7280) + Grafana (port 3000) docker compose up # Override versions QUICKWIT_VERSION=0.8.0 GRAFANA_VERSION=11.0.0 docker compose up ``` -------------------------------- ### Install Quickwit Datasource via Docker Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Installs the Quickwit Datasource plugin for Grafana using Docker. Supports Grafana 12.1+ with GF_PLUGINS_PREINSTALL_SYNC and older versions with GF_INSTALL_PLUGINS. ```bash # Grafana 12.1+ (GF_PLUGINS_PREINSTALL_SYNC replaces GF_INSTALL_PLUGINS) docker run -p 3000:3000 \ -e GF_PLUGINS_PREINSTALL_SYNC="quickwit-quickwit-datasource@0.5.0@https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.5.0/quickwit-quickwit-datasource-0.5.0.zip" \ grafana/grafana run # Grafana 11.x docker run -p 3000:3000 \ -e GF_INSTALL_PLUGINS="https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.5.0/quickwit-quickwit-datasource-0.5.0.zip;quickwit-quickwit-datasource" \ grafana/grafana run # Manual install + mount wget https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.5.0/quickwit-quickwit-datasource-0.5.0.zip mkdir -p plugins unzip quickwit-quickwit-datasource-0.5.0.zip -d plugins/quickwit-quickwit-datasource-0.5.0 docker run -p 3000:3000 \ -e GF_PATHS_PLUGINS=/data/plugins \ -v ${PWD}/plugins:/data/plugins \ grafana/grafana run ``` -------------------------------- ### Install Quickwit Datasource v0.4.6 for Grafana 10 Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Install the Quickwit datasource plugin version 0.4.6 for Grafana 10 using the GF_INSTALL_PLUGINS environment variable with the grafana/grafana-oss image. ```bash docker run -p 3000:3000 -e GF_INSTALL_PLUGINS="https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.4.6/quickwit-quickwit-datasource-0.4.6.zip;quickwit-quickwit-datasource" grafana/grafana-oss run ``` -------------------------------- ### Install Quickwit Data Source via Docker Environment Variable Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/src/README.md Configure your Docker environment to automatically install the Quickwit data source plugin. Set the GF_INSTALL_PLUGINS environment variable with the plugin ID. ```bash GF_INSTALL_PLUGINS="quickwit-quickwit-datasource" ``` -------------------------------- ### Install Quickwit Datasource v0.5.0 for Grafana 11 Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Use the GF_INSTALL_PLUGINS environment variable to install the Quickwit datasource plugin version 0.5.0 for Grafana 11. Ensure the URL and plugin name are correctly specified. ```bash docker run -p 3000:3000 -e GF_INSTALL_PLUGINS="https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.5.0/quickwit-quickwit-datasource-0.5.0.zip;quickwit-quickwit-datasource" grafana/grafana run ``` -------------------------------- ### Install Quickwit Datasource v0.5.0 for Grafana 12.1 Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Use GF_PLUGINS_PREINSTALL_SYNC to install the Quickwit datasource plugin version 0.5.0 when running Grafana 12.1. This method is preferred over GF_INSTALL_PLUGINS for newer Grafana versions. ```bash docker run -p 3000:3000 -e GF_PLUGINS_PREINSTALL_SYNC="quickwit-quickwit-datasource@0.5.0@https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.5.0/quickwit-quickwit-datasource-0.5.0.zip" grafana/grafana run ``` -------------------------------- ### Manual Install Quickwit Datasource v0.4.6 for Grafana 10 Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Manually download and unzip the Quickwit datasource plugin version 0.4.6 into the plugins directory for Grafana 10 installations. ```bash wget https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.4.6/quickwit-quickwit-datasource-0.4.6.zip mkdir -p plugins unzip quickwit-quickwit-datasource-0.4.6.zip -d plugins/quickwit-quickwit-datasource-0.4.6 docker run -p 3000:3000 -e GF_PATHS_PLUGINS=/data/plugins -v ${PWD}/plugins:/data/plugins grafana/grafana-oss run ``` -------------------------------- ### Manual Install Quickwit Datasource v0.5.0 for Grafana 12.1 Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Manually download and unzip the Quickwit datasource plugin version 0.5.0 into the Grafana plugins directory. This is an alternative installation method for Grafana 12.1. ```bash wget https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.5.0/quickwit-quickwit-datasource-0.5.0.zip mkdir -p plugins unzip quickwit-quickwit-datasource-0.5.0.zip -d plugins/quickwit-quickwit-datasource-0.5.0 docker run -p 3000:3000 -e GF_PATHS_PLUGINS=/data/plugins -v ${PWD}/plugins:/data/plugins grafana/grafana run ``` -------------------------------- ### BaseQuickwitDataSource.getFields() Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Fetches Quickwit `_field_caps` API to get a list of field names and their types. Used for populating field pickers and filter operators. ```APIDOC ## `BaseQuickwitDataSource.getFields()` ### Description Fetches the Quickwit `_field_caps` API for the configured index and returns a list of field names with their types. Used to populate field pickers in the query editor and to resolve appropriate filter operators. Results are cached on the datasource instance to speed up `modifyQuery`. ### Method `getFields(options?: { aggregatable?: boolean; type?: string[]; range?: TimeRange })` ### Parameters #### Options - **aggregatable** (boolean) - Optional - If true, returns only aggregatable fields. - **type** (string[]) - Optional - An array of field types to filter by (e.g., ['keyword', 'text']). - **range** (TimeRange) - Optional - The time range to consider for field capabilities. ### Request Example ```typescript // Get all aggregatable fields ds.getFields({ aggregatable: true }).subscribe({ next: (fields) => { // [{ text: 'severity_text', type: 'keyword' }, { text: 'duration_millis', type: 'f64' }, ...] console.log(fields); }, }); // Get only keyword/text fields within a specific time range ds.getFields({ type: ['keyword', 'text'], range: getDefaultTimeRange(), }).subscribe({ next: (fields) => fields.forEach(f => console.log(f.text, f.type)), }); // Get all fields (no filter) ds.getFields({}).subscribe({ next: (fields) => console.log(`Index has ${fields.length} fields`), }); ``` ### Response #### Success Response (200) - **fields** (Array<{ text: string; type: string }>) - An array of objects, where each object represents a field with its name (`text`) and type (`type`). ``` -------------------------------- ### Get Fields with BaseQuickwitDataSource.getFields() Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Fetches field capabilities from the Quickwit API, used for populating query editor pickers and resolving filter operators. Results are cached. You can filter by aggregatable status, field type, and time range. ```typescript import { getDefaultTimeRange } from '@grafana/data'; // Get all aggregatable fields (fast fields) — used for ad-hoc filter key suggestions ds.getFields({ aggregatable: true }).subscribe({ next: (fields) => { // [{ text: 'severity_text', type: 'keyword' }, { text: 'duration_millis', type: 'f64' }, ...] console.log(fields); }, }); // Get only keyword/text fields within a specific time range ds.getFields({ type: ['keyword', 'text'], range: getDefaultTimeRange(), }).subscribe({ next: (fields) => fields.forEach(f => console.log(f.text, f.type)), }); // Get all fields (no filter) ds.getFields({}).subscribe({ next: (fields) => console.log(`Index has ${fields.length} fields`), }); ``` -------------------------------- ### Get Terms with BaseQuickwitDataSource.getTerms() Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Queries for distinct field values using a terms aggregation, powering template variable dropdowns and ad-hoc filter value suggestions. You can specify field, query filters, ordering, and size. ```typescript import { getDefaultTimeRange } from '@grafana/data'; // Get top 100 unique values of 'service_name', filtered to ERROR logs ds.getTerms( { field: 'service_name', query: 'severity_text:ERROR', orderBy: 'doc_count', // '_count' ordering — most-frequent first order: 'desc', size: 50, }, getDefaultTimeRange() ).subscribe({ next: (values) => { // [{ text: 'checkout', value: 'checkout' }, { text: 'auth', value: 'auth' }, ...] console.log(values); }, }); // Get values ordered alphabetically (key ordering, default) ds.getTerms({ field: 'http_method' }).subscribe({ next: (values) => console.log(values.map(v => v.text)), // ['DELETE', 'GET', 'POST', 'PUT'] }); ``` -------------------------------- ### Execute Backend Multi-Search (Go) Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Serializes search requests into Quickwit's Elasticsearch-compatible NDJSON format, sends the request, and returns raw JSON responses. Requires a configured DatasourceInfo and a new client. ```go import ( "context" "time" es "github.com/quickwit-oss/quickwit-datasource/pkg/quickwit/client" ) dsInfo := &es.DatasourceInfo{ URL: "http://localhost:7280/api/v1", Database: "hdfs-logs", HTTPClient: &http.Client{Timeout: 30 * time.Second}, MaxConcurrentShardRequests: 5, } client, err := es.NewClient(context.Background(), dsInfo) if err != nil { panic(err) } // Build two search requests as part of a multi-search ms := es.NewMultiSearchRequestBuilder() b1 := ms.Search(500 * time.Millisecond) b1.Size(0) b1.Query().Bool().Filter().AddQueryStringFilter("severity_text:ERROR", true, "AND") b1.Agg().DateHistogram("1", "timestamp", func(a *es.DateHistogramAgg, b es.AggBuilder) { a.FixedInterval = "1m" a.MinDocCount = 0 }) requests, _ := ms.Build() rawResponses, err := client.ExecuteMultisearch(requests) if err != nil { // e.g. `{"Status":400,"Message":"Error on multisearch","ResponseBody":...}` panic(err) } // rawResponses[0] is *json.RawMessage — decoded by response_parser.go ``` -------------------------------- ### Run Backend Tests Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/CONTRIBUTING.md Execute the backend tests using the Go test command. The `-v` flag enables verbose output for all tests in the specified package. ```bash $ go test -v ./pkg/... ``` -------------------------------- ### New Quickwit Datasource Go Constructor Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt The Go backend entry point for creating a new Quickwit datasource instance. It discovers the timestamp field by querying the Quickwit `/indexes` API. ```go package main import ( "context" "github.com/grafana/grafana-plugin-sdk-go/backend" quickwit "github.com/quickwit-oss/quickwit-datasource/pkg/quickwit" ) // Grafana SDK calls this factory — not invoked manually. // Shown here for illustration: settings := backend.DataSourceInstanceSettings{ ID: 42, URL: "http://quickwit-host:7280/api/v1", JSONData: []byte(`{ "index": "otel-logs-v0", "logMessageField": "body.message", "logLevelField": "severity_text", "maxConcurrentShardRequests": 256 }`), } instance, err := quickwit.NewQuickwitDatasource(context.Background(), settings) if err != nil { // Startup failures are surfaced to Grafana; the ready channel // will carry the error to health-check and query handlers. panic(err) } d := instance.(*quickwit.QuickwitDatasource) // ds is ready; timestamp field discovered asynchronously via goroutine ``` -------------------------------- ### Run Frontend Tests Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/CONTRIBUTING.md Execute the frontend test suite using npm. This command runs all defined frontend tests. ```bash $ npm run test ``` -------------------------------- ### Configure Quickwit Datasource via YAML Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Declaratively configures the Quickwit datasource using a YAML provisioning file. Specifies the Quickwit API URL, index, and optional log message/level fields. ```yaml # provisioning/datasources/quickwit.yaml apiVersion: 1 datasources: - name: Quickwit type: quickwit-quickwit-datasource # Quickwit API base URL — must end with /api/v1 url: http://localhost:7280/api/v1 jsonData: index: 'hdfs-logs' # Required: Quickwit index ID (wildcards supported, e.g. "otel-logs-*") logMessageField: body # Optional: field shown as log line in Explore view logLevelField: severity_text # Optional: fast field used for log level coloring queryEditorConfig: defaults: 'metricAggregation.logs.settings.limit': '200' # Default row limit in logs queries ``` -------------------------------- ### Run Mage Backend Build Command Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/CONTRIBUTING.md Use the Mage build tool to compile and manage backend tasks. The `-v` flag provides verbose output. ```bash $ mage -v ``` -------------------------------- ### Execute Logs Query with QuickwitDataSource Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Demonstrates how to programmatically execute a logs query using the QuickwitDataSource instance. This method is also used internally by Grafana panels. Ensure you have the necessary imports and a DataSource instance. ```typescript import { QuickwitDataSource } from 'datasource'; // Grafana creates this; shown here for illustration. // All Grafana DataSourceWithBackend methods are available. declare const ds: QuickwitDataSource; // Execute a logs query programmatically (also used internally by Grafana panels) import { getDefaultTimeRange } from '@grafana/data'; const request = { targets: [{ refId: 'A', query: 'severity_text:ERROR AND service_name:checkout', metrics: [{ id: '1', type: 'logs', settings: { limit: '50' } }], }], range: getDefaultTimeRange(), // ...other DataQueryRequest fields }; ds.query(request).subscribe({ next: (response) => { // response.data is DataFrame[] // Each DataFrame has a $qw_message field prepended by processLogsDataFrame() console.log(response.data[0].fields.map(f => f.name)); // ['Time', '$qw_message', 'severity_text', 'body', ...] }, error: (err) => console.error('Query failed', err), }); ``` -------------------------------- ### Fetch Index Metadata and Timestamp Info (Go) Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Fetches index metadata using a wildcard pattern and extracts timestamp field information. Ensures all matching indexes have identical timestamp configurations. ```go import ( "net/http" quickwit "github.com/quickwit-oss/quickwit-datasource/pkg/quickwit" ) cli := &http.Client{} qwURL := "http://localhost:7280/api/v1" // Fetch metadata for all indexes matching "otel-logs-*" metadataList, err := quickwit.GetIndexesMetadata("otel-logs-*", qwURL, cli) if err != nil { // e.g. "API returned invalid response: error = ..." panic(err) } // Extract the single timestamp field name + output format // (validates all indexes have the same timestamp config) timeField, outputFormat, err := quickwit.GetTimestampFieldInfos(metadataList) if err != nil { // e.g. "Indexes matching pattern have incompatible timestamp fields, // found: timestamp_nanos (unix_timestamp_nanos) and ts (unix_timestamp_secs)" panic(err) } // timeField → "timestamp_nanos" // outputFormat → "unix_timestamp_nanos" or "rfc3339" etc. ``` -------------------------------- ### Configure Quickwit Datasource with YAML Source: https://github.com/quickwit-oss/quickwit-datasource/blob/main/README.md Use this YAML configuration to set up the Quickwit datasource in Grafana. Specify the Quickwit API URL, index name, and optional log message and level fields. ```yaml apiVersion: 1 datasources: - name: Quickwit type: quickwit-quickwit-datasource url: http://localhost:7280/api/v1 jsonData: index: 'hdfs-logs' logMessageField: body logLevelField: severity_text ``` -------------------------------- ### Fetch Log Context with LogContextProvider Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Retrieves surrounding log lines before or after a selected log row in Grafana Explore. It utilizes Quickwit's `search_after` mechanism for pagination. ```typescript import { LogContextProvider, LogRowContextQueryDirection } from 'LogContext/LogContextProvider'; import { LogRowModel } from '@grafana/data'; const provider = new LogContextProvider(ds); // Simulated log row selected in Explore const row: LogRowModel = { timeEpochMs: 1700000000000, timeEpochNs: '1700000000000000000', rowIndex: 5, dataFrame: { refId: 'A', fields: [ { name: 'sort', values: { get: () => [1700000000000000000n] } }, ], }, } as any; // Fetch 10 lines before the selected log (default direction: BACKWARD) const contextBefore = await provider.getLogRowContext(row, { direction: LogRowContextQueryDirection.Backward, limit: 10, }); // contextBefore.data: DataFrame[] — each frame contains the preceding log lines // Fetch 20 lines after the selected log const contextAfter = await provider.getLogRowContext(row, { direction: LogRowContextQueryDirection.Forward, limit: 20, }); ``` -------------------------------- ### Generate Log Volume Histogram Query Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt The `withSupplementaryQueries` mixin provides `getSupplementaryQuery()` and `getLogsVolumeDataProvider()`. `getLogsVolumeDataProvider` auto-generates a `date_histogram` aggregation query for the Explore log volume panel. ```typescript import { SupplementaryQueryType } from '@grafana/data'; import { ElasticsearchQuery } from 'types'; // A standard logs query targeting the datasource const logsTarget: ElasticsearchQuery = { refId: 'A', query: 'service_name:checkout', metrics: [{ id: '1', type: 'logs' }], }; // Grafana calls this internally; shown for illustration: const volumeQuery = ds.getSupplementaryQuery( { type: SupplementaryQueryType.LogsVolume }, logsTarget ); /* volumeQuery = { refId: 'log-volume-A', query: 'service_name:checkout', metrics: [{ type: 'count', id: '1' }], bucketAggs: [ // If ds.logLevelField is set, a terms agg on that field comes first: { id: '2', type: 'terms', field: 'severity_text', settings: { size: '0', order: 'desc', orderBy: '_count' } }, // Always includes a date_histogram agg on the time field: { id: '3', type: 'date_histogram', field: '', settings: { interval: 'auto', min_doc_count: '0', trimEdges: '0' } }, ], } */ // The volume observable (used by Grafana automatically): const volumeObservable = ds.getLogsVolumeDataProvider(request); volumeObservable?.subscribe({ next: (response) => { // response.data contains stacked bar chart DataFrames per log level }, }); ``` -------------------------------- ### QuickwitDataSource.query() Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Executes a logs query against Quickwit. This method is used both internally by Grafana panels and can be called programmatically. ```APIDOC ## `QuickwitDataSource.query()` ### Description Executes a logs query against Quickwit. This method is used both internally by Grafana panels and can be called programmatically. ### Method `query(request: DataQueryRequest)` ### Parameters #### Request Body - **targets** (array) - Required - The query targets to execute. - **refId** (string) - Required - The reference ID of the target. - **query** (string) - Required - The Lucene query string. - **metrics** (array) - Optional - Metrics to apply to the query. - **id** (string) - Required - The ID of the metric. - **type** (string) - Required - The type of metric (e.g., 'logs'). - **settings** (object) - Optional - Settings for the metric. - **limit** (string) - Optional - The maximum number of results to return. - **range** (TimeRange) - Required - The time range for the query. ### Request Example ```json { "targets": [ { "refId": "A", "query": "severity_text:ERROR AND service_name:checkout", "metrics": [ { "id": "1", "type": "logs", "settings": { "limit": "50" } } ] } ], "range": { "from": "2023-10-27T10:00:00.000Z", "to": "2023-10-27T12:00:00.000Z", "raw": { "from": "now-2h", "to": "now" } } } ``` ### Response #### Success Response (200) - **data** (DataFrame[]) - An array of DataFrames containing the query results. - Each DataFrame has a `$qw_message` field prepended by `processLogsDataFrame()`. #### Response Example ```json { "data": [ { "fields": [ { "name": "Time" }, { "name": "$qw_message" }, { "name": "severity_text" }, { "name": "body" } ] } ] } ``` ``` -------------------------------- ### ExecuteMultisearch Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt The low-level Go client method that serializes one or more `SearchRequest` objects into Quickwit's Elasticsearch-compatible `_elastic/_msearch` NDJSON format, sends the HTTP request, and returns the raw JSON responses for downstream parsing. ```APIDOC ## `ExecuteMultisearch` — Backend multi-search client (Go) The low-level Go client method that serializes one or more `SearchRequest` objects into Quickwit's Elasticsearch-compatible `_elastic/_msearch` NDJSON format, sends the HTTP request, and returns the raw JSON responses for downstream parsing. ```go import ( "context" "time" es "github.com/quickwit-oss/quickwit-datasource/pkg/quickwit/client" ) dsInfo := &es.DatasourceInfo{ URL: "http://localhost:7280/api/v1", Database: "hdfs-logs", HTTPClient: &http.Client{Timeout: 30 * time.Second}, MaxConcurrentShardRequests: 5, } client, err := es.NewClient(context.Background(), dsInfo) if err != nil { panic(err) } // Build two search requests as part of a multi-search ms := es.NewMultiSearchRequestBuilder() b1 := ms.Search(500 * time.Millisecond) b1.Size(0) b1.Query().Bool().Filter().AddQueryStringFilter("severity_text:ERROR", true, "AND") b1.Agg().DateHistogram("1", "timestamp", func(a *es.DateHistogramAgg, b es.AggBuilder) { a.FixedInterval = "1m" a.MinDocCount = 0 }) requests, _ := ms.Build() rawResponses, err := client.ExecuteMultisearch(requests) if err != nil { // e.g. `{"Status":400,"Message":"Error on multisearch","ResponseBody":...}` panic(err) } // rawResponses[0] is *json.RawMessage — decoded by response_parser.go ``` ``` -------------------------------- ### BaseQuickwitDataSource.metricFindQuery() Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Resolves Grafana template variable queries. Supports finding fields or terms within a specified time range. ```APIDOC ## `BaseQuickwitDataSource.metricFindQuery()` ### Description Resolves Grafana template variable queries. Supports two `find` modes: `"fields"` (returns field names) and `"terms"` (returns field values). The query string is JSON. ### Method `metricFindQuery(query: string, options: { range: TimeRange })` ### Parameters #### Query - **query** (string) - Required - A JSON string representing the template variable query. Supported modes are `"fields"` and `"terms"`. - **find** (string) - Required - The mode for the query (`"fields"` or `"terms"`). - **field** (string) - Required for `"terms"` mode - The field to retrieve values for. - **type** (string[]) - Optional for `"fields"` mode - An array of field types to filter by. - **query** (string) - Optional for `"terms"` mode - A Lucene query string to pre-filter the terms. #### Options - **range** (TimeRange) - Required - The time range for the query. ### Request Example ```typescript const range = getDefaultTimeRange(); // Find all aggregatable keyword fields const fieldNames = await ds.metricFindQuery( JSON.stringify({ find: 'fields', type: ['keyword'], }), { range } ); // [{ text: 'service_name', value: 'service_name' }, ...] // Find all unique values of the 'env' field, filtered by current variable selections const envValues = await ds.metricFindQuery( JSON.stringify({ find: 'terms', field: 'env', query: 'region:us-east-1', }), { range } ); // [{ text: 'production', value: 'production' }, { text: 'staging', value: 'staging' }] ``` ### Response #### Success Response (200) - **results** (Array<{ text: string; value: string }>) - An array of objects, where each object represents a found field name or term value, with `text` and `value` properties. ``` -------------------------------- ### GetIndexesMetadata and GetTimestampFieldInfos Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Fetches index metadata from Quickwit's REST API and extracts the timestamp field name and its output format. Supports wildcard index patterns. If multiple indexes match the pattern, all must have identical timestamp field configurations; a mismatch returns an error. ```APIDOC ## `GetIndexesMetadata` / `GetTimestampFieldInfos` — Index introspection (Go) Fetches index metadata from Quickwit's REST API and extracts the timestamp field name and its output format. Supports wildcard index patterns. If multiple indexes match the pattern, all must have identical timestamp field configurations; a mismatch returns an error. ```go import ( "net/http" quickwit "github.com/quickwit-oss/quickwit-datasource/pkg/quickwit" ) cli := &http.Client{} qwURL := "http://localhost:7280/api/v1" // Fetch metadata for all indexes matching "otel-logs-*" metadataList, err := quickwit.GetIndexesMetadata("otel-logs-*", qwURL, cli) if err != nil { // e.g. "API returned invalid response: error = ..." panic(err) } // Extract the single timestamp field name + output format // (validates all indexes have the same timestamp config) timeField, outputFormat, err := quickwit.GetTimestampFieldInfos(metadataList) if err != nil { // e.g. "Indexes matching pattern have incompatible timestamp fields, // found: timestamp_nanos (unix_timestamp_nanos) and ts (unix_timestamp_secs)" panic(err) } // timeField → "timestamp_nanos" // outputFormat → "unix_timestamp_nanos" or "rfc3339" etc. ``` ``` -------------------------------- ### QuickwitOptions Type for Frontend Configuration Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Defines the TypeScript interface for `jsonData` in Grafana's datasource settings. Controls index targeting, log rendering, data links, and editor defaults. ```typescript import { QuickwitOptions } from 'quickwit'; import { DataSourceInstanceSettings } from '@grafana/data'; // Shape of options stored as jsonData in datasource settings const exampleOptions: QuickwitOptions = { index: 'otel-logs-v0', // Quickwit index ID (required) logMessageField: 'body.message', // Comma-separated list of fields to concatenate as log line logLevelField: 'severity_text', // Fast field for log level (critical/error/warning/info/debug) dataLinks: [ { field: 'trace_id', url: 'http://localhost:16686/trace/${__value.raw}', urlDisplayLabel: 'View in Jaeger', }, ], queryEditorConfig: { defaults: { 'metricAggregation.logs.settings.limit': '500', }, }, }; // The constructor reads jsonData automatically from instanceSettings // QuickwitDataSource is instantiated by Grafana's plugin system, not manually. const instanceSettings: DataSourceInstanceSettings = { jsonData: exampleOptions, // ...other Grafana fields } as any; ``` -------------------------------- ### Test Datasource Health Check Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Validates the datasource configuration by calling the backend health-check endpoint. This verifies the Quickwit index exists and has a valid timestamp field. ```typescript // Called automatically when user clicks "Save & test" in the datasource config UI. // Can also be triggered programmatically: const result = await ds.testDatasource(); // Success: { status: 'ok', message: 'plugin is running' } // Error (bad index): { status: 'error', message: 'Failed to initialize datasource: no index found for my-index' } // Error (missing timestamp): { status: 'error', message: 'timefield is missing from index config "my-index"' } if (result.status !== 'ok') { console.error('Datasource unhealthy:', result.message); } ``` -------------------------------- ### Metric Find Query with BaseQuickwitDataSource.metricFindQuery() Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Resolves Grafana template variable queries, supporting 'fields' and 'terms' find modes. The query string must be JSON. This method is useful for dynamically populating variable options based on data. ```typescript import { getDefaultTimeRange } from '@grafana/data'; const range = getDefaultTimeRange(); // Find all aggregatable keyword fields — use as variable options const fieldNames = await ds.metricFindQuery( JSON.stringify({ find: 'fields', type: ['keyword'] }), { range } ); // [{ text: 'service_name', value: 'service_name' }, ...] // Find all unique values of the 'env' field — filtered by current variable selections const envValues = await ds.metricFindQuery( JSON.stringify({ find: 'terms', field: 'env', query: 'region:us-east-1', // optional Lucene pre-filter }), { range } ); // [{ text: 'production', value: 'production' }, { text: 'staging', value: 'staging' }] ``` -------------------------------- ### processLogsDataFrame Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Mutates a Grafana `DataFrame` returned from a logs query to prepend a computed `$qw_message` field (the human-readable log line) and attach configured data links to their target fields. It supports single message fields, multi-field concatenation, and an OTel-aware fallback that assembles a `key=value` string from non-metadata fields. ```APIDOC ## `processLogsDataFrame` — Log response post-processing (TypeScript) Mutates a Grafana `DataFrame` returned from a logs query to prepend a computed `$qw_message` field (the human-readable log line) and attach configured data links to their target fields. It supports single message fields, multi-field concatenation, and an OTel-aware fallback that assembles a `key=value` string from non-metadata fields. ```typescript import { processLogsDataFrame } from 'datasource/processResponse'; import { FieldType, DataFrame } from '@grafana/data'; // This is called automatically inside QuickwitDataSource.query() // Manual usage for testing/custom processing: const mockDataFrame: DataFrame = { refId: 'A', length: 2, fields: [ { name: 'timestamp', type: FieldType.time, config: {}, values: [1700000000000, 1700000001000] }, { name: 'body.message', type: FieldType.string, config: {}, values: ['Connection refused', 'Timeout'] }, { name: 'service_name', type: FieldType.string, config: {}, values: ['auth', 'checkout'] }, { name: 'severity_text', type: FieldType.string, config: {}, values: ['ERROR', 'WARN'] }, ], }; // ds.logMessageField = 'body.message', ds.dataLinks = [] processLogsDataFrame(ds, mockDataFrame); // After processing, $qw_message is inserted as the second field: // mockDataFrame.fields[1].name === '$qw_message' // mockDataFrame.fields[1].values[0] === 'Connection refused' // mockDataFrame.fields[1].values[1] === 'Timeout' ``` ``` -------------------------------- ### Process Logs DataFrame (TypeScript) Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Mutates a Grafana DataFrame to prepend a computed '$qw_message' field and attach data links. Supports various message field configurations and an OTel-aware fallback. ```typescript import { processLogsDataFrame } from 'datasource/processResponse'; import { FieldType, DataFrame } from '@grafana/data'; // This is called automatically inside QuickwitDataSource.query() // Manual usage for testing/custom processing: const mockDataFrame: DataFrame = { refId: 'A', length: 2, fields: [ { name: 'timestamp', type: FieldType.time, config: {}, values: [1700000000000, 1700000001000] }, { name: 'body.message', type: FieldType.string, config: {}, values: ['Connection refused', 'Timeout'] }, { name: 'service_name', type: FieldType.string, config: {}, values: ['auth', 'checkout'] }, { name: 'severity_text', type: FieldType.string, config: {}, values: ['ERROR', 'WARN'] }, ], }; // ds.logMessageField = 'body.message', ds.dataLinks = [] processLogsDataFrame(ds, mockDataFrame); // After processing, $qw_message is inserted as the second field: // mockDataFrame.fields[1].name === '$qw_message' // mockDataFrame.fields[1].values[0] === 'Connection refused' // mockDataFrame.fields[1].values[1] === 'Timeout' ``` -------------------------------- ### BaseQuickwitDataSource.getTerms() Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Queries for distinct values of a field using a terms aggregation. Powers template variable dropdowns and ad-hoc filter value suggestions. ```APIDOC ## `BaseQuickwitDataSource.getTerms()` ### Description Queries for the distinct values of a field using a terms aggregation. Powers template variable dropdowns and ad-hoc filter value suggestions. ### Method `getTerms(options: { field: string; query?: string; orderBy?: string; order?: 'asc' | 'desc'; size?: number }, range: TimeRange)` ### Parameters #### Options - **field** (string) - Required - The field to retrieve terms for. - **query** (string) - Optional - A Lucene query string to filter the terms. - **orderBy** (string) - Optional - The field to order the terms by. Common values include 'doc_count' or '_count'. Defaults to '_key'. - **order** ('asc' | 'desc') - Optional - The order of sorting. Defaults to 'asc'. - **size** (number) - Optional - The maximum number of terms to return. Defaults to 10. #### Range - **range** (TimeRange) - Required - The time range for the query. ### Request Example ```typescript // Get top 50 unique values of 'service_name', filtered to ERROR logs, ordered by document count descending ds.getTerms( { field: 'service_name', query: 'severity_text:ERROR', orderBy: 'doc_count', order: 'desc', size: 50, }, getDefaultTimeRange() ).subscribe({ next: (values) => { // [{ text: 'checkout', value: 'checkout' }, { text: 'auth', value: 'auth' }, ...] console.log(values); }, }); // Get values ordered alphabetically (key ordering, default) ds.getTerms({ field: 'http_method' }).subscribe({ next: (values) => console.log(values.map(v => v.text)), // ['DELETE', 'GET', 'POST', 'PUT'] }); ``` ### Response #### Success Response (200) - **values** (Array<{ text: string; value: string }>) - An array of objects, where each object represents a unique value of the field, with `text` and `value` properties. ``` -------------------------------- ### Interactive Log Filtering with modifyQuery and toggleQueryFilter Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt These methods are used for interactive log filtering within Grafana. `modifyQuery` handles legacy action types like ADD_FILTER and ADD_FILTER_OUT, while `toggleQueryFilter` is a newer interface for dashboard Logs panels that adds or removes filters. ```APIDOC ## `BaseQuickwitDataSource.modifyQuery()` / `toggleQueryFilter()` — Interactive log filtering Used by Grafana's Explore view when a user clicks a field value in a log line to add or exclude it as a filter. `modifyQuery` handles the legacy `ADD_FILTER` / `ADD_FILTER_OUT` action types. `toggleQueryFilter` is the newer interface used by dashboard Logs panels; it removes the filter if already present, otherwise adds it. ```typescript import { ElasticsearchQuery } from 'types'; const baseQuery: ElasticsearchQuery = { refId: 'A', query: 'region:us-east-1', metrics: [{ id: '1', type: 'logs' }], filters: [], }; // Add a positive filter via modifyQuery (Explore click) const filtered = ds.modifyQuery(baseQuery, { type: 'ADD_FILTER', options: { key: 'severity_text', value: 'ERROR' }, }); // filtered.filters => [{ id: '...', filter: { key: 'severity_text', operator: '=', value: 'ERROR' } }] // Add a negative (exclusion) filter const excluded = ds.modifyQuery(baseQuery, { type: 'ADD_FILTER_OUT', options: { key: 'service_name', value: 'noisy-service' }, }); // excluded.filters => [{ filter: { key: 'service_name', operator: '!=', value: 'noisy-service' } }] // Toggle filter on/off via Logs panel (newer API) const toggled = ds.toggleQueryFilter(filtered, { type: 'FILTER_FOR', options: { key: 'severity_text', value: 'ERROR' }, }); // Removes the filter since it was already present -> toggled.filters => [] ``` ``` -------------------------------- ### Modify Query and Toggle Filter for Log Filtering Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt Use `modifyQuery` for legacy filter actions and `toggleQueryFilter` for newer dashboard log panel interactions. These methods help add or remove filters based on clicked log field values. ```typescript import { ElasticsearchQuery } from 'types'; const baseQuery: ElasticsearchQuery = { refId: 'A', query: 'region:us-east-1', metrics: [{ id: '1', type: 'logs' }], filters: [], }; // Add a positive filter via modifyQuery (Explore click) const filtered = ds.modifyQuery(baseQuery, { type: 'ADD_FILTER', options: { key: 'severity_text', value: 'ERROR' }, }); // filtered.filters => [{ id: '...', filter: { key: 'severity_text', operator: '=', value: 'ERROR' } }] // Add a negative (exclusion) filter const excluded = ds.modifyQuery(baseQuery, { type: 'ADD_FILTER_OUT', options: { key: 'service_name', value: 'noisy-service' }, }); // excluded.filters => [{ filter: { key: 'service_name', operator: '!=', value: 'noisy-service' } }] // Toggle filter on/off via Logs panel (newer API) const toggled = ds.toggleQueryFilter(filtered, { type: 'FILTER_FOR', options: { key: 'severity_text', value: 'ERROR' }, }); // Removes the filter since it was already present -> toggled.filters => [] ``` -------------------------------- ### Datasource Health Check with testDatasource Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt This method validates the datasource configuration by calling the backend health-check endpoint. It verifies the index existence and the presence of a valid timestamp field. ```APIDOC ## `BaseQuickwitDataSource.testDatasource()` — Health check Validates the datasource configuration by calling the backend health-check endpoint, which in turn queries the Quickwit `/indexes` API to verify the index exists and has a valid timestamp field. ```typescript // Called automatically when user clicks "Save & test" in the datasource config UI. // Can also be triggered programmatically: const result = await ds.testDatasource(); // Success: { status: 'ok', message: 'plugin is running' } // Error (bad index): { status: 'error', message: 'Failed to initialize datasource: no index found for my-index' } // Error (missing timestamp): { status: 'error', message: 'timefield is missing from index config "my-index"' } if (result.status !== 'ok') { console.error('Datasource unhealthy:', result.message); } ``` ``` -------------------------------- ### Ad-hoc Filter Injection with addAdHocFilters Source: https://context7.com/quickwit-oss/quickwit-datasource/llms.txt This method applies a set of ad-hoc variable filters from Grafana dashboard ad-hoc variables to a raw Lucene query string. It automatically selects the correct Lucene operator based on the field's type. ```APIDOC ## `BaseQuickwitDataSource.addAdHocFilters()` — Ad-hoc filter injection Applies a set of ad-hoc variable filters (from Grafana dashboard ad-hoc variables) to a raw Lucene query string, automatically choosing the correct Lucene operator based on each field's type (`=` vs `term` for text fields). ```typescript // Internal usage — called automatically by applyTemplateVariables() // Can also be used directly: const filtersFromDashboard = [ { key: 'env', operator: '=', value: 'production' }, { key: 'service_name', operator: '!=', value: 'legacy-api' }, { key: 'body.message', operator: '=', value: 'timeout' }, // text field → becomes 'term' operator ]; const baseQuery = 'severity_text:ERROR'; const finalQuery = ds.addAdHocFilters(baseQuery, filtersFromDashboard); // Result: 'severity_text:ERROR AND env:"production" AND -service_name:"legacy-api" AND body.message term timeout' ``` ```