Claude
Skills
Sign in
Back

python-micrometer-business-metrics

Included with Lifetime
$97 forever

Implements domain-specific KPI metrics for business operations like charges, invoices, payments. Use when instrumenting service layer operations, measuring business process outcomes, implementing SLI/SLO monitoring for KPIs, or tracking supplier/invoice/charge lifecycle events. Targets Java/Spring Boot services with structured business metrics for observability.

Backend & APIs

What this skill does


# Micrometer Business Metrics

## Table of Contents

1. [Purpose](#purpose)
2. [When to Use](#when-to-use)
3. [Quick Start](#quick-start)
4. [Instructions](#instructions)
5. [Examples](#examples)
6. [Requirements](#requirements)
7. [Anti-Patterns to Avoid](#anti-patterns-to-avoid)
8. [See Also](#see-also)

---

## Purpose

While technical metrics (latency, errors, resource usage) measure system health, business metrics measure business outcomes. This skill shows how to instrument domain entities (Charges, Invoices, Suppliers, Payments) with meaningful KPI metrics that track business impact.

## When to Use

Use this skill when you need to:

- **Track business KPIs** - Measure charges processed, invoices generated, payments completed, supplier onboarding
- **Instrument service layer operations** - Add metrics at domain service level (not infrastructure)
- **Monitor business process outcomes** - Track approval rates, rejection reasons, processing times
- **Implement SLI/SLO for business metrics** - Define service levels based on business value (e.g., 99% of charges approved in 5 minutes)
- **Correlate business and technical metrics** - Link business outcomes to system performance
- **Create executive dashboards** - Provide business-oriented observability (revenue, transactions, customer impact)
- **Track domain entity lifecycles** - Monitor state transitions (created → approved → invoiced → paid)

**When NOT to use:**
- For purely technical metrics (use `python-micrometer-core` instead)
- For high-cardinality user/request tracking (use distributed tracing instead)
- When metrics backend isn't configured (use `python-micrometer-metrics-setup` first)

---

## Quick Start

Create a dedicated metrics component for your domain:

```java
@Component
public class ChargeMetrics {

    private final Counter chargesReceived;
    private final Counter chargesApproved;
    private final Counter chargesFailed;
    private final Timer approvalDuration;
    private final DistributionSummary chargeValue;

    public ChargeMetrics(MeterRegistry registry) {
        this.chargesReceived = Counter.builder("charge.received")
            .description("Total charges received")
            .register(registry);

        this.chargesApproved = Counter.builder("charge.approved")
            .description("Charges approved for payment")
            .register(registry);

        this.chargesFailed = Counter.builder("charge.failed")
            .description("Charges that failed processing")
            .register(registry);

        this.approvalDuration = Timer.builder("charge.approval.duration")
            .description("Time from submission to approval")
            .register(registry);

        this.chargeValue = DistributionSummary.builder("charge.value")
            .baseUnit("GBP")
            .serviceLevelObjectives(10, 50, 100, 500, 1000)
            .register(registry);
    }

    // Public methods to record events
    public void recordChargeReceived(Charge charge) {
        chargesReceived.increment();
        chargeValue.record(charge.getAmount().doubleValue());
    }

    public void recordChargeApproved(Charge charge, Duration approvalTime) {
        chargesApproved.increment();
        approvalDuration.record(approvalTime);
    }

    public void recordChargeFailed(String reason) {
        chargesFailed.increment();
    }
}
```

## Instructions

### Step 1: Identify Business Metrics

List the key KPIs for your domain:

**Charges:**
- Count: received, approved, rejected, duplicates
- Values: distribution of charge amounts
- Duration: submission to approval time
- Status: by rejection reason (validation, duplicate, amount)

**Invoices:**
- Count: generated, sent, paid, outstanding
- Values: distribution of invoice amounts
- Duration: generation time, payment processing time
- Status: by invoice state (draft, sent, paid, overdue)

**Payments:**
- Count: pending, completed, failed
- Values: distribution of payment amounts
- Duration: request to completion time
- Method: by payment type (bank transfer, card, check)

**Suppliers:**
- Count: active, onboarded, inactive
- Values: by category (tier1, direct, international, standard)
- Duration: onboarding time
- Status: by registration state

### Step 2: Create Metrics Component

Design a reusable metrics holder for your domain entity:

```java
@Component
public class SupplierChargesMetrics {

    private final MeterRegistry registry;
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    // Charge metrics
    private final Counter chargesReceived;
    private final Counter chargesApproved;
    private final Counter chargesRejected;
    private final DistributionSummary chargeValue;
    private final Timer chargeApprovalDuration;

    // Supplier metrics
    private final Gauge activeSuppliers;
    private final Counter suppliersOnboarded;

    // Invoice metrics
    private final Counter invoicesGenerated;
    private final Counter invoicesSent;
    private final DistributionSummary invoiceAmount;
    private final Timer invoiceGenerationTime;
    private final Gauge outstandingInvoices;

    // Payment metrics
    private final Counter paymentsPending;
    private final Counter paymentsCompleted;
    private final Counter paymentsFailed;
    private final Timer paymentDuration;

    public SupplierChargesMetrics(
            MeterRegistry registry,
            SupplierRepository supplierRepo,
            InvoiceRepository invoiceRepo) {

        this.registry = registry;

        // CHARGES
        this.chargesReceived = Counter.builder("charge.received")
            .description("Total charges received from suppliers")
            .register(registry);

        this.chargesApproved = Counter.builder("charge.approved")
            .description("Charges approved for payment")
            .register(registry);

        this.chargesRejected = Counter.builder("charge.rejected")
            .description("Charges rejected by validation")
            .register(registry);

        this.chargeValue = DistributionSummary.builder("charge.value")
            .baseUnit("GBP")
            .description("Distribution of charge values")
            .serviceLevelObjectives(10, 50, 100, 500, 1000, 5000)
            .register(registry);

        this.chargeApprovalDuration = Timer.builder("charge.approval.duration")
            .description("Time from submission to approval")
            .publishPercentiles(0.5, 0.95, 0.99)
            .register(registry);

        // SUPPLIERS
        this.activeSuppliers = Gauge.builder("supplier.active.count",
                                             supplierRepo,
                                             SupplierRepository::countActive)
            .description("Number of active suppliers")
            .register(registry);

        this.suppliersOnboarded = Counter.builder("supplier.onboarded")
            .description("New suppliers onboarded")
            .register(registry);

        // INVOICES
        this.invoicesGenerated = Counter.builder("invoice.generated")
            .description("Invoices generated")
            .register(registry);

        this.invoicesSent = Counter.builder("invoice.sent")
            .tag("channel", "email")
            .description("Invoices sent to suppliers")
            .register(registry);

        this.invoiceAmount = DistributionSummary.builder("invoice.amount")
            .baseUnit("GBP")
            .description("Invoice amount distribution")
            .serviceLevelObjectives(100, 500, 1000, 5000, 10000, 50000)
            .register(registry);

        this.invoiceGenerationTime = Timer.builder("invoice.generation.duration")
            .description("Invoice generation time")
            .publishPercentiles(0.95, 0.99)
            .register(registry);

        this.outstandingInvoices = Gauge.builder("invoice.outstanding",
                                                 invoiceRepo,
                                                 

Related in Backend & APIs