# python/02-metrics-collection.py"""Metrics collection and monitoring patterns"""fromtypingimportList,Dict,Any,Optional,Union,Tupleimporttimeimportthreadingfromcollectionsimportdefaultdict,dequefromdatetimeimportdatetime,timedeltaimportjsonimportpsutilimportrequestsfromprometheus_clientimportCounter,Histogram,Gauge,Summary,start_http_serverfromprometheus_client.coreimportCollectorRegistryimportlogginglogger=logging.getLogger(__name__)classMetricsCollector:"""Advanced metrics collector"""def__init__(self,service_name:str):self.service_name=service_nameself.registry=CollectorRegistry()self.metrics={}self.custom_metrics={}self.metrics_thread=Noneself.running=Falsedefcreate_counter(self,name:str,description:str,labels:List[str]=None)->Counter:"""Create counter metric"""counter=Counter(name,description,labelsor[],registry=self.registry)self.metrics[name]=counterreturncounterdefcreate_histogram(self,name:str,description:str,buckets:List[float]=None,labels:List[str]=None)->Histogram:"""Create histogram metric"""histogram=Histogram(name,description,labelsor[],buckets=buckets,registry=self.registry)self.metrics[name]=histogramreturnhistogramdefcreate_gauge(self,name:str,description:str,labels:List[str]=None)->Gauge:"""Create gauge metric"""gauge=Gauge(name,description,labelsor[],registry=self.registry)self.metrics[name]=gaugereturngaugedefcreate_summary(self,name:str,description:str,labels:List[str]=None)->Summary:"""Create summary metric"""summary=Summary(name,description,labelsor[],registry=self.registry)self.metrics[name]=summaryreturnsummarydefincrement_counter(self,name:str,value:float=1,labels:Dict[str,str]=None)->None:"""Increment counter metric"""ifnameinself.metricsandisinstance(self.metrics[name],Counter):iflabels:self.metrics[name].labels(**labels).inc(value)else:self.metrics[name].inc(value)defobserve_histogram(self,name:str,value:float,labels:Dict[str,str]=None)->None:"""Observe histogram metric"""ifnameinself.metricsandisinstance(self.metrics[name],Histogram):iflabels:self.metrics[name].labels(**labels).observe(value)else:self.metrics[name].observe(value)defset_gauge(self,name:str,value:float,labels:Dict[str,str]=None)->None:"""Set gauge metric value"""ifnameinself.metricsandisinstance(self.metrics[name],Gauge):iflabels:self.metrics[name].labels(**labels).set(value)else:self.metrics[name].set(value)defobserve_summary(self,name:str,value:float,labels:Dict[str,str]=None)->None:"""Observe summary metric"""ifnameinself.metricsandisinstance(self.metrics[name],Summary):iflabels:self.metrics[name].labels(**labels).observe(value)else:self.metrics[name].observe(value)defstart_metrics_server(self,port:int=8000)->None:"""Start metrics HTTP server"""start_http_server(port,registry=self.registry)logger.info(f"Metrics server started on port {port}")defstart_system_metrics_collection(self,interval:int=30)->None:"""Start system metrics collection"""self.running=Trueself.metrics_thread=threading.Thread(target=self._collect_system_metrics,args=(interval,),daemon=True)self.metrics_thread.start()defstop_system_metrics_collection(self)->None:"""Stop system metrics collection"""self.running=Falseifself.metrics_thread:self.metrics_thread.join()def_collect_system_metrics(self,interval:int)->None:"""Collect system metrics"""whileself.running:try:# CPU metricscpu_percent=psutil.cpu_percent(interval=1)self.set_gauge("system_cpu_percent",cpu_percent)# Memory metricsmemory=psutil.virtual_memory()self.set_gauge("system_memory_percent",memory.percent)self.set_gauge("system_memory_used_bytes",memory.used)self.set_gauge("system_memory_available_bytes",memory.available)# Disk metricsdisk=psutil.disk_usage('/')self.set_gauge("system_disk_percent",disk.percent)self.set_gauge("system_disk_used_bytes",disk.used)self.set_gauge("system_disk_free_bytes",disk.free)# Network metricsnetwork=psutil.net_io_counters()self.set_gauge("system_network_bytes_sent",network.bytes_sent)self.set_gauge("system_network_bytes_recv",network.bytes_recv)time.sleep(interval)exceptExceptionase:logger.error(f"Error collecting system metrics: {e}")time.sleep(interval)classApplicationMetrics:"""Application-specific metrics"""def__init__(self,collector:MetricsCollector):self.collector=collectorself.setup_metrics()defsetup_metrics(self)->None:"""Setup application metrics"""# HTTP metricsself.collector.create_counter("http_requests_total","Total HTTP requests",["method","endpoint","status_code"])self.collector.create_histogram("http_request_duration_seconds","HTTP request duration",buckets=[0.1,0.5,1.0,2.5,5.0,10.0])# Database metricsself.collector.create_counter("database_queries_total","Total database queries",["operation","table","status"])self.collector.create_histogram("database_query_duration_seconds","Database query duration",buckets=[0.01,0.05,0.1,0.5,1.0,5.0])# Business metricsself.collector.create_counter("business_events_total","Total business events",["event_type","status"])self.collector.create_gauge("active_users","Number of active users")self.collector.create_gauge("queue_size","Queue size",["queue_name"])defrecord_http_request(self,method:str,endpoint:str,status_code:int,duration:float)->None:"""Record HTTP request metrics"""self.collector.increment_counter("http_requests_total",labels={"method":method,"endpoint":endpoint,"status_code":str(status_code)})self.collector.observe_histogram("http_request_duration_seconds",duration)defrecord_database_query(self,operation:str,table:str,status:str,duration:float)->None:"""Record database query metrics"""self.collector.increment_counter("database_queries_total",labels={"operation":operation,"table":table,"status":status})self.collector.observe_histogram("database_query_duration_seconds",duration)defrecord_business_event(self,event_type:str,status:str)->None:"""Record business event metrics"""self.collector.increment_counter("business_events_total",labels={"event_type":event_type,"status":status})defupdate_active_users(self,count:int)->None:"""Update active users count"""self.collector.set_gauge("active_users",count)defupdate_queue_size(self,queue_name:str,size:int)->None:"""Update queue size"""self.collector.set_gauge("queue_size",size,labels={"queue_name":queue_name})classMetricsMiddleware:"""Metrics middleware for web applications"""def__init__(self,app,metrics:ApplicationMetrics):self.app=appself.metrics=metricsdef__call__(self,environ,start_response):"""WSGI middleware for metrics collection"""start_time=time.time()# Process requestresponse=self.app(environ,start_response)# Calculate metricsduration=time.time()-start_timemethod=environ.get('REQUEST_METHOD','UNKNOWN')path=environ.get('PATH_INFO','/')status_code=200# This would be extracted from response# Record metricsself.metrics.record_http_request(method,path,status_code,duration)returnresponseclassHealthChecker:"""Health check utilities"""def__init__(self,metrics_collector:MetricsCollector):self.metrics_collector=metrics_collectorself.health_checks={}self.setup_health_metrics()defsetup_health_metrics(self)->None:"""Setup health check metrics"""self.metrics_collector.create_gauge("health_check_status","Health check status (1=healthy, 0=unhealthy)",["check_name"])self.metrics_collector.create_histogram("health_check_duration_seconds","Health check duration",["check_name"])defadd_health_check(self,name:str,check_func:callable)->None:"""Add health check"""self.health_checks[name]=check_funcdefrun_health_checks(self)->Dict[str,Any]:"""Run all health checks"""results={}forname,check_funcinself.health_checks.items():start_time=time.time()try:is_healthy=check_func()duration=time.time()-start_timeresults[name]={"healthy":is_healthy,"duration":duration,"error":None}# Record metricsself.metrics_collector.set_gauge("health_check_status",1ifis_healthyelse0,labels={"check_name":name})self.metrics_collector.observe_histogram("health_check_duration_seconds",duration,labels={"check_name":name})exceptExceptionase:duration=time.time()-start_timeresults[name]={"healthy":False,"duration":duration,"error":str(e)}# Record metricsself.metrics_collector.set_gauge("health_check_status",0,labels={"check_name":name})self.metrics_collector.observe_histogram("health_check_duration_seconds",duration,labels={"check_name":name})returnresults# Usage examplesdefexample_metrics_collection():"""Example metrics collection usage"""# Create metrics collectorcollector=MetricsCollector("my_app")# Setup application metricsapp_metrics=ApplicationMetrics(collector)# Start metrics servercollector.start_metrics_server(port=8000)# Start system metrics collectioncollector.start_system_metrics_collection(interval=30)# Record some metricsapp_metrics.record_http_request("GET","/users",200,0.150)app_metrics.record_database_query("SELECT","users","success",0.050)app_metrics.record_business_event("user_registration","success")app_metrics.update_active_users(150)app_metrics.update_queue_size("email_queue",25)# Setup health checkshealth_checker=HealthChecker(collector)defcheck_database():# Simulate database checkreturnTruedefcheck_redis():# Simulate Redis checkreturnTruehealth_checker.add_health_check("database",check_database)health_checker.add_health_check("redis",check_redis)# Run health checkshealth_results=health_checker.run_health_checks()print(f"Health check results: {health_results}")# Stop metrics collectioncollector.stop_system_metrics_collection()
# python/03-distributed-tracing.py"""Distributed tracing implementation and patterns"""fromtypingimportList,Dict,Any,Optional,Union,Tupleimporttimeimportuuidimportjsonfromdatetimeimportdatetime,timedeltaimportrequestsfromdataclassesimportdataclass,asdictimportthreadingfromcontextvarsimportContextVarimportlogginglogger=logging.getLogger(__name__)# Context variables for tracingtrace_id_var:ContextVar[str]=ContextVar('trace_id',default='')span_id_var:ContextVar[str]=ContextVar('span_id',default='')parent_span_id_var:ContextVar[str]=ContextVar('parent_span_id',default='')@dataclassclassSpan:"""Span definition for distributed tracing"""trace_id:strspan_id:strparent_span_id:str=Noneoperation_name:str=""start_time:datetime=Noneend_time:datetime=Noneduration:float=0.0tags:Dict[str,Any]=Nonelogs:List[Dict[str,Any]]=Nonestatus:str="ok"error:str=Nonedef__post_init__(self):ifself.tagsisNone:self.tags={}ifself.logsisNone:self.logs=[]ifself.start_timeisNone:self.start_time=datetime.utcnow()deffinish(self,status:str="ok",error:str=None)->None:"""Finish the span"""self.end_time=datetime.utcnow()self.duration=(self.end_time-self.start_time).total_seconds()self.status=statusself.error=errordefadd_tag(self,key:str,value:Any)->None:"""Add tag to span"""self.tags[key]=valuedefadd_log(self,message:str,**kwargs)->None:"""Add log to span"""log_entry={"timestamp":datetime.utcnow().isoformat(),"message":message,**kwargs}self.logs.append(log_entry)defto_dict(self)->Dict[str,Any]:"""Convert span to dictionary"""returnasdict(self)classTracer:"""Distributed tracer implementation"""def__init__(self,service_name:str,endpoint:str=None):self.service_name=service_nameself.endpoint=endpointself.spans=[]self.active_spans={}self.trace_context={}defstart_span(self,operation_name:str,parent_span_id:str=None,tags:Dict[str,Any]=None)->Span:"""Start a new span"""trace_id=trace_id_var.get()orstr(uuid.uuid4())span_id=str(uuid.uuid4())ifparent_span_idisNone:parent_span_id=span_id_var.get()span=Span(trace_id=trace_id,span_id=span_id,parent_span_id=parent_span_id,operation_name=operation_name,tags=tagsor{})# Set context variablestrace_id_var.set(trace_id)span_id_var.set(span_id)parent_span_id_var.set(parent_span_id)# Add service tagspan.add_tag("service.name",self.service_name)# Store active spanself.active_spans[span_id]=spanreturnspandeffinish_span(self,span:Span,status:str="ok",error:str=None)->None:"""Finish a span"""span.finish(status,error)# Remove from active spansifspan.span_idinself.active_spans:delself.active_spans[span.span_id]# Add to completed spansself.spans.append(span)# Send to tracing backend if endpoint is configuredifself.endpoint:self._send_span(span)def_send_span(self,span:Span)->None:"""Send span to tracing backend"""try:ifself.endpoint:requests.post(self.endpoint,json=span.to_dict(),timeout=5)exceptExceptionase:logger.error(f"Failed to send span to tracing backend: {e}")defget_trace(self,trace_id:str)->List[Span]:"""Get all spans for a trace"""return[spanforspaninself.spansifspan.trace_id==trace_id]defget_active_spans(self)->List[Span]:"""Get all active spans"""returnlist(self.active_spans.values())defcreate_child_span(self,operation_name:str,tags:Dict[str,Any]=None)->Span:"""Create child span of current active span"""current_span_id=span_id_var.get()returnself.start_span(operation_name,current_span_id,tags)classTraceMiddleware:"""Tracing middleware for web applications"""def__init__(self,app,tracer:Tracer):self.app=appself.tracer=tracerdef__call__(self,environ,start_response):"""WSGI middleware for tracing"""# Start root spanspan=self.tracer.start_span(f"{environ.get('REQUEST_METHOD')}{environ.get('PATH_INFO')}",tags={"http.method":environ.get('REQUEST_METHOD'),"http.url":environ.get('PATH_INFO'),"http.user_agent":environ.get('HTTP_USER_AGENT'),"http.remote_addr":environ.get('REMOTE_ADDR')})try:# Process requestresponse=self.app(environ,start_response)# Finish span successfullyself.tracer.finish_span(span,status="ok")returnresponseexceptExceptionase:# Finish span with errorself.tracer.finish_span(span,status="error",error=str(e))raisedeftrace_function(operation_name:str=None):"""Decorator to trace function execution"""defdecorator(func):defwrapper(*args,**kwargs):tracer=Tracer("my_app")span_name=operation_nameorfunc.__name__span=tracer.start_span(span_name,tags={"function.name":func.__name__,"function.module":func.__module__})try:result=func(*args,**kwargs)tracer.finish_span(span,status="ok")returnresultexceptExceptionase:tracer.finish_span(span,status="error",error=str(e))raisereturnwrapperreturndecoratorclassTraceAnalyzer:"""Trace analysis utilities"""def__init__(self,tracer:Tracer):self.tracer=tracerdefanalyze_trace(self,trace_id:str)->Dict[str,Any]:"""Analyze a trace"""spans=self.tracer.get_trace(trace_id)ifnotspans:return{"error":"Trace not found"}# Calculate trace durationstart_times=[span.start_timeforspaninspans]end_times=[span.end_timeforspaninspansifspan.end_time]ifnotend_times:return{"error":"Trace not completed"}trace_start=min(start_times)trace_end=max(end_times)trace_duration=(trace_end-trace_start).total_seconds()# Find root spanroot_spans=[spanforspaninspansifspan.parent_span_idisNone]root_span=root_spans[0]ifroot_spanselsespans[0]# Analyze span hierarchyspan_tree=self._build_span_tree(spans)# Find slow spansslow_spans=[spanforspaninspansifspan.duration>1.0]# Find error spanserror_spans=[spanforspaninspansifspan.status=="error"]return{"trace_id":trace_id,"duration":trace_duration,"span_count":len(spans),"root_operation":root_span.operation_name,"slow_spans":[{"operation":span.operation_name,"duration":span.duration}forspaninslow_spans],"error_spans":[{"operation":span.operation_name,"error":span.error}forspaninerror_spans],"span_tree":span_tree}def_build_span_tree(self,spans:List[Span])->Dict[str,Any]:"""Build span hierarchy tree"""span_dict={span.span_id:spanforspaninspans}root_spans=[spanforspaninspansifspan.parent_span_idisNone]defbuild_tree(span:Span)->Dict[str,Any]:children=[sforsinspansifs.parent_span_id==span.span_id]return{"span_id":span.span_id,"operation":span.operation_name,"duration":span.duration,"status":span.status,"children":[build_tree(child)forchildinchildren]}return[build_tree(span)forspaninroot_spans]# Usage examplesdefexample_distributed_tracing():"""Example distributed tracing usage"""# Create tracertracer=Tracer("my_app",endpoint="http://localhost:14268/api/traces")# Start root spanroot_span=tracer.start_span("user_registration",tags={"user_id":"12345"})# Create child spanchild_span=tracer.create_child_span("validate_user_data",tags={"validation_type":"email"})time.sleep(0.1)# Simulate worktracer.finish_span(child_span)# Create another child spanchild_span2=tracer.create_child_span("save_user",tags={"table":"users"})time.sleep(0.2)# Simulate worktracer.finish_span(child_span2)# Finish root spantracer.finish_span(root_span)# Analyze traceanalyzer=TraceAnalyzer(tracer)trace_analysis=analyzer.analyze_trace(root_span.trace_id)print(f"Trace analysis: {trace_analysis}")# Function tracing@trace_function("database_query")defquery_database(query:str):time.sleep(0.1)return{"result":"success"}result=query_database("SELECT * FROM users")print(f"Database query result: {result}")