Skip to content

Commit e75dae3

Browse files
Merge pull request #1947 from elizandropacheco/feat/prometheus-metrics
Feat/prometheus metrics
2 parents 1fabb1f + edfcb0c commit e75dae3

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

Dockerfile.metrics

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM evoapicloud/evolution-api:latest AS base
2+
WORKDIR /evolution
3+
4+
# Copiamos apenas o necessário para recompilar o dist com as mudanças locais
5+
COPY tsconfig.json tsup.config.ts package.json ./
6+
COPY src ./src
7+
8+
# Recompila usando os node_modules já presentes na imagem base
9+
RUN npm run build
10+
11+
# Runtime final: reaproveita a imagem oficial e apenas sobrepõe o dist
12+
FROM evoapicloud/evolution-api:latest AS final
13+
WORKDIR /evolution
14+
COPY --from=base /evolution/dist ./dist
15+
16+
ENV PROMETHEUS_METRICS=true
17+
18+
# Entrada original da imagem oficial já sobe o app em /evolution
19+

docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: "3.8"
33
services:
44
api:
55
container_name: evolution_api
6-
image: evoapicloud/evolution-api:latest
6+
image: evolution/api:metrics
77
restart: always
88
depends_on:
99
- redis

src/api/routes/index.router.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ChannelRouter } from '@api/integrations/channel/channel.router';
55
import { ChatbotRouter } from '@api/integrations/chatbot/chatbot.router';
66
import { EventRouter } from '@api/integrations/event/event.router';
77
import { StorageRouter } from '@api/integrations/storage/storage.router';
8+
import { waMonitor } from '@api/server.module';
89
import { configService } from '@config/env.config';
910
import { fetchLatestWaWebVersion } from '@utils/fetchLatestWaWebVersion';
1011
import { Router } from 'express';
@@ -42,6 +43,65 @@ const telemetry = new Telemetry();
4243

4344
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
4445

46+
// Expose Prometheus metrics when enabled by env flag
47+
if (process.env.PROMETHEUS_METRICS === 'true') {
48+
router.get('/metrics', async (req, res) => {
49+
res.set('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');
50+
res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
51+
52+
const escapeLabel = (value: unknown) =>
53+
String(value ?? '')
54+
.replace(/\\/g, '\\\\')
55+
.replace(/\n/g, '\\n')
56+
.replace(/"/g, '\\"');
57+
58+
const lines: string[] = [];
59+
60+
const clientName = process.env.DATABASE_CONNECTION_CLIENT_NAME || 'unknown';
61+
const serverUrl = serverConfig.URL || '';
62+
63+
// environment info
64+
lines.push('# HELP evolution_environment_info Environment information');
65+
lines.push('# TYPE evolution_environment_info gauge');
66+
lines.push(
67+
`evolution_environment_info{version="${escapeLabel(packageJson.version)}",clientName="${escapeLabel(
68+
clientName,
69+
)}",serverUrl="${escapeLabel(serverUrl)}"} 1`,
70+
);
71+
72+
const instances = (waMonitor && waMonitor.waInstances) || {};
73+
const instanceEntries = Object.entries(instances);
74+
75+
// total instances
76+
lines.push('# HELP evolution_instances_total Total number of instances');
77+
lines.push('# TYPE evolution_instances_total gauge');
78+
lines.push(`evolution_instances_total ${instanceEntries.length}`);
79+
80+
// per-instance status
81+
lines.push('# HELP evolution_instance_up 1 if instance state is open, else 0');
82+
lines.push('# TYPE evolution_instance_up gauge');
83+
lines.push('# HELP evolution_instance_state Instance state as a labelled metric');
84+
lines.push('# TYPE evolution_instance_state gauge');
85+
86+
for (const [name, instance] of instanceEntries) {
87+
const state = instance?.connectionStatus?.state || 'unknown';
88+
const integration = instance?.integration || '';
89+
const up = state === 'open' ? 1 : 0;
90+
91+
lines.push(
92+
`evolution_instance_up{instance="${escapeLabel(name)}",integration="${escapeLabel(integration)}"} ${up}`,
93+
);
94+
lines.push(
95+
`evolution_instance_state{instance="${escapeLabel(name)}",integration="${escapeLabel(
96+
integration,
97+
)}",state="${escapeLabel(state)}"} 1`,
98+
);
99+
}
100+
101+
res.send(lines.join('\n') + '\n');
102+
});
103+
}
104+
45105
if (!serverConfig.DISABLE_MANAGER) router.use('/manager', new ViewsRouter().router);
46106

47107
router.get('/assets/*', (req, res) => {

0 commit comments

Comments
 (0)