Skip to main content
The protocol buffers required for protobuf ingestion are not yet available in the public repository. To retrieve them, see Protocol Buffers below.
Protobuf ingestion enables sending serialized protobuf messages to Sift. Sift derives telemetry channels from the field paths defined in the message structure. The ingestion request accepts a serialized protobuf message (bytes value), and the server creates channels based on the message structure.

How channels are generated from protobuf fields

Given the following protobuf message:
Sift generates the following channels:
  • Vehicle.velocity
  • Vehicle.direction[0]
  • Vehicle.direction[1] (one channel per array index)
  • Vehicle.vehicle_state
  • Vehicle.propulsion.fuel_level
  • Vehicle.batteries[cpu].voltage (one channel per map key)
  • Vehicle.batteries[cpu].temp
  • Vehicle.batteries[propulsion].voltage
  • Vehicle.batteries[propulsion].temp

Schema registration

ProtobufDescriptorService

Use ProtobufDescriptorService.AddProtobufDescriptor to register a protobuf schema before ingesting messages. Registration process
  • Registration is performed by message type and namespace. The namespace field enables schema separation between environments. For example, a developer can iterate on protobuf definitions in a separate namespace without affecting live telemetry.
  • The request takes a file_descriptor_set field generated by compiling the protobuf with protoc:
Versioning Adding multiple ProtobufDescriptors with the same message type and namespace stores a new version of the descriptor. When a message is ingested, all stored descriptor sets for that message type and namespace are used to generate channel values. The unique set of channels generated is then ingested. Backward compatibility New protobuf descriptors must be backward compatible with existing descriptors that share the same message_type_full_name and namespace. A descriptor is not backward compatible when a field name changes (for example, velocity with field number 1 is renamed to speed). When a new descriptor is not backward compatible, you will receive an error such as:
To resolve this, either make the new descriptor backward compatible by adding a new field and reserving the old one, or delete the old descriptor using the ID in the error message. Use CheckProtobufDescriptorCompatibility to check compatibility before registering. Deletion DeleteProtobufDescriptors removes all descriptors for a given message type and namespace. This is useful for:
  • Cleaning up test protobuf messages that are no longer in use.
  • Simplifying ingestion when a new version of the descriptor is fully backward compatible.

Data ingestion

Once the schema is registered, send serialized messages using IngestService.IngestArbitraryProtobufDataStream.

Sift protobuf options

To create more descriptive channels, add custom options from channel_parsing_options.proto to your protobuf definitions.

Tagging example

A tag source identifies a field whose value becomes a tag on related channels.
Channels without tags (assuming basic map key and array values):
  • TestProto.name
  • TestProto.primary_child.child_name
  • TestProto.primary_child.map_int_to_message[1].sub_child_name
  • TestProto.primary_child.map_int_to_message[1].id
  • TestProto.array_of_children[0].child_name
  • TestProto.array_of_children[0].map_int_to_message[1].sub_child_name
  • TestProto.array_of_children[0].map_int_to_message[1].id
  • TestProto.type_id
Channels with tags applied:
  • TestProto(type_id:3).name
  • TestProto(type_id:3).primary_child(kid_name:childname).child_name
  • TestProto(type_id:3).primary_child(kid_name:childname).map_int_to_message[1].sub_child_name(id:35)
  • TestProto(type_id:3).primary_child(kid_name:childname).map_int_to_message[1].id
  • TestProto(type_id:3).array_of_children[0].child_name
  • TestProto(type_id:3).array_of_children[0].map_int_to_message[1].sub_child_name(id:35)
  • TestProto(type_id:3).array_of_children[0].map_int_to_message[1].id
  • TestProto(type_id:3).type_id
Multiple tag values display as field_name(field_1:value_1)(field_2:value_2).

Map key and array index override example

Channels without overrides (assuming 0 is the only map key):
  • TestProto.name
  • TestProto.map_key_test[0].new_key
  • TestProto.map_key_test[0].some_value
  • TestProto.map_key_removal_test[0]
  • TestProto.map_key_enum_test[0]
  • TestProto.array_index_override_test[0].new_index
  • TestProto.array_index_override_test[0].other_value
  • TestProto.array_index_override_remove_index[0]
  • TestProto.array_index_enum_test[0]
Channels with overrides applied (assuming new_key value is my-new-key and new_index value is my-new-index):
  • TestProto.name
  • TestProto.map_key_test[my-new-key].new_key
  • TestProto.map_key_test[my-new-key].some_value
  • TestProto.map_key_removal_test
  • TestProto.map_key_enum_test[NONE]
  • TestProto.array_index_override_test[my-new-index].new_index
  • TestProto.array_index_override_test[my-new-index].other_value
  • TestProto.array_index_override_remove_index
  • TestProto.array_index_enum_test[NONE]
If multiple override sources apply to the same target, the latest one is used and an error is logged.

Protocol buffers