22// Licensed under the MIT License.
33
44using System ;
5+ using System . Diagnostics ;
6+ using System . Linq ;
57using System . Net ;
68using System . Net . Mime ;
79using System . Threading . Tasks ;
810using Azure . DataApiBuilder . Config . ObjectModel ;
11+ using Azure . DataApiBuilder . Core . Configurations ;
912using Azure . DataApiBuilder . Core . Models ;
1013using Azure . DataApiBuilder . Core . Services ;
1114using Azure . DataApiBuilder . Service . Exceptions ;
15+ using Azure . DataApiBuilder . Service . Telemetry ;
1216using Microsoft . AspNetCore . Http ;
1317using Microsoft . AspNetCore . Mvc ;
18+ using Microsoft . AspNetCore . Server . Kestrel . Core . Internal . Http ;
1419using Microsoft . Extensions . Logging ;
1520
1621namespace Azure . DataApiBuilder . Service . Controllers
@@ -47,11 +52,14 @@ public class RestController : ControllerBase
4752
4853 private readonly ILogger < RestController > _logger ;
4954
55+ private readonly RuntimeConfigProvider _runtimeConfigProvider ;
56+
5057 /// <summary>
5158 /// Constructor.
5259 /// </summary>
53- public RestController ( RestService restService , IOpenApiDocumentor openApiDocumentor , ILogger < RestController > logger )
60+ public RestController ( RuntimeConfigProvider runtimeConfigProvider , RestService restService , IOpenApiDocumentor openApiDocumentor , ILogger < RestController > logger )
5461 {
62+ _runtimeConfigProvider = runtimeConfigProvider ;
5563 _restService = restService ;
5664 _openApiDocumentor = openApiDocumentor ;
5765 _logger = logger ;
@@ -185,11 +193,29 @@ private async Task<IActionResult> HandleOperation(
185193 string route ,
186194 EntityActionOperation operationType )
187195 {
196+ if ( route . Equals ( REDIRECTED_ROUTE ) )
197+ {
198+ return NotFound ( ) ;
199+ }
200+
201+ Stopwatch stopwatch = Stopwatch . StartNew ( ) ;
202+ // This activity tracks the entire REST request.
203+ using Activity ? activity = TelemetryTracesHelper . DABActivitySource . StartActivity ( $ "{ HttpContext . Request . Method } { ( route . Split ( '/' ) . Length > 1 ? route . Split ( '/' ) [ 1 ] : string . Empty ) } ") ;
204+
188205 try
189206 {
190- if ( route . Equals ( REDIRECTED_ROUTE ) )
207+ TelemetryMetricsHelper . IncrementActiveRequests ( ApiType . REST ) ;
208+
209+ if ( activity is not null )
191210 {
192- return NotFound ( ) ;
211+ activity . TrackRestControllerActivityStarted (
212+ Enum . Parse < HttpMethod > ( HttpContext . Request . Method , ignoreCase : true ) ,
213+ HttpContext . Request . Headers [ "User-Agent" ] . ToString ( ) ,
214+ operationType . ToString ( ) ,
215+ route ,
216+ HttpContext . Request . QueryString . ToString ( ) ,
217+ HttpContext . Request . Headers [ "X-MS-API-ROLE" ] . FirstOrDefault ( ) ?? HttpContext . User . FindFirst ( "role" ) ? . Value ,
218+ ApiType . REST ) ;
193219 }
194220
195221 // Validate the PathBase matches the configured REST path.
@@ -208,8 +234,21 @@ private async Task<IActionResult> HandleOperation(
208234
209235 ( string entityName , string primaryKeyRoute ) = _restService . GetEntityNameAndPrimaryKeyRouteFromRoute ( routeAfterPathBase ) ;
210236
237+ // This activity tracks the query execution. This will create a new activity nested under the REST request activity.
238+ using Activity ? queryActivity = TelemetryTracesHelper . DABActivitySource . StartActivity ( $ "QUERY { entityName } ") ;
211239 IActionResult ? result = await _restService . ExecuteAsync ( entityName , operationType , primaryKeyRoute ) ;
212240
241+ RuntimeConfig runtimeConfig = _runtimeConfigProvider . GetConfig ( ) ;
242+ string dataSourceName = runtimeConfig . GetDataSourceNameFromEntityName ( entityName ) ;
243+ DatabaseType databaseType = runtimeConfig . GetDataSourceFromDataSourceName ( dataSourceName ) . DatabaseType ;
244+
245+ if ( queryActivity is not null )
246+ {
247+ queryActivity . TrackQueryActivityStarted (
248+ databaseType ,
249+ dataSourceName ) ;
250+ }
251+
213252 if ( result is null )
214253 {
215254 throw new DataApiBuilderException (
@@ -218,6 +257,13 @@ private async Task<IActionResult> HandleOperation(
218257 subStatusCode : DataApiBuilderException . SubStatusCodes . EntityNotFound ) ;
219258 }
220259
260+ int statusCode = ( result as ObjectResult ) ? . StatusCode ?? ( result as StatusCodeResult ) ? . StatusCode ?? ( result as JsonResult ) ? . StatusCode ?? 200 ;
261+ if ( activity is not null && activity . IsAllDataRequested )
262+ {
263+ HttpStatusCode httpStatusCode = Enum . Parse < HttpStatusCode > ( statusCode . ToString ( ) , ignoreCase : true ) ;
264+ activity . TrackRestControllerActivityFinished ( httpStatusCode ) ;
265+ }
266+
221267 return result ;
222268 }
223269 catch ( DataApiBuilderException ex )
@@ -228,6 +274,10 @@ private async Task<IActionResult> HandleOperation(
228274 HttpContextExtensions . GetLoggerCorrelationId ( HttpContext ) ) ;
229275
230276 Response . StatusCode = ( int ) ex . StatusCode ;
277+ activity ? . TrackRestControllerActivityFinishedWithException ( ex , ex . StatusCode ) ;
278+
279+ HttpMethod method = Enum . Parse < HttpMethod > ( HttpContext . Request . Method , ignoreCase : true ) ;
280+ TelemetryMetricsHelper . TrackError ( method , ex . StatusCode , route , ApiType . REST , ex ) ;
231281 return ErrorResponse ( ex . SubStatusCode . ToString ( ) , ex . Message , ex . StatusCode ) ;
232282 }
233283 catch ( Exception ex )
@@ -238,11 +288,26 @@ private async Task<IActionResult> HandleOperation(
238288 HttpContextExtensions . GetLoggerCorrelationId ( HttpContext ) ) ;
239289
240290 Response . StatusCode = ( int ) HttpStatusCode . InternalServerError ;
291+
292+ HttpMethod method = Enum . Parse < HttpMethod > ( HttpContext . Request . Method , ignoreCase : true ) ;
293+ activity ? . TrackRestControllerActivityFinishedWithException ( ex , HttpStatusCode . InternalServerError ) ;
294+
295+ TelemetryMetricsHelper . TrackError ( method , HttpStatusCode . InternalServerError , route , ApiType . REST , ex ) ;
241296 return ErrorResponse (
242297 DataApiBuilderException . SubStatusCodes . UnexpectedError . ToString ( ) ,
243298 SERVER_ERROR ,
244299 HttpStatusCode . InternalServerError ) ;
245300 }
301+ finally
302+ {
303+ stopwatch . Stop ( ) ;
304+ HttpMethod method = Enum . Parse < HttpMethod > ( HttpContext . Request . Method , ignoreCase : true ) ;
305+ HttpStatusCode httpStatusCode = Enum . Parse < HttpStatusCode > ( Response . StatusCode . ToString ( ) , ignoreCase : true ) ;
306+ TelemetryMetricsHelper . TrackRequest ( method , httpStatusCode , route , ApiType . REST ) ;
307+ TelemetryMetricsHelper . TrackRequestDuration ( method , httpStatusCode , route , ApiType . REST , stopwatch . Elapsed ) ;
308+
309+ TelemetryMetricsHelper . DecrementActiveRequests ( ApiType . REST ) ;
310+ }
246311 }
247312
248313 /// <summary>
0 commit comments