Quickwit as a service
Quickwit is a modern observability solution compliant with Grafana, Jaegger and OpenTelemetry.
For now it handles logs and traces with an efficiant search engine written in Rust (comparable to Apache Lucene used by Elasticsearch and Apache SolR) and it's able to store the data on object storage in order to lower the price.
Translationsβ
This tutorial is also available in the following languages:
Installation and testsβ
Choose the Quickwit environment:
Once the installation is finished, test the access to Quickwit's GUI with this URL: https://{your_instance_hash}.quickwit.comwork.(cloud|dev|info)
. The default credentials are:
- Username:
quickwit
- Password:
changeit
Then test with the same credentials, the Grafana's access with this URL: https://grafana.{your_instance_hash}.quickwit.comwork.(cloud|dev|info)
The default grafana credentials are:
- Username:
admin
- Password:
admin
Then, you'll be asked to change-it, don't forget to remember-it somewhere safe!
DNS issue with Grafanaβ
If you have some issue to connect with grafana:
- Connect with ssh
- Check if you have DNS issues in the logs of the grafana container:
$ docker logs grafana -f
Error: β failed to download plugin archive: Get "https://github.com/quickwit-oss/quickwit-datasource/releases/download/v0.4.5/quickwit-quickwit-datasource-0.4.5.zip": dial tcp: lookup github.com on 127.0.0.11:53: read udp 127.0.0.1:43845->127.0.0.11:53: i/o timeout
- In this case, enable docker iptables by disabling this flag in the
env/{env_name}.yml
file:
docker_disable_iptables: false
- Then push and wait until Grafana's back. Then revert your previous change
Update your passwordβ
You can change your password in the env/{env_name}.yml
file:
gw_auth_files:
- name: qw.keys
users:
- name: quickwit
passwd: $apr1$M4x65b92$KsQCdoC.BzdBcuTai2MuG0
For generating a new password to copy in the passwd
field:
htpasswd -c .htpasswd.tmp quickwit
cat .htpasswd.tmp | cut -d ":" -f2 # copy the output as passwd
rm -rf .htpasswd.tmp
Change storage to object storageβ
Ask for storage, see this page to get more informations.
Let's suppose you have this bucket created:
With this endpoint on Scaleway: https://qw-indexes-wmb0pz.s3.fr-par.scw.cloud
Fill this variables in the env/{env_name}.yml
file:
quickwit_bucket_access_key_id: access_key_id_value
quickwit_bucket_secret_key: secret_key_id_value
quickwit_bucket_region: fr-par
quickwit_bucket_name: qw-indexes-wmb0pz
quickwit_bucket_endpoint: https://s3.fr-par.scw.cloud
Replace access_key_id_value
and secret_key_id_value
with credentials you'll have generated in your IAM (Identity Access Management).
Go back on Quickwit and check if the changes are applied in the node configuration:
Grafana datasource for logsβ
Go back to Grafana: https://grafana.{your_instance_hash}.quickwit.comwork.(cloud|dev|info)
Add a new connection:
Then search "quickwit" and click on the right plugin:
Then click on "Add new datasource":
Then fill the form:
- Name:
otel-logs-v0_7
- URL:
http://quickwit:7280/api/v1
- Index ID:
otel-logs-v0_7
Then click on "Save and tests":
Then you'll be able to explore the data:
Then you'll be able to run some queries:
As you can see, there's already some logs and traces sent by the imalive container via OpenTelemetry.
Grafana datasources for tracesβ
Create a quickwit datasource the same way:
- Name:
otel-traces-v0_7
- URL:
http://quickwit:7280/api/v1
- Index ID:
otel-traces-v0_7
Create a jaeger datasource:
- Name:
jaeger
- URL:
http://jaeger:16686
Then click on save and tests, and then explore. You'll be able to watch the traces from imalive or quickwit itself:
Correlate logs and tracesβ
Edit the datasources otel-logs-v0_7
and otel-traces-v0_7
in order to add a datalink with the jaeger
datasource:
Then you'll be able to find a datalink when you're exploring the logs :
And when you click on it, you'll be able to watch the associated traces with your logs:
Logs and traces ingestionβ
In addition to the quickwit's API and two OTLP endpoint for grpc and http protocols:
- otlp/grpc:
https://otlp-grpc.{your_instance_hash}.quickwit.comwork.(cloud|dev|info)
- otlp/http:
https://otlp-grpc.{your_instance_hash}.quickwit.comwork.(cloud|dev|info)
Those endpoints are authenticated with the same credentials (defined in the qw.keys
file).
You can directly plug your applications with otlp or continue to send logs via the quickwit /ingest
endpoint.
If you're using docker and you want to index the stdout
and stderr
of your containers, or if you want to index a classic log file produced by an application on the filesystem, we recommand you to use vector.
Here's an example of configuration (file /etc/vector/vector.yaml
) who's ingesting the stdout
and stderr
of docker containers and log files produced by a gitlab instance :
sources:
log_docker:
type: docker_logs
log_files:
type: file
include:
- "/var/opt/gitlab/gitlab-ci/builds/*/*/*.log"
transforms:
remap_app_logs:
inputs:
- "log_files"
- "log_docker"
type: "remap"
source: |
.timestamp_nanos, _ = to_unix_timestamp(.timestamp, unit: "nanoseconds")
.message = string!(.message)
if contains(.message, "error", case_sensitive: false) || contains(.message, "errno", case_sensitive: false) {
.message = replace(.message, r'^ERROR:[^:]*:', "")
.severity_text = "ERROR"
} else if contains(.message, "warn", case_sensitive: false) {
.message = replace(.message, r'^WARNING:[^:]*:', "")
.severity_text = "WARN"
} else if contains(.message, "debug", case_sensitive: false) {
.message = replace(.message, r'^DEBUG:[^:]*:', "")
.severity_text = "DEBUG"
} else {
.message = replace(.message, r'^INFO:[^:]*:', "")
.severity_text = "INFO"
}
.body, err = parse_json(.message)
if err != null || is_null(.body) {
.body = {"message": .message}
} else {
.body.message = .message
}
.resource_attributes.host.hostname, _ = get_hostname()
if is_string(.container_name) {
.service_name = .container_name
.resource_attributes.service.name = .container_name
.body.container_name = .container_name
} else {
.service_name = .resource_attributes.host.hostname
.resource_attributes.service.name = .resource_attributes.host.hostname
}
if is_string(.container_id) {
.body.container_id = del(.container_id)
}
if ! is_null(.container_created_at) {
.body.container_created_at = del(.container_created_at)
}
if is_string(.stream) {
.body.stream = del(.stream)
}
if is_string(.file) {
.body.file = del(.file)
}
if is_string(.host) {
.body.host = del(.host)
}
if is_string(.image) {
.body.image = del(.image)
}
if ! is_null(.label) {
.body.label = del(.label)
}
if is_string(.source_type) {
.resource_attributes.source_type = .source_type
} else if is_string(.container_name) {
.resource_attributes.source_type = "docker"
}
del(.message)
del(.timestamp)
del(.source_type)
del(.container_name)
sinks:
quickwit_logs:
type: "http"
method: "post"
inputs: ["remap_app_logs"]
encoding:
codec: "json"
framing:
method: "newline_delimited"
uri: "https://quickwit:XXXXXXX@quickwit.comwork.io:443/api/v1/otel-logs-v0_7/ingest"
Replace XXXXXXX
by the password defined in qw.keys
.