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.

L'inscription crée à la fois l'utilisateur et un tenant rattaché, dont l'inscrivant devient 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.lyncea.io/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
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.lyncea.io/v1/logs",
            headers={"Authorization": "Bearer lyn_live_xxx"},
        )
    )
)
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.lyncea.io
    headers:
      Authorization: Bearer ${env:LYNCEA_API_KEY}
    compression: gzip

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

Pour un test rapide depuis le terminal :

curl -X POST https://api.lyncea.io/v1/logs \
  -H "Authorization: Bearer lyn_live_xxx" \
  -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": "1717171717000000000",
          "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.lyncea.io et ajoutent eux-mêmes /v1/logs. Un exporter OTLP appelé directement (par exemple OTLPLogExporter) attend l'URL complète https://api.lyncea.io/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 arrivé dans ClickHouse, 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.lyncea.io/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.lyncea.io/api/v1/logs/${LOG_ID}" \
  -H "Authorization: Bearer ${JWT}"

# Live tail via Server-Sent Events
curl -N "https://api.lyncea.io/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.

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

Et ensuite ?

On this page