feat(config): add telemetry and metrics configuration options

- Introduce new environment variables for telemetry and Prometheus metrics in .env.example
- Create example configuration files for Prometheus and Grafana dashboards
- Update main application to utilize new configuration settings for Sentry, audio converter, and proxy
- Enhance channel services to support audio conversion API integration
- Implement middleware for metrics IP whitelisting and basic authentication in routes
This commit is contained in:
Davidson Gomes 2025-09-17 16:50:36 -03:00
parent 81a991a62e
commit 3ddbd6a7fb
16 changed files with 538 additions and 44 deletions

View File

@ -9,6 +9,28 @@ SSL_CONF_FULLCHAIN=/path/to/cert.crt
SENTRY_DSN=
# Telemetry - Set to false to disable telemetry
TELEMETRY_ENABLED=true
TELEMETRY_URL=
# Prometheus metrics - Set to true to enable Prometheus metrics
PROMETHEUS_METRICS=false
METRICS_AUTH_REQUIRED=true
METRICS_USER=prometheus
METRICS_PASSWORD=secure_random_password_here
METRICS_ALLOWED_IPS=127.0.0.1,10.0.0.100,192.168.1.50
# Proxy configuration (optional)
PROXY_HOST=
PROXY_PORT=
PROXY_PROTOCOL=
PROXY_USERNAME=
PROXY_PASSWORD=
# Audio converter API (optional)
API_AUDIO_CONVERTER=
API_AUDIO_CONVERTER_KEY=
# Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com'
CORS_ORIGIN=*
CORS_METHODS=GET,POST,PUT,DELETE

View File

@ -0,0 +1,238 @@
{
"dashboard": {
"id": null,
"title": "Evolution API Monitoring",
"tags": ["evolution-api", "whatsapp", "monitoring"],
"style": "dark",
"timezone": "browser",
"panels": [
{
"id": 1,
"title": "API Status",
"type": "stat",
"targets": [
{
"expr": "up{job=\"evolution-api\"}",
"legendFormat": "API Status"
}
],
"fieldConfig": {
"defaults": {
"mappings": [
{
"options": {
"0": {
"text": "DOWN",
"color": "red"
},
"1": {
"text": "UP",
"color": "green"
}
},
"type": "value"
}
]
}
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
}
},
{
"id": 2,
"title": "Total Instances",
"type": "stat",
"targets": [
{
"expr": "evolution_instances_total",
"legendFormat": "Total Instances"
}
],
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
}
},
{
"id": 3,
"title": "Instance Status Overview",
"type": "piechart",
"targets": [
{
"expr": "sum by (state) (evolution_instance_state)",
"legendFormat": "{{ state }}"
}
],
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 8
}
},
{
"id": 4,
"title": "Instances by Integration Type",
"type": "piechart",
"targets": [
{
"expr": "sum by (integration) (evolution_instance_up)",
"legendFormat": "{{ integration }}"
}
],
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 8
}
},
{
"id": 5,
"title": "Instance Uptime",
"type": "table",
"targets": [
{
"expr": "evolution_instance_up",
"format": "table",
"instant": true
}
],
"transformations": [
{
"id": "organize",
"options": {
"excludeByName": {
"Time": true,
"__name__": true
},
"renameByName": {
"instance": "Instance Name",
"integration": "Integration Type",
"Value": "Status"
}
}
}
],
"fieldConfig": {
"overrides": [
{
"matcher": {
"id": "byName",
"options": "Status"
},
"properties": [
{
"id": "mappings",
"value": [
{
"options": {
"0": {
"text": "DOWN",
"color": "red"
},
"1": {
"text": "UP",
"color": "green"
}
},
"type": "value"
}
]
}
]
}
]
},
"gridPos": {
"h": 9,
"w": 24,
"x": 0,
"y": 17
}
},
{
"id": 6,
"title": "Instance Status Timeline",
"type": "timeseries",
"targets": [
{
"expr": "evolution_instance_up",
"legendFormat": "{{ instance }} ({{ integration }})"
}
],
"fieldConfig": {
"defaults": {
"custom": {
"drawStyle": "line",
"lineInterpolation": "stepAfter",
"lineWidth": 2,
"fillOpacity": 10,
"gradientMode": "none",
"spanNulls": false,
"insertNulls": false,
"showPoints": "never",
"pointSize": 5,
"stacking": {
"mode": "none",
"group": "A"
},
"axisPlacement": "auto",
"axisLabel": "",
"scaleDistribution": {
"type": "linear"
},
"hideFrom": {
"legend": false,
"tooltip": false,
"vis": false
},
"thresholdsStyle": {
"mode": "off"
}
},
"min": 0,
"max": 1
}
},
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 26
}
}
],
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"templating": {
"list": []
},
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"refresh": "30s",
"schemaVersion": 27,
"version": 0,
"links": []
}
}

