- 8 minutes to read

Event Hub Policy

Use scalable, policy-based logging for Azure API Management with Nodinite. This guide helps you set up Event Hub logging, configure loggers, and implement policies so you can securely and efficiently track all requests and responses.

✅ Log requests and responses with full payload and headers
✅ Integrate with Azure Event Hub for scalable, asynchronous logging
✅ Monitor and manage loggers directly from Nodinite
✅ Use policy-based logging for flexibility and security
✅ Prevent data loss with robust pickup and monitoring agents

Info

This guide shows you how to apply a Nodinite-specific policy to enable logging from the Azure API Management platform to Nodinite.

Warning

The Event Hub logging option enforces a 200 KB limit. If you log messages larger than this, the event will not be logged. For large messages, use the Blob Storage Policy.

graph LR subgraph "Payload < 200KB" A[Azure API Management
with Policy 2] A -->|1. Log Event,
payload < 200KB| B(Azure Event Hub) end subgraph "Nodinite" B --> C{Pickup Service} C --> F[Log API] end

Diagram: Event Hub policy-based logging from Azure API Management to Nodinite.

Event Hub Overview

You create a Nodinite Log Event and send it to Azure Event Hub as intermediate storage. The Nodinite Pickup Log Events Service Logging Agent transfers the data to your Nodinite instance for use in self-service Log Views.

To enable Nodinite logging from your APIs in Azure API Management:

When you activate the policy, Azure API Management creates a Nodinite-specific JSON Log Event and posts it to the named Event Hub. The Nodinite Pickup Log Events Service Logging Agent asynchronously moves the JSON Log Event to Nodinite.

Event Hub Logger

To log using Azure Event Hub, create a named Event Hub Logger. Reference this logger by name in your policy. You cannot rename a logger—delete and recreate it if needed. Create it using Nodinite or tools like Insomnia.

Add one or more named Event Hub loggers to create the Event Hub Logger used by the Policy. This enables logging to Nodinite using Azure Event Hub as intermediate storage.

Tip

Use the Nodinite Azure Monitoring Agent to manage and monitor your Event Hub Loggers.

Important

If you use Postman, review Security Risks of Postman.

You can also create the Event Hub Logger by performing a PUT method with a Body; a template is provided below:

Method URL
PUT https://management.azure.com/subscriptions/{{subscriptionId}}/resourceGroups/{{resourceGroup}}/providers/Microsoft.ApiManagement/service/{{APIMGMTServiceName}}/loggers/{{loggerName}}?api-version=2019-12-01
DELETE https://management.azure.com/subscriptions/{{subscriptionId}}/resourceGroups/{{resourceGroup}}/providers/Microsoft.ApiManagement/service/{{APIMGMTServiceName}}/loggers/{{loggerName}}?api-version=2019-12-01
  • {{subscriptionId}}

The {loggerName} uniquely identifies this logger in your API Management Service ({{APIMGMTServiceName}}). Use a unique name per Event Hub and environment (Prod, QA, Test, ...).

Important

Once you reference a Logger in any APIM Policy, you cannot remove it. To change the name, remove all references, drop the old one, and recreate it with the new name.

{
  "properties": {
    "loggerType": "azureEventHub",
    "description": "{description}",
    "resourceId": "{resourceId}",
    "credentials": {
      "name": "{`eventHubEntityName`}",
      "connectionString": "Endpoint=sb://{namespace}.servicebus.windows.net/;SharedAccessKeyName={sharedAccessKeyName};SharedAccessKey={sharedAccessKey};EntityPath={entityPath}"
    }
  }
}

Use this Body as a template and modify it for your needs.

