Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Multi-Cloud Observability: Metrics, Logs, Traces

By Kokil Thapa | Last reviewed: August 2026

When your Laravel API runs on AWS EC2, your queue workers sit on a DigitalOcean droplet, and your staging cluster lives in Azure, a single-cloud dashboard cannot tell you why checkout failed at 2 a.m. Multi-Cloud Observability: Metrics, Logs, Traces is the practice of collecting the three telemetry pillars — time-series metrics, structured logs, and distributed traces — into one correlated view that works regardless of where each workload runs. On production systems I maintain, observability is not a luxury add-on; it is how you survive failed deployments, payment gateway timeouts, and slow database queries without guessing. This guide covers what to instrument, how to ship telemetry across providers, and which stacks actually work for small teams in 2026.

What is multi-cloud observability and why do metrics, logs, and traces matter?

Observability answers questions you did not know to ask before an outage. Monitoring tells you a threshold was breached; observability lets you follow a failed request from the load balancer through three microservices to a dead Redis connection. In a multi-cloud setup, that request might cross an AWS ALB, a Laravel app on a VPS, and a PostgreSQL read replica in another region — each with its own native tooling (CloudWatch, Azure Monitor, Google Cloud Operations).

The three pillars serve distinct roles:

  • Metrics — numeric time-series data: request rate, error rate, latency percentiles (p50, p95, p99), CPU, memory, queue depth. You alert on metrics.
  • Logs — discrete events with context: stack traces, payment callback payloads (redacted), authentication failures. You search logs during incidents.
  • Traces — end-to-end request paths across services, showing where time was spent and which span failed. You use traces to find bottlenecks and cascading failures.

Without correlation between the three, you end up with three tabs open and a spreadsheet of timestamps. The goal of Multi-Cloud Observability: Metrics, Logs, Traces is a shared context — typically a trace_id and span_id injected into every log line and attached to every metric data point where possible.

Three Pillars of Multi-Cloud ObservabilityMetricsPrometheus / OTLPRED / USE methodsLogsStructured JSONtrace_id in every lineTracesOpenTelemetry spansW3C Trace ContextUnified Correlation LayerGrafana / Datadog / Honeycomb — one trace_id links all threeAWS EC2Azure AKSGCP Cloud RunVPS / DO
Multi-Cloud Observability: Metrics, Logs, Traces — three signal types converge through a correlation layer that spans every cloud provider.

A common mistake is treating native cloud monitoring as sufficient. CloudWatch, Azure Monitor, and Google Cloud Operations are excellent within their own boundaries, but they do not automatically correlate a trace from your GCP Cloud Run function with a Laravel queue job on a bare-metal VPS. You need a vendor-neutral instrumentation layer. That is where OpenTelemetry becomes the foundation of any serious multi-cloud observability strategy.

How do you instrument applications for metrics, logs, and traces?

Instrumentation is the code and agents that produce telemetry. In 2026, OpenTelemetry (OTel) is the standard. It replaces the old pattern of installing separate Prometheus client libraries, Jaeger agents, and custom log formatters with one SDK and one collector pipeline.

Laravel and PHP instrumentation

For Laravel 11 or 12 on PHP 8.2+, install the OpenTelemetry PHP extension and auto-instrumentation packages via Composer:

composer require open-telemetry/opentelemetry open-telemetry/exporter-otlp
composer require open-telemetry/opentelemetry-auto-laravel

Configure the OTLP exporter in your .env so every environment sends to the same collector endpoint, regardless of hosting provider:

OTEL_SERVICE_NAME=checkout-api
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.internal:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,cloud.provider=aws

The cloud.provider resource attribute is critical in multi-cloud setups. It lets you filter dashboards by AWS vs Azure vs a VPS without maintaining separate service names per provider.

Structured logging with trace correlation

Switch from plain-text logs to JSON. In Laravel, configure the stack channel to output JSON and inject trace context via a custom processor or Monolog formatter:

// config/logging.php — json channel
'json' => [
    'driver' => 'monolog',
    'handler' => StreamHandler::class,
    'formatter' => Monolog\Formatter\JsonFormatter::class,
    'with' => ['stream' => 'php://stderr'],
],

Every log line should include trace_id, span_id, service.name, and deployment.environment. When you click a slow span in Grafana Tempo, you jump directly to the log lines from that exact request — no manual timestamp matching.

Metrics: RED method for HTTP services

For each HTTP endpoint, track:

  1. Rate — requests per second
  2. Errors — count of 5xx responses and unhandled exceptions
  3. Duration — histogram of response times with p50, p95, p99 buckets

OTel auto-instrumentation captures these for Laravel routes out of the box. For queue workers and scheduled tasks, add manual spans around php artisan queue:work jobs and Schedule callbacks so background work appears in the same trace graph as the HTTP request that dispatched it.

How should you collect and route telemetry across AWS, Azure, and GCP?

The OpenTelemetry Collector is the hub of multi-cloud observability. Deploy it as a DaemonSet in Kubernetes, a sidecar in ECS, or a standalone service on your VPS fleet. Applications send OTLP to the nearest collector; the collector handles batching, filtering, PII redaction, and routing to backends.

OTel Collector Multi-Cloud PipelineAWS AppsAzure AppsGCP AppsVPS / LaravelOTel Collectorbatch · filter · redactOTLP in → routes outPrometheus / MimirLoki (Logs)Tempo (Traces)Grafana Dashboards
OpenTelemetry Collector centralises Multi-Cloud Observability: Metrics, Logs, Traces from every provider into one backend pipeline.

A production collector config splits telemetry by signal type. Here is a minimal but functional example:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 5s
    send_batch_size: 1024
  attributes:
    actions:
      - key: cloud.region
        action: upsert
        from_attribute: host.id

exporters:
  prometheus:
    endpoint: 0.0.0.0:8889
  otlp/tempo:
    endpoint: tempo.internal:4317
    tls:
      insecure: true
  loki:
    endpoint: http://loki.internal:3100/loki/api/v1/push

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [batch, attributes]
      exporters: [prometheus]
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/tempo]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [loki]

Handling cloud-native agents without double-paying

You do not need to abandon CloudWatch or Azure Monitor entirely. Many teams run a hybrid model: native agents for infrastructure metrics (EBS IOPS, AKS node health), OTel for application-level signals. Use the collector's awscloudwatch or azuremonitor receivers to pull cloud metrics into Grafana alongside application traces — one dashboard, two data sources.

For log shipping from VPS servers where you cannot install a collector on every host, Fluent Bit or Vector agents tail /var/log/ files and forward JSON logs to Loki or Elasticsearch. Tag each agent with cloud.provider=vps and host.name so you can distinguish a DigitalOcean droplet from an AWS EC2 instance at query time.

What is the best observability stack for multi-cloud in 2026?

There is no single winner — the right stack depends on team size, budget, and compliance requirements. Here is an honest comparison of the four approaches I see most often on real projects.

StackMetricsLogsTracesBest forTypical cost (small team)
Grafana LGTM (self-hosted)Mimir / PrometheusLokiTempoTeams with DevOps capacity, data sovereignty needsRs 15,000–40,000/mo infra (~USD 110–295)
Grafana CloudHosted MimirHosted LokiHosted TempoSmall teams, multi-cloud without ops overheadFree tier → Rs 25,000+/mo (~USD 185+)
DatadogNativeNativeAPMFastest time-to-value, budget availableRs 50,000–200,000/mo (~USD 370–1,480)
Cloud-native onlyCloudWatch / Azure Monitor / GCP OpsSameX-Ray / App Insights / Cloud TraceSingle-cloud or low observability maturityIncluded in cloud bill (fragmented across providers)

For a Nepal-based startup running Laravel on a VPS plus a few AWS services, Grafana Cloud with OpenTelemetry is the sweet spot in 2026. You get correlated metrics, logs, and traces without maintaining Mimir, Loki, and Tempo yourself. Datadog is excellent but the per-host pricing adds up fast when you count queue workers, cron containers, and staging environments separately.

Multi-Cloud Stack Decision MatrixSelf-Hosted LGTM✓ Full data control✓ Lowest at scale✗ Ops overhead✗ You run upgradesTeam: 2+ DevOpsBudget: mediumGrafana Cloud✓ Managed backends✓ OTel native✓ Free tier to start✗ Egress costsTeam: 1 developerBest for small teamsDatadog✓ Fastest setup✓ Rich APM UI✗ Per-host pricing✗ Vendor lock-inTeam: any sizeBudget: highAll three support OpenTelemetry — your instrumentation survives a backend switch
Choosing a Multi-Cloud Observability: Metrics, Logs, Traces backend — self-hosted LGTM, managed Grafana Cloud, or commercial APM.

Whichever backend you pick, standardise on OpenTelemetry instrumentation from day one. I have migrated observability backends without touching application code because the OTel SDK stayed constant while only the collector exporters changed. That portability is the entire point of multi-cloud observability.

How do you troubleshoot production incidents with correlated metrics, logs, and traces?

During an incident, you need a repeatable workflow — not improvisation. The pattern I use on production Laravel applications follows five steps, and it works whether the failing service runs on AWS, Azure, or a VPS.

  1. Check the SLO dashboard — Is error rate or latency breaching your SLO threshold? Identify which service and which cloud provider label is affected.
  2. Drill into traces — Filter Tempo or your APM trace view by status=error and the last 15 minutes. Find the slowest or most frequent failing span.
  3. Jump to logs — Click the trace ID to pull correlated log lines. Look for exceptions, timeout messages, or third-party API error codes.
  4. Cross-reference metrics — Check if CPU, memory, or database connection pool metrics spiked at the same timestamp. A queue backlog metric often explains trace latency better than the trace itself.
  5. Document in a postmortem — Capture the trace ID, root cause, and fix in a blameless postmortem so the next engineer does not start from zero.
Incident Debug WorkflowAlert fires: checkout error rate > 5%Step 1: Metrics — which service / cloud?Step 2: Traces — find failing span + trace_idStep 3: Logs via trace_idStep 4: Infra metrics check
Production incident workflow for Multi-Cloud Observability: Metrics, Logs, Traces — alert to root cause in four correlated steps.

Example: payment gateway timeout across clouds

Imagine checkout fails on a Laravel eCommerce app. Metrics show http_server_duration_p99 spiking on the payment-api service tagged cloud.provider=aws. Traces reveal the Khalti callback span timing out after 30 seconds. Logs for that trace_id show cURL error 28: Connection timed out. Infrastructure metrics on the VPS running the queue worker show normal CPU — the problem is external, not resource exhaustion.

Without trace-log correlation, you would grep Laravel logs across three servers, manually match timestamps, and still miss the connection. With Multi-Cloud Observability: Metrics, Logs, Traces wired correctly, that investigation takes minutes instead of an hour.

Service maps and dependency graphs

Modern backends auto-generate service maps from trace data. These maps show which services call which, average latency between nodes, and error rates on edges. In a multi-cloud architecture, the service map immediately reveals that your Azure-hosted API gateway is routing 40% of traffic to an AWS RDS instance with 200ms higher latency — a topology problem visible only when traces span providers.

How much does multi-cloud observability cost and how do you control it?

Observability costs scale with data volume, not server count alone. Traces are the most expensive signal because each request generates multiple spans. Logs are second — verbose debug logging in production can double your bill overnight. Metrics are the cheapest per data point but add up with high-cardinality labels.

Cost control tactics that actually work

  • Sample traces — Use head-based sampling (e.g., 10% of requests) in the OTel Collector for normal traffic. Always capture error traces at 100%.
  • Drop debug logs in production — Set log level to info or warning in production; reserve debug for staging.
  • Limit metric cardinality — Never put user IDs, order IDs, or unbounded URL paths in metric labels. High-cardinality labels explode storage costs in Prometheus and Mimir.
  • Set retention tiers — Hot storage for 7 days (incident response), warm for 30 days (trend analysis), cold/archive for compliance if required.
  • Use recording rules — Pre-aggregate expensive queries in Prometheus rather than scanning raw data on every dashboard refresh.
Observability Cost ControlExpensive SignalsTraces: 10% sample (100% errors)Logs: info+ only in prodMetrics: no high-cardinality labelsRetention TiersHot: 7 days — incident responseWarm: 30 days — trend analysisCold: 90+ days — compliance archiveOTel Collector: filter · sample · aggregate before exportTypical small-team budget: Rs 15,000–50,000/mo (~USD 110–370)Rule: if you cannot afford to store it, do not emit it — tune at the collector
Cost control for Multi-Cloud Observability: Metrics, Logs, Traces — sampling, retention tiers, and cardinality limits keep bills predictable.