76
prometheus.yml.example Normal file
View File

@ -0,0 +1,76 @@
# Prometheus configuration example for Evolution API
# Copy this file to prometheus.yml and adjust the settings
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
scrape_configs:
# Evolution API metrics
- job_name: 'evolution-api'
static_configs:
- targets: ['localhost:8080'] # Adjust to your Evolution API URL
# Metrics endpoint path
metrics_path: '/metrics'
# Scrape interval for this job
scrape_interval: 30s
# Basic authentication (if METRICS_AUTH_REQUIRED=true)
basic_auth:
username: 'prometheus' # Should match METRICS_USER
password: 'secure_random_password_here' # Should match METRICS_PASSWORD
# Optional: Add custom labels
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:8080 # Evolution API address
# Alerting configuration (optional)
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Example alert rules for Evolution API
# Create a file called evolution_alerts.yml with these rules:
#
# groups:
# - name: evolution-api
# rules:
# - alert: EvolutionAPIDown
# expr: up{job="evolution-api"} == 0
# for: 1m
# labels:
# severity: critical
# annotations:
# summary: "Evolution API is down"
# description: "Evolution API has been down for more than 1 minute."
#
# - alert: EvolutionInstanceDown
# expr: evolution_instance_up == 0
# for: 2m
# labels:
# severity: warning
# annotations:
# summary: "Evolution instance {{ $labels.instance }} is down"
# description: "Instance {{ $labels.instance }} has been down for more than 2 minutes."
#
# - alert: HighInstanceCount
# expr: evolution_instances_total > 100
# for: 5m
# labels:
# severity: warning
# annotations:
# summary: "High number of Evolution instances"
# description: "Evolution API is managing {{ $value }} instances."

View File

@ -13,7 +13,7 @@ import { chatbotController } from '@api/server.module';
import { CacheService } from '@api/services/cache.service';
import { ChannelStartupService } from '@api/services/channel.service';
import { Events, wa } from '@api/types/wa.types';
import { Chatwoot, ConfigService, Openai, S3 } from '@config/env.config';
import { AudioConverter, Chatwoot, ConfigService, Openai, S3 } from '@config/env.config';
import { BadRequestException, InternalServerErrorException } from '@exceptions';
import { createJid } from '@utils/createJid';
import axios from 'axios';
@ -622,7 +622,8 @@ export class EvolutionStartupService extends ChannelStartupService {
number = number.replace(/\D/g, '');
const hash = `${number}-${new Date().getTime()}`;
if (process.env.API_AUDIO_CONVERTER) {
const audioConverterConfig = this.configService.get<AudioConverter>('AUDIO_CONVERTER');
if (audioConverterConfig.API_URL) {
try {
this.logger.verbose('Using audio converter API');
const formData = new FormData();
@ -640,10 +641,10 @@ export class EvolutionStartupService extends ChannelStartupService {
formData.append('format', 'mp4');
const response = await axios.post(process.env.API_AUDIO_CONVERTER, formData, {
const response = await axios.post(audioConverterConfig.API_URL, formData, {
headers: {
...formData.getHeaders(),
apikey: process.env.API_AUDIO_CONVERTER_KEY,
apikey: audioConverterConfig.API_KEY,
},
});

View File

@ -20,7 +20,7 @@ import { chatbotController } from '@api/server.module';
import { CacheService } from '@api/services/cache.service';
import { ChannelStartupService } from '@api/services/channel.service';
import { Events, wa } from '@api/types/wa.types';
import { Chatwoot, ConfigService, Database, Openai, S3, WaBusiness } from '@config/env.config';
import { AudioConverter, Chatwoot, ConfigService, Database, Openai, S3, WaBusiness } from '@config/env.config';
import { BadRequestException, InternalServerErrorException } from '@exceptions';
import { createJid } from '@utils/createJid';
import { status } from '@utils/renderStatus';
@ -1300,7 +1300,8 @@ export class BusinessStartupService extends ChannelStartupService {
number = number.replace(/\D/g, '');
const hash = `${number}-${new Date().getTime()}`;
if (process.env.API_AUDIO_CONVERTER) {
const audioConverterConfig = this.configService.get<AudioConverter>('AUDIO_CONVERTER');
if (audioConverterConfig.API_URL) {
this.logger.verbose('Using audio converter API');
const formData = new FormData();
@ -1317,10 +1318,10 @@ export class BusinessStartupService extends ChannelStartupService {
formData.append('format', 'mp3');
const response = await axios.post(process.env.API_AUDIO_CONVERTER, formData, {
const response = await axios.post(audioConverterConfig.API_URL, formData, {
headers: {
...formData.getHeaders(),
apikey: process.env.API_AUDIO_CONVERTER_KEY,
apikey: audioConverterConfig.API_KEY,
},
});

View File

@ -62,6 +62,7 @@ import { ChannelStartupService } from '@api/services/channel.service';
import { Events, MessageSubtype, TypeMediaMessage, wa } from '@api/types/wa.types';
import { CacheEngine } from '@cache/cacheengine';
import {
AudioConverter,
CacheConf,
Chatwoot,
ConfigService,
@ -2837,7 +2838,8 @@ export class BaileysStartupService extends ChannelStartupService {
}
public async processAudio(audio: string): Promise<Buffer> {
if (process.env.API_AUDIO_CONVERTER) {
const audioConverterConfig = this.configService.get<AudioConverter>('AUDIO_CONVERTER');
if (audioConverterConfig.API_URL) {
this.logger.verbose('Using audio converter API');
const formData = new FormData();
@ -2847,8 +2849,8 @@ export class BaileysStartupService extends ChannelStartupService {
formData.append('base64', audio);
}
const { data } = await axios.post(process.env.API_AUDIO_CONVERTER, formData, {
headers: { ...formData.getHeaders(), apikey: process.env.API_AUDIO_CONVERTER_KEY },
const { data } = await axios.post(audioConverterConfig.API_URL, formData, {
headers: { ...formData.getHeaders(), apikey: audioConverterConfig.API_KEY },
});
if (!data.audio) {

View File

@ -31,7 +31,9 @@ export class WebsocketController extends EventController implements EventControl
const params = new URLSearchParams(url.search);
const { remoteAddress } = req.socket;
const isAllowedHost = (process.env.WEBSOCKET_ALLOWED_HOSTS || '127.0.0.1,::1,::ffff:127.0.0.1')
const websocketConfig = configService.get<Websocket>('WEBSOCKET');
const allowedHosts = websocketConfig.ALLOWED_HOSTS || '127.0.0.1,::1,::ffff:127.0.0.1';
const isAllowedHost = allowedHosts
.split(',')
.map((h) => h.trim())
.includes(remoteAddress);

View File

@ -26,7 +26,7 @@ const minioClient = (() => {
}
})();
const bucketName = process.env.S3_BUCKET;
const bucketName = BUCKET.BUCKET_NAME;
const bucketExists = async () => {
if (minioClient) {

View File

@ -6,9 +6,9 @@ import { ChatbotRouter } from '@api/integrations/chatbot/chatbot.router';
import { EventRouter } from '@api/integrations/event/event.router';
import { StorageRouter } from '@api/integrations/storage/storage.router';
import { waMonitor } from '@api/server.module';
import { configService } from '@config/env.config';
import { configService, Database, Facebook } from '@config/env.config';
import { fetchLatestWaWebVersion } from '@utils/fetchLatestWaWebVersion';
import { Router } from 'express';
import { NextFunction, Request, Response, Router } from 'express';
import fs from 'fs';
import mimeTypes from 'mime-types';
import path from 'path';
@ -37,15 +37,68 @@ enum HttpStatus {
const router: Router = Router();
const serverConfig = configService.get('SERVER');
const databaseConfig = configService.get<Database>('DATABASE');
const guards = [instanceExistsGuard, instanceLoggedGuard, authGuard['apikey']];
const telemetry = new Telemetry();
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
// Middleware for metrics IP whitelist
const metricsIPWhitelist = (req: Request, res: Response, next: NextFunction) => {
const metricsConfig = configService.get('METRICS');
const allowedIPs = metricsConfig.ALLOWED_IPS?.split(',').map((ip) => ip.trim()) || ['127.0.0.1'];
const clientIP = req.ip || req.connection.remoteAddress || req.socket.remoteAddress;
if (!allowedIPs.includes(clientIP)) {
return res.status(403).send('Forbidden: IP not allowed');
}
next();
};
// Middleware for metrics Basic Authentication
const metricsBasicAuth = (req: Request, res: Response, next: NextFunction) => {
const metricsConfig = configService.get('METRICS');
const metricsUser = metricsConfig.USER;
const metricsPass = metricsConfig.PASSWORD;
if (!metricsUser || !metricsPass) {
return res.status(500).send('Metrics authentication not configured');
}
const auth = req.get('Authorization');
if (!auth || !auth.startsWith('Basic ')) {
res.set('WWW-Authenticate', 'Basic realm="Evolution API Metrics"');
return res.status(401).send('Authentication required');
}
const credentials = Buffer.from(auth.slice(6), 'base64').toString();
const [user, pass] = credentials.split(':');
if (user !== metricsUser || pass !== metricsPass) {
return res.status(401).send('Invalid credentials');
}
next();
};
// Expose Prometheus metrics when enabled by env flag
if (process.env.PROMETHEUS_METRICS === 'true') {
router.get('/metrics', async (req, res) => {
const metricsConfig = configService.get('METRICS');
if (metricsConfig.ENABLED) {
const metricsMiddleware = [];
// Add IP whitelist if configured
if (metricsConfig.ALLOWED_IPS) {
metricsMiddleware.push(metricsIPWhitelist);
}
// Add Basic Auth if required
if (metricsConfig.AUTH_REQUIRED) {
metricsMiddleware.push(metricsBasicAuth);
}
router.get('/metrics', ...metricsMiddleware, async (req, res) => {
res.set('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');
res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
@ -57,7 +110,7 @@ if (process.env.PROMETHEUS_METRICS === 'true') {
const lines: string[] = [];
const clientName = process.env.DATABASE_CONNECTION_CLIENT_NAME || 'unknown';
const clientName = databaseConfig.CONNECTION.CLIENT_NAME || 'unknown';
const serverUrl = serverConfig.URL || '';
// environment info
@ -140,19 +193,20 @@ router
status: HttpStatus.OK,
message: 'Welcome to the Evolution API, it is working!',
version: packageJson.version,
clientName: process.env.DATABASE_CONNECTION_CLIENT_NAME,
clientName: databaseConfig.CONNECTION.CLIENT_NAME,
manager: !serverConfig.DISABLE_MANAGER ? `${req.protocol}://${req.get('host')}/manager` : undefined,
documentation: `https://doc.evolution-api.com`,
whatsappWebVersion: (await fetchLatestWaWebVersion({})).version.join('.'),
});
})
.post('/verify-creds', authGuard['apikey'], async (req, res) => {
const facebookConfig = configService.get<Facebook>('FACEBOOK');
return res.status(HttpStatus.OK).json({
status: HttpStatus.OK,
message: 'Credentials are valid',
facebookAppId: process.env.FACEBOOK_APP_ID,
facebookConfigId: process.env.FACEBOOK_CONFIG_ID,
facebookUserToken: process.env.FACEBOOK_USER_TOKEN,
facebookAppId: facebookConfig.APP_ID,
facebookConfigId: facebookConfig.CONFIG_ID,
facebookUserToken: facebookConfig.USER_TOKEN,
});
})
.use('/instance', new InstanceRouter(configService, ...guards).router)

View File

@ -9,7 +9,7 @@ import { TypebotService } from '@api/integrations/chatbot/typebot/services/typeb
import { PrismaRepository, Query } from '@api/repository/repository.service';
import { eventManager, waMonitor } from '@api/server.module';
import { Events, wa } from '@api/types/wa.types';
import { Auth, Chatwoot, ConfigService, HttpServer } from '@config/env.config';
import { Auth, Chatwoot, ConfigService, HttpServer, Proxy } from '@config/env.config';
import { Logger } from '@config/logger.config';
import { NotFoundException } from '@exceptions';
import { Contact, Message, Prisma } from '@prisma/client';
@ -364,13 +364,14 @@ export class ChannelStartupService {
public async loadProxy() {
this.localProxy.enabled = false;
if (process.env.PROXY_HOST) {
const proxyConfig = this.configService.get<Proxy>('PROXY');
if (proxyConfig.HOST) {
this.localProxy.enabled = true;
this.localProxy.host = process.env.PROXY_HOST;
this.localProxy.port = process.env.PROXY_PORT || '80';
this.localProxy.protocol = process.env.PROXY_PROTOCOL || 'http';
this.localProxy.username = process.env.PROXY_USERNAME;
this.localProxy.password = process.env.PROXY_PASSWORD;
this.localProxy.host = proxyConfig.HOST;
this.localProxy.port = proxyConfig.PORT || '80';
this.localProxy.protocol = proxyConfig.PROTOCOL || 'http';
this.localProxy.username = proxyConfig.USERNAME;
this.localProxy.password = proxyConfig.PASSWORD;
}
const data = await this.prismaRepository.proxy.findUnique({

View File

@ -156,6 +156,7 @@ export type Sqs = {
export type Websocket = {
ENABLED: boolean;
GLOBAL_EVENTS: boolean;
ALLOWED_HOSTS?: string;
};
export type WaBusiness = {
@ -320,6 +321,46 @@ export type S3 = {
};
export type CacheConf = { REDIS: CacheConfRedis; LOCAL: CacheConfLocal };
export type Metrics = {
ENABLED: boolean;
AUTH_REQUIRED: boolean;
USER?: string;
PASSWORD?: string;
ALLOWED_IPS?: string;
};
export type Telemetry = {
ENABLED: boolean;
URL?: string;
};
export type Proxy = {
HOST?: string;
PORT?: string;
PROTOCOL?: string;
USERNAME?: string;
PASSWORD?: string;
};
export type AudioConverter = {
API_URL?: string;
API_KEY?: string;
};
export type Facebook = {
APP_ID?: string;
CONFIG_ID?: string;
USER_TOKEN?: string;
};
export type Sentry = {
DSN?: string;
};
export type EventEmitter = {
MAX_LISTENERS: number;
};
export type Production = boolean;
export interface Env {
@ -351,6 +392,13 @@ export interface Env {
CACHE: CacheConf;
S3?: S3;
AUTHENTICATION: Auth;
METRICS: Metrics;
TELEMETRY: Telemetry;
PROXY: Proxy;
AUDIO_CONVERTER: AudioConverter;
FACEBOOK: Facebook;
SENTRY: Sentry;
EVENT_EMITTER: EventEmitter;
PRODUCTION?: Production;
}
@ -542,6 +590,7 @@ export class ConfigService {
WEBSOCKET: {
ENABLED: process.env?.WEBSOCKET_ENABLED === 'true',
GLOBAL_EVENTS: process.env?.WEBSOCKET_GLOBAL_EVENTS === 'true',
ALLOWED_HOSTS: process.env?.WEBSOCKET_ALLOWED_HOSTS,
},
PUSHER: {
ENABLED: process.env?.PUSHER_ENABLED === 'true',
@ -730,6 +779,39 @@ export class ConfigService {
},
EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true',
},
METRICS: {
ENABLED: process.env?.PROMETHEUS_METRICS === 'true',
AUTH_REQUIRED: process.env?.METRICS_AUTH_REQUIRED === 'true',
USER: process.env?.METRICS_USER,
PASSWORD: process.env?.METRICS_PASSWORD,
ALLOWED_IPS: process.env?.METRICS_ALLOWED_IPS,
},
TELEMETRY: {
ENABLED: process.env?.TELEMETRY_ENABLED === undefined || process.env?.TELEMETRY_ENABLED === 'true',
URL: process.env?.TELEMETRY_URL,
},
PROXY: {
HOST: process.env?.PROXY_HOST,
PORT: process.env?.PROXY_PORT,
PROTOCOL: process.env?.PROXY_PROTOCOL,
USERNAME: process.env?.PROXY_USERNAME,
PASSWORD: process.env?.PROXY_PASSWORD,
},
AUDIO_CONVERTER: {
API_URL: process.env?.API_AUDIO_CONVERTER,
API_KEY: process.env?.API_AUDIO_CONVERTER_KEY,
},
FACEBOOK: {
APP_ID: process.env?.FACEBOOK_APP_ID,
CONFIG_ID: process.env?.FACEBOOK_CONFIG_ID,
USER_TOKEN: process.env?.FACEBOOK_USER_TOKEN,
},
SENTRY: {
DSN: process.env?.SENTRY_DSN,
},
EVENT_EMITTER: {
MAX_LISTENERS: Number.parseInt(process.env?.EVENT_EMITTER_MAX_LISTENERS) || 50,
},
};
}
}

View File

@ -1,10 +1,11 @@
import { configService, EventEmitter as EventEmitterConfig } from '@config/env.config';
import EventEmitter2 from 'eventemitter2';
const maxListeners = parseInt(process.env.EVENT_EMITTER_MAX_LISTENERS, 10) || 50;
const eventEmitterConfig = configService.get<EventEmitterConfig>('EVENT_EMITTER');
export const eventEmitter = new EventEmitter2({
delimiter: '.',
newListener: false,
ignoreErrors: false,
maxListeners: maxListeners,
maxListeners: eventEmitterConfig.MAX_LISTENERS,
});

View File

@ -6,7 +6,15 @@ import { ProviderFiles } from '@api/provider/sessions';
import { PrismaRepository } from '@api/repository/repository.service';
import { HttpStatus, router } from '@api/routes/index.router';
import { eventManager, waMonitor } from '@api/server.module';
import { Auth, configService, Cors, HttpServer, ProviderSession, Webhook } from '@config/env.config';
import {
Auth,
configService,
Cors,
HttpServer,
ProviderSession,
Sentry as SentryConfig,
Webhook,
} from '@config/env.config';
import { onUnexpectedError } from '@config/error.config';
import { Logger } from '@config/logger.config';
import { ROOT_DIR } from '@config/path.config';
@ -140,7 +148,8 @@ async function bootstrap() {
eventManager.init(server);
if (process.env.SENTRY_DSN) {
const sentryConfig = configService.get<SentryConfig>('SENTRY');
if (sentryConfig.DSN) {
logger.info('Sentry - ON');
// Add this after all routes,

View File

@ -1,10 +1,11 @@
import { configService, Sentry as SentryConfig } from '@config/env.config';
import * as Sentry from '@sentry/node';
const dsn = process.env.SENTRY_DSN;
const sentryConfig = configService.get<SentryConfig>('SENTRY');
if (dsn) {
if (sentryConfig.DSN) {
Sentry.init({
dsn: dsn,
dsn: sentryConfig.DSN,
environment: process.env.NODE_ENV || 'development',
tracesSampleRate: 1.0,
profilesSampleRate: 1.0,

View File

@ -1,3 +1,4 @@
import { configService, Telemetry } from '@config/env.config';
import axios from 'axios';
import fs from 'fs';
@ -10,9 +11,9 @@ export interface TelemetryData {
}
export const sendTelemetry = async (route: string): Promise<void> => {
const enabled = process.env.TELEMETRY_ENABLED === undefined || process.env.TELEMETRY_ENABLED === 'true';
const telemetryConfig = configService.get<Telemetry>('TELEMETRY');
if (!enabled) {
if (!telemetryConfig.ENABLED) {
return;
}
@ -27,9 +28,7 @@ export const sendTelemetry = async (route: string): Promise<void> => {
};
const url =
process.env.TELEMETRY_URL && process.env.TELEMETRY_URL !== ''
? process.env.TELEMETRY_URL
: 'https://log.evolution-api.com/telemetry';
telemetryConfig.URL && telemetryConfig.URL !== '' ? telemetryConfig.URL : 'https://log.evolution-api.com/telemetry';
axios
.post(url, telemetry)

View File

@ -1,5 +1,6 @@
import { prismaRepository } from '@api/server.module';
import { CacheService } from '@api/services/cache.service';
import { CacheConf, configService } from '@config/env.config';
import { INSTANCE_DIR } from '@config/path.config';
import { AuthenticationState, BufferJSON, initAuthCreds, WAProto as proto } from 'baileys';
import fs from 'fs/promises';
@ -85,9 +86,10 @@ export default async function useMultiFileAuthStatePrisma(
async function writeData(data: any, key: string): Promise<any> {
const dataString = JSON.stringify(data, BufferJSON.replacer);
const cacheConfig = configService.get<CacheConf>('CACHE');
if (key != 'creds') {
if (process.env.CACHE_REDIS_ENABLED === 'true') {
if (cacheConfig.REDIS.ENABLED) {
return await cache.hSet(sessionId, key, data);
} else {
await fs.writeFile(localFile(key), dataString);
@ -101,9 +103,10 @@ export default async function useMultiFileAuthStatePrisma(
async function readData(key: string): Promise<any> {
try {
let rawData;
const cacheConfig = configService.get<CacheConf>('CACHE');
if (key != 'creds') {
if (process.env.CACHE_REDIS_ENABLED === 'true') {
if (cacheConfig.REDIS.ENABLED) {
return await cache.hGet(sessionId, key);
} else {
if (!(await fileExists(localFile(key)))) return null;
@ -123,8 +126,10 @@ export default async function useMultiFileAuthStatePrisma(
async function removeData(key: string): Promise<any> {
try {
const cacheConfig = configService.get<CacheConf>('CACHE');
if (key != 'creds') {
if (process.env.CACHE_REDIS_ENABLED === 'true') {
if (cacheConfig.REDIS.ENABLED) {
return await cache.hDelete(sessionId, key);
} else {
await fs.unlink(localFile(key));