Field Variable Value Description
loggerType - azureEventHub Hard coded value. DO NOT CHANGE!
description {description} Doing good Add a user-friendly description for this Event Hub Logger
resourceId {resourceId} /subscriptions/{SubscriptionId}/resourceGroups/{ResourceGroupName}/providers/Microsoft.EventHub/namespaces/{EventHubNamespaceName}/eventhubs/{eventhubName} NOTE: The target Event Hub Entity may be in another subscription/resource group. Enter values accordingly
name {eventHubEntityName} eventHubEntityName OPTIONAL: Name of the Event Hub Entity if not provided in the connection string
connectionString {namespace} The namespace with the target Event Hub
connectionString {sharedAccessKeyName} Name of the shared access key
connectionString {sharedAccessKey} The shared access key for the provided key name
connectionString {entityPath} Name of the target event hub entity for Nodinite JSON Log Event. If you provide {entityPath}, you do not need to specify {eventHubEntityName}

Tip

Use a SAS key with Manage permission to create the Event Hub Logger. The Send permission is not enough. We recommend a dedicated SAS key for each Event Hub Logger for easy revocation and best security.

API Policy Configuration

Decide what to log (Request and/or Response) and add the configuration to your policy in the inbound, outbound, or both sections.

Direction Type
Inbound Request
Outbound Response

The template below logs:

  • Mandatory properties for a Nodinite Log Event (modify as needed for your business)
  • HTTP Headers as context properties

    Info

    Some properties are excluded in the sample code

  • Body

Replace '{loggerName}' in both the API management logger and the code snippets below for the Policy configuration.

The example below creates a basic Nodinite JSON Log Event with common, mandatory, and optional properties.

  • Context is optional
  • Body is optional (note the 200 KB limit on the JSON using the Event Hub Logger; consider Blob Storage Policy[] for larger messages).
<log-to-eventhub logger-id='{loggerName}'>
    @{
    var body =  context.Request.Body.As<string>(preserveContent: true);

    var bodyToLog = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(body));

    var headers = context.Request.Headers
                .Where(h => h.Key != "Authorization" && h.Key != "Ocp-Apim-Subscription-Key");

    Dictionary<string, string> contextProperties = new Dictionary<string, string>();
    foreach (var h in headers) {
        contextProperties.Add(string.Format("Header#{0}", h.Key), String.Join(", ", h.Value));
    }
    
    var requestLogMessage = new {
        LogAgentValueId = 15,
        EndPointName = context.Deployment.ServiceName + "/" + context.Api.Name + "/" + context.Operation.Name,
        EndPointUri = context.Deployment.ServiceName + "/" + context.Api.Name + "/" + context.Operation.Name,
        EndPointDirection = 10,
        EndPointTypeId = 71,
        OriginalMessageTypeName = "Nodinite.Schemas/Nodinite.Demo/5.0#Orders",
        LogDateTime = DateTime.UtcNow,
        Context = contextProperties,
        Body = bodyToLog
    };

    return JsonConvert.SerializeObject(requestLogMessage);
    }
</log-to-eventhub>

Example Azure Event Hub Policy

This complete policy logs both inbound (Request) and outbound (Response) information.

In this example, you add a clientTrackingId (guid) if not provided in the x-ms-client-tracking-id HTTP header, plus other optional properties for a Nodinite Log Event.

x-ms-client-tracking-id
<policies>
    <inbound>
        <!-- creating a tracking/correlation id -->
        <set-variable name="clientTrackingId" value="@{ 
            return Guid.NewGuid().ToString();
        }" />
        <!-- if x-ms-client-tracking-id exists use it, if not, use clientTrackingId -->
        <set-header name="x-ms-client-tracking-id" exists-action="skip">
            <value>@(context.Variables.GetValueOrDefault<string>("clientTrackingId"))</value>
        </set-header>
        <!-- Put on logger -->
        <log-to-eventhub logger-id="{loggerName}">
            @{
                var body =  context.Request.Body.As<string>(preserveContent: true); // in case we need it later...

                var bodyToLog = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(body));

                var headers = context.Request.Headers
                            .Where(h => h.Key != "Authorization" && h.Key != "Ocp-Apim-Subscription-Key");

                var correlationId = headers.Any(h=>h.Key == "x-ms-client-tracking-id") ? headers.First(h => h.Key == "x-ms-client-tracking-id").Value[0] : context.Variables.GetValueOrDefault<string>("clientTrackingId"); 

                Dictionary<string, string> contextProperties = new Dictionary<string, string>();
                contextProperties.Add("Correlation Id", correlationId);
            
                foreach (var h in headers) {
                    contextProperties.Add(string.Format("Header#{0}", h.Key), String.Join(", ", h.Value));
                }
                
                var requestLogMessage = new {
                    LogAgentValueId = 15,
                    EndPointName = context.Deployment.ServiceName + "/" + context.Api.Name + "/" + context.Operation.Name,
                    EndPointUri = context.Deployment.ServiceName + "/" + context.Api.Name + "/" + context.Operation.Name,
                    EndPointDirection = 10,
                    EndPointTypeId = 71,
                    EventDirection=21,
                    OriginalMessageTypeName = "Nodinite.Schemas/Nodinite.Demo/5.0#Orders",
                    LogDateTime = DateTime.UtcNow,
                    LogStatus = 0,
                    ApplicationInterchangeId = correlationId,
                    Context = contextProperties,
                    LogText = "Hello World from Nodinite API mgmt logging policy",
                    Body = bodyToLog
                };

                return JsonConvert.SerializeObject(requestLogMessage);
            }
        </log-to-eventhub>
    </inbound>
    <backend>
        <forward-request />
    </backend>
    <outbound>
        <!-- if x-ms-client-tracking-id exists use it, if not, use clientTrackingId -->
        <set-header name="x-ms-client-tracking-id" exists-action="skip">
            <value>@(context.Variables.GetValueOrDefault<string>("Correlation Id"))</value>
        </set-header>
        <log-to-eventhub logger-id="{loggerName}">
            @{
                var body =  context.Response.Body.As<string>(preserveContent: true); // in case we need it later...

                var bodyToLog = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(body));

                var headers = context.Response.Headers
                            .Where(h => h.Key != "Authorization" && h.Key != "Ocp-Apim-Subscription-Key");
                
                var correlationId = headers.Any(h=>h.Key == "x-ms-client-tracking-id") ? headers.First(h => h.Key == "x-ms-client-tracking-id").Value[0] : context.Variables.GetValueOrDefault<string>("clientTrackingId"); 

                Dictionary<string, string> contextProperties = new Dictionary<string, string>();
                contextProperties.Add("Correlation Id", correlationId);
                foreach (var h in headers) {
                    contextProperties.Add(string.Format("Header#{0}", h.Key), String.Join(", ", h.Value));
                }
                string logText = "";

                if (context.Response.StatusCode > 300)
                {
                    logText = "Guru meditation";
                }
                
                var requestLogMessage = new {
                    LogAgentValueId = 15,
                    EndPointName = context.Deployment.ServiceName + "/" + context.Api.Name + "/" + context.Operation.Name,
                    EndPointUri = context.Deployment.ServiceName + "/" + context.Api.Name + "/" + context.Operation.Name,
                    EndPointDirection = 10,
                    EndPointTypeId = 71,
                    EventDirection=25,
                    OriginalMessageTypeName = "Nodinite.Schemas/Nodinite.Demo/5.0#OrderResponses",
                    LogDateTime = DateTime.UtcNow,
                    ApplicationInterchangeId = correlationId,
                    Context = contextProperties,
                    Body = bodyToLog,
                    LogStatus = context.Response.StatusCode,
                    LogText = logText
                };
                return JsonConvert.SerializeObject(requestLogMessage);
            }
        </log-to-eventhub>
    </outbound>
    <on-error />
</policies>

Troubleshooting

Contact our Support if you need help implementing Logging.

Next Step

Search Fields
Log Views

Azure Application Access
JSON Log Event
Managing
Monitoring
Non Events Agent
Pickup Log Events Service Logging Agent

Interested in logging from other Azure Related Services?