A while back I had to integrate logging for my Azure APIM Integration that enabled logging outside of APIM (to be picked up by different groups) and logged information to separate locations.

To accomplish this task, I leveraged Azure Event Hubs for storing the logs and have outlined the steps below.  The high-level steps for this implementation are available here – https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-log-event-hubs – but there are some pieces I had to figure out to make this work correctly.

Create an Azure Event Namespace and Event Hubs

The first step is to create an Azure Event Hub Namespace (note this does not need to be in the current subscription and can be separate.  Once you have created the Namespace, you will need to create the individual Azure Event Hubs to which you want logs to be sent.

All that is required is to select the name of the Event Hub, all other defaults can be left as is.  In this scenario, I created three separate event hubs (all within the same namespace), aptly called Logger1, Logger2 & Logger3.

Copy the name of each EventHub as these will be the logger-ids used in the next steps.

Linking the Event Hubs to Azure APIM

This step requires you to go to this URL to link your Azure APIM instance to your Azure Event Hubs.  (You could also write this code on your own if you like, but this way is simpler).  When you have successfully logged in, navigate to the above page and click “Try It” – this will prompt you to sign in to your azure tenant.

You will need to fill in the values of the request as follows.

Field Description
LoggerId The id of the logger that you created in the prior step.
resourceGroupName The name of the Resource Group associated to the serviceName.
ServiceName The name of the Azure APIM instance you are creating this for
Name The pretty name you want to give your logger (can have spaces in it)

 

Lower down in the page you will need to set the messagebody of the request.  The loggerType will stay as “azureEventHub”.  The rest of the body is outlined below where to go to ensure you have the correct information.

{
“properties”: {
“loggerType”: “azureEventHub”,
“credentials”: {
“name” : “NAME_OF_LOGGER_GOES_HERE”,
“connectionString”: “Endpoint=”CONNECTION_STRING_GOES_HERE”
},
“description”: “This is the unclassified logger for Savannah”,
“resourceid”: “RESOURCE_ID_GOES_HERE”
}
}

Field Description
Name Use the name of the loggerId that you created.
Description Create a different description for each logger.
resourceId This is the resourceId for your name Azure Event Hub.  In your Azure Event Hub configuration, click on Properties in the left-hand navigation and then copy the value from the “Id” property.
Connectionstring The connectionstring is the path to your main Azure Event Hub namespace.  To find this information, navigate to the Azure Event Hub, click on Configuration (in the left-hand navigation), click on the default policy that has been created (RootManageSharedAccessKey) and then copy the value from the Connection string-primary key field.

 

When complete, hit the “Run” button at the bottom of the screen.  Upon successful completion you will receive a 200 response indicating the link has been created.  Be wary if you receive a 201 response, this means that the request was successfully but might not be correctly configured (In my case I forgot to change the logger name and was overwriting the same one).

Add logging into your Azure APIM Application

Logging for Azure APIM is done via the log-to-eventhub policy.  In the below example, I have encapsulated this as a policy fragment that I call from my APIs letting it determine where to log in based on the context of the request.

Below is a snippet of a sample fragment that logs to a specific logger.

<fragment>
    <set-header name="ErrorReason" exists-action="override">
        <value>@(context.LastError.Reason)</value>
    </set-header>
    <set-header name="ErrorMessage" exists-action="override">
        <value>@(context.LastError.Message)</value>
    </set-header>
    <set-variable name="logline" value="@{
                return new JObject(
                    new JProperty("Log-Level", context.Variables["log-level"]),                    
                    new JProperty("EventTime", DateTime.UtcNow.ToString()),
                    new JProperty("RequestIp", context.Request.IpAddress),
                    new JProperty("ErrorSource", context.LastError.Source),
                    new JProperty("ErrorReason", context.LastError.Reason),
                    new JProperty("ErrorMessage", context.LastError.Message),
                    new JProperty("ErrorScope", context.LastError.Scope),
                    new JProperty("ErrorSection", context.LastError.Section),
                    new JProperty("ErrorPath", context.LastError.Path),
                    new JProperty("ErrorPolicyId", context.LastError.PolicyId),
                    new JProperty("ErrorStatusCode",context.Response.StatusCode.ToString())).ToString();
            }" />

<log-to-eventhub logger-id="logger-1">@((string)context.Variables["logline"])/log-to-eventhub>
  </fragment>

Want more? Check out my book Code Your Way Up – available as an eBook or Paperback on Amazon (CAN and US).  I’m also the co-host of the Remotely Prepared podcast.

Author

Write A Comment