Skip to content

Commit cafa7f7

Browse files
committed
[Entities] Add entity events specification
Add a new specification for Entity Events as structured log events for communicating richer entity information based on https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/entities/0256-entities-data-model.md
1 parent 732a83f commit cafa7f7

3 files changed

Lines changed: 291 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ release.
2626

2727
### Entities
2828

29+
- Add specification for communicating entity information as structured log events.
30+
([#4836](https://github.com/open-telemetry/opentelemetry-specification/pull/4836))
31+
2932
### OpenTelemetry Protocol
3033

3134
### Compatibility

specification/entities/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ Entities can be instantiated through two complementary approaches:
3333

3434
- [Data Model](./data-model.md)
3535
- [Entity Propagation](./entity-propagation.md) - Describes the push-based model for entity instantiation
36+
- [Entity Events](./entity-events.md) - Describes how to communicate entity information as structured log events
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
<!--- Hugo front matter used to generate the website version of this page:
2+
linkTitle: Entity Events
3+
weight: 3
4+
--->
5+
6+
# Entity Events
7+
8+
**Status**: [Development](../document-status.md)
9+
10+
<details>
11+
<summary>Table of Contents</summary>
12+
13+
<!-- toc -->
14+
15+
- [Overview](#overview)
16+
- [When to Use Entity Events](#when-to-use-entity-events)
17+
- [Entity Events Data Model](#entity-events-data-model)
18+
* [Entity State Event](#entity-state-event)
19+
* [Entity Delete Event](#entity-delete-event)
20+
- [Entity Relationships](#entity-relationships)
21+
* [Relationship Structure](#relationship-structure)
22+
* [Standard Relationship Types](#standard-relationship-types)
23+
* [Relationship Lifecycle](#relationship-lifecycle)
24+
- [Examples](#examples)
25+
* [Kubernetes Pod Entity State](#kubernetes-pod-entity-state)
26+
* [Entity Delete Event](#entity-delete-event-1)
27+
28+
<!-- tocstop -->
29+
30+
</details>
31+
32+
## Overview
33+
34+
Entity events provide a way to communicate entity information as structured log events.
35+
This approach is complementary to defining entities as part of Resource data (see [Entity Data Model](./data-model.md)).
36+
37+
Entity events are represented as structured events using the OpenTelemetry [Logs Data Model](../logs/data-model.md),
38+
specifically as [Events](../logs/data-model.md#events) with a defined `EventName` and attribute structure.
39+
40+
## When to Use Entity Events
41+
42+
Entity events SHOULD be used when:
43+
44+
1. **No Associated Telemetry**: The entity has no telemetry signals associated with it, or
45+
the telemetry is less important than the entity data itself.
46+
47+
2. **Complex Descriptive Information**: Entity descriptive information is too complex for
48+
simple resource attribute values. The resource attribute values are expected to be simple
49+
strings, but entity descriptions can contain complex values like maps and arrays
50+
(e.g., Kubernetes ConfigMap content, complex cloud metadata, nested tags).
51+
52+
3. **Entity Relationships**: The entity information needs to include relationships to other
53+
entities. Resource data cannot contain relationship information.
54+
55+
4. **Lifecycle Tracking**: There is a need to explicitly track entity lifecycle events
56+
(creation, state changes, deletion) independently from telemetry signals.
57+
58+
## Entity Events Data Model
59+
60+
Entity events use the OpenTelemetry Logs Data Model with specific conventions for the
61+
`EventName` and `Attributes` fields.
62+
63+
### Entity State Event
64+
65+
The Entity State Event stores information about the state of an entity at a particular moment in time.
66+
67+
**Event Name**: `entity.state`
68+
69+
**Required Attributes**:
70+
71+
| Attribute | Type | Description |
72+
| --------- | ---- | ----------- |
73+
| `entity.type` | string | Defines the type of the entity. MUST not change during the lifetime of the entity. For example: "service", "host", "k8s.pod". |
74+
| `entity.id` | map<string, AnyValue> | Attributes that identify the entity. MUST not change during the lifetime of the entity. The map MUST contain at least one attribute. Follows OpenTelemetry [attribute definition](../common/README.md#attribute). |
75+
76+
**Optional Attributes**:
77+
78+
| Attribute | Type | Description |
79+
| --------- | ---- | ----------- |
80+
| `entity.description` | map<string, AnyValue> | Descriptive (non-identifying) attributes of the entity. MAY change over the lifetime of the entity. These attributes are not part of the entity's identity. Follows [AnyValue](../common/README.md#anyvalue) definition: can contain scalar values, arrays, or nested maps. SHOULD follow OpenTelemetry [semantic conventions](https://github.com/open-telemetry/semantic-conventions) for attributes. |
81+
| `entity.interval` | int64 (milliseconds) | Defines the reporting period, i.e., how frequently information about this entity is reported via Entity State events even if the entity does not change. The next expected Entity State event for this entity is expected at (Timestamp + Interval) time. Can be used by receivers to infer that a no longer reported entity is gone, even if the Entity Delete event was not observed. |
82+
| `entity.relationships` | array of map<string, AnyValue> | Array of relationships that this entity has with other entities. See [Entity Relationships](#entity-relationships) for details. |
83+
84+
**Timestamp Field**:
85+
86+
The `Timestamp` field of the LogRecord represents the time when the entity state described
87+
by this event became effective. This is the time measured by the origin clock.
88+
89+
**State Mutations**:
90+
91+
An entity mutates (changes) when one or more of its descriptive attributes changes, or when
92+
its relationships change. A new descriptive attribute may be added, an existing descriptive
93+
attribute may be deleted, or a value of an existing descriptive attribute may be changed.
94+
All these changes represent valid mutations of an entity over time. When these mutations
95+
happen, the identity of the entity does not change.
96+
97+
When the entity's state changes, sources SHOULD emit a new Entity State event with a fresh
98+
timestamp and the complete current state of all fields.
99+
100+
**Periodic Reporting**:
101+
102+
Entity event producers SHOULD periodically emit Entity State events even if the entity does
103+
not change. In this case, the `entity.type`, `entity.id`, `entity.description`, and
104+
`entity.relationships` fields will remain the same, but a fresh `Timestamp` will be recorded.
105+
Producing such events allows the system to be resilient to event losses and serves as a
106+
liveliness indicator.
107+
108+
### Entity Delete Event
109+
110+
The Entity Delete Event indicates that a particular entity is gone.
111+
112+
**Event Name**: `entity.delete`
113+
114+
**Required Attributes**:
115+
116+
| Attribute | Type | Description |
117+
| --------- | ---- | ----------- |
118+
| `entity.type` | string | The type of the entity being deleted. |
119+
| `entity.id` | map<string, AnyValue> | Attributes that identify the entity being deleted. |
120+
121+
**Optional Attributes**:
122+
123+
| Attribute | Type | Description |
124+
| --------- | ---- | ----------- |
125+
| `entity.delete.reason` | string | The reason for entity deletion. Examples: "terminated", "expired", "evicted", "user_requested", "scaled_down". |
126+
127+
**Timestamp Field**:
128+
129+
The `Timestamp` field of the LogRecord represents the time when the entity was deleted,
130+
measured by the origin clock.
131+
132+
**Delivery Guarantees**:
133+
134+
Transmitting Entity Delete events is not guaranteed when an entity is gone. Recipients of
135+
entity signals MUST be prepared to handle this situation by expiring entities that are no
136+
longer seeing Entity State events reported. The expiration mechanism is based on the
137+
previously reported `entity.interval` field. Recipients can use this value to compute when
138+
to expect the next Entity State event and, if the event does not arrive in a timely manner
139+
(plus some slack), consider the entity to be gone even if the Entity Delete event was not observed.
140+
141+
## Entity Relationships
142+
143+
Entity relationships describe how entities are connected to each other. Relationships are
144+
embedded within Entity State events as an array of relationship descriptors.
145+
146+
### Relationship Structure
147+
148+
Each relationship in the `entity.relationships` array is a map containing:
149+
150+
**Required Fields**:
151+
152+
| Field | Type | Description |
153+
| ----- | ---- | ----------- |
154+
| `relationship.type` | string | The type of relationship. Describes the semantic meaning of the relationship (e.g., "scheduled_on", "contains", "depends_on"). See [Standard Relationship Types](#standard-relationship-types). |
155+
| `entity.type` | string | The type of the target entity. |
156+
| `entity.id` | map<string, AnyValue> | The identifying attributes of the target entity. |
157+
158+
**Optional Fields**:
159+
160+
| Field | Type | Description |
161+
| ----- | ---- | ----------- |
162+
| `attributes` | map<string, AnyValue> | Additional relationship-specific attributes that provide context about the relationship. |
163+
164+
**Relationship Direction**:
165+
166+
Relationships have direction: `source --[type]--> target`, where:
167+
168+
- The **source** is the entity emitting the Entity State event
169+
- The **target** is referenced in the relationship descriptor
170+
171+
### Standard Relationship Types
172+
173+
The following are recommended relationship types with their semantic meanings:
174+
175+
| Type | Direction | Meaning | Example |
176+
| ---- | --------- | ------- | ------- |
177+
| `runs_on` | Logical → Infrastructure | A logical entity runs on infrastructure | Process → Host |
178+
| `scheduled_on` | Workload → Infrastructure | A workload is scheduled on infrastructure | Pod → Node |
179+
| `contains` | Parent → Child | A parent entity contains a child entity | Pod → Container |
180+
| `part_of` | Child → Parent | A child entity is part of a parent | Container → Pod |
181+
| `depends_on` | Consumer → Dependency | An entity depends on another for functionality | Service → Database |
182+
| `manages` | Controller → Controlled | An entity manages the lifecycle of another | Deployment → ReplicaSet |
183+
| `hosts` | Infrastructure → Workload | Infrastructure hosts a workload (reverse of scheduled_on) | Node → Pod |
184+
185+
Custom relationship types MAY be defined to represent domain-specific relationships.
186+
Semantic conventions MUST define standard relationship types for common entity types.
187+
188+
### Relationship Lifecycle
189+
190+
**Creating Relationships**:
191+
Emit an Entity State event with the new relationship included in the `entity.relationships` array.
192+
193+
**Updating Relationships**:
194+
Emit a new Entity State event with the updated `entity.relationships` array reflecting the current state.
195+
196+
**Deleting Relationships**:
197+
Emit a new Entity State event with the relationship removed from the `entity.relationships` array.
198+
199+
**Implicit Deletion**:
200+
When an entity is deleted (Entity Delete event is emitted), all relationships where that
201+
entity is the source are implicitly deleted. Backends SHOULD handle this accordingly.
202+
203+
## Examples
204+
205+
### Kubernetes Pod Entity State
206+
207+
```json
208+
{
209+
"timestamp": "2026-01-12T10:30:00.000000000Z",
210+
"eventName": "entity.state",
211+
"resource": {
212+
"attributes": {
213+
"k8s.cluster.name": "prod-cluster"
214+
}
215+
},
216+
"attributes": {
217+
"entity.type": "k8s.pod",
218+
"entity.id": {
219+
"k8s.pod.uid": "abc-123-def-456"
220+
},
221+
"entity.description": {
222+
"k8s.pod.name": "nginx-deployment-66b6c",
223+
"k8s.namespace.name": "default",
224+
"k8s.pod.labels": {
225+
"app": "nginx",
226+
"version": "1.21",
227+
"tier": "frontend"
228+
},
229+
"k8s.pod.phase": "Running",
230+
},
231+
"entity.interval": 60000,
232+
"entity.relationships": [
233+
{
234+
"relationship.type": "scheduled_on",
235+
"entity.type": "k8s.node",
236+
"entity.id": {
237+
"k8s.node.uid": "node-001"
238+
}
239+
},
240+
{
241+
"relationship.type": "contains",
242+
"entity.type": "container",
243+
"entity.id": {
244+
"container.id": "container-456"
245+
}
246+
},
247+
{
248+
"relationship.type": "contains",
249+
"entity.type": "container",
250+
"entity.id": {
251+
"container.id": "container-789"
252+
}
253+
},
254+
{
255+
"relationship.type": "part_of",
256+
"entity.type": "k8s.replicaset",
257+
"entity.id": {
258+
"k8s.replicaset.uid": "rs-456"
259+
}
260+
}
261+
]
262+
}
263+
}
264+
```
265+
266+
### Entity Delete Event
267+
268+
When the Pod is terminated:
269+
270+
```json
271+
{
272+
"timestamp": "2026-01-12T11:00:00.000000000Z",
273+
"eventName": "entity.delete",
274+
"resource": {
275+
"attributes": {
276+
"k8s.cluster.name": "prod-cluster"
277+
}
278+
},
279+
"attributes": {
280+
"entity.type": "k8s.pod",
281+
"entity.id": {
282+
"k8s.pod.uid": "abc-123-def-456"
283+
},
284+
"entity.delete.reason": "terminated"
285+
}
286+
}
287+
```

0 commit comments

Comments
 (0)