Application Performance Monitoring Best Practices for Cloud Applications

What is Application Performance Monitoring?
Application Performance Monitoring (APM) goes beyond server-level metrics like CPU and memory. It tracks the behavior of your application code itself: how long HTTP requests take, where database queries spend their time, which API calls fail, and what end users actually experience.
For applications running on ServerRaja cloud servers, APM provides the missing layer between infrastructure monitoring and user experience.
The Four Pillars of APM
Effective APM covers four key areas:
- **Request Tracing**: Follow individual requests through your application, identifying slow code paths and bottlenecks
- **Error Tracking**: Capture and aggregate application exceptions with full stack traces and context
- **Metrics Collection**: Track business and technical metrics like request rate, error rate, and response time percentiles
- **Log Correlation**: Connect application logs to specific requests for easier debugging
Golden Signals for Application Monitoring
Google's SRE book defines four golden signals that every application should monitor:
Latency
Track how long requests take to serve. Focus on the 95th and 99th percentiles rather than averages:
import time
from prometheus_client import HistogramREQUEST_LATENCY = Histogram( 'http_request_duration_seconds', 'HTTP request latency in seconds', ['method', 'endpoint', 'status'], buckets=[0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0] )
@app.middleware("http") async def track_latency(request, call_next): start = time.perf_counter() response = await call_next(request) duration = time.perf_counter() - start REQUEST_LATENCY.labels( method=request.method, endpoint=request.url.path, status=response.status_code ).observe(duration) return response ```
Traffic
Measure the rate of requests hitting your application:
from prometheus_client import CounterREQUEST_COUNT = Counter( 'http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status'] ) ```
Errors
Track the proportion of failed requests:
ERROR_COUNT = Counter(
'http_errors_total',
'Total HTTP errors',
['method', 'endpoint', 'status', 'error_type']
)@app.exception_handler(Exception) async def global_exception_handler(request, exc): ERROR_COUNT.labels( method=request.method, endpoint=request.url.path, status=500, error_type=type(exc).__name__ ).inc() return JSONResponse(status_code=500, content={"error": "Internal server error"}) ```
Saturation
Monitor how close your application is to its resource limits:
from prometheus_client import GaugeACTIVE_CONNECTIONS = Gauge( 'app_active_connections', 'Number of active connections' )
DB_POOL_USAGE = Gauge( 'app_db_pool_connections', 'Database connection pool usage', ['state'] ) ```
Database Performance Monitoring
Database queries are often the biggest bottleneck. Track query performance:
import functools
import time
from prometheus_client import HistogramDB_QUERY_DURATION = Histogram( 'db_query_duration_seconds', 'Database query duration', ['query_type', 'table'], buckets=[0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0] )
def monitor_query(func): @functools.wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() try: result = func(*args, **kwargs) return result finally: duration = time.perf_counter() - start DB_QUERY_DURATION.labels( query_type=func.__name__, table=kwargs.get('table', 'unknown') ).observe(duration) return wrapper ```
Enable slow query logging in MySQL:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
Enable slow query logging in PostgreSQL:
ALTER SYSTEM SET log_min_duration_statement = 1000;
ALTER SYSTEM SET log_statement = 'none';
SELECT pg_reload_conf();
Setting Up Error Tracking with Sentry
Integrate Sentry for comprehensive error tracking:
import sentry_sdk
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from sentry_sdk.integrations.redis import RedisIntegrationsentry_sdk.init( dsn="https://[email protected]/project", environment="production", traces_sample_rate=0.1, profiles_sample_rate=0.1, integrations=[ SqlalchemyIntegration(), RedisIntegration(), ], before_send=filter_sensitive_data, ) ```
Implementing Distributed Tracing
For microservices architectures, distributed tracing follows requests across service boundaries:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.jaeger.thrift import JaegerExporterprovider = TracerProvider() jaeger_exporter = JaegerExporter(agent_host_name="jaeger", agent_port=6831) provider.add_span_processor(BatchSpanProcessor(jaeger_exporter)) trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
async def process_order(order_id): with tracer.start_as_current_span("process_order") as span: span.set_attribute("order.id", order_id) with tracer.start_as_current_span("validate_payment"): await validate_payment(order_id) with tracer.start_as_current_span("update_inventory"): await update_inventory(order_id) with tracer.start_as_current_span("send_confirmation"): await send_confirmation(order_id) ```
Creating Effective Dashboards
Organize your Grafana APM dashboards into these sections:
- **Overview**: Request rate, error rate, p95 latency, active users
- **Latency Distribution**: Heatmap of response times with percentile lines
- **Error Analysis**: Top errors by count, error rate over time, affected endpoints
- **Database Performance**: Query duration by type, connection pool usage, slow queries
- **Resource Utilization**: CPU, memory, and I/O correlated with application metrics
Alerting Strategy
Set up tiered alerts based on severity:
- **P1 (Critical)**: Error rate > 5% for 2 minutes, server down, database unreachable
- **P2 (Warning)**: p95 latency > 2 seconds for 5 minutes, disk space < 15%
- **P3 (Info)**: Deployment completed, certificate expiring in 30 days
Conclusion
Effective APM combines request tracing, error tracking, metrics, and logs into a cohesive observability strategy. Start by instrumenting your application with Prometheus metrics and Sentry for error tracking. Add distributed tracing as your architecture grows. ServerRaja cloud servers provide the reliable foundation your monitored applications need.