Sanjay Kumar
OMVPOpal Tools CertificationConfigured Commerce Developer Certification +3
Nov 19, 2025
visibility 927
star star star star star star
(3 votes)

Operational observability using application insights to trace checkout end to end

You can’t fix what you can’t see. In a modern, distributed e‑commerce system, the checkout flow touches multiple services from the front-end UI to backend APIs, payment gateways, and inventory systems. Failures, performance issues, or unexpected latencies often hide in the gaps between these components.

This is where operational observability becomes critical. By leveraging Azure Application Insights together with your existing structured logging, you can achieve actionable, end-to-end visibility into every checkout transaction.

What to trace

  • Page/controller actions: enter/exit, validation failures.
  • Payment orchestration: gateway called, result, latency, timeouts.
  • Business events: cart created, booking info saved, order created.
  • Correlation keys: cartReference, paymentMethod, user/device attributes.

Let's Configure and Code

  • Application Insights is configured:
ApplicationInsights":{
  "ConnectionString": "InstrumentationKey={my_key};IngestionEndpoint= {applicationinsights_endpoint}"
}
  • Checkout logs key breadcrumbs with a cart reference (great for correlation)
    Note: In this implementation, cartReference is used as a meta‑key to identify and track each cart / checkout session across telemetry. You are free to replace it with any custom key / value that suits your domain model (e.g., orderId, sessionId, checkoutId).

Entry:

_fluentLogger
    .Data(("CartReference", cart.GetCartReference()),
          ("BookingInfo", model.BookingInfo))
    .LogInfo("Booking calendar");
return View(GetViewPath(currentPage), model);

Exit:

_fluentLogger
    .Data((nameof(checkoutBookingInfo), checkoutBookingInfo),
          ("CartReference", cart.GetCartReference()))
    .LogInfo("Booking POST");

Add rich telemetry with correlation

Use cartReference as your primary correlation property across logs, traces, and metrics. If you’re already using ILogger (or Serilog) with AI export, enrich the scope; otherwise, send custom events via TelemetryClient.New code (example pattern):

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;

public class CheckoutTelemetryService
{
    private readonly TelemetryClient _telemetryClient;

    public CheckoutTelemetryService(TelemetryClient telemetryClient)
    {
        _telemetryClient = telemetryClient ?? throw new ArgumentNullException(nameof(telemetryClient));
    }

    /// <summary>
    /// Tracks a specific step in the checkout process.
    /// </summary>
    /// <param name="stepName">Name of the checkout step (e.g., "cartValidation").</param>
    /// <param name="cartReference">Unique identifier for the cart.</param>
    /// <param name="properties">Optional custom properties.</param>
    /// <param name="durationMs">Optional duration of the step in milliseconds.</param>
    public void TrackCheckoutStep(
        string stepName, 
        string cartReference, 
        IDictionary<string, string>? properties = null, 
        double? durationMs = null)
    {
        var telemetryEvent = new EventTelemetry($"checkout_{stepName}");
        telemetryEvent.Properties["cartReference"] = cartReference;

        if (properties != null)
        {
            foreach (var kvp in properties)
            {
                telemetryEvent.Properties[kvp.Key] = kvp.Value;
            }
        }

        if (durationMs.HasValue)
        {
            telemetryEvent.Metrics["duration_ms"] = durationMs.Value;
        }

        _telemetryClient.TrackEvent(telemetryEvent);
    }

    /// <summary>
    /// Starts a dependency telemetry operation, such as payment or inventory check.
    /// </summary>
    /// <param name="dependencyName">Name of the dependency operation.</param>
    /// <param name="cartReference">Cart reference ID.</param>
    /// <param name="dependency">Outputs the created DependencyTelemetry object.</param>
    /// <returns>IDisposable to stop the operation when disposed.</returns>
    public IDisposable StartDependencyOperation(
        string dependencyName, 
        string cartReference, 
        out DependencyTelemetry dependency)
    {
        dependency = new DependencyTelemetry("checkoutDependency", dependencyName, DateTimeOffset.UtcNow, TimeSpan.Zero, success: true);
        dependency.Properties["cartReference"] = cartReference;

        return new TelemetryOperation(_telemetryClient, dependency);
    }

