Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Npgsql/NpgsqlDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,12 @@ internal NpgsqlDataSource(NpgsqlConnectionStringBuilder settings, NpgsqlDataSour
ConnectionString = settings.ToString();

// The data source name is reported in tracing/metrics, so avoid leaking the password through there.
Name = name ?? settings.ToStringWithoutPassword();
Name = name ?? settings.ApplicationName ?? settings.ToStringWithoutPassword();
}
else
{
ConnectionString = settings.ToStringWithoutPassword();
Name = name ?? ConnectionString;
Name = name ?? settings.ApplicationName ?? ConnectionString;
}

_password = settings.Password;
Expand Down
28 changes: 25 additions & 3 deletions test/Npgsql.Tests/MetricTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,29 @@ public async Task ConnectionMax()
Assert.That(tags["db.client.connection.pool.name"], Is.EqualTo(dataSource.Name));
}

[Test]
public async Task Pool_name_defaults_to_application_name()
{
var exportedItems = new List<Metric>();
using var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("Npgsql")
.AddInMemoryExporter(exportedItems)
.Build();

var applicationName = "MetricsDataSource" + Interlocked.Increment(ref _dataSourceCounter);
var dataSourceBuilder = base.CreateDataSourceBuilder();
dataSourceBuilder.ConnectionStringBuilder.ApplicationName = applicationName;
// Do not set the data source name - this makes the pool name default to the Application Name
await using var dataSource = dataSourceBuilder.Build();
Comment on lines +139 to +143
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

This test uses an instance-level counter to generate applicationName. Since the test assembly is parallelizable, different MetricTests instances can run concurrently and produce the same MetricsDataSource1 name, which can cause metric aggregation across tests (same db.client.connection.pool.name) and lead to flaky assertions. Use a process-wide unique value (e.g., a static counter, Guid, or include TestContext.CurrentContext.Test.ID) to avoid collisions under parallel execution.

Copilot uses AI. Check for mistakes.

meterProvider.ForceFlush();

var metric = exportedItems.Single(m => m.Name == "db.client.connection.max");
var point = GetFilteredPoints(metric.GetMetricPoints(), dataSource.Name).First();
var tags = ToDictionary(point.Tags);
Assert.That(tags["db.client.connection.pool.name"], Is.EqualTo(applicationName));
}

[Test]
public async Task Password_does_not_leak_via_datasource_name([Values] bool persistSecurityInfo)
{
Expand All @@ -137,10 +160,9 @@ public async Task Password_does_not_leak_via_datasource_name([Values] bool persi
.Build();

var dataSourceBuilder = base.CreateDataSourceBuilder();
dataSourceBuilder.ConnectionStringBuilder.ApplicationName = "MetricsDataSource" + Interlocked.Increment(ref _dataSourceCounter);
dataSourceBuilder.ConnectionStringBuilder.PersistSecurityInfo = persistSecurityInfo;
// Do not set the data source name - this makes it default to the connection string, but without
// the password (even when Persist Security Info is true)
// Do not set the data source name or the application name - this makes the pool name default to the
// connection string, but without the password (even when Persist Security Info is true)
await using var dataSource = dataSourceBuilder.Build();

meterProvider.ForceFlush();
Expand Down
Loading