Skip to content

Commit

Permalink
Unify Application Name and UseName. Fixes #1434
Browse files Browse the repository at this point in the history
  • Loading branch information
bgrainger committed Jan 14, 2024
1 parent 64e4fc5 commit c9d2217
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 13 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions docs/content/connection-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,13 @@ These are the other options that MySqlConnector supports. They are set to sensib
<tr id="ApplicationName">
<td>Application Name, ApplicationName</td>
<td>null</td>
<td>Sets the <c>program_name</c> connection attribute passed to MySQL Server. This value may be displayed by diagnostic tools,
e.g., as the “Program” column in “Client Connections” in <a href="https://www.mysql.com/products/workbench/">MySQL Workbench</a>.</td>
<td><p>Sets the <c>program_name</c> connection attribute passed to MySQL Server. This value may be displayed by diagnostic tools,
e.g., as the “Program” column in “Client Connections” in <a href="https://www.mysql.com/products/workbench/">MySQL Workbench</a>.
It also sets the connection pool name reported by the <code>pool.name</code> tag associated with connection pool metrics.</p>
<p>This connection string option is deprecated and is provided for backwards compatibility. Newer applications should
use <a href="/api/MySqlConnector/MySqlDataSourceBuilder/UseName/"><code>MySqlDataSourceBuilder.UseName</code></a> instead.
</p></td>
</td>
</tr>
<tr id="AutoEnlist">
<td>Auto Enlist, AutoEnlist</td>
Expand Down
52 changes: 52 additions & 0 deletions docs/content/diagnostics/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,55 @@ Name | Type | Unit | Description
`db.client.connections.idle.max` | UpDownCounter | `{connection}` | The maximum number of idle open connections allowed; this corresponds to `MaximumPoolSize` in the connection string.
`db.client.connections.idle.min` | UpDownCounter | `{connection}` | The minimum number of idle open connections allowed; this corresponds to `MinimumPoolSize` in the connection string.
`db.client.connections.max` | UpDownCounter | `{connection}` | The maximum number of open connections allowed; this corresponds to `MaximumPoolSize` in the connection string.

## Supported Tags

Name | Description
--- | ---
`pool.name` | The name of the connection pool (see below).
`state` | `idle` or `used`; this tag is used with the `db.client.connections.usage` instrument.

## Connection Pool Name

A connection pool name can be specified by one of the following means:

### UseName

The `MySqlDataSourceBuilder.UseName` method can be used to specify a name for the connection pool:

```csharp
using var dataSource = new MySqlDataSourceBuilder("...connection string...")
.UseName("MyPoolName")
.Build();
```

This can also be used with dependency injection:

```csharp
builder.Services.AddMySqlDataSource(builder.Configuration.GetConnectionString("Default"),
x => x.UseName("MyPoolName"));
```

### Keyed Services

