Skip to content

Commit ac641f8

Browse files
committed
fix type values and name used for hash
1 parent 2eebdaa commit ac641f8

File tree

3 files changed

+123
-25
lines changed

3 files changed

+123
-25
lines changed

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Protobuf/IMessageProxy.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ internal interface IFieldDescriptorProxy
4343

4444
bool IsRepeated { get; }
4545

46-
int FieldType { get; } // actually an enum
46+
ProtobufDotnetFieldType FieldType { get; }
4747

4848
int FieldNumber { get; }
4949

@@ -59,6 +59,7 @@ internal interface IFieldDescriptorProxy
5959
internal struct MessageDescriptorProxy
6060
{
6161
public string Name;
62+
public string FullName;
6263
public IFieldCollectionProxy Fields;
6364

6465
public IDescriptorProxy File;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// <copyright file="ProtobufTypes.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
using System;
7+
8+
namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Protobuf;
9+
10+
/// <summary>
11+
/// This represents protobuf types when they are handled by the C# code.
12+
/// copy-pasted from https://github.com/protocolbuffers/protobuf/blob/main/csharp/src/Google.Protobuf/Reflection/FieldType.cs
13+
/// </summary>
14+
internal enum ProtobufDotnetFieldType
15+
{
16+
Double,
17+
Float,
18+
Int64,
19+
UInt64,
20+
Int32,
21+
Fixed64,
22+
Fixed32,
23+
Bool,
24+
String,
25+
Group,
26+
Message,
27+
Bytes,
28+
UInt32,
29+
SFixed32,
30+
SFixed64,
31+
SInt32,
32+
SInt64,
33+
Enum
34+
}
35+
36+
/// <summary>
37+
/// This is the definition of types common to all languages.
38+
/// copy pasted from https://github.com/protocolbuffers/protobuf/blob/78db3094a46e7a8cc34d207808b8008997b5fc82/csharp/src/Google.Protobuf/Reflection/Descriptor.pb.cs#L3962
39+
/// </summary>
40+
internal enum ProtobufDotnetProtoType
41+
{
42+
Double = 1,
43+
Float = 2,
44+
Int64 = 3,
45+
Uint64 = 4,
46+
Int32 = 5,
47+
Fixed64 = 6,
48+
Fixed32 = 7,
49+
Bool = 8,
50+
String = 9,
51+
Group = 10,
52+
Message = 11,
53+
Bytes = 12,
54+
Uint32 = 13,
55+
Enum = 14,
56+
Sfixed32 = 15,
57+
Sfixed64 = 16,
58+
Sint32 = 17,
59+
Sint64 = 18,
60+
Unknown = 999 // this one I added myself, to avoid using exceptions
61+
}
62+
63+
/// <summary> Just a class to host the extension method. Must match the name of the file. </summary>
64+
internal static class ProtobufTypes
65+
{
66+
/// <summary>
67+
/// Converts from the dotnet-specific enum to the common enum.
68+
/// this is the opposite of this function https://github.com/protocolbuffers/protobuf/blob/78db3094a46e7a8cc34d207808b8008997b5fc82/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs#L206
69+
/// </summary>
70+
public static ProtobufDotnetProtoType ToProtoType(this ProtobufDotnetFieldType type)
71+
{
72+
return type switch
73+
{
74+
ProtobufDotnetFieldType.Double => ProtobufDotnetProtoType.Double,
75+
ProtobufDotnetFieldType.Float => ProtobufDotnetProtoType.Float,
76+
ProtobufDotnetFieldType.Int64 => ProtobufDotnetProtoType.Int64,
77+
ProtobufDotnetFieldType.UInt64 => ProtobufDotnetProtoType.Uint64,
78+
ProtobufDotnetFieldType.Int32 => ProtobufDotnetProtoType.Int32,
79+
ProtobufDotnetFieldType.Fixed64 => ProtobufDotnetProtoType.Fixed64,
80+
ProtobufDotnetFieldType.Fixed32 => ProtobufDotnetProtoType.Fixed32,
81+
ProtobufDotnetFieldType.Bool => ProtobufDotnetProtoType.Bool,
82+
ProtobufDotnetFieldType.String => ProtobufDotnetProtoType.String,
83+
ProtobufDotnetFieldType.Group => ProtobufDotnetProtoType.Group,
84+
ProtobufDotnetFieldType.Message => ProtobufDotnetProtoType.Message,
85+
ProtobufDotnetFieldType.Bytes => ProtobufDotnetProtoType.Bytes,
86+
ProtobufDotnetFieldType.UInt32 => ProtobufDotnetProtoType.Uint32,
87+
ProtobufDotnetFieldType.Enum => ProtobufDotnetProtoType.Enum,
88+
ProtobufDotnetFieldType.SFixed32 => ProtobufDotnetProtoType.Sfixed32,
89+
ProtobufDotnetFieldType.SFixed64 => ProtobufDotnetProtoType.Sfixed64,
90+
ProtobufDotnetFieldType.SInt32 => ProtobufDotnetProtoType.Sint32,
91+
ProtobufDotnetFieldType.SInt64 => ProtobufDotnetProtoType.Sint64,
92+
_ => ProtobufDotnetProtoType.Unknown
93+
};
94+
}
95+
}

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Protobuf/SchemaExtractor.cs

+26-24
Original file line numberDiff line numberDiff line change
@@ -185,78 +185,81 @@ private Dictionary<string, OpenApiSchema> ExtractFields(MessageDescriptorProxy d
185185
string? type = null, format = null, description = null;
186186
OpenApiReference? reference = null;
187187
IList<IOpenApiAny>? enumValues = null;
188-
switch (field.FieldType)
188+
189+
// the csharp implementation of protobuf uses an enum with different values to handle types internally.
190+
// we must convert it back to the "common" value for consistency with other tracers
191+
var protoType = field.FieldType.ToProtoType();
192+
switch (protoType)
189193
{
190-
case 0:
194+
case ProtobufDotnetProtoType.Double:
191195
type = "number";
192196
format = "double";
193197
break;
194-
case 1:
198+
case ProtobufDotnetProtoType.Float:
195199
type = "number";
196200
format = "float";
197201
break;
198-
case 2:
202+
case ProtobufDotnetProtoType.Int64:
199203
type = "integer";
200204
format = "int64";
201205
break;
202-
case 3:
203-
case 16: // sint64
206+
case ProtobufDotnetProtoType.Uint64:
207+
case ProtobufDotnetProtoType.Sint64:
204208
// OpenAPI does not directly support unsigned integers, treated as integers
205209
type = "integer";
206210
format = "uint64";
207211
break;
208-
case 4:
209-
case 15: // sint32
212+
case ProtobufDotnetProtoType.Int32:
213+
case ProtobufDotnetProtoType.Sint32:
210214
type = "integer";
211215
format = "int32";
212216
break;
213-
case 5:
217+
case ProtobufDotnetProtoType.Fixed64:
214218
// Treated as an integer because OpenAPI does not have a fixed64 format.
215219
type = "integer";
216220
format = "fixed64";
217221
break;
218-
case 6:
222+
case ProtobufDotnetProtoType.Fixed32:
219223
type = "integer";
220224
format = "fixed32";
221225
break;
222-
case 7:
226+
case ProtobufDotnetProtoType.Bool:
223227
type = "boolean";
224228
break;
225-
case 8:
229+
case ProtobufDotnetProtoType.String:
226230
type = "string";
227231
break;
228-
case 9: // group
232+
case ProtobufDotnetProtoType.Group:
229233
// Groups are deprecated and usually represented as nested messages in OpenAPI
230234
type = "object";
231235
description = "Group type";
232236
break;
233-
case 10: // message
237+
case ProtobufDotnetProtoType.Message:
234238
FillSchemasWith(field.MessageType, depth + 1); // Recursively add nested schemas (conditions apply)
235239
reference = new OpenApiReference { Id = field.MessageType.Name, Type = ReferenceType.Schema };
236-
_computedHash = FnvHash64.GenerateHash(reference.Id, FnvHash64.Version.V1A, _computedHash);
240+
_computedHash = FnvHash64.GenerateHash(field.MessageType.FullName, FnvHash64.Version.V1A, _computedHash);
237241
HashData.Append("|");
238242
HashData.Append(reference.Id);
239243
break;
240-
case 11:
244+
case ProtobufDotnetProtoType.Bytes:
241245
type = "string";
242246
format = "byte";
243247
break;
244-
case 12:
248+
case ProtobufDotnetProtoType.Uint32:
245249
// As with UINT64, treated as integers or strings because OpenAPI does not directly
246250
// support unsigned integers
247251
type = "integer";
248252
format = "uint32";
249253
break;
250-
case 13:
254+
case ProtobufDotnetProtoType.Sfixed32:
251255
type = "integer";
252256
format = "sfixed32";
253257
break;
254-
case 14:
258+
case ProtobufDotnetProtoType.Sfixed64:
255259
type = "integer";
256260
format = "sfixed64";
257261
break;
258-
// cases 15 and 16 are above
259-
case 17: // enum
262+
case ProtobufDotnetProtoType.Enum:
260263
type = "string";
261264
enumValues = new List<IOpenApiAny>(field.EnumType.Values.Count);
262265
foreach (var e in field.EnumType.Values)
@@ -278,13 +281,12 @@ private Dictionary<string, OpenApiSchema> ExtractFields(MessageDescriptorProxy d
278281
}
279282

280283
_computedHash = FnvHash64.GenerateHash(field.FieldNumber.ToString(CultureInfo.InvariantCulture), FnvHash64.Version.V1A, _computedHash);
281-
var fieldTypeForHash = field.FieldType + 1; // the enum values are not the same in all languages. We align on the reference, which is java, which has enum values that start at 1.
282-
_computedHash = FnvHash64.GenerateHash(fieldTypeForHash.ToString(CultureInfo.InvariantCulture), FnvHash64.Version.V1A, _computedHash);
284+
_computedHash = FnvHash64.GenerateHash(((int)protoType).ToString(CultureInfo.InvariantCulture), FnvHash64.Version.V1A, _computedHash);
283285
_computedHash = FnvHash64.GenerateHash(depth.ToString(CultureInfo.InvariantCulture), FnvHash64.Version.V1A, _computedHash);
284286
HashData.Append("|");
285287
HashData.Append(field.FieldNumber.ToString(CultureInfo.InvariantCulture));
286288
HashData.Append("|");
287-
HashData.Append(fieldTypeForHash.ToString(CultureInfo.InvariantCulture));
289+
HashData.Append(((int)protoType).ToString(CultureInfo.InvariantCulture));
288290
HashData.Append("|");
289291
HashData.Append(depth.ToString(CultureInfo.InvariantCulture));
290292

0 commit comments

Comments
 (0)