Skip to content
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
30b0ed3
Adding EcsNamespacingProcessor
eyalkoren Mar 26, 2025
b96cc0c
Adding module-info
eyalkoren Mar 27, 2025
469df61
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren Mar 27, 2025
2bd819f
Exposing and testing the processor
eyalkoren Mar 27, 2025
1c2a670
Add test and some algorithm fixes
eyalkoren Mar 27, 2025
904c19c
Making scope non-mandatory
eyalkoren Mar 27, 2025
bd75b06
Minimize dependencies
eyalkoren Mar 27, 2025
50f3c4d
Extending REST tests
eyalkoren Mar 27, 2025
cb0dcee
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren Mar 27, 2025
f68cf93
Update docs/changelog/125699.yaml
eyalkoren Mar 27, 2025
9dbe94b
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren Mar 30, 2025
79bf683
instanceOf with pattern matching
eyalkoren Mar 30, 2025
dbc4d4a
instanceOf with pattern matching
eyalkoren Mar 30, 2025
d160fe6
revert constants usage
eyalkoren Mar 30, 2025
dfe33fc
Merge remote-tracking branch 'eyalkoren/ECS-namespacing-processor' in…
eyalkoren Mar 30, 2025
2b77e3c
Complete review change proposals
eyalkoren Mar 30, 2025
4773cf6
fix typo in test name
eyalkoren Mar 30, 2025
054a76f
[CI] Auto commit changes from spotless
Mar 30, 2025
4afacd0
Applying review suggestions
eyalkoren Mar 30, 2025
d67fa2c
Merge remote-tracking branch 'eyalkoren/ECS-namespacing-processor' in…
eyalkoren Mar 30, 2025
bef3643
Silence a warning from Intellij
joegallo Apr 3, 2025
49d439f
Rename this variable
joegallo Apr 3, 2025
e15984b
Fix some typos and reflow a comment
joegallo Apr 3, 2025
e09fa14
Use ofEntries for increased clarity
joegallo Apr 3, 2025
b71fa3f
Save a rehash and some traversals
joegallo Apr 3, 2025
e8338f8
Merge branch 'main' into ECS-namespacing-processor
joegallo Apr 3, 2025
98880ca
This can be static
joegallo Apr 9, 2025
d37587d
Rely on mutability for these tests
joegallo Apr 9, 2025
21f2f9e
Rename some variables
joegallo Apr 9, 2025
b0037c3
Drop the top-level warnings suppression
joegallo Apr 9, 2025
96ff183
Merge branch 'main' into ECS-namespacing-processor
joegallo Apr 9, 2025
65f7ea2
Rewrite this test
joegallo Apr 9, 2025
3639c77
Merge branch 'main' into ECS-namespacing-processor
joegallo Apr 25, 2025
f9421ac
Drop yaml-rest-compat-test
joegallo Apr 25, 2025
b2dd61d
Refactor ECS Namespacing to Normalize to OTel
eyalkoren Apr 28, 2025
c66663b
Apply review comments
eyalkoren Apr 28, 2025
7d536a7
Adding accurate resource attributes handling
eyalkoren May 5, 2025
9493a73
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 5, 2025
bb538a6
Suppress warning for forbidden usage of System.out in tests
eyalkoren May 5, 2025
e7c1f9d
Eliminating some more forbidden APIs
eyalkoren May 5, 2025
605bdc9
[CI] Auto commit changes from spotless
May 5, 2025
e65c0ef
Reverting shameful refactoring errors
eyalkoren May 6, 2025
916eaca
Merge remote-tracking branch 'eyalkoren/ECS-namespacing-processor' in…
eyalkoren May 6, 2025
07e78a2
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 6, 2025
5c34f94
Disabling ResourceAttributesTests
eyalkoren May 6, 2025
e11ea51
Adding local disk crawler
eyalkoren May 8, 2025
c85ddf1
Disabling tests with @LuceneTestCase.Nightly()
eyalkoren May 8, 2025
717472b
Disabling forbidden APIs
eyalkoren May 8, 2025
d93f043
Disabling test and adding javadoc
eyalkoren May 8, 2025
1c4bcaa
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 8, 2025
9d0da6a
Fix Logger#warn usage
eyalkoren May 8, 2025
0a6a5d4
Adding documentation
eyalkoren May 11, 2025
0f12253
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 11, 2025
cd90ca9
Fix typo
eyalkoren May 12, 2025
c1c4d1f
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 21, 2025
a259ce6
Disabling the tests temporarily with @Ignore
eyalkoren May 22, 2025
9d77fcd
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 22, 2025
45f02b6
Adding to toc
eyalkoren May 22, 2025
675ef90
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 27, 2025
2b8441d
Remove GitHub-API-based crawler
eyalkoren May 27, 2025
bf906e2
Merge remote-tracking branch 'upstream/main' into ECS-namespacing-pro…
eyalkoren May 29, 2025
f279b7a
Refactor: renaming to normalize_for_stream
eyalkoren May 29, 2025
44ac64b
Merge branch 'main' into ECS-namespacing-processor
joegallo May 29, 2025
55885a8
Merge branch 'main' into ECS-namespacing-processor
joegallo May 30, 2025
978b163
Merge branch 'main' into ECS-namespacing-processor
joegallo Jun 2, 2025
bc4a015
Merge branch 'main' into ECS-namespacing-processor
eyalkoren Jun 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/125699.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 125699
summary: Adding `NormalizeToOTelProcessor`
area: Ingest Node
type: feature
issues: []
3 changes: 3 additions & 0 deletions docs/reference/enrich-processor/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ Refer to [Enrich your data](docs-content://manage-data/ingest/transform-enrich/d
[`network_direction` processor](/reference/enrich-processor/network-direction-processor.md)
: Calculates the network direction given a source IP address, destination IP address, and a list of internal networks.

[`normalize_to_otel` processor](/reference/enrich-processor/normalize-to-otel-processor.md)
: Normalizes non-OpenTelemetry documents to be OpenTelemetry-compliant.

[`registered_domain` processor](/reference/enrich-processor/registered-domain-processor.md)
: Extracts the registered domain (also known as the effective top-level domain or eTLD), sub-domain, and top-level domain from a fully qualified domain name (FQDN).

Expand Down
149 changes: 149 additions & 0 deletions docs/reference/enrich-processor/normalize-to-otel-processor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
navigation_title: "Normalize to OTel"
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/reference/current/normalize-to-otel-processor.html
---

# Normalize-to-OTel processor [normalize-to-otel-processor]


Detects whether a document is OpenTelemetry-compliant and if not - normalizes it as described below. The resulting document can be queried seamlessly by clients that expect either [ECS](https://www.elastic.co/guide/en/ecs/current/index.html) or OpenTelemetry-[Semantic-Conventions](https://github.com/open-telemetry/semantic-conventions) formats.

::::{note}
This processor is in tech preview and is not available in our serverless offering.
::::

## Detecting OpenTelemetry compliance

The processor detects OpenTelemetry compliance by checking the following fields:
* `resource` exists as a key and the value is a map
* `resource` either doesn't contain an `attributes` field, or contains an `attributes` field of type map
* `scope` is either missing or a map
* `attributes` is either missing or a map
* `body` is either missing or a map
* `body` either doesn't contain a `text` field, or contains a `text` field of type `String`
* `body` either doesn't contain a `structured` field, or contains a `structured` field that is not of type `String`

If all of these conditions are met, the document is considered OpenTelemetry-compliant and is not modified by the processor.

## Normalization

If the document is not OpenTelemetry-compliant, the processor normalizes it as follows:
* Specific ECS fields are renamed to have their corresponding OpenTelemetry Semantic Conventions attribute names. These include the following:

| ECS Field | Semantic Conventions Attribute |
|-------------|--------------------------------|
| `span.id` | `span_id` |
| `trace.id` | `trace_id` |
| `message` | `body.text` |
| `log.level` | `severity_text` |
The processor first looks for the nested form of the ECS field and if such does not exist, it looks for a top-level field with the dotted field name.
* Other specific ECS fields that describe resources and have corresponding counterparts in the OpenTelemetry Semantic Conventions are moved to the `resource.attribtues` map. Fields that are considered resource attributes are such that conform to the following conditions:
* They are ECS fields that have corresponding counterparts (either with
the same name or with a different name) in OpenTelemetry Semantic Conventions.
* The corresponding OpenTelemetry attribute is defined in
[Semantic Conventions](https://github.com/open-telemetry/semantic-conventions/tree/main/model)
within a group that is defined as `type: enitity`.
* All other fields, except from `@timestamp` are moved to the `attributes` map.
* All non-array entries of the `attributes` and `resource.attributes` maps are flattened. Flattening means that nested objects are merged into their parent object, and the keys are concatenated with a dot. See examples below.

## Examples

If an OpenTelemetry-compliant document is detected, the processor does nothing. For example, the following document will stay unchanged:

```json
{
"resource": {
"attributes": {
"service.name": "my-service"
}
},
"scope": {
"name": "my-library",
"version": "1.0.0"
},
"attributes": {
"http.method": "GET"
},
"body": {
"text": "Hello, world!"
}
}
```

If a non-OpenTelemetry-compliant document is detected, the processor normalizes it. For example, the following document:

```json
{
"@timestamp": "2023-10-01T12:00:00Z",
"service": {
"name": "my-service",
"version": "1.0.0",
"environment": "production",
"language": {
"name": "python",
"version": "3.8"
}
},
"log": {
"level": "INFO"
},
"message": "Hello, world!",
"http": {
"method": "GET",
"url": {
"path": "/api/v1/resource"
},
"headers": [
{
"name": "Authorization",
"value": "Bearer token"
},
{
"name": "User-Agent",
"value": "my-client/1.0"
}
]
},
"span" : {
"id": "1234567890abcdef"
},
"span.id": "abcdef1234567890",
"trace.id": "abcdef1234567890abcdef1234567890"
}
```
will be normalized into the following form:

```json
{
"@timestamp": "2023-10-01T12:00:00Z",
"resource": {
"attributes": {
"service.name": "my-service",
"service.version": "1.0.0",
"service.environment": "production"
}
},
"attributes": {
"service.language.name": "python",
"service.language.version": "3.8",
"http.method": "GET",
"http.url.path": "/api/v1/resource",
"http.headers": [
{
"name": "Authorization",
"value": "Bearer token"
},
{
"name": "User-Agent",
"value": "my-client/1.0"
}
]
},
"body": {
"text": "Hello, world!"
},
"span_id": "1234567890abcdef",
"trace_id": "abcdef1234567890abcdef1234567890"
}
```
21 changes: 21 additions & 0 deletions modules/ingest-otel/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

apply plugin: 'elasticsearch.internal-yaml-rest-test'

esplugin {
description = 'Ingest processor that normalizes ECS documents to OpenTelemetry-compatible namespaces'
classname ='org.elasticsearch.ingest.otel.NormalizeToOTelPlugin'
}

restResources {
restApi {
include '_common', 'indices', 'index', 'cluster', 'nodes', 'get', 'ingest'
}
}
13 changes: 13 additions & 0 deletions modules/ingest-otel/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

module org.elasticsearch.ingest.otel {
requires org.elasticsearch.base;
requires org.elasticsearch.server;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.ingest.otel;

import java.util.Set;

final class EcsOTelResourceAttributes {

/**
* The set of ECS (Elastic Common Schema) field names that are mapped to OpenTelemetry resource attributes,
* as defined by the OpenTelemetry Semantic Conventions.
* The list is produced by the {@code ResourceAttributesTests#testAttributesSetUpToDate} test.
*
* @see <a href="https://github.com/open-telemetry/semantic-conventions">OpenTelemetry Semantic Conventions</a>
*/
static final Set<String> LATEST = Set.of(
"agent.type",
"agent.build.original",
"agent.name",
"agent.id",
"agent.ephemeral_id",
"agent.version",
"container.image.tag",
"device.model.identifier",
"container.image.hash.all",
"service.node.name",
"process.pid",
"device.id",
"host.mac",
"host.type",
"container.id",
"cloud.availability_zone",
"host.ip",
"container.name",
"container.image.name",
"device.model.name",
"host.name",
"host.id",
"process.executable",
"user_agent.original",
"service.environment",
"cloud.region",
"service.name",
"faas.name",
"device.manufacturer",
"process.args",
"host.architecture",
"cloud.provider",
"container.runtime",
"service.version",
"cloud.service.name",
"cloud.account.id",
"process.command_line",
"faas.version"
);

private EcsOTelResourceAttributes() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.ingest.otel;

import org.elasticsearch.ingest.Processor;
import org.elasticsearch.plugins.IngestPlugin;
import org.elasticsearch.plugins.Plugin;

import java.util.Map;

public class NormalizeToOTelPlugin extends Plugin implements IngestPlugin {

@Override
public Map<String, Processor.Factory> getProcessors(Processor.Parameters parameters) {
return Map.of(NormalizeToOTelProcessor.TYPE, new NormalizeToOTelProcessor.Factory());
}
}
Loading
Loading