{"id":14,"date":"2026-07-13T15:33:11","date_gmt":"2026-07-13T15:33:11","guid":{"rendered":"https:\/\/blogs.aithor.ca\/nhost\/2026\/07\/13\/how-to-set-up-observability-and-monitoring-for-your-nhost-stack-with-opentelemetry\/"},"modified":"2026-07-13T15:33:11","modified_gmt":"2026-07-13T15:33:11","slug":"how-to-set-up-observability-and-monitoring-for-your-nhost-stack-with-opentelemetry","status":"publish","type":"post","link":"https:\/\/blogs.aithor.ca\/nhost\/2026\/07\/13\/how-to-set-up-observability-and-monitoring-for-your-nhost-stack-with-opentelemetry\/","title":{"rendered":"How to Set Up Observability and Monitoring for Your Nhost Stack with OpenTelemetry"},"content":{"rendered":"<h2>What you\u2019ll build<\/h2>\n<p>You already move fast with Nhost: Postgres, real-time GraphQL, Authentication, Storage, and Serverless Functions without touching servers. Now you can add observability and monitoring that is just as fast. In this guide, you\u2019ll set up a vendor-neutral OpenTelemetry pipeline so your Nhost GraphQL API and Functions emit traces, logs and metrics to your OpenTelemetry Collector and visualization tool of choice. You\u2019ll see one coherent, end-to-end trace that flows across GraphQL resolvers, Actions, Event Triggers, Functions, Postgres timings, Auth webhooks, Storage operations, and even Bring Your Own Containers (BYOC) services\u2014without managing any infrastructure on your own.<\/p>\n<p>The result: reliable Nhost monitoring and performance monitoring with service graphs that make sense, alerting that catches real problems, and dashboards that explain \u201cwhy\u201d when latency spikes or error rates creep up.<\/p>\n<h2>Reference architecture<\/h2>\n<figure><img decoding=\"async\" src=\"https:\/\/images.unsplash.com\/photo-1762330470070-249e7c23c8c0?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3w4NDY5MTd8MHwxfHNlYXJjaHwxfHxXaGF0JTIweW91JUUyJTgwJTk5bGwlMjBidWlsZCUwQVlvdSUyMGFscmVhZHklMjBtb3ZlJTIwZmFzdCUyMHdpdGglMjBOaG9zdCUzQSUyMFBvc3RncmVzJTJDJTIwcmVhbC10aW1lJTIwR3JhcGhRTCUyQyUyMEF1dGhlbnRpY2F0aW9uJTJDJTIwU3RvcmFnZSUyQyUyMGFuZCUyMFNlcnZlcmxlc3MlMjBGdW5jdGlvbnMlMjB3aXRob3V0JTIwdG91Y2hpbmclMjBzZXJ2ZXJzLiUyME5vdyUyMHlvdSUyMGNhbiUyMGFkZCUyMG9ic2VydmFiaWxpdHklMjBhbmQlMjBtb25pdG9yaW5nJTIwdGhhdCUyMGlzJTIwanVzdCUyMGFzJTIwZmFzdC4lMjBJbiUyMHRoaXMlMjBndWlkZSUyQyUyMHlvdSVFMiU4MCU5OWxsJTIwc2V0JTIwdXAlMjBhJTIwdmVuZG9yLW5ldXRyYWwlMjBPcGVuVGVsZW1ldHJ5JTIwcGlwZWxpbmUlMjBzbyUyMHlvdXIlMjBOaG9zdCUyMEdyYXBoUUwlMjBBUEklMjBhbmQlMjBGdW5jdGlvbnMlMjBlbWl0JTIwdHJhY2VzJTJDJTIwbG9ncyUyMGFuZCUyMG1ldHJpY3MlMjB0byUyMHlvdXIlMjBPcGVuVGVsZW1ldHJ5JTIwQ29sbGVjdG9yJTIwYW5kJTIwdmlzdWFsaXphdGlvbiUyMHRvb2wlMjBvZiUyMGNob2ljZS4lMjBZb3UlRTIlODAlOTlsbCUyMHNlZSUyMG9uZSUyMGNvaGVyZW50JTJDJTIwZW5kLXRvLWVuZCUyMHRyYWNlJTIwdGhhdCUyMGZsb3dzJTIwYWNyb3NzJTIwR3JhcGhRTCUyMHJlc29sdmVycyUyQyUyMEFjdGlvbnMlMkMlMjBFdmVudCUyMFRyaWdnZXJzJTJDJTIwRnVuY3Rpb25zJTJDJTIwUG9zdGdyZXMlMjB0aW1pbmdzJTJDJTIwQXV0aCUyMHdlYmhvb2tzJTJDJTIwU3RvcmFnZSUyMG9wZXJhdGlvbnMlMkMlMjBhbmQlMjBldmVuJTIwQnJpbmclMjBZb3VyJTIwT3duJTIwQ29udGFpbmVycyUyMCUyOEJZT0MlMjklMjBzZXJ2aWNlcyVFMiU4MCU5NHdpdGhvdXQlMjBtYW5hZ2luZyUyMGFueSUyMGluZnJhc3RydWN0dXJlJTIwb24lMjB5b3VyJTIwb3duLiUwQVRoZSUyMHJlc3VsdCUzQSUyMHJlbGlhYmxlJTIwTmhvc3QlMjBtb25pdG9yaW5nJTIwYW5kJTIwcGVyZm9ybWFuY2UlMjBtb25pdG9yaW5nJTIwd2l0aCUyMHNlcnZpY2UlMjBncmFwaHMlMjB0aGF0JTIwbWFrZSUyMHNlbnNlJTJDJTIwYWxlcnRpbmclMjB0aGF0JTIwY2F0Y2hlcyUyMHJlYWwlMjBwcm9ibGVtcyUyQyUyMGFuZCUyMGRhc2hib2FyZHMlMjB0aGF0JTIwZXhwbGFpbiUyMCVFMiU4MCU5Q3doeSVFMiU4MCU5RCUyMHdoZW4lMjBsYXRlbmN5JTIwc3Bpa2VzJTIwb3IlMjBlcnJvciUyMHJhdGVzJTIwY3JlZXAlMjB1cC4lMEElMEFSZWZlcmVuY2UlMjBhcmNoaXRlY3R1cmV8ZW58MHwwfHx8MTc4Mzk1Njc3OXww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080\" alt=\"Digital interface with &apos;ask anything&apos; prompt.\"><figcaption>Photo by <a href=\"https:\/\/unsplash.com\/@zulfugarkarimov\" target=\"_blank\" rel=\"nofollow noopener\">Zulfugar Karimov<\/a> on <a href=\"https:\/\/unsplash.com\" target=\"_blank\" rel=\"nofollow noopener\">Unsplash<\/a><\/figcaption><\/figure>\n<p>The architecture is intentionally simple and portable. Nhost services export OpenTelemetry signals over OTLP\/HTTPS to an internet-accessible Collector that fans out to your preferred backends (Grafana Tempo\/Loki\/Mimir, Honeycomb, Datadog, New Relic, or any OTEL-compatible destination).<\/p>\n<ul>\n<li>GraphQL API, Functions, and BYOC services send traces, logs and metrics via OTLP\/HTTP(S).<\/li>\n<li>An OpenTelemetry Collector receives, batches, samples, scrubs, and routes signals.<\/li>\n<li>Dashboards and alerts run in your chosen tool, fed by the Collector\u2019s exporters.<\/li>\n<\/ul>\n<h3>Signals and flow<\/h3>\n<p>Use W3C Trace Context so requests stitch across every hop. The <em>traceparent<\/em> and <em>tracestate<\/em> headers start in the GraphQL API, pass through Actions or Event Triggers to Serverless Functions, and return with enriched spans. Database timings appear in GraphQL resolver spans, so the same distributed trace shows client request, resolver latency, HTTP calls to Functions, and query timing inside Postgres.<\/p>\n<h3>Required Nhost touchpoints<\/h3>\n<p>You do not need to provision or manage any Nhost servers. Configure environment variables in the Nhost Console for the GraphQL API and for Serverless Functions (Node\/TypeScript). Point them to your Collector\u2019s public OTLP endpoint, add a token header, and define resource attributes. Redeploy, and signals flow. That\u2019s it\u2014observability and monitoring without cluster setup.<\/p>\n<h2>Prerequisites<\/h2>\n<ul>\n<li>An OpenTelemetry Collector reachable over the internet (public URL) with a token or API key for auth.<\/li>\n<li>Outbound HTTPS allowed from your Nhost project (default). Validate TLS and firewall rules on your Collector.<\/li>\n<li>Your Nhost project subdomain\/ID (for resource attributes and filters).<\/li>\n<li>Access to your telemetry backend (Grafana, Honeycomb, Datadog, etc.) to verify data and build dashboards.<\/li>\n<\/ul>\n<p>If you are still evaluating backend platforms and how they compare for tracing, auth, and pricing, see the open-source comparison: <a href=\"https:\/\/blogs.aithor.ca\/nhost\/2026\/07\/12\/nhost-vs-supabase-vs-appwrite-2026-open-source-backend-comparison-for-postgres-graphql-auth-and-pricing\/\">Nhost vs Supabase vs Appwrite (2026): Open-Source Backend Comparison for Postgres, GraphQL, Auth, and Pricing<\/a>.<\/p>\n<h2>Enable OpenTelemetry in the GraphQL API<\/h2>\n<p>Turn on tracing and export to OTLP using environment variables in the Nhost Console. The GraphQL engine supports OpenTelemetry natively, so you do not add code or sidecars. After configuring, trigger a redeploy of the GraphQL service and confirm traces appear in your backend.<\/p>\n<h3>Exporter endpoint and sampling<\/h3>\n<ul>\n<li>Set your OTLP\/HTTP or OTLP\/gRPC endpoint to your Collector URL (HTTPS recommended).<\/li>\n<li>Provide authentication via headers (for example, an <em>Authorization<\/em> bearer token) in the exporter configuration.<\/li>\n<li>Start with parent-based 10\u201320% sampling in the Collector or exporter. This balances visibility with cost and keeps performance monitoring representative. For incident triage, you can temporarily raise sampling to 100% to capture every trace.<\/li>\n<\/ul>\n<h3>Resource attributes<\/h3>\n<ul>\n<li><strong>service.name<\/strong>: nhost-graphql<\/li>\n<li><strong>deployment.environment<\/strong>: dev, staging, or prod<\/li>\n<li><strong>nhost.project.id<\/strong>: your Nhost project ID or subdomain<\/li>\n<li>Optional: <strong>service.version<\/strong> from Git SHA, and <strong>cloud.region<\/strong> if you run multi-region<\/li>\n<\/ul>\n<p>These attributes power clean service graphs and let you filter Nhost monitoring views by project and environment without cardinality explosions.<\/p>\n<h2>Instrument Serverless Functions (Node\/TS)<\/h2>\n<p>For Functions, add the OpenTelemetry Node SDK once at startup and enable auto-instrumentation for HTTP servers, fetch\/axios, and popular libraries. Configure the SDK to export traces, logs and metrics to the same Collector as GraphQL. Because Functions run in a managed environment, set exporter details and resource attributes via Nhost environment variables, not hard-coded values.<\/p>\n<h3>OTLP exporter config<\/h3>\n<ul>\n<li>Use OTLP over HTTPS with a token in headers for secure delivery.<\/li>\n<li>Mirror GraphQL settings for <em>deployment.environment<\/em> and <em>nhost.project.id<\/em> to keep dashboards and alerts unified.<\/li>\n<li>Prefer batch exporters with reasonable flush intervals to minimize overhead.<\/li>\n<\/ul>\n<h3>Context propagation<\/h3>\n<p>Forward and respect the <em>traceparent<\/em> header. When GraphQL invokes Actions or Event Triggers, ensure the Function reads the trace context and continues the parent trace. When Functions call back into GraphQL or other services, include the same W3C headers so spans link bi-directionally. This is the key to end-to-end observability and monitoring that tells one story instead of scattering signals across isolated views.<\/p>\n<h2>End-to-end trace: GraphQL -&gt; Action -&gt; Function -&gt; Postgres<\/h2>\n<p>To validate setup, create a GraphQL Action that triggers a Function which queries Postgres through the GraphQL engine. In your trace, you should see:<\/p>\n<ul>\n<li>The incoming GraphQL operation with <em>operationName<\/em> and variables size<\/li>\n<li>An HTTP client span from GraphQL to the Function (or an Action span if proxied)<\/li>\n<li>Function spans for handler execution, external calls, and cache checks<\/li>\n<li>Resolver\/database spans showing Postgres timings, row counts, and errors if any<\/li>\n<\/ul>\n<p>When that single trace shows the resolver and downstream Function time together, your performance monitoring workflow becomes straightforward: identify outliers, inspect spans, and pin down whether time is spent in validation, business logic, network, or the database.<\/p>\n<h2>Database metrics and slow queries<\/h2>\n<p>You can extract a lot of value from GraphQL resolver spans. They include query timings and labels like <em>operationName<\/em> and table\/field context. Use them to chart p95 latency by operation, error rate by mutation, and throughput across environments. This keeps Nhost monitoring focused on what users experience rather than raw query text.<\/p>\n<h3>Optional postgres receiver<\/h3>\n<p>If you maintain a secure read-only connection outside of Nhost, add the Collector\u2019s Postgres receiver to scrape <em>pg_stat*<\/em> views. Correlate with traces using <em>db.system=postgres<\/em> and align <em>service.name<\/em> and <em>nhost.project.id<\/em>. Use this for capacity planning and query planning trends; keep high-cardinality fields like <em>db.statement<\/em> sanitized or truncated to avoid metric blowups. If you prefer not to manage any DB connections, rely on resolver timings\u2014they are often sufficient for practical performance monitoring.<\/p>\n<h2>Authentication and Storage signals<\/h2>\n<p>Instrument Auth webhooks and Storage handlers so they emit traces, logs and metrics. This lets you catch 401\/403 spikes, token issuance latency, and upload\/download slowdowns quickly. When a user flow fails, you want immediate visibility across signup, login, avatar upload, and profile update in a single distributed trace.<\/p>\n<p>For deeper guidance on securing agents and services with JWTs, see <a href=\"https:\/\/blogs.aithor.ca\/nhost\/2026\/07\/11\/how-to-add-oauth2-and-jwt-authentication-to-your-ai-agents-step-by-step-guide\/\">How to Add OAuth2 and JWT Authentication to Your AI Agents (Step-by-Step Guide)<\/a>. The same token practices apply to webhook auth and cross-service calls, and your logs and metrics should reflect token validation outcomes.<\/p>\n<h3>Metrics to emit<\/h3>\n<ul>\n<li><strong>Auth<\/strong>: counters for signups, logins, refreshes; error counters by status (401, 403); latency histograms for token issuance and webhook processing<\/li>\n<li><strong>Storage<\/strong>: counters for uploads\/downloads; bytes_in\/bytes_out; latency histograms by object size bucket; error counters by status<\/li>\n<li><strong>Sessions<\/strong>: gauge for active sessions if available, counters for session starts\/ends<\/li>\n<\/ul>\n<h2>Bring your own containers (polyglot services)<\/h2>\n<p>When you deploy BYOC services, run an OTEL Collector sidecar per service or embed language SDKs (Go, Python, Rust). Keep resource attributes aligned with Nhost components so dashboards remain cohesive:<\/p>\n<ul>\n<li><strong>service.name<\/strong>: meaningful and stable per service<\/li>\n<li><strong>nhost.project.id<\/strong>: same as GraphQL and Functions<\/li>\n<li><strong>deployment.environment<\/strong>: dev\/staging\/prod<\/li>\n<\/ul>\n<p>This standardization ensures Nhost monitoring spans all your services regardless of language or framework.<\/p>\n<h3>Internal service calls<\/h3>\n<p>Ensure HTTP and gRPC clients propagate W3C headers. With consistent propagation between BYOC, Functions, and GraphQL, your traces remain contiguous\u2014even for multi-hop calls and retries. Add error attributes and retry metadata to spans so debugging intermittent failures doesn\u2019t require guessing.<\/p>\n<h2>Logs and metrics that matter<\/h2>\n<figure><img decoding=\"async\" src=\"https:\/\/images.unsplash.com\/photo-1551288049-bebda4e38f71?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3w4NDY5MTd8MHwxfHNlYXJjaHwxfHxvYnNlcnZhYmlsaXR5JTIwYW5kJTIwbW9uaXRvcmluZ3xlbnwwfDB8fHwxNzgzOTU2NzgwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080\" alt=\"Speedcurve Performance Analytics\"><figcaption>Photo by <a href=\"https:\/\/unsplash.com\/@lukechesser\" target=\"_blank\" rel=\"nofollow noopener\">Luke Chesser<\/a> on <a href=\"https:\/\/unsplash.com\" target=\"_blank\" rel=\"nofollow noopener\">Unsplash<\/a><\/figcaption><\/figure>\n<p>Emit structured JSON logs from Functions and BYOC services and route them through OTEL logs. Include <em>trace_id<\/em> and <em>span_id<\/em> in each log record. With this, a production error log jumps straight to the exact trace that captured the failure, eliminating context-switching. Your logs and metrics should tell the same story as your traces.<\/p>\n<h3>Low-cardinality metrics<\/h3>\n<ul>\n<li><strong>request_duration<\/strong> (histogram) with labels: service.name, deployment.environment, operationName (for GraphQL)<\/li>\n<li><strong>error_rate<\/strong> (counter or ratio) with labels: service.name, status_class (2xx\/4xx\/5xx)<\/li>\n<li><strong>cold_start<\/strong> (counter) for Functions to track warmup impact<\/li>\n<li><strong>queue_time<\/strong> (histogram) when using queues; measure time-to-start vs time-in-handler<\/li>\n<li><strong>GraphQL resolver latency<\/strong> (histogram) by operationName and top-level field, not by full query text<\/li>\n<\/ul>\n<p>Favor stable labels and bucketing to avoid metric cardinality explosions. Your goal is actionable observability and monitoring, not an unbounded time series bill.<\/p>\n<h2>Dashboards and alerts for Nhost stacks<\/h2>\n<p>Pre-build a few focused dashboards so engineers get answers in one view:<\/p>\n<ul>\n<li><strong>GraphQL<\/strong>: p95 latency by operationName; 5xx rate; top slow operations; request volume and cache hit\/miss if applicable<\/li>\n<li><strong>Functions<\/strong>: error budget burn; cold start counts and percent; handler p95; external call latency<\/li>\n<li><strong>Auth\/Storage<\/strong>: signup\/login success rate, token issuance latency, 401\/403 spikes; upload\/download p95 and egress volume<\/li>\n<li><strong>Postgres (optional)<\/strong>: lock wait time, buffer hit ratio, top tables by IO, correlated with resolver spans<\/li>\n<\/ul>\n<h3>SLOs and alerts<\/h3>\n<ul>\n<li>Alert when GraphQL p95 exceeds a threshold for a sustained window (e.g., 5 minutes) to avoid noise.<\/li>\n<li>Error budget burn alerts for Functions: fast-burn for severe incidents, slow-burn for steady regressions.<\/li>\n<li>Signup\/login failure spikes: alert on ratio changes, not just raw counts.<\/li>\n<li>Storage egress anomalies: detect sudden jumps in bytes_out or 5xx on downloads.<\/li>\n<\/ul>\n<h2>Local development with the Nhost CLI<\/h2>\n<p>Run the same stack on your laptop and preview traces before merging. Start a local Collector and point your local Nhost services at its OTLP endpoint using the same environment variable keys as production. This lets you tune sampling, verify context propagation, and align resource attributes early. For a step-by-step local workflow, see <a href=\"https:\/\/blogs.aithor.ca\/nhost\/2026\/07\/12\/local-development-with-the-nhost-cli-run-postgres-graphql-and-auth-in-containers-byoc-step-by-step\/\">Local Development with the Nhost CLI: Run Postgres, GraphQL, and Auth in Containers (BYOC Step-by-Step)<\/a>.<\/p>\n<h2>CI\/CD and secrets management<\/h2>\n<ul>\n<li>Commit OpenTelemetry configuration templates to version control (document resource attributes and naming).<\/li>\n<li>Inject OTLP endpoints and tokens via Nhost environment variables per environment (dev\/staging\/prod).<\/li>\n<li>Use different sampling strategies per environment: 100% in dev, 20% in staging, and 5\u201320% in prod depending on traffic.<\/li>\n<li>Pin <em>service.version<\/em> to Git SHA for rollbacks and deployment diffing in dashboards.<\/li>\n<\/ul>\n<h2>Troubleshooting<\/h2>\n<p>Most issues fall into three buckets: no data, broken trace joins, or high cardinality. Here\u2019s how to resolve each quickly.<\/p>\n<h3>No traces arriving<\/h3>\n<ul>\n<li>Verify the OTLP URL is correct (protocol, path, and port). Prefer HTTPS with valid TLS certs.<\/li>\n<li>Confirm the token\/header name matches what the Collector expects.<\/li>\n<li>Temporarily raise sampling to 100% to rule out sampling as the cause.<\/li>\n<li>Check Collector logs for rate limits, auth failures, or bad content-type.<\/li>\n<\/ul>\n<h3>Broken joins<\/h3>\n<ul>\n<li>Ensure <em>traceparent<\/em> is forwarded from GraphQL to Functions (Actions\/Event Triggers) and from Functions to any downstream calls.<\/li>\n<li>Use consistent <em>service.name<\/em> per component; do not append dynamic suffixes.<\/li>\n<li>Confirm your backend isn\u2019t rewriting headers or stripping W3C fields.<\/li>\n<\/ul>\n<h3>Cardinality control<\/h3>\n<ul>\n<li>Do not store raw <em>db.statement<\/em> values as high-cardinality attributes; prefer operationName and table\/field summaries.<\/li>\n<li>Truncate large attribute values in the Collector and cap label sets for metrics.<\/li>\n<li>Whitelist a minimal set of resource attributes: <em>service.name<\/em>, <em>nhost.project.id<\/em>, <em>deployment.environment<\/em>, <em>service.version<\/em>.<\/li>\n<\/ul>\n<h2>Next steps<\/h2>\n<ul>\n<li>Add synthetic probes for critical routes and correlate with GraphQL resolver latency.<\/li>\n<li>Define SLOs per service, wire alerts to Slack or PagerDuty, and document runbooks.<\/li>\n<li>Roll out OpenTelemetry to all BYOC services and standardize resource attributes across languages.<\/li>\n<li>Continuously review dashboards for signal-to-noise and refine sampling based on incident learning.<\/li>\n<\/ul>\n<p><strong>Why Nhost?<\/strong> Because you get a complete, production-ready backend\u2014Postgres, GraphQL, Authentication, Storage, Serverless Functions, and BYOC\u2014plus a straightforward path to end-to-end OpenTelemetry. Set a few environment variables in the Console, redeploy, and your observability and monitoring are live with clean traces, logs and metrics. No DevOps detours. No infrastructure to babysit.<\/p>\n<h2>Conclusion<\/h2>\n<p>With a vendor-neutral OpenTelemetry pipeline, you can achieve real Nhost monitoring in hours, not weeks. Tie GraphQL, Functions, Postgres timings, Auth, Storage, and BYOC into one distributed trace. Build dashboards focused on user-facing outcomes, keep metrics low-cardinality, and alert on what truly matters. That\u2019s how fast-moving teams ship confidently without getting slowed down by infrastructure.<\/p>\n<p>Ready to see it in action on your stack? Get started for free.<\/p>\n<h2>Frequently Asked Questions<\/h2>\n<h3>Do I need to host my own OpenTelemetry Collector, or can I point Nhost directly to a vendor\u2019s OTLP endpoint?<\/h3>\n<p>You can do either. Many vendors expose a public OTLP endpoint with token-based auth, so Nhost services can export directly. Others recommend placing your own Collector in front to handle sampling, scrubbing, and routing to multiple backends. Start with a managed vendor endpoint for speed; introduce your own Collector later if you need advanced control.<\/p>\n<h3>How do I enable OpenTelemetry on the Nhost GraphQL API if I don\u2019t control servers?<\/h3>\n<p>Use the Nhost Console to set the GraphQL engine\u2019s OpenTelemetry environment variables: the OTLP endpoint, headers for auth, and resource attributes like service.name and deployment.environment. Redeploy the GraphQL service. No server access or sidecars are required.<\/p>\n<h3>Can I get database-level metrics from Postgres on Nhost, or should I rely on GraphQL resolver timings?<\/h3>\n<p>Resolver timings are usually sufficient for actionable performance monitoring because they reflect what users experience. If you operate a read-only Postgres connection elsewhere, you can scrape <em>pg_stat*<\/em> via the Collector\u2019s postgres receiver and correlate with traces using db.system=postgres. If you prefer zero infrastructure, stick with resolver spans and operationName-based dashboards.<\/p>\n<h3>How do I correlate serverless function logs with GraphQL traces in one view?<\/h3>\n<p>Emit structured JSON logs from Functions that include trace_id and span_id and route them through OTEL logs. Ensure Functions propagate the traceparent header from GraphQL. In your backend, use trace-based log correlation to jump from an error log to the exact distributed trace.<\/p>\n<h3>What is the performance overhead of enabling OpenTelemetry on a production Nhost project?<\/h3>\n<p>With batching and 10\u201320% parent-based sampling, overhead is typically low single digits of CPU and memory. Network overhead scales with sampling and span size. Start conservative, measure p95 and error rates, and adjust sampling as needed. For incident response, it\u2019s safe to temporarily raise sampling to 100% to capture full fidelity.<\/h3>\n","protected":false},"excerpt":{"rendered":"<p>What you\u2019ll build You already move fast with Nhost: Postgres, real-time GraphQL, Authentication, Storage, and Serverless Functions without touching se&#8230;<\/p>\n","protected":false},"author":2,"featured_media":15,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[27,29,25,26,28],"class_list":["post-14","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-observability","tag-logs-and-metrics","tag-nhost-monitoring","tag-observability-and-monitoring","tag-opentelemetry","tag-performance-monitoring"],"_links":{"self":[{"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/comments?post=14"}],"version-history":[{"count":0,"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/posts\/14\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/media\/15"}],"wp:attachment":[{"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/media?parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/categories?post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.aithor.ca\/nhost\/wp-json\/wp\/v2\/tags?post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}