PulseRadarDocumentation

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 :

bash
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.

Pour envoyer des logs depuis une application sans agent, utilisez l'API d'ingestion directement.

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

bash
# 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
# 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

FonctionFréquenceDétail
Métriques systèmeToutes les 10sCPU, RAM, swap, disk I/O, réseau
HeartbeatToutes les 30sStatut online/offline dans le dashboard
Logs applicatifsTemps réelVia Fluent Bit (tail des fichiers log)
Mise à jour autoAu démarrageVérifie et télécharge les nouvelles versions

Gestion du service

bash
# 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
L'agent enregistre automatiquement le serveur dans votre compte via la clé API. Le SERVER_ID est stocké dans /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

json
{
  "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

bash
# 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

NiveauAlias acceptésCouleur dashboard
criticalfatalRouge vif
errorerr, exceptionRouge
warningwarnOrange
infoBleu
debugtraceGris
Les logs 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

bash
npm install @pulseradar/sdk
js
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

bash
pip install pulseradar
python
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

bash
composer require pulseradar/pulseradar-php
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

bash
gem install pulseradar
ruby
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')
end

Java / Spring Boot

xml
<!-- pom.xml -->
<dependency>
  <groupId>cloud.pulseradar</groupId>
  <artifactId>pulseradar-java</artifactId>
  <version>1.0.0</version>
</dependency>
java
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) :

xml
<!-- 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>
Le paramètre 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.

SourceValeur sourceFonctionnalités
journaldjournaldTous les services systemd (filet universel)
auth.logauthSSH, sudo, PAM — audit sécurité
NginxnginxLogs accès + APM Web + métriques
ApacheapacheLogs accès + APM Web + métriques
MySQLmysqlSlow query log + fingerprinting SQL
PostgreSQLpostgresSlow query log + fingerprinting SQL
PHP-FPMphp-fpmSlow log + saturation + stack trace
Dockerdockerstdout/stderr des conteneurs
RedisredisLogs erreur
HAProxyhaproxyLogs accès
SyslogsyslogLogs système kernel/auth
CustomlibreVia API directe ou Fluent Bit personnalisé

Ajouter une source personnalisée

Dans /etc/fluent-bit/fluent-bit.conf, ajoutez un bloc INPUT et FILTER :

ini
[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étriqueUnitéDescription
cpu_pct%Utilisation CPU (moyenne tous cœurs)
mem_pct%RAM utilisée / RAM totale
swap_pct%Swap utilisé / Swap total
load1floatLoad average 1 minute
disk_read_bpsbytes/sDébit lecture disque
disk_write_bpsbytes/sDébit écriture disque
net_recv_bpsbytes/sBande passante entrante
net_sent_bpsbytes/sBande 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étriqueDescription
req_countNombre de requêtes
err_4xx / err_5xxErreurs client / serveur
avg_ms / p50 / p75 / p99Latence (depuis nginx request_time)
count_fast / ok / slow< 500ms / 500ms–2s / > 2s
bytes_outBande passante sortante
top_ips5 IPs les plus actives par minute

Format de log Nginx requis

Ajoutez ce format dans votre nginx.conf pour activer la latence :

nginx
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é

ScoreCondition
✅ BonTaux erreur < 1% ET P99 < 500ms
⚠️ MoyenTaux erreur < 5% OU P99 < 2s
🔴 DégradéTaux erreur > 5% OU P99 > 2s
En mode agrégé, les logs 2xx/3xx ne sont pas stockés dans ClickHouse, seules les métriques le sont. Les erreurs 4xx/5xx restent visibles dans les logs. Cela réduit significativement votre quota.

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

ini
# /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

ini
# /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 :

ini
slowlog = /var/log/php-fpm-slow.log
request_slowlog_timeout = 2s

Métriques DB APM

MétriqueDescription
fingerprintRequête normalisée (littéraux remplacés par ?)
call_countNombre d'exécutions sur la période
avg_ms / max_msDurée moyenne / maximale
rows_examinedLignes analysées (MySQL uniquement)
rows_sentLignes 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

ÉtatSignificationAction
ActifErreur toujours présenteRésoudre / Ignorer
RésoluMarqué comme corrigéRouvre si réapparaît (Régression)
IgnoréSupprimé de la vue activeRouvre 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)

bash
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

bash
npm install @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http
js
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

bash
pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
python
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)

bash
composer require open-telemetry/sdk open-telemetry/exporter-otlp
ini
# .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 OTLPAffiché comme
service.nameService
span.name / operationOpération
http.method + http.urlRequête HTTP
http.status_codeCode HTTP
db.system + db.statementRequête DB
duration (start→end)Durée en ms
status.code = 2Erreur (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égorieTypeDescription
Logserror_rateTaux d'erreurs > seuil sur N minutes
Logserror_spikePic d'erreurs (anomalie)
APM Webp99_latencyLatence P99 > seuil (ms)
APM Weberror_rate_5xxTaux HTTP 5xx > seuil (%)
APM Webcrash_loopErreurs 5xx répétées sur une route
Infrastructurecpu_highCPU > seuil (%)
Infrastructurememory_highRAM > seuil (%)
Infrastructuredisk_highDisque > seuil (%)
Infrastructureserver_offlineServeur 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éthodeEndpointDescription
POST/v1/logsIngestion logs JSON (single ou batch)
POST/v1/logs/fluent-bitIngestion format Fluent Bit
POST/v1/metricsMétriques serveur (agent)
POST/v1/tracesSpans OTLP JSON
GET/healthStatut du service

Headers optionnels

HeaderDescription
X-Server-IdUUID du serveur (pour lier logs/traces/métriques)
X-Project-IdUUID du projet (si multi-projets)

Limites de débit (rate limiting)

PlanRequêtes / minute
Free60
Starter300
Pro1 000
Business5 000
EnterpriseIllimité

En cas de dépassement : code HTTP 429 avec header Retry-After: 60.

Lecture des logs (API publique)

bash
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
Ne commitez jamais une clé API dans un dépôt Git. Utilisez des variables d'environnement ou un gestionnaire de secrets.

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écanismeRé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éesMax 100 occurrences/heure par fingerprint
Slow logs DBAgré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.

Sur le plan Enterprise, il n'y a pas de limite d'événements. Le flood protection reste actif pour éviter de surcharger ClickHouse.