For a typical small business running Laravel across two cloud providers plus a VPS, budget Rs 15,000–50,000 per month (~USD 110–370) for a managed observability platform with reasonable retention. Self-hosted LGTM on a dedicated server costs less at scale but requires someone who can maintain it — a hidden cost if that person is you after hours.

Alerting should follow the same discipline. Use Prometheus Alertmanager or Grafana unified alerting with SLO-based rules, not raw threshold alerts on every metric. Page a human only when customer-facing error budget is burning. Everything else goes to Slack or email during business hours.

Build multi-cloud observability before you need it

Multi-Cloud Observability: Metrics, Logs, Traces is not something you bolt on after the third production outage. Instrument with OpenTelemetry from the first deployment, standardise structured JSON logging with trace correlation, deploy a collector that routes all three signals to one backend, and practice the incident workflow before an alert wakes you at 3 a.m. The teams that debug multi-cloud failures in minutes instead of hours all share one trait: they correlated metrics, logs, and traces early, while the system was still simple.

If you are running Laravel or PHP workloads across AWS, Azure, VPS hosting, or a hybrid setup and need help designing an observability pipeline that fits a small-team budget, get in touch — or explore the Grafana dashboards guide and microservices observability patterns for deeper implementation detail.

Frequently Asked Questions

Multi-cloud observability is the practice of collecting, correlating, and analysing metrics, logs, and distributed traces from applications and infrastructure running across two or more cloud providers or hybrid environments. It gives you a unified view of system health, performance, and failures regardless of where a workload runs. Without it, each cloud's native monitoring console becomes a silo, and cross-service debugging during incidents becomes guesswork.

Metrics are numeric time-series measurements such as request rate, error percentage, CPU usage, and queue depth. Logs are timestamped event records with context, like an HTTP 500 with stack trace or a payment callback payload. Traces follow a single request as it crosses services, showing latency at each hop. In production, you need all three: metrics alert you that something broke, logs explain why, and traces show where time was spent across microservices or external APIs.

When workloads span AWS, GCP, Azure, on-prem Ubuntu servers, or multiple regions and you cannot diagnose incidents from one vendor console alone.

Costs vary widely. Self-hosted OpenTelemetry plus Prometheus, Grafana, and Loki on a single Ubuntu 24 server might run Rs 8,000–15,000/month (~USD 60–110) in compute and storage. Managed platforms like Datadog or New Relic typically start around Rs 20,000–40,000/month (~USD 150–300) for small production stacks and scale with ingested data volume. The expensive part is usually log and trace ingestion, not metrics. Budget for retention policies early or bills spike fast.

OpenTelemetry for instrumentation and export, Prometheus or Mimir for metrics, Grafana for dashboards and alerting, Loki or OpenSearch for logs, and Tempo or Jaeger for traces is the most common production-grade open-source combination I've seen on self-managed Ubuntu infrastructure. OTel avoids vendor lock-in because you instrument once and route telemetry to any backend. Grafana Alloy or the OTel Collector handles aggregation, sampling, and redaction before data leaves each environment. This stack runs well on modest EC2 or VPS hardware if you tune retention and cardinality.

Use OpenTelemetry as the instrumentation layer even if you also send data to AWS CloudWatch, Azure Monitor, or Google Cloud Operations. Cloud-native tools work fine within one provider but do not correlate a Laravel API on EC2 with a Redis cache on DigitalOcean and a managed MySQL instance elsewhere. OTel gives consistent trace and log context across environments. Keep vendor agents only where OTel exporters are immature, such as some managed database services, and forward everything to one Grafana or Datadog workspace for incident response.

Standardise on a shared trace ID and request ID propagated through HTTP headers, queue jobs, and cron tasks. In Laravel, middleware can inject X-Request-ID and pass it to Monolog context and outbound Guzzle calls. Your logging stack should index that ID, and your trace backend should expose it as a span attribute. In Grafana, clicking a high-latency trace should jump to related logs and metric panels for the same service and time window. Without that correlation, on-call engineers waste minutes switching between three unrelated dashboards.