Use the `AddKeyedMySqlDataSource` method to register a `MySqlDataSource` as a [keyed service](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8#keyed-di-services).
If the service key is a string, it will automatically be used as the `MySqlDataSource` name.

```csharp
builder.Services.AddKeyedMySqlDataSource("MyPoolName",
builder.Configuration.GetConnectionString("MyConnectionString"));
```

### Application Name

Finally, the connection pool name can be specified by setting the `Application Name` connection string option:

```csharp
using var connection = new MySqlConnection("server=dbserver;...;Application Name=MyPoolName");
```

If `UseName` is used, it will override the `Application Name` connection string option.

### Default

For metrics, if no pool name is specified, the connection string (without a password) will be used as the pool name.
11 changes: 7 additions & 4 deletions src/MySqlConnector/Core/ConnectionPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,12 @@ private async ValueTask<ServerSession> ConnectSessionAsync(MySqlConnection conne
if (!connectionStringBuilder.Pooling)
return null;

if (name is not null)
connectionStringBuilder.ApplicationName = name;

// force a new pool to be created, ignoring the cache
var connectionSettings = new ConnectionSettings(connectionStringBuilder);
var pool = new ConnectionPool(loggingConfiguration, connectionSettings, name);
var pool = new ConnectionPool(loggingConfiguration, connectionSettings);
pool.StartReaperTask();
pool.StartDnsCheckTimer();
return pool;
Expand Down Expand Up @@ -551,7 +554,7 @@ private async ValueTask<ServerSession> ConnectSessionAsync(MySqlConnection conne

// create a new pool and attempt to insert it; if someone else beats us to it, just use their value
var connectionSettings = new ConnectionSettings(connectionStringBuilder);
var newPool = new ConnectionPool(loggingConfiguration!, connectionSettings, name: null);
var newPool = new ConnectionPool(loggingConfiguration!, connectionSettings);
pool = s_pools.GetOrAdd(normalizedConnectionString, newPool);

if (pool == newPool)
Expand Down Expand Up @@ -591,12 +594,12 @@ static List<ConnectionPool> GetCachedPools()
}
}

private ConnectionPool(MySqlConnectorLoggingConfiguration loggingConfiguration, ConnectionSettings cs, string? name)
private ConnectionPool(MySqlConnectorLoggingConfiguration loggingConfiguration, ConnectionSettings cs)
{
m_logger = loggingConfiguration.PoolLogger;
m_connectionLogger = loggingConfiguration.ConnectionLogger;
ConnectionSettings = cs;
Name = name;
Name = cs.ApplicationName;
SslProtocols = cs.TlsVersions;
m_generation = 0;
m_cleanSemaphore = new(1);
Expand Down
4 changes: 2 additions & 2 deletions src/MySqlConnector/Core/ConnectionSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public ConnectionSettings(MySqlConnectionStringBuilder csb)
AllowPublicKeyRetrieval = csb.AllowPublicKeyRetrieval;
AllowUserVariables = csb.AllowUserVariables;
AllowZeroDateTime = csb.AllowZeroDateTime;
ApplicationName = csb.ApplicationName;
ApplicationName = csb.ApplicationName is { Length: 0 } ? null : csb.ApplicationName;
AutoEnlist = csb.AutoEnlist;
CancellationTimeout = csb.CancellationTimeout;
ConnectionTimeout = ToSigned(csb.ConnectionTimeout);
Expand Down Expand Up @@ -216,7 +216,7 @@ private static MySqlGuidFormat GetEffectiveGuidFormat(MySqlGuidFormat guidFormat
public bool AllowPublicKeyRetrieval { get; }
public bool AllowUserVariables { get; }
public bool AllowZeroDateTime { get; }
public string ApplicationName { get; }
public string? ApplicationName { get; }
public bool AutoEnlist { get; }
public int CancellationTimeout { get; }
public int ConnectionTimeout { get; }
Expand Down
2 changes: 1 addition & 1 deletion src/MySqlConnector/Core/MetricsReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ internal static class MetricsReporter
public static void RemoveIdle(ConnectionPool pool) => s_connectionsUsageCounter.Add(-1, pool.IdleStateTagList);
public static void AddUsed(ConnectionPool pool) => s_connectionsUsageCounter.Add(1, pool.UsedStateTagList);
public static void RemoveUsed(ConnectionPool pool) => s_connectionsUsageCounter.Add(-1, pool.UsedStateTagList);
public static void AddTimeout(ConnectionPool? pool, ConnectionSettings connectionSettings) => s_connectionTimeouts.Add(1, new KeyValuePair<string, object?>("pool.name", pool?.Name ?? connectionSettings.ConnectionStringBuilder.GetConnectionString(includePassword: false)));
public static void AddTimeout(ConnectionPool? pool, ConnectionSettings connectionSettings) => s_connectionTimeouts.Add(1, new KeyValuePair<string, object?>("pool.name", pool?.Name ?? connectionSettings.ApplicationName ?? connectionSettings.ConnectionStringBuilder.GetConnectionString(includePassword: false)));
public static void RecordCreateTime(ConnectionPool pool, double seconds) => s_createTimeHistory.Record(seconds, pool.PoolNameTagList);
public static void RecordUseTime(ConnectionPool pool, double seconds) => s_useTimeHistory.Record(seconds, pool.PoolNameTagList);
public static void RecordWaitTime(ConnectionPool pool, double seconds) => s_waitTimeHistory.Record(seconds, pool.PoolNameTagList);
Expand Down
4 changes: 2 additions & 2 deletions src/MySqlConnector/Core/ServerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1777,7 +1777,7 @@ private void VerifyState(State state1, State state2, State state3, State state4,

internal SslProtocols SslProtocol => m_sslStream?.SslProtocol ?? SslProtocols.None;

private byte[] CreateConnectionAttributes(string programName)
private byte[] CreateConnectionAttributes(string? programName)
{
Log.CreatingConnectionAttributes(m_logger, Id);
var attributesWriter = new ByteBufferWriter();
Expand Down Expand Up @@ -1815,7 +1815,7 @@ private byte[] CreateConnectionAttributes(string programName)
#endif
attributesWriter.WriteLengthEncodedString("_pid");
attributesWriter.WriteLengthEncodedString(processId.ToString(CultureInfo.InvariantCulture));
if (programName.Length != 0)
if (!string.IsNullOrEmpty(programName))
{
attributesWriter.WriteLengthEncodedString("program_name");
attributesWriter.WriteLengthEncodedString(programName!);
Expand Down
3 changes: 3 additions & 0 deletions src/MySqlConnector/MySqlDataSourceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public MySqlDataSourceBuilder UseLoggerFactory(ILoggerFactory? loggerFactory)
/// </summary>
/// <param name="name">The data source name.</param>
/// <returns>This builder, so that method calls can be chained.</returns>
/// <remarks>The connection pool name is used to set the <c>program_name</c> connection attribute
/// (which is visible to some diagnostic tools) and the <c>pool.name</c> tag supplied with
/// <a href="https://mysqlconnector.net/diagnostics/metrics/">connection pool metrics</a>.</remarks>
public MySqlDataSourceBuilder UseName(string? name)
{
m_name = name;
Expand Down
4 changes: 2 additions & 2 deletions tests/MySqlConnector.Tests/Metrics/IConnectionCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public DataSourceConnectionCreator(bool usePooling, string? poolName, string? ap
m_dataSource = new MySqlDataSourceBuilder(connectionStringBuilder.ConnectionString)
.UseName(poolName)
.Build();
PoolName = poolName ?? connectionStringBuilder!.GetConnectionString(includePassword: false);
PoolName = poolName ?? applicationName ?? connectionStringBuilder!.GetConnectionString(includePassword: false);
}

public MySqlConnection OpenConnection() => m_dataSource!.OpenConnection();
Expand All @@ -34,7 +34,7 @@ public PlainConnectionCreator(bool usePooling, string? applicationName, MySqlCon
connectionStringBuilder.Pooling = usePooling;
connectionStringBuilder.ApplicationName = applicationName;
m_connectionString = connectionStringBuilder.ConnectionString;
PoolName = connectionStringBuilder.GetConnectionString(includePassword: false);
PoolName = applicationName ?? connectionStringBuilder.GetConnectionString(includePassword: false);
}

public MySqlConnection OpenConnection()
Expand Down

0 comments on commit c9d2217

Please sign in to comment.