Lyncea

Premiers pas

Créer un projet, générer une clé d'API et envoyer un premier log en moins de cinq minutes.

Ce guide couvre le parcours minimal pour faire arriver votre premier log dans Lyncea. Toutes les étapes d'administration se font depuis la console ; les détails du contrat HTTP (payload, codes d'erreur, retry, limites) vivent dans la référence ingestion, et chaque endpoint dans la référence API.

L'inscription publique est ouverte : créer un compte provisionne aussi un nouveau tenant dont vous êtes propriétaire (owner).

Si vous avez été invité à rejoindre un tenant existant, connectez-vous puis ouvrez vos invitations en attente pour les accepter. L'envoi d'email d'invitation n'est pas encore implémenté (bientôt disponible) — l'invitation doit être communiquée hors-bande pour le moment.

Créer un compte (ou se connecter)

Depuis la console : s'inscrire ou

se connecter.

Deux voies au choix :

  • Email + mot de passe : l'inscription pose un mot de passe ≥ 12 caractères (NIST SP 800-63B), hashé en argon2id côté serveur.
  • Continuer avec Google : OAuth 2.0 + PKCE. Le bouton apparaît sur les pages /login et /register. À la première connexion via Google, un mini-wizard vous demande le nom et l'identifiant URL de votre organisation, puis vous redirige sur votre tableau de bord. Aux connexions suivantes, vous arrivez directement sur le dashboard. L'email Google doit être vérifié côté Google.

Si vous avez déjà un compte avec mot de passe, cliquer sur « Continuer avec Google » lie automatiquement votre compte à votre identité Google (sous réserve que l'email Google soit vérifié) — pas de compte doublon créé.

Que ce soit par mot de passe ou Google, l'inscription crée à la fois l'utilisateur et un tenant rattaché dont vous devenez owner. Une fois authentifié, le serveur émet un JWT EdDSA/Ed25519 de 15 minutes accompagné d'un cookie de refresh à rotation 30 jours. Si vous appartenez à plusieurs tenants, sélectionnez celui sur lequel travailler — le JWT est scopé à un seul tenant actif à la fois.

Référence API : POST /api/v1/auth/register, POST /api/v1/auth/login, POST /api/v1/auth/switch-tenant.

Créer un projet

Depuis la console : ouvrez le formulaire de création de projet. Il pré-remplit le slug (URL-safe, unique dans le tenant) et l'allowlist d'environnements OTel acceptés (dev, staging, prod par défaut). Consultez Environnements de projet pour comprendre comment cette allowlist fonctionne et comment taguer vos logs avec le bon environnement.

Un projet représente le périmètre auquel s'appliquent une rétention, un quota d'ingestion et un jeu de clés d'API. La granularité courante est un projet par périmètre opérationnel (typiquement par produit ou par environnement majeur), avec service.name qui distingue les services à l'intérieur. Multiplier les projets n'a de sens que si vous voulez des rétentions, quotas ou clés séparés.

Référence API : POST /api/v1/projects.

Générer une clé d'API

Depuis la console : ouvrez la liste des projets, sélectionnez le vôtre, puis l'onglet « API keys » et cliquez sur « Créer une clé » avec le scope write:logs.

Le secret en clair n'est affiché qu'une seule fois à la création — Lyncea ne stocke qu'un hash. Conservez-le dans un gestionnaire de secrets (Vault, AWS Secrets Manager, Doppler, etc.). Le secret retourné a la forme lyn_live_xxx (déploiement Lyncea de production) ou lyn_test_xxx (sandbox). Ce préfixe est destiné aux outils de détection de secrets — il ne restreint pas pour quels environnements dev / staging / prod la clé peut envoyer des logs. Voir Environnements de projet.

Référence API : POST /api/v1/projects/{projectId}/api-keys.

Envoyer un log via OTLP/HTTP

L'ingestion est purement programmatique : pas de formulaire d'upload, vous configurez votre logger applicatif existant (Pino, Python logging, etc.) pour exporter en OTLP/HTTP vers https://api.monitoring.crahe-arthur.com/v1/logs — ou vous déployez un OTel Collector si votre stack n'a pas de bridge SDK. Authentification par clé d'API (header Authorization: Bearer lyn_live_xxx), body protobuf (par défaut côté SDK) ou JSON.

pnpm add pino pino-opentelemetry-transport
import pino from 'pino';

export const logger = pino({
  level: 'info',
  transport: {
    target: 'pino-opentelemetry-transport',
    options: {
      logRecordProcessorOptions: {
        recordProcessorType: 'batch',
        exporterOptions: {
          protocol: 'http/json',
          url: 'https://api.monitoring.crahe-arthur.com/v1/logs',
          headers: { Authorization: `Bearer ${process.env.LYNCEA_API_KEY}` },
        },
      },
      resourceAttributes: {
        'service.name': 'checkout-api',
        'deployment.environment': 'prod',
      },
    },
  },
});

logger.info({ userId: 42 }, 'user logged in');
pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
import logging
import os
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter

provider = LoggerProvider(resource=Resource.create({
    "service.name": "checkout-api",
    "deployment.environment": "prod",
}))
provider.add_log_record_processor(
    BatchLogRecordProcessor(
        OTLPLogExporter(
            endpoint="https://api.monitoring.crahe-arthur.com/v1/logs",
            headers={"Authorization": f"Bearer {os.environ['LYNCEA_API_KEY']}"},
        )
    )
)
logging.getLogger().addHandler(LoggingHandler(logger_provider=provider))
logging.getLogger().setLevel(logging.INFO)

logging.info("user logged in")

À utiliser quand votre stack n'a pas de bridge SDK (Java/Logback, Go, Ruby, .NET…) ou quand vous avez déjà un Collector qui collecte logs/traces/metrics pour d'autres backends.

exporters:
  otlphttp/lyncea:
    endpoint: https://api.monitoring.crahe-arthur.com
    headers:
      Authorization: Bearer ${env:LYNCEA_API_KEY}
    compression: gzip

service:
  pipelines:
    logs:
      exporters: [otlphttp/lyncea]

Pour un test rapide depuis le terminal :

# Timestamp « maintenant » — un log plus ancien sort de la fenêtre par défaut
TS="$(date +%s)000000000"

curl -X POST https://api.monitoring.crahe-arthur.com/v1/logs \
  -H "Authorization: Bearer ${LYNCEA_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "resourceLogs": [{
      "resource": { "attributes": [
        { "key": "service.name", "value": { "stringValue": "checkout-api" } },
        { "key": "deployment.environment", "value": { "stringValue": "prod" } }
      ]},
      "scopeLogs": [{
        "scope": { "name": "lyncea-quickstart" },
        "logRecords": [{
          "timeUnixNano": "'"${TS}"'",
          "severityNumber": 9,
          "severityText": "INFO",
          "body": { "stringValue": "user logged in" }
        }]
      }]
    }]
  }'

Une réponse 200 OK confirme la prise en charge — Lyncea applique un contrat full-success (pas de rejet par enregistrement remonté synchroniquement).

À retenir :

  • OTel Collector et bridges SDK pointent vers la racine https://api.monitoring.crahe-arthur.com et ajoutent eux-mêmes /v1/logs. Un exporter OTLP appelé directement (par exemple OTLPLogExporter) attend l'URL complète https://api.monitoring.crahe-arthur.com/v1/logs.
  • L'API de recherche est disponible — voir l'étape « Lire vos logs » ci-dessous. Un appel GET /api/v1/logs confirme aussi côté lecture que l'intégration fonctionne.

Pour le détail du contrat HTTP (payload OTLP/JSON complet, codes d'erreur, sévérité OTel, retry/backoff, limites), voir la référence ingestion.

Référence API : POST /v1/logs.

Lire vos logs

Une fois qu'au moins un log est ingéré, vous pouvez interroger la fenêtre de rétention via l'API de lecture. Le tenant actif provient de votre JWT — ne jamais passer un tenantId en query parameter, la passerelle refusera la requête.

# Les dernières 24 h, filtrées par sévérité et projet
curl -G "https://api.monitoring.crahe-arthur.com/api/v1/logs" \
  -H "Authorization: Bearer ${JWT}" \
  --data-urlencode "severities=ERROR,FATAL" \
  --data-urlencode "projectIds=${PROJECT_ID}" \
  --data-urlencode "limit=100"
// 200 OK
{
  "data": [ { "id": "…", "timestamp": "…", "severityText": "ERROR", "body": "…",  } ],
  "nextCursor": "eyJ0aW1lc3RhbXAiOiIyMDI2LTA1LTEwVDIz…",
  "totalScanned": 1234
}

La pagination est keyset : passer le nextCursor reçu tel quel via ?cursor=… à l'appel suivant. Le curseur est opaque — ne pas le décoder.

# Un seul log par id (404 si l'id n'appartient pas à votre tenant)
curl "https://api.monitoring.crahe-arthur.com/api/v1/logs/${LOG_ID}" \
  -H "Authorization: Bearer ${JWT}"

# Live tail via Server-Sent Events
curl -N "https://api.monitoring.crahe-arthur.com/api/v1/logs/stream?projectIds=${PROJECT_ID}" \
  -H "Authorization: Bearer ${JWT}"

Throttling plan-aware : chaque tenant a un budget de requêtes par minute et un max_execution_time ClickHouse. Une erreur query_rate_limited (429) suggère de ralentir ; un query_timeout (504) suggère de réduire la fenêtre de recherche.

Deux endpoints supplémentaires disponibles :

  • GET /api/v1/logs/facets?projectId=<uuid> — découvrez les clés d'attributs observées dans un projet (fenêtre 1h, 24h ou 7d). Utile pour pré-remplir des filtres ou suggérer des valeurs dans une UI de recherche.
  • GET /api/v1/dashboard/severity-timeline — série temporelle par sévérité, utile pour construire un graphique en aires empilées sur les dernières 24 h.

Référence API : GET /api/v1/logs, GET /api/v1/logs/{logId}, GET /api/v1/logs/stream, GET /api/v1/logs/facets, GET /api/v1/dashboard/summary, GET /api/v1/dashboard/severity-timeline.

Et ensuite ?

On this page