Inconsistent timestamps across regions and hosts break correlation; enforce NTP on every server. High-cardinality labels like user IDs or order IDs in Prometheus metrics explode storage costs and slow queries. Logging full request bodies from payment callbacks creates PCI and privacy risk. Each cloud's default agent uses different field names, so normalise schema in the collector. Sampling traces at 100% on high-traffic Laravel apps generates terabytes quickly. Network egress fees for shipping logs from AWS to a Grafana Cloud endpoint add up silently. Test alert routing before production, not during a 2 a.m. outage.

Instrument Laravel 12 with OpenTelemetry PHP SDK or packages like Keepsuit Laravel OpenTelemetry, export traces via OTLP to a collector, and ship structured JSON logs through Monolog to Loki or OpenSearch. Expose /metrics for PHP-FPM, queue workers, and Horizon if you use Redis queues. Tag every deployment with service.name, deployment.environment, and cloud.provider attributes. On the infrastructure side, node_exporter on Ubuntu servers plus cloud provider metrics for RDS or managed databases gives full-stack visibility. I've found queue job failures and slow N+1 queries are the first signals worth alerting on.

Datadog wins on speed of setup and out-of-the-box integrations but costs more at scale, often Rs 50,000+/month (~USD 370+) once log volume grows. Grafana Cloud reduces ops burden while keeping OTel flexibility; pricing is more predictable if you control cardinality and retention. Self-hosted Grafana, Prometheus, and Loki on Ubuntu gives maximum control and lowest recurring cost but you own upgrades, backups, and on-call for the monitoring stack itself. For small Nepal agencies managing multiple client clouds, Grafana Cloud or a single shared self-hosted stack usually beats per-client Datadog accounts.

Treat logs and traces as sensitive because they contain session tokens, emails, payment references, and API keys. Redact or hash PII at the OpenTelemetry Collector before export. Use TLS for all OTLP and syslog shipping, restrict collector ingress with firewall rules and mTLS where possible, and store credentials in environment secrets not dashboard configs. Apply RBAC in Grafana so client data never shares one workspace inappropriately. Encrypt data at rest on Elasticsearch or S3 backends. Retention policies should match compliance needs; legal-tech portals I work on often require 90-day log retention with stricter access controls than generic SaaS defaults.

Missing traces usually mean broken context propagation. A frontend call, API gateway, Laravel service, and Redis-backed queue worker each need the traceparent header forwarded. Async jobs must serialise trace context into the job payload and restore it in the worker. If one hop uses a different tracer or no instrumentation, the trace appears fragmented or absent. Check collector logs for dropped spans, verify sampling rules are not set to 0% for that service, and confirm outbound HTTP clients propagate headers. Partial traces are still useful but indicate exactly which service skipped instrumentation.

Sample traces at 1–10% for normal traffic but always capture errors and slow requests above a latency threshold using tail-based sampling in the OTel Collector. Drop debug-level logs in production and avoid logging full payloads. Use metric aggregation instead of logging every heartbeat. Set Prometheus retention to 15–30 days locally and archive long-term metrics to object storage if needed. Index only searchable fields in log backends. Review cardinality weekly; one bad label can double your bill. Alert on ingestion rate spikes so a log loop does not drain budget overnight.

Yes, but each console only sees its own cloud natively. Multi-cloud observability requires forwarding telemetry to a central platform via CloudWatch Metric Streams, Azure Monitor Data Collection Rules, or GCP Pub/Sub exporters into Prometheus remote write, Grafana, or a commercial aggregator. Running three separate alerting systems guarantees missed pages and duplicate noise. Pick one alerting destination, map equivalent metrics across providers with consistent naming, and use federated dashboards. Hybrid setups with Ubuntu VPS plus one cloud provider are common; treat the VPS as a first-class telemetry source, not an afterthought.

Start with availability and latency SLIs at the user-facing edge: percentage of successful HTTP responses and p95 response time for critical routes like checkout, login, and API auth. Add queue processing time for Laravel jobs, payment webhook success rate, and third-party API dependency latency. Define SLOs with realistic error budgets, for example 99.9% availability over 30 days, and wire alerts to burn rate, not raw threshold spikes. Multi-cloud adds dependency on cross-network paths, so include synthetic checks from multiple regions. SLOs give engineering and business owners shared language during incidents instead of debating whether 500 errors are acceptable.

Share this article

Quick Contact Options
Choose how you want to connect me: