如何在MongoDB C#驱动中为序列化/反序列化操作添加Activity?
为MongoDB序列化/反序列化操作添加Activity追踪
方案1:基于自定义ClassMap注入追踪逻辑
针对你已在使用的BsonClassMap,可以通过包装默认序列化器的方式,为指定类的序列化/反序列化操作添加Activity:
首先创建通用的追踪序列化器包装类:
public class ActivityTrackingSerializer<T> : IBsonSerializer<T> { private readonly IBsonSerializer<T> _innerSerializer; public ActivityTrackingSerializer(IBsonSerializer<T> innerSerializer) { _innerSerializer = innerSerializer; } public T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { using var activity = new Activity($"MongoDB Deserialize: {typeof(T).Name}").Start(); activity.AddTag("mongo.type", typeof(T).FullName); try { return _innerSerializer.Deserialize(context, args); } catch (Exception ex) { activity.SetStatus(ActivityStatusCode.Error); activity.AddTag("error.message", ex.Message); throw; } } public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value) { using var activity = new Activity($"MongoDB Serialize: {typeof(T).Name}").Start(); activity.AddTag("mongo.type", typeof(T).FullName); try { _innerSerializer.Serialize(context, args, value); } catch (Exception ex) { activity.SetStatus(ActivityStatusCode.Error); activity.AddTag("error.message", ex.Message); throw; } } // 转发IBsonSerializer接口的其他成员实现 public Type ValueType => _innerSerializer.ValueType; public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context, args); public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) => Serialize(context, args, (T)value); }
然后在ClassMap注册时替换默认序列化器:
BsonClassMap.RegisterClassMap<MyClass>(cm => { cm.AutoMap(); cm.SetIgnoreExtraElements(true); // 为类的所有属性添加追踪 foreach (var memberMap in cm.AllMemberMaps) { var originalSerializer = memberMap.GetSerializer(); memberMap.SetSerializer(new ActivityTrackingSerializer<object>(originalSerializer)); } // 或者为整个类的根序列化添加追踪 var classSerializer = cm.GetSerializer(); cm.SetSerializer(new ActivityTrackingSerializer<MyClass>(classSerializer)); });
方案2:全局注册追踪逻辑(覆盖所有类型)
如果需要为所有MongoDB序列化/反序列化操作添加Activity,可以自定义序列化器注册表实现全局拦截:
public class ActivityTrackingSerializerRegistry : IBsonSerializerRegistry { private readonly IBsonSerializerRegistry _innerRegistry; public ActivityTrackingSerializerRegistry(IBsonSerializerRegistry innerRegistry) { _innerRegistry = innerRegistry; } public IBsonSerializer GetSerializer(Type type) { var innerSerializer = _innerRegistry.GetSerializer(type); // 避免重复包装序列化器 if (innerSerializer.GetType().IsGenericType && innerSerializer.GetType().GetGenericTypeDefinition() == typeof(ActivityTrackingSerializer<>)) return innerSerializer; var genericWrapper = typeof(ActivityTrackingSerializer<>).MakeGenericType(type); return (IBsonSerializer)Activator.CreateInstance(genericWrapper, innerSerializer); } public IBsonSerializer<T> GetSerializer<T>() { var innerSerializer = _innerRegistry.GetSerializer<T>(); if (innerSerializer is ActivityTrackingSerializer<T>) return innerSerializer; return new ActivityTrackingSerializer<T>(innerSerializer); } } // 注册全局序列化器注册表 BsonSerializer.RegisterSerializerRegistry(new ActivityTrackingSerializerRegistry(BsonSerializer.SerializerRegistry));
与MongoDB诊断扩展包联动
你提到的诊断包已覆盖MongoDB核心操作(查询、写入等),可以修改追踪序列化器的Activity创建逻辑,让序列化操作作为核心操作的子Activity:
// 在ActivityTrackingSerializer的Serialize/Deserialize方法中调整Activity创建逻辑 using var activity = new Activity($"MongoDB Serialize: {typeof(T).Name}") { ParentId = Activity.Current?.Id }.Start();
这样分布式追踪链路中,序列化/反序列化的耗时会被关联到对应的MongoDB命令操作下,完整展示全链路耗时。
注意事项
- 性能评估:高并发场景下,每个序列化/反序列化创建Activity会带来一定开销,可通过开关控制是否启用。
- 异常追踪:Activity中记录的异常标签可辅助排查序列化失败问题。
- 避免重复包装:全局注册时需判断序列化器是否已被包装,防止无限嵌套。
内容的提问来源于stack exchange,提问作者TheoM
相关产品推荐
相关产品推荐