    /// <summary>
    /// Helper class to manage the lifetime of telemetry operations.
    /// </summary>
    private sealed class TelemetryOperation : IDisposable
    {
        private readonly TelemetryClient _telemetryClient;
        private readonly IOperationHolder<DependencyTelemetry> _operationHolder;

        public TelemetryOperation(TelemetryClient telemetryClient, DependencyTelemetry telemetry)
        {
            _telemetryClient = telemetryClient ?? throw new ArgumentNullException(nameof(telemetryClient));
            _operationHolder = _telemetryClient.StartOperation(telemetry);
        }

        public void Dispose()
        {
            _telemetryClient.StopOperation(_operationHolder);
        }
    }
}

Use it in checkout/payment paths:

var cartRef = cart.GetCartReference();
_checkoutTelemetry.TrackCheckoutStep("shipping_viewed", cartRef, new Dictionary<string,string> {
    ["device"] = Request.Headers["User-Agent"].ToString().Contains("Mobile") ? "mobile" : "desktop"
});

Around a payment call

using (_checkoutTelemetry.StartDependencyOperation("bank_charge", cartRef, out var dep))
{
    var sw = Stopwatch.StartNew();
    var result = await _paymentService.ProcessBankCheckoutAsync(chargeId, transactionId, cartRef);
    sw.Stop();
    dep.Duration = sw.Elapsed;
    dep.Success = result.Success;
    dep.Properties["paymentMethod"] = "CreditCard";
    dep.Properties["timeout"] = result.Timeout.ToString();
    _checkoutTelemetry.TrackStep("payment_processed", cartRef, new Dictionary<string,string>{
        ["paymentMethod"] = "CreditCard",
        ["errorType"] = result.ErrorType.ToString()
    }, sw.Elapsed.TotalMilliseconds);
}

 

Kusto queries (copy‑paste in Logs) examples:  

  • End‑to‑end for a single cart:
union traces, customEvents, dependencies, requests
| extend cartReference = tostring(customDimensions.cartReference)
| where isnotempty(cartReference) and cartReference == "<CART_REF>"
| project timestamp, itemType = itemType, name, message, resultCode, success, duration, cartReference, customDimensions
| order by timestamp asc
  • Payment gateway health:
dependencies
| where type == "payment"
| summarize count(), failures = countif(success == false), p95=percentile(duration,95) by name, bin(timestamp, 5m)
| extend failureRate = todouble(failures) / todouble(count())
  • Checkout bottlenecks by step:
customEvents
| where name startswith "checkout_"
| summarize p95=percentile(todouble(tostring(customMeasurements["duration_ms"])),95)
          , count() by name
| order by p95 desc

Guardrails

  • Don’t log PII, whitelist properties. Treat cartReference as non‑PII.
  • Sample high‑volume events if needed; never drop error paths.
  • Secure the AI connection string via secrets/Key Vault; avoid plain text in config.

Outcomes

  • Fast root cause: correlate a customer’s failed payment through controller, dependency, and custom events.
  • Trend insights: detect gateway degradation and timeouts before conversion drops.
  • Measurable improvements: reducing MTTR (Mean Time To Resolve/Recover) and payment‑related abandonment with targeted fixes.



Nov 19, 2025

Comments

error Please login to comment.
Latest blogs
Surviving a Dirty Feed. Part 3: Error Handling and Event Batching

Committing a 250,000-row Optimizely catalog import row by row, returning a per-row failure report, and coalescing catalog events into one per batch.

Stanisław Szołkowski | Oct 16, 2026 |

Building UI Extensions for Optimizely SaaS CMS

Introduction Developers have been extending the functionality of Optimizely PaaS CMS for years using addons built in C# and deployed as NuGet...

Mark Stott | Oct 15, 2026

Cheapskate AI Translator: Because Translation Should Not Require a Second Mortgage

There is a particular kind of software project that begins with a detailed architecture document, a product roadmap, and a carefully assembled...

Linh Doan Cuu | Oct 15, 2026

Computed Fields in CMS 13 Content Contracts with Optimizely Graph

Content Contracts in Optimizely CMS 13 allow different content types to share a common structure when querying Optimizely Graph. But what if the...

Mardy | Oct 14, 2026