@@ -15,17 +15,20 @@ pub struct AvroSerializerConfig {
1515
1616impl AvroSerializerConfig {
1717 /// Creates a new `AvroSerializerConfig`.
18- pub const fn new ( schema : String ) -> Self {
18+ pub const fn new ( schema : String , schema_id : Option < i32 > ) -> Self {
1919 Self {
20- avro : AvroSerializerOptions { schema } ,
20+ avro : AvroSerializerOptions { schema, schema_id } ,
2121 }
2222 }
2323
2424 /// Build the `AvroSerializer` from this configuration.
2525 pub fn build ( & self ) -> Result < AvroSerializer , BuildError > {
2626 let schema = apache_avro:: Schema :: parse_str ( & self . avro . schema )
2727 . map_err ( |error| format ! ( "Failed building Avro serializer: {error}" ) ) ?;
28- Ok ( AvroSerializer { schema } )
28+ Ok ( AvroSerializer {
29+ schema,
30+ schema_id : self . avro . schema_id ,
31+ } )
2932 }
3033
3134 /// The data type of events that are accepted by `AvroSerializer`.
@@ -50,18 +53,27 @@ pub struct AvroSerializerOptions {
5053 ) ) ]
5154 #[ configurable( metadata( docs:: human_name = "Schema JSON" ) ) ]
5255 pub schema : String ,
56+ /// Confluent Avro schema ID
57+ ///
58+ /// When set, each message will use the [Confluent wire format][wire_format] (a 5-byte prefix
59+ /// containing a magic byte and a 4-byte big-endian schema ID).
60+ ///
61+ /// [wire_format]: https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/index.html#wire-format
62+ #[ configurable( metadata( docs:: examples = "42" ) ) ]
63+ pub schema_id : Option < i32 > ,
5364}
5465
5566/// Serializer that converts an `Event` to bytes using the Apache Avro format.
5667#[ derive( Debug , Clone ) ]
5768pub struct AvroSerializer {
5869 schema : apache_avro:: Schema ,
70+ schema_id : Option < i32 > ,
5971}
6072
6173impl AvroSerializer {
6274 /// Creates a new `AvroSerializer`.
63- pub const fn new ( schema : apache_avro:: Schema ) -> Self {
64- Self { schema }
75+ pub const fn new ( schema : apache_avro:: Schema , schema_id : Option < i32 > ) -> Self {
76+ Self { schema, schema_id }
6577 }
6678}
6779
@@ -73,7 +85,13 @@ impl Encoder<Event> for AvroSerializer {
7385 let value = apache_avro:: to_value ( log) ?;
7486 let value = value. resolve ( & self . schema ) ?;
7587 let bytes = apache_avro:: to_avro_datum ( & self . schema , value) ?;
88+
89+ if let Some ( schema_id) = self . schema_id {
90+ buffer. put_slice ( & [ 0x00 ] ) ; // magic byte
91+ buffer. put_slice ( & schema_id. to_be_bytes ( ) ) ; // schema id data
92+ }
7693 buffer. put_slice ( & bytes) ;
94+
7795 Ok ( ( ) )
7896 }
7997}
@@ -105,12 +123,39 @@ mod tests {
105123 }
106124 "# }
107125 . to_owned ( ) ;
108- let config = AvroSerializerConfig :: new ( schema) ;
126+ let config = AvroSerializerConfig :: new ( schema, None ) ;
109127 let mut serializer = config. build ( ) . unwrap ( ) ;
110128 let mut bytes = BytesMut :: new ( ) ;
111129
112130 serializer. encode ( event, & mut bytes) . unwrap ( ) ;
113131
114132 assert_eq ! ( bytes. freeze( ) , b"\0 \x06 bar" . as_slice( ) ) ;
115133 }
134+
135+ #[ test]
136+ fn serialize_avro_with_schema_id ( ) {
137+ let event = Event :: Log ( LogEvent :: from ( btreemap ! {
138+ "foo" => Value :: from( "bar" )
139+ } ) ) ;
140+ let schema = indoc ! { r#"
141+ {
142+ "type": "record",
143+ "name": "Log",
144+ "fields": [
145+ {
146+ "name": "foo",
147+ "type": ["string"]
148+ }
149+ ]
150+ }
151+ "# }
152+ . to_owned ( ) ;
153+ let config = AvroSerializerConfig :: new ( schema, Some ( 42 ) ) ;
154+ let mut serializer = config. build ( ) . unwrap ( ) ;
155+ let mut bytes = BytesMut :: new ( ) ;
156+
157+ serializer. encode ( event, & mut bytes) . unwrap ( ) ;
158+
159+ assert_eq ! ( bytes. freeze( ) , b"\0 \0 \0 \0 \x2A \0 \x06 bar" . as_slice( ) ) ;
160+ }
116161}
0 commit comments