Reputation: 229
I've created an Azure Function with an HTTP trigger. I would like detailed error information to be returned to callers. Is there a way of doing for uncaught exceptions? Strangely, Azure Functions does return the detailed error info when running in Visual Studio, but not when deployed.
[FunctionName("MyAzureFunction")]
public static async Task<HttpResponseMessage> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage httpRequest,
TraceWriter traceWriter,
CancellationToken cancellationToken)
{
try
{
var response = await ProcessAsync(request, cancellationToken);
return httpRequest.CreateResponse(HttpStatusCode.OK, response);
}
catch (ArgumentException ex)
{
traceWriter.LogWarning($"Argument error: {ex}");
return httpRequest.CreateResponse(HttpStatusCode.BadRequest, ex.Message);
}
catch (Exception ex)
{
traceWriter.LogError($"Error: {ex}");
throw;
}
}
Upvotes: 6
Views: 20318
Reputation: 93
As a more recent solution for request and response, it is preferable to use the HttpRequest and IActionResult instead of HttpRequestMessage and HttpResponseMessage respectively. Also, you can handle the failed operations manually without a throw using the telemetry client. In case of a bad request, this code would create a failed operation on the Application Insights.
[FunctionName(nameof(MyAzureFunction))]
public static async Task<IActionResult> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest httpRequest,
ILogger logger,
CancellationToken cancellationToken)
{
using var operation = _telemetryClient.StartOperation(new RequestTelemetry
{
Name = $"Execute MyAzureFunction"
});
try
{
var response = await ProcessAsync(request, cancellationToken);
// NOTE: You can alternatively handle the response in a layer before and use a generic object result here:
//return new ObjectResult(response)
//{
// StatusCode = response.Status
//};
return new OkObjectResult(result);
}
catch (ArgumentException ex)
{
logger.LogWarning(ex, $"Argument error: {ex.Message}");
// NOTE: Without this, the original request would be considered as successful, although the Http response code would be 400
operation.Telemetry.Success = false;
operation.Telemetry.ResponseCode = HttpStatusCode.BadRequest.ToString();
return new BadRequestObjectResult(ex.Message);
}
catch (Exception ex)
{
logger.LogError($"Error: {ex}");
throw;
}
}
Upvotes: 5
Reputation: 35134
Generally, returning exception details to the external caller is considered bad practice from security standpoint and otherwise. Because of that, it makes sense to block this information by default.
I would replace throw;
statement with the one returning manually formatted error. If you are OK with exposing the exception message to the caller, it's as simple as
return httpRequest.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
If the caller is external, again, I would not do that: instead, return a generic error message and then rely on logging for debugging.
Upvotes: 6