1. Overview
CI/CD Monitoring & Observability encompasses the comprehensive approach to gaining visibility into CI/CD pipelines, application performance, and system health. This includes metrics collection, logging, tracing, alerting, and dashboard creation to ensure reliable software delivery and operations.
Key Characteristics
- Pipeline visibility - Real-time monitoring of CI/CD processes
- Application observability - Performance and health monitoring
- Proactive alerting - Early detection of issues and anomalies
- Comprehensive logging - Centralized log aggregation and analysis
- Distributed tracing - End-to-end request tracking
- Custom metrics - Business and technical KPI monitoring
- Automated remediation - Self-healing systems and processes
What Problem Does It Solve?
- Provides visibility into pipeline performance and reliability
- Enables proactive issue detection and resolution
- Supports root cause analysis and troubleshooting
- Facilitates performance optimization and capacity planning
- Ensures SLA compliance and service reliability
- Enables data-driven decision making for improvements
2. Monitoring Architecture
Three Pillars of Observability
- Metrics - Quantitative measurements over time
- Logs - Discrete event records with context
- Traces - Request flow through distributed systems
Monitoring Layers
- Infrastructure - Servers, containers, network, storage
- Platform - Kubernetes, ECS, Lambda, databases
- Application - Business logic, APIs, user experience
- Pipeline - CI/CD processes, deployments, quality gates
3. CloudWatch Integration
Pipeline Metrics Collection
import boto3
import json
from datetime import datetime
def publish_pipeline_metrics(pipeline_name, stage_name, action_name, status, duration):
"""
Publish custom pipeline metrics to CloudWatch
"""
cloudwatch = boto3.client('cloudwatch')
# Publish pipeline execution metrics
cloudwatch.put_metric_data(
Namespace='CodePipeline/Custom',
MetricData=[
{
'MetricName': 'PipelineExecution',
'Dimensions': [
{'Name': 'PipelineName', 'Value': pipeline_name},
{'Name': 'Stage', 'Value': stage_name},
{'Name': 'Action', 'Value': action_name},
{'Name': 'Status', 'Value': status}
],
'Value': 1,
'Unit': 'Count',
'Timestamp': datetime.utcnow()
},
{
'MetricName': 'ExecutionDuration',
'Dimensions': [
{'Name': 'PipelineName', 'Value': pipeline_name},
{'Name': 'Stage', 'Value': stage_name},
{'Name': 'Action', 'Value': action_name}
],
'Value': duration,
'Unit': 'Seconds',
'Timestamp': datetime.utcnow()
}
]
)
def lambda_handler(event, context):
"""
Process CodePipeline events and publish metrics
"""
# Parse EventBridge event
detail = event['detail']
pipeline_name = detail['pipeline']
execution_id = detail['execution-id']
state = detail['state']
# Get pipeline execution details
codepipeline = boto3.client('codepipeline')
try:
execution = codepipeline.get_pipeline_execution(
pipelineName=pipeline_name,
pipelineExecutionId=execution_id
)
start_time = execution['pipelineExecution']['creationTime']
end_time = datetime.utcnow()
duration = (end_time - start_time.replace(tzinfo=None)).total_seconds()
# Publish metrics
publish_pipeline_metrics(
pipeline_name=pipeline_name,
stage_name='Overall',
action_name='Pipeline',
status=state,
duration=duration
)
# Calculate success rate
calculate_and_publish_success_rate(pipeline_name)
# Check for SLA violations
check_sla_compliance(pipeline_name, duration)
except Exception as e:
print(f"Error processing pipeline event: {str(e)}")
raise
def calculate_and_publish_success_rate(pipeline_name):
"""
Calculate and publish pipeline success rate
"""
cloudwatch = boto3.client('cloudwatch')
# Get recent pipeline executions
end_time = datetime.utcnow()
start_time = end_time - timedelta(days=7) # Last 7 days
# Query successful executions
success_response = cloudwatch.get_metric_statistics(
Namespace='CodePipeline/Custom',
MetricName='PipelineExecution',
Dimensions=[
{'Name': 'PipelineName', 'Value': pipeline_name},
{'Name': 'Status', 'Value': 'SUCCEEDED'}
],
StartTime=start_time,
EndTime=end_time,
Period=86400, # Daily
Statistics=['Sum']
)
# Query total executions
total_response = cloudwatch.get_metric_statistics(
Namespace='CodePipeline/Custom',
MetricName='PipelineExecution',
Dimensions=[
{'Name': 'PipelineName', 'Value': pipeline_name}
],
StartTime=start_time,
EndTime=end_time,
Period=86400,
Statistics=['Sum']
)
# Calculate success rate
total_successes = sum(point['Sum'] for point in success_response['Datapoints'])
total_executions = sum(point['Sum'] for point in total_response['Datapoints'])
success_rate = (total_successes / total_executions * 100) if total_executions > 0 else 0
# Publish success rate metric
cloudwatch.put_metric_data(
Namespace='CodePipeline/Custom',
MetricData=[
{
'MetricName': 'SuccessRate',
'Dimensions': [
{'Name': 'PipelineName', 'Value': pipeline_name}
],
'Value': success_rate,
'Unit': 'Percent'
}
]
)CloudWatch Dashboard Configuration
Resources:
PipelineDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardName: CI-CD-Pipeline-Dashboard
DashboardBody: !Sub |
{
"widgets": [
{
"type": "metric",
"x": 0,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": [
["CodePipeline/Custom", "PipelineExecution", "PipelineName", "MyPipeline", "Status", "SUCCEEDED"],
[".", ".", ".", ".", ".", "FAILED"],
[".", ".", ".", ".", ".", "CANCELED"]
],
"period": 300,
"stat": "Sum",
"region": "${AWS::Region}",
"title": "Pipeline Executions by Status",
"view": "timeSeries"
}
},
{
"type": "metric",
"x": 12,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": [
["CodePipeline/Custom", "ExecutionDuration", "PipelineName", "MyPipeline"]
],
"period": 300,
"stat": "Average",
"region": "${AWS::Region}",
"title": "Average Pipeline Duration",
"view": "timeSeries"
}
},
{
"type": "metric",
"x": 0,
"y": 6,
"width": 24,
"height": 6,
"properties": {
"metrics": [
["CodePipeline/Custom", "SuccessRate", "PipelineName", "MyPipeline"]
],
"period": 86400,
"stat": "Average",
"region": "${AWS::Region}",
"title": "Pipeline Success Rate (7-day rolling)",
"view": "timeSeries",
"yAxis": {
"left": {
"min": 0,
"max": 100
}
}
}
}
]
}
PipelineAlarms:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: Pipeline-High-Failure-Rate
AlarmDescription: Alert when pipeline failure rate is high
MetricName: SuccessRate
Namespace: CodePipeline/Custom
Statistic: Average
Period: 3600
EvaluationPeriods: 2
Threshold: 80
ComparisonOperator: LessThanThreshold
Dimensions:
- Name: PipelineName
Value: MyPipeline
AlarmActions:
- !Ref PipelineAlertTopic4. Application Performance Monitoring
APM Integration with X-Ray
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch_all
import boto3
import json
# Patch AWS SDK calls
patch_all()
@xray_recorder.capture('deployment_health_check')
def check_deployment_health(deployment_id, application_name):
"""
Comprehensive deployment health check with tracing
"""
# Add deployment context
xray_recorder.current_subsegment().put_annotation('deployment_id', deployment_id)
xray_recorder.current_subsegment().put_annotation('application', application_name)
health_checks = []
# Check application endpoints
with xray_recorder.in_subsegment('endpoint_health_check'):
endpoint_health = check_application_endpoints(application_name)
health_checks.append(endpoint_health)
# Check database connectivity
with xray_recorder.in_subsegment('database_health_check'):
db_health = check_database_health(application_name)
health_checks.append(db_health)
# Check external dependencies
with xray_recorder.in_subsegment('dependency_health_check'):
dependency_health = check_external_dependencies(application_name)
health_checks.append(dependency_health)
# Aggregate health status
overall_health = all(check['healthy'] for check in health_checks)
# Add health metrics
xray_recorder.current_subsegment().put_metadata('health_checks', health_checks)
xray_recorder.current_subsegment().put_annotation('overall_health', overall_health)
# Publish health metrics
publish_health_metrics(application_name, health_checks, overall_health)
return {
'deployment_id': deployment_id,
'application': application_name,
'healthy': overall_health,
'checks': health_checks
}
def publish_health_metrics(application_name, health_checks, overall_health):
"""
Publish application health metrics to CloudWatch
"""
cloudwatch = boto3.client('cloudwatch')
metric_data = [
{
'MetricName': 'ApplicationHealth',
'Dimensions': [
{'Name': 'Application', 'Value': application_name}
],
'Value': 1 if overall_health else 0,
'Unit': 'None'
}
]
# Individual health check metrics
for check in health_checks:
metric_data.append({
'MetricName': f"{check['type']}Health",
'Dimensions': [
{'Name': 'Application', 'Value': application_name}
],
'Value': 1 if check['healthy'] else 0,
'Unit': 'None'
})
# Response time metrics
if 'response_time' in check:
metric_data.append({
'MetricName': f"{check['type']}ResponseTime",
'Dimensions': [
{'Name': 'Application', 'Value': application_name}
],
'Value': check['response_time'],
'Unit': 'Milliseconds'
})
cloudwatch.put_metric_data(
Namespace='Application/Health',
MetricData=metric_data
)Custom Application Metrics
import boto3
import time
from functools import wraps
def monitor_performance(metric_name, namespace='Application/Performance'):
"""
Decorator to monitor function performance
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
try:
result = func(*args, **kwargs)
status = 'Success'
return result
except Exception as e:
status = 'Error'
raise
finally:
end_time = time.time()
duration = (end_time - start_time) * 1000 # Convert to milliseconds
# Publish performance metrics
cloudwatch = boto3.client('cloudwatch')
cloudwatch.put_metric_data(
Namespace=namespace,
MetricData=[
{
'MetricName': f'{metric_name}Duration',
'Value': duration,
'Unit': 'Milliseconds'
},
{
'MetricName': f'{metric_name}Invocations',
'Dimensions': [
{'Name': 'Status', 'Value': status}
],
'Value': 1,
'Unit': 'Count'
}
]
)
return wrapper
return decorator
# Usage example
@monitor_performance('UserRegistration')
def register_user(user_data):
"""
User registration function with performance monitoring
"""
# Business logic here
pass
@monitor_performance('OrderProcessing')
def process_order(order_data):
"""
Order processing function with performance monitoring
"""
# Business logic here
pass5. Log Aggregation and Analysis
Centralized Logging Architecture
Resources:
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/application/myapp
RetentionInDays: 30
LogStream:
Type: AWS::Logs::LogStream
Properties:
LogGroupName: !Ref LogGroup
LogStreamName: application-logs
# Kinesis Data Firehose for log shipping
LogDeliveryStream:
Type: AWS::KinesisFirehose::DeliveryStream
Properties:
DeliveryStreamName: application-logs-delivery
DeliveryStreamType: DirectPut
S3DestinationConfiguration:
BucketARN: !GetAtt LogsBucket.Arn
Prefix: logs/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/hour=!{timestamp:HH}/
ErrorOutputPrefix: error-logs/
BufferingHints:
SizeInMBs: 5
IntervalInSeconds: 300
CompressionFormat: GZIP
RoleARN: !GetAtt FirehoseRole.Arn
# Lambda for log processing
LogProcessor:
Type: AWS::Lambda::Function
Properties:
FunctionName: LogProcessor
Runtime: python3.9
Handler: index.handler
Code:
ZipFile: |
import json
import base64
import gzip
import boto3
def handler(event, context):
cloudwatch = boto3.client('cloudwatch')
# Process CloudWatch Logs data
cw_data = event['awslogs']['data']
compressed_payload = base64.b64decode(cw_data)
uncompressed_payload = gzip.decompress(compressed_payload)
log_data = json.loads(uncompressed_payload)
# Extract metrics from logs
error_count = 0
warning_count = 0
for log_event in log_data['logEvents']:
message = log_event['message']
if 'ERROR' in message:
error_count += 1
elif 'WARN' in message:
warning_count += 1
# Publish log-based metrics
if error_count > 0 or warning_count > 0:
cloudwatch.put_metric_data(
Namespace='Application/Logs',
MetricData=[
{
'MetricName': 'ErrorCount',
'Value': error_count,
'Unit': 'Count'
},
{
'MetricName': 'WarningCount',
'Value': warning_count,
'Unit': 'Count'
}
]
)
return {'statusCode': 200}
LogSubscriptionFilter:
Type: AWS::Logs::SubscriptionFilter
Properties:
LogGroupName: !Ref LogGroup
FilterPattern: '[timestamp, request_id, level="ERROR" || level="WARN", ...]'
DestinationArn: !GetAtt LogProcessor.ArnLog Analysis with CloudWatch Insights
-- Query for error analysis
fields @timestamp, @message
| filter @message like /ERROR/
| stats count() by bin(5m)
| sort @timestamp desc
-- Query for performance analysis
fields @timestamp, @duration
| filter @type = "REPORT"
| stats avg(@duration), max(@duration), min(@duration) by bin(5m)
-- Query for user activity analysis
fields @timestamp, user_id, action
| filter action = "login"
| stats count() by user_id
| sort count desc
| limit 10
-- Query for API endpoint performance
fields @timestamp, endpoint, response_time
| filter endpoint like /api/
| stats avg(response_time), count() by endpoint
| sort avg(response_time) desc6. Alerting and Incident Response
Comprehensive Alerting Strategy
Resources:
# Critical pipeline failure alert
PipelineFailureAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: Critical-Pipeline-Failure
AlarmDescription: Alert on critical pipeline failures
MetricName: PipelineExecution
Namespace: CodePipeline/Custom
Statistic: Sum
Period: 300
EvaluationPeriods: 1
Threshold: 1
ComparisonOperator: GreaterThanOrEqualToThreshold
Dimensions:
- Name: PipelineName
Value: ProductionPipeline
- Name: Status
Value: FAILED
AlarmActions:
- !Ref CriticalAlertTopic
TreatMissingData: notBreaching
# Application error rate alarm
ApplicationErrorAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: High-Application-Error-Rate
AlarmDescription: Alert when application error rate is high
MetricName: ErrorCount
Namespace: Application/Logs
Statistic: Sum
Period: 300
EvaluationPeriods: 2
Threshold: 10
ComparisonOperator: GreaterThanThreshold
AlarmActions:
- !Ref ApplicationAlertTopic
# Performance degradation alarm
PerformanceAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: Performance-Degradation
AlarmDescription: Alert when response time degrades
MetricName: ResponseTime
Namespace: Application/Performance
Statistic: Average
Period: 300
EvaluationPeriods: 3
Threshold: 2000 # 2 seconds
ComparisonOperator: GreaterThanThreshold
AlarmActions:
- !Ref PerformanceAlertTopic
# Composite alarm for overall system health
SystemHealthAlarm:
Type: AWS::CloudWatch::CompositeAlarm
Properties:
AlarmName: Overall-System-Health
AlarmDescription: Composite alarm for overall system health
AlarmRule: !Sub |
ALARM(${PipelineFailureAlarm}) OR
ALARM(${ApplicationErrorAlarm}) OR
ALARM(${PerformanceAlarm})
AlarmActions:
- !Ref SystemHealthTopicAutomated Incident Response
import boto3
import json
from datetime import datetime
def lambda_handler(event, context):
"""
Automated incident response handler
"""
# Parse SNS message
sns_message = json.loads(event['Records'][0]['Sns']['Message'])
alarm_name = sns_message['AlarmName']
new_state = sns_message['NewStateValue']
reason = sns_message['NewStateReason']
if new_state == 'ALARM':
# Create incident ticket
incident_id = create_incident_ticket(alarm_name, reason)
# Determine response based on alarm type
if 'Critical' in alarm_name:
handle_critical_incident(incident_id, alarm_name, sns_message)
elif 'Performance' in alarm_name:
handle_performance_incident(incident_id, alarm_name, sns_message)
elif 'Error' in alarm_name:
handle_error_incident(incident_id, alarm_name, sns_message)
# Send notifications
send_incident_notifications(incident_id, alarm_name, reason)
elif new_state == 'OK':
# Resolve incident if exists
resolve_incident(alarm_name)
return {
'statusCode': 200,
'body': json.dumps('Incident response completed')
}
def handle_critical_incident(incident_id, alarm_name, alarm_data):
"""
Handle critical incidents with immediate response
"""
# Page on-call engineer
page_oncall_engineer(incident_id, alarm_name)
# Start automated diagnostics
run_automated_diagnostics(alarm_name)
# Initiate rollback if pipeline failure
if 'Pipeline' in alarm_name:
initiate_pipeline_rollback(alarm_data)
def handle_performance_incident(incident_id, alarm_name, alarm_data):
"""
Handle performance degradation incidents
"""
# Scale up resources automatically
trigger_auto_scaling(alarm_data)
# Collect performance diagnostics
collect_performance_diagnostics()
# Notify performance team
notify_performance_team(incident_id, alarm_data)
def create_incident_ticket(alarm_name, reason):
"""
Create incident ticket in ticketing system
"""
# Integration with ticketing system (ServiceNow, Jira, etc.)
incident_data = {
'title': f'Alert: {alarm_name}',
'description': reason,
'severity': determine_severity(alarm_name),
'created_at': datetime.utcnow().isoformat(),
'source': 'CloudWatch Alarm'
}
# Store in DynamoDB for tracking
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('IncidentTracking')
incident_id = str(uuid.uuid4())
table.put_item(
Item={
'IncidentId': incident_id,
'AlarmName': alarm_name,
'Status': 'OPEN',
'CreatedAt': incident_data['created_at'],
'Severity': incident_data['severity'],
'Description': reason
}
)
return incident_id7. Common Exam Scenarios
Scenario 1: Implement comprehensive pipeline monitoring
Solution:
- Set up CloudWatch metrics for pipeline executions and duration
- Create dashboards for pipeline visibility and trends
- Configure alerts for pipeline failures and performance degradation
- Implement automated incident response workflows
Scenario 2: Application performance monitoring and alerting
Solution:
- Integrate X-Ray for distributed tracing
- Set up custom application metrics in CloudWatch
- Configure performance alarms with appropriate thresholds
- Implement automated scaling based on performance metrics
Scenario 3: Centralized logging and log analysis
Solution:
- Configure CloudWatch Logs for application and infrastructure logs
- Set up log aggregation with Kinesis Data Firehose
- Implement log-based metrics and alerting
- Use CloudWatch Insights for log analysis and troubleshooting
Scenario 4: SLA monitoring and compliance reporting
Solution:
- Define SLA metrics and thresholds
- Implement SLA monitoring with CloudWatch
- Create compliance dashboards and reports
- Set up automated SLA violation alerts and responses
Scenario 5: Cost monitoring and optimization
Solution:
- Implement cost tracking for CI/CD resources
- Set up cost alerts and budgets
- Monitor resource utilization and optimization opportunities
- Create cost optimization recommendations and automation
Scenario 6: Security monitoring and compliance
Solution:
- Integrate security monitoring with CloudTrail and Config
- Set up security event alerting and response
- Implement compliance monitoring and reporting
- Create security dashboards and metrics
Scenario 7: Multi-environment monitoring strategy
Solution:
- Implement environment-specific monitoring and alerting
- Set up cross-environment correlation and analysis
- Create environment comparison dashboards
- Implement environment-specific incident response
Scenario 8: Proactive monitoring and predictive analytics
Solution:
- Implement anomaly detection with CloudWatch
- Set up predictive scaling and capacity planning
- Create trend analysis and forecasting
- Implement proactive alerting and remediation
8. CLI Commands Reference
CloudWatch Operations
# Put custom metrics
aws cloudwatch put-metric-data \
--namespace "CodePipeline/Custom" \
--metric-data MetricName=PipelineExecution,Value=1,Unit=Count
# Get metric statistics
aws cloudwatch get-metric-statistics \
--namespace "CodePipeline/Custom" \
--metric-name PipelineExecution \
--start-time 2024-01-01T00:00:00Z \
--end-time 2024-01-02T00:00:00Z \
--period 3600 \
--statistics Sum
# Create alarm
aws cloudwatch put-metric-alarm \
--alarm-name "Pipeline-Failure-Rate" \
--alarm-description "Alert on high pipeline failure rate" \
--metric-name FailureRate \
--namespace "CodePipeline/Custom" \
--statistic Average \
--period 300 \
--threshold 20 \
--comparison-operator GreaterThanThresholdCloudWatch Logs Operations
# Create log group
aws logs create-log-group --log-group-name /aws/application/myapp
# Put log events
aws logs put-log-events \
--log-group-name /aws/application/myapp \
--log-stream-name application-stream \
--log-events timestamp=1640995200000,message="Application started"
# Start query
aws logs start-query \
--log-group-name /aws/application/myapp \
--start-time 1640995200 \
--end-time 1640998800 \
--query-string 'fields @timestamp, @message | filter @message like /ERROR/'9. Best Practices for DOP-C02 Exam
Monitoring Strategy
- Implement comprehensive monitoring across all layers
- Use appropriate metrics, logs, and traces for different use cases
- Set up proactive alerting with meaningful thresholds
- Create actionable dashboards for different audiences
Performance Monitoring
- Monitor key performance indicators (KPIs) and service level objectives (SLOs)
- Implement distributed tracing for complex applications
- Set up performance baselines and trend analysis
- Use automated performance testing and monitoring
Incident Response
- Implement automated incident detection and response
- Create runbooks and playbooks for common issues
- Set up escalation procedures and on-call rotations
- Conduct post-incident reviews and continuous improvement
Cost Optimization
- Monitor and optimize monitoring costs
- Use appropriate retention policies for logs and metrics
- Implement cost allocation and chargeback mechanisms
- Regular review and optimization of monitoring resources
10. Exam Tips
What to Remember
- Three pillars of observability - metrics, logs, traces
- CloudWatch is the primary monitoring service for AWS
- X-Ray provides distributed tracing capabilities
- Custom metrics enable business-specific monitoring
- Composite alarms combine multiple alarm conditions
- Log Insights provides powerful log analysis capabilities
- EventBridge enables event-driven monitoring workflows
Common Traps
- Not implementing comprehensive monitoring across all layers
- Setting inappropriate alarm thresholds (too sensitive or not sensitive enough)
- Missing log retention and cost management policies
- Not implementing proper incident response automation
- Overlooking security and compliance monitoring requirements
- Not correlating metrics, logs, and traces for effective troubleshooting
Scenario-Based Questions
- Focus on monitoring strategy design and implementation
- Understand alerting and incident response patterns
- Know cost optimization strategies for monitoring
- Understand integration with CI/CD pipelines
- Know security and compliance monitoring requirements
- Understand performance monitoring and optimization
11. Quick Reference Cheat Sheet
Monitoring Components
Metrics: Quantitative measurements (CPU, memory, response time)
Logs: Event records (application logs, access logs, error logs)
Traces: Request flow (distributed system request tracking)
Alarms: Automated alerts (threshold-based, anomaly detection)CloudWatch Services
CloudWatch Metrics: Time-series data collection
CloudWatch Logs: Log aggregation and analysis
CloudWatch Alarms: Automated alerting
CloudWatch Dashboards: Visualization and reporting
CloudWatch Insights: Log analysis and queryingKey Metrics
Pipeline: Success rate, duration, failure count
Application: Response time, error rate, throughput
Infrastructure: CPU, memory, disk, network
Business: User activity, revenue, conversion rate12. Summary
CI/CD Monitoring & Observability is critical for reliable software delivery and operations and is heavily emphasized in the DOP-C02 exam. Key areas to master:
- Monitoring architecture (metrics, logs, traces integration)
- CloudWatch integration (custom metrics, dashboards, alarms)
- Application performance monitoring (X-Ray, custom metrics)
- Log aggregation and analysis (centralized logging, log insights)
- Alerting and incident response (automated response, escalation)
- Performance monitoring (SLA tracking, optimization)
- Cost monitoring (resource optimization, budget alerts)
- Security monitoring (compliance, threat detection)
Understanding these concepts with hands-on practice will ensure success on monitoring and observability questions in the DOP-C02 exam.