The 3 AM "Everything looks fine" Nightmare
It’s 3:14 AM on a Tuesday. PagerDuty screams. You open your laptop, squinting at the glare. You check your Grafana dashboard. CPU is at 40%. Memory is flat. Disk space is plentiful. All status checks are returning 200 OK.
Yet, the support ticket queue is flooding with angry Norwegians unable to process payments. This is the failure of monitoring. You are watching a dashboard of aggregate averages that lie to you. You know something is broken, but your tools are only capable of answering the questions you predicted you'd need to ask three months ago.
This is where we draw the line. In 2022, if you are still relying solely on static thresholds (Nagios style) or simple metric scraping, you are flying blind. We need observability—the ability to understand the internal state of a system based on its external outputs. It's the difference between "The server is up" and "The database connection pool is exhausted specifically for requests originating from the Oslo node due to a misconfigured firewall rule."
The Three Pillars in the Real World
We often chant "Metrics, Logs, Traces" like a religious mantra, but implementation is where teams fail. They install the tools but don't configure the correlation.
1. Structured Logging (The Foundation)
If you are still grepping raw text files in /var/log/nginx/, stop. You cannot aggregate text efficiently. To make logs queryable (for example, with Loki), you need JSON. A raw text log is data; a JSON log is information.
Here is the exact nginx.conf snippet I use on every CoolVDS high-performance instance to ensure logs are machine-readable:
http {
log_format json_analytics escape=json
'{'
'"msec": "$msec", ' # Request time in seconds with milliseconds resolution
'"connection": "$connection", '
'"connection_requests": "$connection_requests", '
'"pid": "$pid", '
'"request_id": "$request_id", ' # Crucial for tracing correlation
'"request_length": "$request_length", '
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"remote_port": "$remote_port", '
'"time_local": "$time_local", '
'"time_iso8601": "$time_iso8601", '
'"request": "$request", '
'"request_uri": "$request_uri", '
'"args": "$args", '
'"status": "$status", '
'"body_bytes_sent": "$body_bytes_sent", '
'"bytes_sent": "$bytes_sent", '
'"http_referer": "$http_referer", '
'"http_user_agent": "$http_user_agent", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"http_host": "$http_host", '
'"server_name": "$server_name", '
'"request_time": "$request_time", '
'"upstream": "$upstream_addr", '
'"upstream_connect_time": "$upstream_connect_time", '
'"upstream_header_time": "$upstream_header_time", '
'"upstream_response_time": "$upstream_response_time", '
'"upstream_response_length": "$upstream_response_length", '
'"upstream_cache_status": "$upstream_cache_status", '
'"ssl_protocol": "$ssl_protocol", '
'"ssl_cipher": "$ssl_cipher", '
'"scheme": "$scheme", '
'"request_method": "$request_method"'
'}';
access_log /var/log/nginx/access_json.log json_analytics;
}2. Metrics (The Context)
Metrics are cheap. They give you the "what." Use Prometheus for this. But don't just use the default Node Exporter. You need to understand pressure.
Linux Load Average is a legacy metric. It’s confusing. Instead, look at PSI (Pressure Stall Information). This has been available in the Linux kernel since 4.20, and by now (mid-2022), it is stable and essential. It tells you exactly how much time your tasks are stalling on CPU, IO, or Memory.
Pro Tip: On a CoolVDS instance, run cat /proc/pressure/io. If the "some" value is rising, your storage is the bottleneck, not your code. This is often where cheap VPS providers fail—their noisy neighbors steal your IOPS. We use NVMe exclusively to prevent this IO stall.3. Distributed Tracing (The Why)
This is the hard part. In 2022, OpenTelemetry (OTel) is the standard we are all coalescing around. It allows you to tag a request at the load balancer and follow it through your PHP-FPM workers, into your Redis cache, and back out.
You don't need a complex SaaS for this. You can run Jaeger or Grafana Tempo on your own infrastructure, provided you have the I/O throughput to handle the writes.
The Infrastructure Tax: High IOPS or Death
Here is the uncomfortable truth: Observability is heavy.
Monitoring is light; it’s just reading counters. Observability involves ingesting gigabytes of log data and millions of trace spans per hour. If you try to run an ELK stack (Elasticsearch, Logstash, Kibana) or a PLG stack (Promtail, Loki, Grafana) on a standard spinning disk or a throttled cloud volume, your observability tool will crash before your application does.
I recently audited a setup for a client in Bergen. They were logging heavily to a managed volume on a major US cloud provider. Their bill for "IOPS provisioning" was higher than their compute bill.
We moved them to a CoolVDS Compute instance. Why? Because we provide raw NVMe access. We don't artificially throttle your IOPS to upsell you. When you are writing 5,000 log lines per second to Loki, you need the disk to just accept the data without latency spikes.
| Feature | Standard Monitoring | Full Observability |
|---|---|---|
| Data Type | Aggregates / Counters | High-cardinality Events |
| Question | "Is the system healthy?" | "Why did this specific user fail?" |
| Storage Impact | Low (Time Series) | High (Logs/Traces + Indexing) |
| Network Impact | Pull-based (Scraping) | Push-based (Streams) |
The Local Angle: GDPR and Schrems II
We cannot talk about logging in 2022 without mentioning compliance. If your logs contain IP addresses (they do) or User IDs (they do), that is PII (Personally Identifiable Information).
Since the Schrems II ruling, sending that log data to a US-owned cloud observability SaaS is a legal minefield. Datatilsynet (The Norwegian Data Protection Authority) has been very clear about data transfers.
Hosting your observability stack (Loki/Prometheus/Tempo) on a Norwegian VPS isn't just about performance; it's about data sovereignty. When the data sits in a data center in Oslo, under Norwegian law, you sleep better than hoping your US provider's "Standard Contractual Clauses" hold up in court.
Deployment: A 2022-Ready Docker Compose Stack
Here is a battle-tested configuration to get the PLG (Promtail, Loki, Grafana) stack running. This assumes you are running on a host with sufficient RAM and fast storage (like our 8GB+ plans).
version: "3"
services:
loki:
image: grafana/loki:2.6.1
command: -config.file=/etc/loki/local-config.yaml
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:2.6.1
volumes:
- /var/log:/var/log
- ./promtail-config.yaml:/etc/promtail/config.yaml
command: -config.file=/etc/promtail/config.yaml
grafana:
image: grafana/grafana:9.0.5
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=secret
- GF_USERS_ALLOW_SIGN_UP=false
This setup allows you to grep logs using LogQL directly in Grafana. For example, to find all 500 errors from Nginx:
{job="nginx"} |= "status": 500Simple. Fast. Owned by you.
Conclusion
You can't fix what you can't see. As systems get more distributed (even simple monoliths now talk to S3, Redis, and external APIs), "up" or "down" is no longer a sufficient status.
You need to see the latency distribution. You need to trace the request. And you need to store that data safely within Norwegian borders on hardware that doesn't choke on writes. Don't let IO wait times kill your insights.
Ready to build a stack that actually tells you the truth? Deploy a high-IOPS NVMe instance on CoolVDS today and stop guessing.