Translate
Overview
The Translate processor rewrites log messages into another language using a self-hosted LibreTranslate instance, so logs from regional applications and non-English appliances arrive readable for analysts and usable by English-centric detection content.
Translation is a network call per message, which is far too expensive at pipeline rates. The processor is built around a cache, and the cache is what makes the node practical:
- Parts of a message that change every time — timestamps, IP addresses, UUIDs, epoch numbers — are hidden before translation and restored afterwards.
- Two messages that differ only in their timestamp therefore collapse to one cache entry and one call, and each still keeps its own timestamp.
A plain-text body is translated whole. A structured body (JSON object or array) has every text value translated in place — the structure, the field names and any numeric or boolean values are left exactly as they were. Empty and oversized values pass through untouched.
Values that contain no actual words — an id field, a bare timestamp, an IP on
its own — are skipped without a request. Those are usually unique per record,
so translating them would miss the cache every time; give them a masking rule
and they cost nothing.
Supported types: Logs
Configuration
| Parameter | Type | Default | Required | Description |
|---|---|---|---|---|
endpoint | string | — | Yes | Base URL of your LibreTranslate instance, e.g. http://libretranslate:5000. Do not include /translate. |
source_lang | string | — | Yes | The language your logs are in, picked from a dropdown. Automatic detection is not supported. |
target_lang | string | en | Yes | The language to translate into, picked from a dropdown. Must differ from source_lang. |
timeout | duration | 10s | No | Maximum time one request may take. There are no retries. |
target_scope | string | body | No | What to translate: body (the whole log body), attributes (one record attribute) or resource (one resource attribute). |
target_field | string | — | No | Dot-separated path to the field to translate, e.g. user.message. Optional for body (blank means the whole body); required for attributes/resource. |
max_batch_size | integer | 32 | No | Distinct messages per request (1–512). |
cache_size | integer | 100 | No | Translated messages kept in memory. 0 disables caching. |
max_concurrent_requests | integer | 0 | No | Simultaneous requests to LibreTranslate. 0 is unlimited. |
max_text_bytes | integer | 1048576 | No | Values larger than this (1MB) pass through untranslated. |
store_original | boolean | true | No | Copy the untranslated value to an attribute. |
original_attribute | string | translate.original | No | Attribute used when store_original is on. |
masking | object | — | No | Controls which parts of a message are hidden from the translator. |
Masking fields
| Field | Type | Default | Description |
|---|---|---|---|
use_defaults | boolean | true | Mask timestamps (ISO8601, slash-separated dates, syslog, bare clock times), UUIDs, email addresses, IPv4 addresses, hex identifiers and epoch numbers. |
disable | string[] | — | Built-in patterns to turn off, by name. |
rules | object[] | — | Extra {name, pattern} rules, applied after the built-ins. |
max_placeholders | integer | 64 | Messages needing more masked entries than this pass through untranslated. |
placeholder_prefix | string | PRX | Letters used to build the marker standing in for a masked entry. |
Built-in pattern names, in evaluation order:
| Name | Covers |
|---|---|
datetime_iso8601 | ISO8601 / RFC3339, e.g. 2026-09-30T20:20:42.123Z |
datetime_slash | Slash-separated dates with an optional clock, e.g. 2026/09/30 20:20:42, 09/30/2026 |
datetime_syslog | RFC3164, e.g. Oct 5 13:45:01 |
uuid | UUID v1-v5 |
email | Email addresses |
ipv4 | IPv4, with optional :port |
hex_id | 0x-prefixed identifiers, e.g. 0xDA7B7E |
time_hms | A clock with no date, e.g. 20:20:42 |
epoch_millis | 13-digit epoch |
epoch_seconds | 10-digit epoch |
datetime_slash matters more than it looks. Left unmasked, a date written with
slashes is not merely volatile, it is corrupted: the model treats the slashes as
droppable separators, so 2026/09/30 20:20:42 comes back as
2026:30 20:20:42. Windows event logs and Japanese-locale logs write dates this
way throughout.
What gets translated
By default the whole log body is translated: a plain-text body whole, a
structured body value by value. Set target_scope to translate one specific
field instead — inside the body (target_field alone), a record attribute
(target_scope: attributes), or a resource attribute (target_scope: resource). A resource attribute is shared by every log under it, so it is
translated once, not once per log.
Why automatic source detection is not offered
LibreTranslate detects the language once per request, not per message. This
processor deliberately batches many distinct messages into one request, so
automatic detection would apply a single guessed language to the whole batch
and mistranslate anything that disagreed. Set source_lang explicitly; if a
pipeline carries two languages, route them to two Translate nodes.
Behaviour when LibreTranslate is unavailable
The processor never drops a message and never fails a batch. On a timeout
or error response, the affected messages keep their original text and the
failure is counted. Because original_attribute is written to messages that
were actually translated, its presence is a reliable marker of which messages
went through.
Partial translations are kept
If a translation comes back with one of the masking markers missing, the
translation is still used. The hidden value that marker stood for is absent
from the translated text, and a marker the model invented is removed rather
than left visible as PRX7Z. A partly-restored translation is more useful than
none.
Be aware of what this costs: such a message can be missing a timestamp or an IP that your downstream parsing or deduplication relies on, with nothing in the message itself to indicate it. Two things protect you:
- Any message with an incomplete restore keeps its untranslated original in
original_attribute, even if you turnedstore_originaloff. On those messages it is the only complete copy left. - Placeholder Restores on the node counts them under
missingandout_of_range, so you can see the rate rather than discover it in the data.
This cannot be switched off. If complete restoration matters more than
translating at all, lower max_placeholders: a message over the limit passes
through untranslated and completely intact.
Tuning
Watch Cache Hit Rate on the node. A low rate almost always means a volatile span in your logs is not covered by the masking rules — add a rule for it and the rate climbs.
Watch Placeholder Restores for the missing and out_of_range results.
Those messages were translated but lost a hidden value. If they are more than a
trickle, lower max_placeholders first: fewer masked entries per line
translate far more reliably than any change to the marker format.
Set max_concurrent_requests if a busy pipeline can saturate your
LibreTranslate instance; translation is CPU-bound and an unbounded number of
collector goroutines can queue up behind it.
Limitations
- Logs only; metrics and traces are not translated.
- One target at a time: the whole body, one field in the body, one record attribute, or one resource attribute. Translating several fields on the same log needs one node per field, chained.
- Field names in a structured body are treated as structure and are never translated; only their values are.
- One language pair per node.
- No retries — a failed message is retried only the next time the same text arrives.