-
Notifications
You must be signed in to change notification settings - Fork 969
[Entities] Add entity events specification #4836
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d6f0208
ac28b77
33fe474
e6da8d2
5e1e07a
c8b875f
e05919a
89589da
aa9b0ee
1dc27d9
7314907
d8f23f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,281 @@ | ||
| <!--- Hugo front matter used to generate the website version of this page: | ||
| linkTitle: Entity Events | ||
| weight: 3 | ||
| ---> | ||
|
|
||
| # Entity Events | ||
|
|
||
| **Status**: [Development](../document-status.md) | ||
|
|
||
| <details> | ||
| <summary>Table of Contents</summary> | ||
|
|
||
| <!-- toc --> | ||
|
|
||
| - [Overview](#overview) | ||
| - [When to Use Entity Events](#when-to-use-entity-events) | ||
| - [Event Types](#event-types) | ||
| * [Entity State Event](#entity-state-event) | ||
| * [Entity Delete Event](#entity-delete-event) | ||
| - [Entity Relationships](#entity-relationships) | ||
| * [Relationship Structure](#relationship-structure) | ||
| * [Standard Relationship Types](#standard-relationship-types) | ||
| * [Relationship Placement](#relationship-placement) | ||
| * [Relationship Lifecycle](#relationship-lifecycle) | ||
| - [Examples](#examples) | ||
| * [Kubernetes Pod Entity State](#kubernetes-pod-entity-state) | ||
| * [Entity Delete](#entity-delete) | ||
|
|
||
| <!-- tocstop --> | ||
|
|
||
| </details> | ||
|
|
||
| ## Overview | ||
|
|
||
| Entity events provide a way to communicate entity information as structured log events. | ||
| This approach is complementary to defining entities as part of Resource data (see [Entity Data Model](./data-model.md)). | ||
|
|
||
| Entity events are represented as structured events using the OpenTelemetry [Logs Data Model](../logs/data-model.md), | ||
| specifically as [Events](../logs/data-model.md#events) with a defined `EventName` and attribute structure. | ||
|
|
||
| ## When to Use Entity Events | ||
|
|
||
| Entity events are particularly useful when: | ||
|
|
||
| 1. **No Associated Telemetry**: The entity has no telemetry signals associated with it, or | ||
| the telemetry is less important than the entity data itself. | ||
|
|
||
| 2. **Complex Descriptive Information**: Entity descriptive information is too complex for | ||
| simple resource attribute values. The resource attribute values are expected to be simple | ||
| strings, but entity descriptions can contain complex values like maps and arrays | ||
| (e.g., Kubernetes ConfigMap content, complex cloud metadata, nested tags). | ||
|
|
||
| 3. **Entity Relationships**: The entity information needs to include relationships to other | ||
| entities. Resource data cannot contain relationship information. | ||
|
|
||
| 4. **Lifecycle Tracking**: There is a need to explicitly track entity lifecycle events | ||
| (creation, state changes, deletion) independently from telemetry signals. | ||
|
|
||
| Entity events can be used alongside telemetry signals associated with entities to provide | ||
| additional context and relationship information. | ||
|
|
||
| ## Event Types | ||
|
|
||
| Entity information is communicated through the following event types: | ||
|
|
||
| 1. **Entity State Event** (`entity.state`): Emitted when an entity is created, when its | ||
| attributes change, or periodically to indicate the entity still exists. | ||
|
|
||
| 2. **Entity Delete Event** (`entity.delete`): Emitted when an entity is removed. | ||
|
|
||
| ### Entity State Event | ||
dmitryax marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| The Entity State Event is emitted when an entity is created, when its descriptive attributes | ||
| change, or periodically to indicate the entity still exists. | ||
|
|
||
| **Event Name**: `entity.state` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe these events should be formally defined in semconv where we can validate, document, enforce back compat, etc. It's still make sense to have some context in the spec, but just link to semconv similarly to what we do for exceptions: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/exceptions.md
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Entity SIG discussion - We still need to decide if these will be a separate signal or actual events. We're going to hold of on that part of this until that decision is made. For now this will describe the entity model and usage of events to report entity state.
Comment on lines
+71
to
+76
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For me, I think this runs the risk of overloading the term Would it be better to describe this as
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The state here doesn't necessarily imply an update. It can also be a heartbeat-like event. See the OTEP section. That said, it might be helpful to distinguish between events generated by a change vs heartbeat events. @tigrannajaryan @jsuereth WDYT?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update is more vague to me. Does update reflect the full state or the change (delta)? "State" to me says it is the full state, not the delta.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For me when I hear state I think of things like created, running, paused etc. Which is Effectively the state attribute. Howabout splitting heartbeat event out & renaming state event to definition as that would be clear that it is the full definition. Alternatively we call it description but suspect links/relationship would need to be an additional event to avoid confusion.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm more concerned we iron out the meaning of events FIRST then we can find a nomenclature. Once we understand the meaning of signals, we can find terms we're comfortable with. |
||
|
|
||
| **Required Attributes**: | ||
|
|
||
| | Attribute | Type | Description | | ||
| | --------- | ---- | ----------- | | ||
| | `entity.type` | string | Defines the type of the entity. MUST not change during the lifetime of the entity. For example: "service", "host", "k8s.pod". | | ||
| | `entity.id` | map<string, string> | Attributes that identify the entity. MUST not change during the lifetime of the entity. The map MUST contain at least one attribute. Keys and values MUST be strings. SHOULD follow OpenTelemetry [semantic conventions](https://github.com/open-telemetry/semantic-conventions) for attribute names. | | ||
|
|
||
| **Optional Attributes**: | ||
|
|
||
| | Attribute | Type | Description | | ||
| | --------- | ---- | ----------- | | ||
| | `entity.description` | map<string, AnyValue> | Descriptive (non-identifying) attributes of the entity. These attributes are not part of the entity's identity. Each Entity State event contains the complete current state of the entity's description. When absent, MUST be treated as an empty map. 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. | | ||
| | `entity.relationships` | array of maps | Relationships to other entities. Each relationship is a map containing: `type` (string, describes the relationship), `entity.type` (string, the type of the related entity), and `entity.id` (map<string, string>, identifying attributes of the related entity). When absent, MUST be treated as an empty array. | | ||
| | `report.interval` | int64 (seconds) | The reporting interval for this entity. MUST be a non-negative value when present. When absent, the reporting interval is unknown. A value of `0` indicates that no periodic heartbeat events will be sent. A positive value indicates the interval at which periodic state events will be emitted. Can be used by receivers to determine when to expect the next event and infer that an entity is gone if events stop arriving. | | ||
|
|
||
| **Timestamp Field**: | ||
|
|
||
| The `Timestamp` field of the LogRecord represents the time when this event was generated and sent. | ||
|
|
||
| **Event Emission**: | ||
|
|
||
| Implementations SHOULD emit Entity State events whenever entity descriptive attributes change, | ||
| and periodically based on the `report.interval` value to indicate the entity still exists. | ||
| Implementations SHOULD also emit Entity Delete events when entities are removed. | ||
|
|
||
| **Future Considerations**: | ||
|
|
||
| Each Entity State event contains the complete current state of the entity. If scalability | ||
| issues arise in the future, the specification may introduce a "patch" event mechanism to | ||
| communicate only the changes rather than the full state. | ||
|
|
||
| ### Entity Delete Event | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I think about usage of this for something like process. The expectation would be we send an update/state event to set the process.state attribute to terminated and then send a deleted event. Could this not be consolidated into the update event with a boolean attribute
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not? A delete event can go along with any other state events.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understand, hence the idea to simply have a property on the update event to indicate that this is the final state of the entity and all future updates should be ignored. This would reduce the qty of events and it avoids using the term delete to describe that an entity should no longer be tracked
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To address the use case of the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Whoever is reporting that the entity is gone via Entity Delete Event may no longer have full state information about the entity that is gone. Which mean it is impossible to correctly report the Entity State Event, which requires full state to be communicated.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about if we did the following:
This way we cater for both use cases.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @thompson-tomo Can you outline the use case you want to support here? I'm with @dmitryax and @tigrannajaryan - I'm not sure we can require description here, and including it may be problematic to implement. As always, would be nice to see a prototype or use-case where this is a must-have, so we can evaluate design decisions.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As per my previous comment, I am not seeking that change but rather adding an optional property ie finalised (boolean) or status (enum), then renaming this event. The use case I am thinking of is that we want to update the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't see a big problem in sending 2 events. This use case seems to be pretty rare, and it's not a lot of duplication, just the entity ID to be sent twice. And even if they are handled out of order, it must not be an issue for backends:
I'd rather keep the events separate for clarity than optimizing for this use case. |
||
|
|
||
| The Entity Delete Event indicates that a particular entity is gone. | ||
|
|
||
| **Event Name**: `entity.delete` | ||
|
|
||
| **Required Attributes**: | ||
|
|
||
| | Attribute | Type | Description | | ||
| | --------- | ---- | ----------- | | ||
| | `entity.type` | string | The type of the entity being deleted. | | ||
| | `entity.id` | map<string, string> | Attributes that identify the entity being deleted. | | ||
|
|
||
| **Optional Attributes**: | ||
|
|
||
| | Attribute | Type | Description | | ||
| | --------- | ---- | ----------- | | ||
| | `entity.delete.reason` | string | The reason for entity deletion. Examples: "terminated", "expired", "evicted", "user_requested", "scaled_down". | | ||
|
|
||
| **Timestamp Field**: | ||
|
|
||
| The `Timestamp` field of the LogRecord represents the time when the entity was deleted. | ||
|
|
||
| **Delivery Guarantees**: | ||
|
|
||
| Transmitting Entity Delete events is not guaranteed when an entity is gone. Recipients of | ||
| entity signals MUST be prepared to handle this situation by expiring entities that are no | ||
| longer seeing Entity State events reported. The expiration mechanism is based on the | ||
| previously reported `report.interval` field. Recipients can use this value to compute when | ||
| to expect the next Entity State event and, if the event does not arrive in a timely manner | ||
| (plus some slack), consider the entity to be gone even if the Entity Delete event was not observed. | ||
dmitryax marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Recipients MUST also be prepared to receive an Entity Delete event out of order, for example, | ||
| before the last Entity State event. In this case, recipients SHOULD apply state updates | ||
| regardless, as each Entity State event represents the full current state of the entity and | ||
| can be used to update a previously deleted entity record. | ||
|
|
||
| ## Entity Relationships | ||
|
|
||
| Entity relationships describe how entities are connected to each other. Relationships are | ||
| embedded within Entity State events as an array of relationship descriptors. | ||
|
|
||
| ### Relationship Structure | ||
|
|
||
| Each relationship in the `entity.relationships` array is a map containing: | ||
|
|
||
| **Required Fields**: | ||
|
|
||
| | Field | Type | Description | | ||
| | ----- | ---- | ----------- | | ||
| | `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). | | ||
jsuereth marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| | `entity.type` | string | The type of the target entity. | | ||
| | `entity.id` | map<string, string> | The identifying attributes of the target entity. | | ||
|
|
||
| **Relationship Direction**: | ||
|
|
||
| Relationships have direction: `source --[type]--> target`, where: | ||
|
|
||
| - The **source** is the entity emitting the Entity State event | ||
| - The **target** is referenced in the relationship descriptor | ||
|
|
||
| ### Standard Relationship Types | ||
|
|
||
| Relationship types form an open enumeration. Standard relationship types SHOULD be defined | ||
| in OpenTelemetry semantic conventions. Custom relationship types MAY be defined to represent | ||
| domain-specific relationships. | ||
|
|
||
| For example, a `scheduled_on` relationship type could be used to express that a workload | ||
| is scheduled on infrastructure (e.g., a Kubernetes Pod scheduled on a Node). | ||
|
|
||
| ### Relationship Placement | ||
|
|
||
| When choosing which entity should contain a relationship in its `entity.relationships` array, | ||
| implementations SHOULD prefer placing relationships on the entity type with the **shorter | ||
| lifespan** or **higher churn rate**. This minimizes the total number of Entity State events | ||
| that need to be sent. | ||
|
|
||
| **Rationale**: Since relationships are embedded in Entity State events, every time an entity's | ||
| relationships change, a new state event must be emitted. Placing relationships on the more | ||
| stable entity would require frequent state event emissions whenever the shorter-lived entities | ||
| are created or destroyed. | ||
|
|
||
| **Examples**: | ||
|
|
||
| - **Prefer**: `k8s.pod -> part_of -> k8s.replicaset` (relationship on the pod) | ||
| - **Rather than**: `k8s.replicaset -> contains -> k8s.pod` (relationship on the replicaset) | ||
| - **Reason**: Pods churn frequently. With relationships on pods, only new pod state events | ||
| are sent when pods are created/destroyed. If relationships were on the replicaset, every | ||
| pod creation/destruction would require a new replicaset state event with an updated list | ||
| of all contained pods. | ||
|
|
||
| - **Prefer**: `container -> part_of -> k8s.pod` (relationship on the container) | ||
| - **Rather than**: `k8s.pod -> contains -> container` (relationship on the pod) | ||
| - **Reason**: Containers may restart independently, so placing the relationship on the | ||
| container reduces the number of pod state events. | ||
|
|
||
| - **Prefer**: `process -> runs_on -> host` (relationship on the process) | ||
| - **Rather than**: `host -> hosts -> process` (relationship on the host) | ||
| - **Reason**: Processes start and stop frequently, while hosts are long-lived. | ||
|
|
||
| When both entities have similar lifespans, either direction is acceptable. Semantic conventions | ||
| SHOULD provide guidance on relationship placement for common entity types. | ||
|
|
||
| ### Relationship Lifecycle | ||
|
|
||
| **Creating Relationships**: | ||
| Emit an Entity State event with the new relationship included in the `entity.relationships` array. | ||
|
|
||
| **Updating Relationships**: | ||
| Emit a new Entity State event with the updated `entity.relationships` array reflecting the current state. | ||
|
|
||
| **Deleting Relationships**: | ||
| Emit a new Entity State event with the relationship removed from the `entity.relationships` array. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized one thing here. When we report entity state event of opposite entity |
||
|
|
||
| **Implicit Deletion**: | ||
| When an entity is deleted (Entity Delete event is emitted), all relationships where that | ||
| entity is involved are implicitly deleted. Backends SHOULD handle this accordingly. | ||
|
|
||
| ## Examples | ||
|
|
||
| The following examples show the logical representation of entity events. These are NOT | ||
| actual OTLP wire format representations, but rather illustrate the semantic structure | ||
| of the events. | ||
|
|
||
| ### Kubernetes Pod Entity State | ||
|
|
||
| When a Kubernetes Pod is created or its attributes change: | ||
|
|
||
| ``` | ||
| LogRecord: | ||
| Timestamp: 2026-01-12T10:30:00.000000000Z | ||
| EventName: entity.state | ||
| Resource: | ||
| k8s.cluster.name: prod-cluster | ||
| Attributes: | ||
| entity.type: k8s.pod | ||
| entity.id: | ||
| k8s.pod.uid: abc-123-def-456 | ||
| entity.description: | ||
| k8s.pod.name: nginx-deployment-66b6c | ||
| k8s.pod.labels: | ||
| app: nginx | ||
| version: "1.21" | ||
| tier: frontend | ||
| k8s.pod.phase: Running | ||
| report.interval: 60 | ||
| entity.relationships: | ||
| - relationship.type: scheduled_on | ||
| entity.type: k8s.node | ||
| entity.id: | ||
| k8s.node.uid: node-001 | ||
| - relationship.type: part_of | ||
| entity.type: k8s.replicaset | ||
| entity.id: | ||
| k8s.replicaset.uid: rs-456 | ||
| ``` | ||
|
|
||
| ### Entity Delete | ||
|
|
||
| When the Pod is terminated: | ||
|
|
||
| ``` | ||
| LogRecord: | ||
| Timestamp: 2026-01-12T11:00:00.000000000Z | ||
| EventName: entity.delete | ||
| Resource: | ||
| k8s.cluster.name: prod-cluster | ||
| Attributes: | ||
| entity.type: k8s.pod | ||
| entity.id: | ||
| k8s.pod.uid: abc-123-def-456 | ||
| entity.delete.reason: terminated | ||
| ``` | ||
Uh oh!
There was an error while loading. Please reload this page.