Graylog keeps its messages in OpenSearch or Elasticsearch, so you have two routes. Use the Graylog REST API, authenticated with an access token, or query the backend indices (graylog_* by default) directly with a script. Either way you get JSON. The original line is in message, and in full_message for some inputs. The export in the Graylog web interface produces a format LogTotal doesn’t read today.
Graylog is a popular open log management platform, often the first central logging a team sets up. Prime Core has 23,274 detection rules for Graylog, mapped to 671 MITRE ATT&CK techniques. Below is how to get messages out, sanitize them, and investigate them for free in LogTotal.
Before you start
An access token. In Graylog, open your user’s settings and create a token. With the API, you authenticate as <token>:token: the token as the username and the word token as the password.
Backend access, if you go direct. The OpenSearch or Elasticsearch cluster behind Graylog often isn’t reachable from outside. Ask whoever runs it for a read-only account.
Streams and index sets. Graylog routes messages into streams, and streams map to index sets with their own prefixes and retention. Know which index set holds your data.
Option 1: Graylog REST API
GL="https://graylog.example.com"
curl -sS -u "$GL_TOKEN:token" -H 'Accept: application/json' -G "$GL/api/search/universal/absolute" \
--data-urlencode 'query=source:web-03' \
--data-urlencode 'from=2026-10-19T00:00:00.000Z' \
--data-urlencode 'to=2026-10-20T00:00:00.000Z' \
--data-urlencode 'limit=10000' \
| jq -c '.messages[].message' > graylog_web03_1019.jsonl
Newer Graylog versions favor the Views search API. For large exports, Option 2 is more reliable.
Option 2: Query the backend indices
This is the same approach as our pointed at Graylog’s indices:
import json, os
from opensearchpy import OpenSearch, helpers
client = OpenSearch("https://opensearch.example.com:9200",
http_auth=("reader", os.environ["OS_PASSWORD"]), verify_certs=True)
query = {"query": {"bool": {"filter": [
{"term": {"source": "web-03"}},
{"range": {"timestamp": {"gte": "2026-10-19 00:00:00.000", "lt": "2026-10-20 00:00:00.000"}}},
]}}}
with open("graylog_web03_1019.jsonl", "w") as out:
for hit in helpers.scan(client, index="graylog_*", query=query, size=1000):
out.write(json.dumps(hit["_source"]) + "\n")
Graylog stores timestamp as yyyy-MM-dd HH:mm:ss.SSS in UTC, which is why the range uses that format. For a backend running Elasticsearch, use the elasticsearch client the same way.
Upload, sanitize and review in LogTotal
- Upload. Open logtotal.com and drop in the file.
- Sanitize.
- Review.
When it goes wrong
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 from the API | Token auth written wrong | Use <token>:token |
| 404 on the search endpoint | Endpoint not available in your version | Use Option 2, or the Views API |
| Backend query returns nothing | Wrong index prefix, or the timestamp format | Check index sets; use yyyy-MM-dd HH:mm:ss.SSS |
| Backend not reachable | Cluster not exposed | Ask for read-only access, or use the API |
FAQ
Message or full_message?
Message is always there. full_message appears for some inputs, such as GELF, and can hold more detail. Export both if you have them.
Does this work for Graylog Cloud?
The API route does. Direct backend access usually isn’t available on hosted plans.