1+ #if NET6_0_OR_GREATER
2+ using System ;
13using System . Collections . Generic ;
24using System . Diagnostics ;
35using System . Diagnostics . Metrics ;
46using Amqp ;
7+ #endif
58
69namespace RabbitMQ . AMQP . Client . Impl
710{
11+ #if NET6_0_OR_GREATER
812// .NET docs on metric instrumentation: https://learn.microsoft.com/en-us/dotnet/core/diagnostics/metrics-instrumentation
913// OpenTelemetry semantic conventions for messaging metric: https://opentelemetry.io/docs/specs/semconv/messaging/messaging-metrics
10- internal sealed class SystemDiagnosticMetricsReporter : IMetricsReporter
14+ internal sealed class MetricsReporter : IMetricsReporter
1115 {
1216 const string Version = "0.1.0" ;
1317
1418 static readonly Meter Meter ;
1519
1620 static readonly Counter < int > MessagingClientSentMessages ;
21+ static readonly Histogram < double > MessagingClientOperationDuration ;
1722
18- readonly KeyValuePair < string , object ? > _messagingOperationSystemTag = new ( MessagingSystem , "rabbitmq" ) ;
23+ static readonly Counter < int > MessagingClientConsumedMessages ;
24+ static readonly Histogram < double > MessagingProcessDuration ;
1925
26+ readonly KeyValuePair < string , object ? >
27+ _messagingOperationSystemTag = new ( MessagingSystem , MessagingSystemValue ) ;
28+
29+ readonly KeyValuePair < string , object ? > _publishOperationName = new ( MessagingOperationName , PublishOperation ) ;
30+ readonly KeyValuePair < string , object ? > _sendOperationType = new ( MessagingOperationType , SendOperation ) ;
31+
32+ readonly KeyValuePair < string , object ? > _deliverOperationName = new ( MessagingOperationName , DeliverOperation ) ;
33+ readonly KeyValuePair < string , object ? > _processOperationType = new ( MessagingOperationType , ProcessOperation ) ;
34+
35+ private const string MessagingOperationName = "messaging.operation.name" ;
36+ private const string MessagingOperationType = "messaging.operation.type" ;
2037 private const string MessagingSystem = "messaging.system" ;
2138 private const string ErrorType = "error.type" ;
2239 private const string MessageDestinationName = "messaging.destination.name" ;
2340 private const string ServerAddress = "server.adress" ;
2441 private const string ServerPort = "server.port" ;
2542
43+ private const string ProcessOperation = "process" ;
44+ private const string DeliverOperation = "deliver" ;
45+ private const string PublishOperation = "publish" ;
46+ private const string SendOperation = "send" ;
47+ private const string MessagingSystemValue = "rabbitmq" ;
2648
27- static SystemDiagnosticMetricsReporter ( )
49+ static MetricsReporter ( )
2850 {
2951 Meter = new ( "RabbitMQ.Amqp" , Version ) ;
3052
@@ -33,26 +55,124 @@ static SystemDiagnosticMetricsReporter()
3355 unit : "{message}" ,
3456 description :
3557 "Number of messages producer attempted to send to the broker." ) ;
58+
59+ MessagingClientOperationDuration = Meter . CreateHistogram < double > (
60+ "messaging.client.operation.duration" ,
61+ unit : "s" ,
62+ description :
63+ "Duration of messaging operation initiated by a producer or consumer client." ) ;
64+
65+ MessagingClientConsumedMessages = Meter . CreateCounter < int > (
66+ "messaging.client.consumed.messages" ,
67+ unit : "{message}" ,
68+ description :
69+ "Number of messages that were delivered to the application. " ) ;
70+
71+ MessagingProcessDuration = Meter . CreateHistogram < double > (
72+ "messaging.process.duration" ,
73+ unit : "s" ,
74+ description :
75+ "Duration of processing operation. " ) ;
3676 }
3777
3878
39- public void ReportMessageSendSuccess ( IMetricsReporter . PublisherContext context )
79+ public void ReportMessageSendSuccess ( IMetricsReporter . PublisherContext context , long startTimestamp )
4080 {
4181 var serverAddress = new KeyValuePair < string , object ? > ( ServerAddress , context . ServerAddress ) ;
4282 var serverPort = new KeyValuePair < string , object ? > ( ServerPort , context . ServerPort ) ;
4383 var destination = new KeyValuePair < string , object ? > ( MessageDestinationName , context . Destination ) ;
44- MessagingClientSentMessages . Add ( 1 , serverAddress , serverPort , destination , _messagingOperationSystemTag ) ;
84+
85+ MessagingClientSentMessages . Add ( 1 , serverAddress , serverPort , destination , _messagingOperationSystemTag ,
86+ _sendOperationType , _publishOperationName ) ;
87+ if ( startTimestamp > 0 )
88+ {
89+ #if NET7_0_OR_GREATER
90+ var duration = Stopwatch . GetElapsedTime ( startTimestamp ) ;
91+ #else
92+ var duration =
93+ new TimeSpan ( ( long ) ( ( Stopwatch . GetTimestamp ( ) - startTimestamp ) * StopWatchTickFrequency ) ) ;
94+ #endif
95+ MessagingClientOperationDuration . Record ( duration . TotalSeconds , serverAddress , serverPort , destination ,
96+ _messagingOperationSystemTag , _sendOperationType , _publishOperationName ) ;
97+ }
4598 }
4699
47100
48- public void ReportMessageSendFailure ( IMetricsReporter . PublisherContext context , AmqpException amqpException )
101+ public void ReportMessageSendFailure ( IMetricsReporter . PublisherContext context , long startTimestamp ,
102+ AmqpException amqpException )
49103 {
50104 var errorType = new KeyValuePair < string , object ? > ( ErrorType , amqpException . GetType ( ) . Name ) ;
51105 var serverAddress = new KeyValuePair < string , object ? > ( ServerAddress , context . ServerAddress ) ;
52106 var serverPort = new KeyValuePair < string , object ? > ( ServerPort , context . ServerPort ) ;
53107 var destination = new KeyValuePair < string , object ? > ( MessageDestinationName , context . Destination ) ;
54108 MessagingClientSentMessages . Add ( 1 , errorType , serverAddress , serverPort , destination ,
55- _messagingOperationSystemTag ) ;
109+ _messagingOperationSystemTag , _sendOperationType , _publishOperationName ) ;
110+
111+ if ( startTimestamp > 0 )
112+ {
113+ #if NET7_0_OR_GREATER
114+ var duration = Stopwatch . GetElapsedTime ( startTimestamp ) ;
115+ #else
116+ var duration =
117+ new TimeSpan ( ( long ) ( ( Stopwatch . GetTimestamp ( ) - startTimestamp ) * StopWatchTickFrequency ) ) ;
118+ #endif
119+ MessagingClientOperationDuration . Record ( duration . TotalSeconds , errorType , serverAddress , serverPort ,
120+ destination ,
121+ _messagingOperationSystemTag , _sendOperationType , _publishOperationName ) ;
122+ }
123+ }
124+
125+ public void ReportMessageDeliverSuccess ( IMetricsReporter . ConsumerContext context , long startTimestamp )
126+ {
127+ var serverAddress = new KeyValuePair < string , object ? > ( ServerAddress , context . ServerAddress ) ;
128+ var serverPort = new KeyValuePair < string , object ? > ( ServerPort , context . ServerPort ) ;
129+ var destination = new KeyValuePair < string , object ? > ( MessageDestinationName , context . Destination ) ;
130+ MessagingClientConsumedMessages . Add ( 1 , serverAddress , serverPort , destination , _messagingOperationSystemTag ,
131+ _processOperationType , _deliverOperationName ) ;
132+ if ( startTimestamp > 0 )
133+ {
134+ #if NET7_0_OR_GREATER
135+ var duration = Stopwatch . GetElapsedTime ( startTimestamp ) ;
136+ #else
137+ var duration =
138+ new TimeSpan ( ( long ) ( ( Stopwatch . GetTimestamp ( ) - startTimestamp ) * StopWatchTickFrequency ) ) ;
139+ #endif
140+ MessagingProcessDuration . Record ( duration . TotalSeconds , serverAddress , serverPort ,
141+ destination ,
142+ _messagingOperationSystemTag , _sendOperationType , _publishOperationName ) ;
143+ }
144+ }
145+
146+ public void ReportMessageDeliverFailure ( IMetricsReporter . ConsumerContext context , long startTimestamp ,
147+ Exception exception )
148+ {
149+ var errorType = new KeyValuePair < string , object ? > ( ErrorType , exception . GetType ( ) . Name ) ;
150+ var serverAddress = new KeyValuePair < string , object ? > ( ServerAddress , context . ServerAddress ) ;
151+ var serverPort = new KeyValuePair < string , object ? > ( ServerPort , context . ServerPort ) ;
152+ var destination = new KeyValuePair < string , object ? > ( MessageDestinationName , context . Destination ) ;
153+ MessagingClientConsumedMessages . Add ( 1 , errorType , serverAddress , serverPort , destination ,
154+ _messagingOperationSystemTag ,
155+ _processOperationType , _deliverOperationName ) ;
156+ if ( startTimestamp > 0 )
157+ {
158+ #if NET7_0_OR_GREATER
159+ var duration = Stopwatch . GetElapsedTime ( startTimestamp ) ;
160+ #else
161+ var duration =
162+ new TimeSpan ( ( long ) ( ( Stopwatch . GetTimestamp ( ) - startTimestamp ) * StopWatchTickFrequency ) ) ;
163+ #endif
164+ MessagingProcessDuration . Record ( duration . TotalSeconds , errorType , serverAddress , serverPort ,
165+ destination ,
166+ _messagingOperationSystemTag , _sendOperationType , _publishOperationName ) ;
167+ }
56168 }
169+ #if ! NET7_0_OR_GREATER
170+ const long TicksPerMicrosecond = 10 ;
171+ const long TicksPerMillisecond = TicksPerMicrosecond * 1000 ;
172+ const long TicksPerSecond = TicksPerMillisecond * 1000 ; // 10,000,000
173+ static readonly double StopWatchTickFrequency = ( double ) TicksPerSecond / Stopwatch . Frequency ;
174+ #endif
57175 }
176+ #else
177+ #endif
58178}
0 commit comments