Incident Management Pages¶
An incident page shows live infrastructure state to everyone on an incident call. No screen-sharing, no console access, no waiting for someone to look something up.
This guide shows how to build a page that displays:
- EC2 instance state and health
- CloudWatch alarm status
- Recent CloudTrail changes
- Health analysis with expected infrastructure rules
See a working example at cloudsandlight.com/demo/app-status-portal.
Page structure¶
An incident management page typically has these sections:
┌────────────────────────────────────────┐
│ Application name / Environment │
├────────────────────────────────────────┤
│ Health Analysis (summary) │
├───────────────────┬────────────────────┤
│ EC2 Instances │ CloudWatch Alarms │
├───────────────────┴────────────────────┤
│ Recent CloudTrail Changes │
├────────────────────────────────────────┤
│ Costs (optional) │
└────────────────────────────────────────┘
Full example¶
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Production Status — Acme App</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link rel="stylesheet"
href="https://cdn.lightpane.cloud/sdk/v1/clouds-and-light.css">
</head>
<body>
<div class="container mt-4">
<h1>Acme App — Production Status</h1>
<p class="text-muted">Live infrastructure data. Refreshes on page load.</p>
<!-- Access key -->
<script>
var serviceDiscoveryConfig = {
accessKey: 'csl_em_YOUR_ACCESS_KEY_HERE'
};
</script>
<!-- Service requests -->
<script>
var serviceDiscoveryRequests = serviceDiscoveryRequests || [];
serviceDiscoveryRequests.push({
service: 'ec2',
provider: 'aws',
region: 'eu-west-2',
source: 'live',
attributes: ['name', 'instance_id', 'instance_type', 'state',
'private_ip', 'launch_time']
});
serviceDiscoveryRequests.push({
service: 'cloudwatch_alarms',
provider: 'aws',
region: 'eu-west-2',
source: 'live',
attributes: ['alarm_name', 'state_value', 'metric_name',
'namespace', 'state_updated']
});
serviceDiscoveryRequests.push({
service: 'cloudtrail',
provider: 'aws',
region: 'eu-west-2',
source: 'live',
attributes: ['event_time', 'event_name', 'username',
'resource_type', 'resource_name']
});
</script>
<!-- Health analysis -->
<div class="mb-4">
<h2>Health Analysis</h2>
<div id="sd-analysis-panel"></div>
</div>
<!-- Infrastructure state -->
<div class="row mb-4">
<div class="col-md-6">
<h2>EC2 Instances</h2>
<div data-sd-service="ec2" data-sd-source="live"></div>
</div>
<div class="col-md-6">
<h2>CloudWatch Alarms</h2>
<div data-sd-service="cloudwatch_alarms" data-sd-source="live"></div>
</div>
</div>
<!-- Recent changes -->
<div class="mb-4">
<h2>Recent Changes (CloudTrail)</h2>
<div data-sd-service="cloudtrail" data-sd-source="live"></div>
</div>
</div>
<!-- SDK scripts -->
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-core.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-fetch.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-render.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-format.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-analysis.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-cloudwatch.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-cloudtrail.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-boot.js"></script>
</body>
</html>
Health analysis rules¶
The analysis pane (sd-analysis.js) evaluates the discovered infrastructure against
rules you define. It produces a summary showing what is healthy, what is degraded,
and what is missing.
Define expected infrastructure before the SDK scripts load:
<script>
var serviceAnalysisConfig = {
rules: [
{
label: "Web servers running",
service: "ec2",
match: {"name": "web-*"},
expect: {"state": "running"},
min_count: 2
},
{
label: "Database available",
service: "rds_instances",
match: {"name": "acme-prod-db"},
expect: {"status": "available"},
min_count: 1
},
{
label: "No CloudWatch alarms firing",
service: "cloudwatch_alarms",
expect_none: {"state_value": "ALARM"}
}
]
};
</script>
Each rule checks:
| Property | Description |
|---|---|
match |
Filter resources by field values. Supports * wildcards. |
expect |
Expected values for matched resources. |
min_count |
Minimum number of matching resources expected. |
expect_none |
Asserts that no resources match these values (e.g. no alarms in ALARM state). |
The analysis pane renders a traffic-light summary:
- Green: All rules pass
- Amber: Some rules pass with warnings (e.g. count is at minimum)
- Red: One or more rules fail
CloudWatch alarm pane¶
The CloudWatch pane (sd-cloudwatch.js) renders alarm state with colour-coded
status indicators:
- ALARM — red
- OK — green
- INSUFFICIENT_DATA — grey
It can also display sparkline graphs of recent alarm state transitions when
sd-sparklines.js is included.
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-sparklines.js"></script>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-cloudwatch.js"></script>
CloudTrail pane¶
The CloudTrail pane (sd-cloudtrail.js) shows recent API calls in your account.
During an incident, this answers the question "what changed recently?" without
anyone needing to open the AWS Console.
Filter to specific event types:
serviceDiscoveryRequests.push({
service: 'cloudtrail',
provider: 'aws',
region: 'eu-west-2',
source: 'live',
attributes: ['event_time', 'event_name', 'username',
'resource_type', 'resource_name']
});
Add a cost summary¶
Include the costs pane to show current-month spend alongside infrastructure state:
serviceDiscoveryRequests.push({
service: 'costs',
provider: 'aws',
region: 'us-east-1',
source: 'live'
});
<div data-sd-service="costs" data-sd-source="live"></div>
<script src="https://cdn.lightpane.cloud/sdk/v1/sd-costs.js"></script>
Cost data region
AWS Cost Explorer is a global service. Use us-east-1 as the region regardless
of where your resources run.
Sharing the page during an incident¶
The page uses an embed key, so anyone with the URL can view it. No LightPane account is needed. Share the URL in your incident channel and everyone sees the same live data.
For security, scope the embed key:
allowed_origins: the domain where the incident page is hosted- Services: only the services relevant to the application
- Cloud account: only the account that runs this application
Auto-refresh¶
Add a meta refresh tag to reload the page at a fixed interval:
Or use the SDK's refresh function for a smoother experience: