Documentation PulseRadar
Observabilité complète pour vos serveurs — logs, métriques, APM, error tracking et traces distribuées, hébergé en France.
Démarrage rapide
Connectez votre premier serveur en moins de 2 minutes.
1. Créez une clé API
Rendez-vous dans Dashboard → Clés API, cliquez sur Nouvelle clé. Copiez la clé affichée — elle ne sera plus visible ensuite.
2. Installez l'agent
Sur votre serveur Linux, lancez en root :
curl -sSL https://pulseradar.cloud/install.sh | bash -s -- --api-key <VOTRE_CLÉ>
L'agent détecte automatiquement les services actifs (Nginx, MySQL, PHP-FPM…) et configure Fluent Bit pour les surveiller.
3. Vérifiez dans le dashboard
Votre serveur apparaît dans Dashboard → Serveurs avec un point vert dans les 30 secondes. Les logs et métriques arrivent en temps réel.
Agent & installation
L'agent PulseRadar est un binaire Go léger (~10 Mo) qui collecte les métriques système et orchestre Fluent Bit pour la collecte des logs applicatifs.
Installation Linux
# Installation automatique (recommandée) curl -sSL https://pulseradar.cloud/install.sh | bash -s -- --api-key <CLÉ> # Options disponibles --api-key <CLÉ> Clé API (obligatoire) --server-name <NOM> Nom affiché dans le dashboard (défaut: hostname)
Installation Windows
# PowerShell en administrateur
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
iex (New-Object Net.WebClient).DownloadString('https://pulseradar.cloud/install.ps1')Ce que fait l'agent
| Fonction | Fréquence | Détail |
|---|---|---|
| Métriques système | Toutes les 10s | CPU, RAM, swap, disk I/O, réseau |
| Heartbeat | Toutes les 30s | Statut online/offline dans le dashboard |
| Logs applicatifs | Temps réel | Via Fluent Bit (tail des fichiers log) |
| Mise à jour auto | Au démarrage | Vérifie et télécharge les nouvelles versions |
Gestion du service
# Statut sudo systemctl status pulseradar-agent # Redémarrage sudo systemctl restart pulseradar-agent # Logs de l'agent sudo journalctl -u pulseradar-agent -f
Fichiers de configuration
/etc/pulseradar/agent.conf Configuration de l'agent /etc/fluent-bit/fluent-bit.conf Configuration Fluent Bit (auto-généré) /etc/fluent-bit/parsers.conf Parseurs de logs
/etc/pulseradar/agent.conf.Ingestion de logs
PulseRadar accepte les logs via HTTP JSON. Chaque événement est normalisé et stocké dans ClickHouse.
Format d'un événement
{
"level": "error", // fatal|critical|error|warning|info|debug
"message": "Connection refused to database",
"source": "mon-app", // identifiant libre de la source
"timestamp": "2026-03-30T14:00:00Z", // optionnel, défaut: maintenant
"host": "web01", // optionnel
"fields": { // données structurées libres
"user_id": "42",
"duration_ms": "320"
}
}Envoyer un log
# Log unique
curl -X POST https://ingest.pulseradar.cloud/v1/logs \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{"level":"error","message":"Oops","source":"mon-app"}'
# Batch (jusqu'à 500 événements par requête)
curl -X POST https://ingest.pulseradar.cloud/v1/logs \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '[{"level":"info","message":"Start"},{"level":"error","message":"Fail"}]'Niveaux de log
| Niveau | Alias acceptés | Couleur dashboard |
|---|---|---|
| critical | fatal | Rouge vif |
| error | err, exception | Rouge |
| warning | warn | Orange |
| info | — | Bleu |
| debug | trace | Gris |
info et debug sont filtrés par défaut pour économiser le quota. Activez Conserver les logs info dans les paramètres du projet pour les stocker.SDKs officiels
Envoyez des logs directement depuis votre code applicatif, sans agent.
Node.js
npm install @pulseradar/sdk
const PulseRadar = require('@pulseradar/sdk')
const logger = new PulseRadar({
apiKey: process.env.PULSERADAR_API_KEY,
serverId: process.env.PULSERADAR_SERVER_ID, // optionnel
source: 'mon-app',
})
logger.info('Démarrage du serveur', { port: '3000' })
logger.error('Erreur DB', { query: 'SELECT ...' })
// Capture automatique d'exceptions
try {
riskyOperation()
} catch (err) {
logger.captureException(err, { context: 'riskyOperation' })
}Python
pip install pulseradar
from pulseradar import PulseRadar
import os
logger = PulseRadar(
api_key=os.environ["PULSERADAR_API_KEY"],
server_id=os.environ.get("PULSERADAR_SERVER_ID"), # optionnel
source="mon-app",
)
logger.info("Démarrage", version="1.0")
logger.error("Erreur DB", query="SELECT ...")
# Capture d'exception
try:
risky()
except Exception:
logger.capture_exception()PHP
composer require pulseradar/pulseradar-php
use PulseRadarPulseRadar;
$logger = new PulseRadar([
'api_key' => getenv('PULSERADAR_API_KEY'),
'server_id' => getenv('PULSERADAR_SERVER_ID'), // optionnel
'source' => 'mon-app',
'async' => true, // batch + flush au __destruct
]);
$logger->info('Démarrage');
$logger->error('Erreur DB', ['query' => 'SELECT ...']);
// Capture d'exception
try {
risky();
} catch (Throwable $e) {
$logger->captureException($e);
}Ruby
gem install pulseradar
require 'pulseradar'
logger = PulseRadar::Client.new(
api_key: ENV['PULSERADAR_API_KEY'],
server_id: ENV['PULSERADAR_SERVER_ID'], # optionnel
source: 'mon-app',
)
logger.info('Démarrage', port: '3000')
logger.error('Erreur DB', query: 'SELECT ...')
# Capture d'exception
begin
risky_operation
rescue => e
logger.capture_exception(e, context: 'risky')
endJava / Spring Boot
<!-- pom.xml --> <dependency> <groupId>cloud.pulseradar</groupId> <artifactId>pulseradar-java</artifactId> <version>1.0.0</version> </dependency>
PulseRadar logger = new PulseRadar.Builder()
.apiKey(System.getenv("PULSERADAR_API_KEY"))
.source("my-app")
.build();
logger.info("Server started", Map.of("port", "8080"));
logger.error("DB connection failed");
try { riskyOperation(); }
catch (Exception e) { logger.captureException(e); }Ou via Logback appender (zéro code) :
<!-- logback.xml -->
<appender name="PULSERADAR" class="cloud.pulseradar.PulseRadarLogbackAppender">
<apiKey>${PULSERADAR_API_KEY}</apiKey>
<source>my-app</source>
</appender>
<root level="WARN">
<appender-ref ref="PULSERADAR" />
</root>server_id permet de lier les logs applicatifs au serveur dans le dashboard. Récupérez-le depuis /etc/pulseradar/agent.conf ou via l'API GET /api/servers.Sources supportées
L'agent configure automatiquement Fluent Bit pour les services détectés.
| Source | Valeur source | Fonctionnalités |
|---|---|---|
| journald | journald | Tous les services systemd (filet universel) |
| auth.log | auth | SSH, sudo, PAM — audit sécurité |
| Nginx | nginx | Logs accès + APM Web + métriques |
| Apache | apache | Logs accès + APM Web + métriques |
| MySQL | mysql | Slow query log + fingerprinting SQL |
| PostgreSQL | postgres | Slow query log + fingerprinting SQL |
| PHP-FPM | php-fpm | Slow log + saturation + stack trace |
| Docker | docker | stdout/stderr des conteneurs |
| Redis | redis | Logs erreur |
| HAProxy | haproxy | Logs accès |
| Syslog | syslog | Logs système kernel/auth |
| Custom | libre | Via API directe ou Fluent Bit personnalisé |
Ajouter une source personnalisée
Dans /etc/fluent-bit/fluent-bit.conf, ajoutez un bloc INPUT et FILTER :
[INPUT]
Name tail
Path /var/log/mon-app/*.log
Tag mon-app
[FILTER]
Name record_modifier
Match mon-app
Record source mon-app
Record server_id ${SERVER_ID}
Record project_id ${PROJECT_ID}
[OUTPUT]
Name http
Match mon-app
Host ingest.pulseradar.cloud
Port 443
URI /v1/logs/fluent-bit
Format json
Header Authorization Bearer ${API_KEY}Métriques serveur
L'agent collecte les métriques système toutes les 10 secondes et les pousse vers l'API.
Métriques collectées
| Métrique | Unité | Description |
|---|---|---|
| cpu_pct | % | Utilisation CPU (moyenne tous cœurs) |
| mem_pct | % | RAM utilisée / RAM totale |
| swap_pct | % | Swap utilisé / Swap total |
| load1 | float | Load average 1 minute |
| disk_read_bps | bytes/s | Débit lecture disque |
| disk_write_bps | bytes/s | Débit écriture disque |
| net_recv_bps | bytes/s | Bande passante entrante |
| net_sent_bps | bytes/s | Bande passante sortante |
| disk_used_pct | % | Espace disque utilisé |
Visualisation
Accédez aux graphes dans Serveur → Système. Fenêtres disponibles : 1h, 3h, 12h, 24h avec points à la minute.
Vue Corrélation
La page Serveur → Corrélation superpose les métriques système (CPU, RAM) avec les métriques HTTP (req/s, latence P99) pour identifier les saturations liées au trafic.
APM Web (Nginx / Apache)
PulseRadar agrège automatiquement les access logs Nginx et Apache en métriques de performance à la minute, sans modifier votre configuration de logs.
Métriques APM calculées
| Métrique | Description |
|---|---|
| req_count | Nombre de requêtes |
| err_4xx / err_5xx | Erreurs client / serveur |
| avg_ms / p50 / p75 / p99 | Latence (depuis nginx request_time) |
| count_fast / ok / slow | < 500ms / 500ms–2s / > 2s |
| bytes_out | Bande passante sortante |
| top_ips | 5 IPs les plus actives par minute |
Format de log Nginx requis
Ajoutez ce format dans votre nginx.conf pour activer la latence :
log_format pulseradar '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time';
access_log /var/log/nginx/access.log pulseradar;Score de santé
| Score | Condition |
|---|---|
| ✅ Bon | Taux erreur < 1% ET P99 < 500ms |
| ⚠️ Moyen | Taux erreur < 5% OU P99 < 2s |
| 🔴 Dégradé | Taux erreur > 5% OU P99 > 2s |
DB APM (MySQL / PostgreSQL / PHP-FPM)
PulseRadar parse les slow logs de base de données, fingerprinte les requêtes SQL et agrège les statistiques par minute.
MySQL — configuration
# /etc/mysql/mysql.conf.d/mysqld.cnf slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 0.5 # requêtes > 500ms log_queries_not_using_indexes = 1
PostgreSQL — configuration
# /etc/postgresql/*/main/postgresql.conf log_min_duration_statement = 500 # ms — requêtes > 500ms log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
PHP-FPM — configuration
L'agent ajoute automatiquement ces lignes dans le pool PHP-FPM :
slowlog = /var/log/php-fpm-slow.log request_slowlog_timeout = 2s
Métriques DB APM
| Métrique | Description |
|---|---|
| fingerprint | Requête normalisée (littéraux remplacés par ?) |
| call_count | Nombre d'exécutions sur la période |
| avg_ms / max_ms | Durée moyenne / maximale |
| rows_examined | Lignes analysées (MySQL uniquement) |
| rows_sent | Lignes retournées (MySQL uniquement) |
Fingerprinting SQL
Les requêtes sont normalisées pour regrouper les variantes identiques :
Avant : SELECT * FROM users WHERE id = 42 AND status = 'active' Après : SELECT * FROM users WHERE id = ? AND status = ? Avant : SELECT * FROM orders WHERE id IN (1, 2, 3, 4, 5) Après : SELECT * FROM orders WHERE id IN (?)
Error Tracking
PulseRadar regroupe automatiquement les erreurs identiques en groupes d'erreurs, avec compteur de fréquence, détection de régression et stack trace colorée.
Fonctionnement
Chaque log error ou critical est normalisé (UUIDs, IPs, nombres remplacés) puis hashé. Les occurrences du même hash incrémentent le même groupe.
États d'un groupe
| État | Signification | Action |
|---|---|---|
| Actif | Erreur toujours présente | Résoudre / Ignorer |
| Résolu | Marqué comme corrigé | Rouvre si réapparaît (Régression) |
| Ignoré | Supprimé de la vue active | Rouvre si réapparaît (Régression) |
| Régression 🔴 | Réapparu après résolution/ignoré | Traiter en priorité |
Protection anti-flood
Une même erreur génère au maximum 100 événements facturés par heure. Au-delà, seul le compteur du groupe est mis à jour — l'événement n'est pas stocké dans ClickHouse et n'est pas comptabilisé dans votre quota mensuel.
Accès
Les groupes d'erreurs sont visibles à deux niveaux :
- Serveur → Erreurs — erreurs de ce serveur spécifique
- Projet → Erreurs — toutes les erreurs du compte
Traces distribuées (OTLP)
PulseRadar accepte les spans OpenTelemetry au format OTLP/HTTP JSONet les visualise en waterfall.
Endpoint
POST https://ingest.pulseradar.cloud/v1/traces Authorization: Bearer <API_KEY> X-Server-Id: <SERVER_ID> Content-Type: application/json
Configuration par langage
Variables d'environnement (universel)
export OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.pulseradar.cloud export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <API_KEY>,X-Server-Id=<SERVER_ID>" export OTEL_EXPORTER_OTLP_PROTOCOL=http/json export OTEL_SERVICE_NAME=mon-app
Node.js
npm install @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http
const { NodeSDK } = require('@opentelemetry/sdk-node')
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http')
new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: 'https://ingest.pulseradar.cloud/v1/traces',
headers: {
'Authorization': 'Bearer <API_KEY>',
'X-Server-Id': '<SERVER_ID>',
},
}),
serviceName: 'mon-app',
}).start()Python
pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
endpoint="https://ingest.pulseradar.cloud/v1/traces",
headers={"Authorization": "Bearer <API_KEY>", "X-Server-Id": "<SERVER_ID>"}
)))PHP (Laravel)
composer require open-telemetry/sdk open-telemetry/exporter-otlp
# .env OTEL_PHP_AUTOLOAD_ENABLED=true OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.pulseradar.cloud OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <API_KEY>,X-Server-Id=<SERVER_ID>"
Données collectées par span
| Attribut OTLP | Affiché comme |
|---|---|
| service.name | Service |
| span.name / operation | Opération |
| http.method + http.url | Requête HTTP |
| http.status_code | Code HTTP |
| db.system + db.statement | Requête DB |
| duration (start→end) | Durée en ms |
| status.code = 2 | Erreur (rouge) |
Rétention des traces : 7 jours.
Alertes
Configurez des règles d'alerte sur vos métriques. Les notifications sont envoyées par email dès qu'un seuil est dépassé, avec cooldown configurable pour éviter le spam.
Types de règles disponibles
| Catégorie | Type | Description |
|---|---|---|
| Logs | error_rate | Taux d'erreurs > seuil sur N minutes |
| Logs | error_spike | Pic d'erreurs (anomalie) |
| APM Web | p99_latency | Latence P99 > seuil (ms) |
| APM Web | error_rate_5xx | Taux HTTP 5xx > seuil (%) |
| APM Web | crash_loop | Erreurs 5xx répétées sur une route |
| Infrastructure | cpu_high | CPU > seuil (%) |
| Infrastructure | memory_high | RAM > seuil (%) |
| Infrastructure | disk_high | Disque > seuil (%) |
| Infrastructure | server_offline | Serveur hors ligne |
Canaux de notification
Actuellement : Email. Slack et webhook sont prévus.
Suggestions automatiques
PulseRadar analyse vos logs et suggère des règles d'alerte pertinentes dans Projet → Alertes → Suggestions. Ajoutez-les en un clic.
Cooldown
Le cooldown (défaut : 30 min) empêche le re-déclenchement d'une alerte pendant cette durée après la première notification.
API d'ingestion
Authentification
Authorization: Bearer <API_KEY>
Endpoints
| Méthode | Endpoint | Description |
|---|---|---|
| POST | /v1/logs | Ingestion logs JSON (single ou batch) |
| POST | /v1/logs/fluent-bit | Ingestion format Fluent Bit |
| POST | /v1/metrics | Métriques serveur (agent) |
| POST | /v1/traces | Spans OTLP JSON |
| GET | /health | Statut du service |
Headers optionnels
| Header | Description |
|---|---|
| X-Server-Id | UUID du serveur (pour lier logs/traces/métriques) |
| X-Project-Id | UUID du projet (si multi-projets) |
Limites de débit (rate limiting)
| Plan | Requêtes / minute |
|---|---|
| Free | 60 |
| Starter | 300 |
| Pro | 1 000 |
| Business | 5 000 |
| Enterprise | Illimité |
En cas de dépassement : code HTTP 429 avec header Retry-After: 60.
Lecture des logs (API publique)
GET /v1/logs?project_id=<ID>&level=error&limit=100 Authorization: Bearer <API_KEY>
Clés API
Les clés API sont au niveau du compte (pas du projet). Une seule clé peut ingérer des données pour tous vos projets et serveurs.
Créer une clé
Dashboard → Clés API → Nouvelle clé. Donnez-lui un nom explicite (ex : prod-server-01, laravel-app).
Sécurité
- La clé n'est affichée qu'une seule fois à la création
- Stockée en base sous forme de hash SHA-256
- Révocable instantanément depuis le dashboard
Plans & quotas
Événements facturés vs reçus
Reçus = tous les événements qui arrivent sur l'API d'ingestion.
Facturés = événements effectivement écrits dans ClickHouse (après filtrage et flood protection).
Ce qui réduit les événements facturés
| Mécanisme | Réduction |
|---|---|
| Filtrage info/debug (si désactivé) | Jusqu'à 90% selon vos sources |
| Mode agrégé Nginx/Apache (2xx/3xx) | Logs remplacés par métriques |
| Flood protection erreurs répétées | Max 100 occurrences/heure par fingerprint |
| Slow logs DB | Agrégés en métriques, non stockés comme logs |
Compteur mensuel
Le compteur se réinitialise le 1er de chaque mois à minuit UTC. Il est visible en haut du dashboard avec une barre de progression.