Skip to content

Conversation

@adelinowona
Copy link
Contributor

No description provided.

@adelinowona adelinowona added the feature Adds new user-facing functionality. label Dec 9, 2025
Copy link
Member

@sanych-sun sanych-sun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review. Also please check failing tests

{
// Check if all requests are of the same type
var firstType = requests[0].ModelType;
var allSameType = requests.All(r => r.ModelType == firstType);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having this code here will lead to multiple enumerations of the requests. We had a ticket to remove the multiple enumerations. Should we move this code into the CreateBulkWriteOperation and merge it into the mapping loop?

connectionId,
$"{state.CommandName} command failed",
null,
reply);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we construct the exception just to record it and never throw it? Looks suspicious.

<PackageReference Include="Snappier" Version="1.0.0" />
<PackageReference Include="ZstdSharp.Port" Version="0.7.3" />
<PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.0" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the System.Diagnostics.DiagnosticSource version should match the target framework.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And looks like it's not needed for net6.

return new OperationContext(Clock, InitialTimestamp, Timeout, CancellationToken)
{
RootContext = RootContext,
OperationName = operationName,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should copy values of all otel related fields in WithTimeout method as well. Otherwise they will be lost if we have to apply the timeout.


internal OperationContext WithOperationMetadata(string operationName, string databaseName, string collectionName, bool isTracingEnabled)
{
return new OperationContext(Clock, InitialTimestamp, Timeout, CancellationToken)
Copy link
Member

@sanych-sun sanych-sun Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Providing InitialTimestamp and Timeout here looks wrong to me, because copied operationContext is suppose to "continue from the point where it was copied". We probably should provide RemainingTimeout instead, in the same way as WithTimeout doing..

};
}

internal OperationContext WithOperationMetadata(string operationName, string databaseName, string collectionName, bool isTracingEnabled)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add unit tests for the new method.

public bool LoadBalanced => _loadBalanced;
public TimeSpan LocalThreshold { get { return _localThreshold; } }
public LoggingSettings LoggingSettings { get { return _loggingSettings; } }
public TracingOptions TracingOptions { get { return _tracingOptions; } }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add comparison of the TracingOptions to the Equals method?

Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, partial review.

<PackageReference Include="Snappier" Version="1.0.0" />
<PackageReference Include="ZstdSharp.Port" Version="0.7.3" />
<PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we include this in BSON lib instead, just in case we'd want to add serialization Otel?

/// </summary>
public static class MongoTelemetry
{
private static readonly string s_driverVersion = ClientDocumentHelper.GetAssemblyVersion(typeof(MongoClient).Assembly);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__driverVersion

/// The ActivitySource used by MongoDB driver for OpenTelemetry tracing.
/// Applications can subscribe to this source to receive MongoDB traces.
/// </summary>
public static readonly ActivitySource ActivitySource = new("MongoDB.Driver", s_driverVersion);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want/need to expose this publicly? Is it the recommended way?

{
var activity = ActivitySource.StartActivity(commandName, ActivityKind.Client);

if (activity == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: activity is checked for null by the callers, so maybe check in one place only?


SetConnectionTags(activity, connectionId);

if (command != null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what cases is the command null?

else
{
// For command-level exceptions, only set error status without recording details
activity.SetStatus(ActivityStatusCode.Error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: maybe this whole if/else block should move into MongoTelemetry.RecordException?

/// When set to true, no OpenTelemetry activities will be created for this client's operations.
/// Default is false (tracing enabled if configured via TracerProvider).
/// </summary>
public bool Disabled { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this additional Disabled switch?

_shouldTrackState = _shouldTrackSucceeded || _shouldTrackFailed;

// Check if tracing is disabled for this client
_shouldTrace = _tracingOptions?.Disabled != true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably not sufficient.
Do we still want to trace if there are not listeners?

operationContext.OperationName,
operationContext.DatabaseName,
operationContext.CollectionName)
: null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider more compact overload:
MongoTelemetry.StartOperationActivity(operationContext);

And ideally (if it's reasonable of course) everything related to telemetry should be handled in single place, so should
TransactionActivityScope be under MongoTelemetry? Should MongoTelemetry.StartOperationActivity also invoke TransactionActivityScope ?

public CollectionNamespace QueryNamespace;
public ExpectedResponseType ExpectedResponseType;
public bool ShouldRedactReply;
public Activity CommandActivity;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this Activity need to be disposed?

_settings.TranslationOptions);

private OperationContext CreateOperationContext(IClientSessionHandle session, TimeSpan? timeout, CancellationToken cancellationToken)
private OperationContext CreateOperationContext(IClientSessionHandle session, TimeSpan? timeout, CancellationToken cancellationToken, string operationName = null)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw I know Cancellation token should be the last parameter here but I did it this way for now since this work is still a draft and I didn't want to have to update every call.

Same idea stands for ExecuteReadOperation and ExecuteWriteOperation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Adds new user-facing functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants