2020using System.ComponentModel;
2121using System.Data;
2222using System.Data.Common;
23+ using System.Diagnostics;
2324using System.Text;
2425using System.Threading;
2526using System.Threading.Tasks;
2627using FirebirdSql.Data.Common;
2728using FirebirdSql.Data.Logging;
29+ using FirebirdSql.Data.Trace;
2830
2931namespace FirebirdSql.Data.FirebirdClient;
3032
@@ -49,6 +51,7 @@ public sealed class FbCommand : DbCommand, IFbPreparedCommand, IDescriptorFiller
4951 private int? _commandTimeout;
5052 private int _fetchSize;
5153 private Type[] _expectedColumnTypes;
54+ private Activity _currentActivity;
5255
5356 #endregion
5457
@@ -1094,6 +1097,13 @@ internal void Release()
10941097 _statement.Dispose2();
10951098 _statement = null;
10961099 }
1100+
1101+ if (_currentActivity != null)
1102+ {
1103+ // Do not set status to Ok: https://opentelemetry.io/docs/concepts/signals/traces/#span-status
1104+ _currentActivity.Dispose();
1105+ _currentActivity = null;
1106+ }
10971107 }
10981108 Task IFbPreparedCommand.ReleaseAsync(CancellationToken cancellationToken) => ReleaseAsync(cancellationToken);
10991109 internal async Task ReleaseAsync(CancellationToken cancellationToken = default)
@@ -1112,6 +1122,13 @@ internal async Task ReleaseAsync(CancellationToken cancellationToken = default)
11121122 await _statement.Dispose2Async(cancellationToken).ConfigureAwait(false);
11131123 _statement = null;
11141124 }
1125+
1126+ if (_currentActivity != null)
1127+ {
1128+ // Do not set status to Ok: https://opentelemetry.io/docs/concepts/signals/traces/#span-status
1129+ _currentActivity.Dispose();
1130+ _currentActivity = null;
1131+ }
11151132 }
11161133
11171134 void IFbPreparedCommand.TransactionCompleted() => TransactionCompleted();
@@ -1332,6 +1349,26 @@ private async ValueTask UpdateParameterValuesAsync(Descriptor descriptor, Cancel
13321349
13331350 #endregion
13341351
1352+ #region Tracing
1353+
1354+ private void TraceCommandStart()
1355+ {
1356+ Debug.Assert(_currentActivity == null);
1357+ if (FbActivitySource.Source.HasListeners())
1358+ _currentActivity = FbActivitySource.CommandStart(this);
1359+ }
1360+
1361+ private void TraceCommandException(Exception e)
1362+ {
1363+ if (_currentActivity != null)
1364+ {
1365+ FbActivitySource.CommandException(_currentActivity, e);
1366+ _currentActivity = null;
1367+ }
1368+ }
1369+
1370+ #endregion Tracing
1371+
13351372 #region Private Methods
13361373
13371374 private void Prepare(bool returnsSet)
@@ -1476,57 +1513,73 @@ private async Task PrepareAsync(bool returnsSet, CancellationToken cancellationT
14761513 private void ExecuteCommand(CommandBehavior behavior, bool returnsSet)
14771514 {
14781515 LogMessages.CommandExecution(Log, this);
1516+ TraceCommandStart();
1517+ try
1518+ {
1519+ Prepare(returnsSet);
14791520
1480- Prepare(returnsSet);
1521+ if ((behavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess ||
1522+ (behavior & CommandBehavior.SingleResult) == CommandBehavior.SingleResult ||
1523+ (behavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow ||
1524+ (behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection ||
1525+ behavior == CommandBehavior.Default)
1526+ {
1527+ // Set the fetch size
1528+ _statement.FetchSize = _fetchSize;
14811529
1482- if ((behavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess ||
1483- (behavior & CommandBehavior.SingleResult) == CommandBehavior.SingleResult ||
1484- (behavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow ||
1485- (behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection ||
1486- behavior == CommandBehavior.Default)
1487- {
1488- // Set the fetch size
1489- _statement.FetchSize = _fetchSize;
1530+ // Set if it's needed the Records Affected information
1531+ _statement.ReturnRecordsAffected = _connection.ConnectionOptions.ReturnRecordsAffected;
14901532
1491- // Set if it's needed the Records Affected information
1492- _statement.ReturnRecordsAffected = _connection.ConnectionOptions.ReturnRecordsAffected;
1533+ // Validate input parameter count
1534+ if (_namedParameters.Count > 0 && !HasParameters)
1535+ {
1536+ throw FbException.Create("Must declare command parameters.");
1537+ }
14931538
1494- // Validate input parameter count
1495- if (_namedParameters.Count > 0 && !HasParameters)
1496- {
1497- throw FbException.Create("Must declare command parameters.");
1539+ // Execute
1540+ _statement.Execute(CommandTimeout * 1000, this);
14981541 }
1499-
1500- // Execute
1501- _statement.Execute(CommandTimeout * 1000, this);
1542+ }
1543+ catch (Exception e)
1544+ {
1545+ TraceCommandException(e);
1546+ throw;
15021547 }
15031548 }
15041549 private async Task ExecuteCommandAsync(CommandBehavior behavior, bool returnsSet, CancellationToken cancellationToken = default)
15051550 {
15061551 LogMessages.CommandExecution(Log, this);
1552+ TraceCommandStart();
1553+ try
1554+ {
1555+ await PrepareAsync(returnsSet, cancellationToken).ConfigureAwait(false);
15071556
1508- await PrepareAsync(returnsSet, cancellationToken).ConfigureAwait(false);
1557+ if ((behavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess ||
1558+ (behavior & CommandBehavior.SingleResult) == CommandBehavior.SingleResult ||
1559+ (behavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow ||
1560+ (behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection ||
1561+ behavior == CommandBehavior.Default)
1562+ {
1563+ // Set the fetch size
1564+ _statement.FetchSize = _fetchSize;
15091565
1510- if ((behavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess ||
1511- (behavior & CommandBehavior.SingleResult) == CommandBehavior.SingleResult ||
1512- (behavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow ||
1513- (behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection ||
1514- behavior == CommandBehavior.Default)
1515- {
1516- // Set the fetch size
1517- _statement.FetchSize = _fetchSize;
1566+ // Set if it's needed the Records Affected information
1567+ _statement.ReturnRecordsAffected = _connection.ConnectionOptions.ReturnRecordsAffected;
15181568
1519- // Set if it's needed the Records Affected information
1520- _statement.ReturnRecordsAffected = _connection.ConnectionOptions.ReturnRecordsAffected;
1569+ // Validate input parameter count
1570+ if (_namedParameters.Count > 0 && !HasParameters)
1571+ {
1572+ throw FbException.Create("Must declare command parameters.");
1573+ }
15211574
1522- // Validate input parameter count
1523- if (_namedParameters.Count > 0 && !HasParameters)
1524- {
1525- throw FbException.Create("Must declare command parameters.");
1575+ // Execute
1576+ await _statement.ExecuteAsync(CommandTimeout * 1000, this, cancellationToken).ConfigureAwait(false);
15261577 }
1527-
1528- // Execute
1529- await _statement.ExecuteAsync(CommandTimeout * 1000, this, cancellationToken).ConfigureAwait(false);
1578+ }
1579+ catch (Exception e)
1580+ {
1581+ TraceCommandException(e);
1582+ throw;
15301583 }
15311584 }
15321585
0 commit comments