pyloggerx 1.0.0
Modern, colorful and simple logging for Python
License: MIT
Requires Python: >=3.7
Keywords: logging, colorful, json, rotation, modern

# PyLoggerX

[![PyPI version](https://badge.fury.io/py/pyloggerx.svg)](https://badge.fury.io/py/pyloggerx)
[![Python](https://img.shields.io/pypi/pyversions/pyloggerx.svg)](https://pypi.org/project/pyloggerx/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Bibliothèque de logging moderne, colorée et riche en fonctionnalités pour Python avec logging structuré, tracking de performance et logging distant.**

PyLoggerX est un wrapper puissant qui étend le module logging standard de Python avec une sortie console élégante, du logging JSON structuré, une rotation automatique des logs, et du logging distant vers des services populaires comme Elasticsearch, Grafana Loki, Sentry, Datadog, et plus encore. Conçu pour les workflows DevOps modernes et les applications cloud-native.

---

## Table des Matières

- [Fonctionnalités](#fonctionnalités)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Intégration DevOps](#intégration-devops)
  - [Docker & Kubernetes](#docker--kubernetes)
  - [Pipelines CI/CD](#pipelines-cicd)
  - [Stack d'Observabilité](#stack-dobservabilité)
  - [Infrastructure as Code](#infrastructure-as-code)
- [Guide d'Utilisation Complet](#guide-dutilisation-complet)
- [Logging Distant](#logging-distant-v30)
- [Fonctionnalités Avancées](#fonctionnalités-avancées)
- [Référence de Configuration](#référence-de-configuration)
- [Configuration Avancée](#configuration-avancée)
  - [Chargement depuis Fichiers](#chargement-depuis-fichiers)
  - [Configuration par Variables d'Environnement](#configuration-par-variables-denvironnement)
  - [Configuration Multi-Sources](#configuration-multi-sources)
  - [Validation de Configuration](#validation-de-configuration)
  - [Configurations Prédéfinies](#configurations-prédéfinies)
- [Monitoring et Métriques](#monitoring-et-métriques)
  - [Collecteur de Métriques](#collecteur-de-métriques)
  - [Gestionnaire d'Alertes](#gestionnaire-dalertes)
  - [Monitoring de Santé](#monitoring-de-santé)
  - [Dashboard Console](#dashboard-console)
- [Intégrations Monitoring](#intégrations-monitoring)
  - [Prometheus](#intégration-prometheus)
  - [Grafana](#intégration-grafana)
  - [Custom Metrics](#métriques-personnalisées)
- [Exemples Complets](#exemples-complets)
- [Référence Config](#référence-config)
- [Exemples Réels](#exemples-réels)
- [Meilleures Pratiques](#meilleures-pratiques)
- [Référence API](#référence-api)
- [Tests](#tests)
- [Dépannage](#dépannage)
- [Contribution](#contribution)
- [Licence](#licence)

---

## Fonctionnalités

### Fonctionnalités Core
- **Sortie Console Colorée** - Logs console élégants avec indicateurs emoji
- **Logging JSON Structuré** - Export de logs en format JSON structuré
- **Rotation Automatique** - Rotation basée sur la taille et le temps
- **Tracking de Performance** - Chronométrage et monitoring intégrés
- **Zéro Configuration** - Fonctionne immédiatement avec des valeurs par défaut sensées
- **Hautement Configurable** - Options de personnalisation étendues
- **Enrichissement de Contexte** - Injection de métadonnées automatique
- **Formats de Sortie Multiples** - Console, JSON, texte

### Fonctionnalités DevOps & Cloud-Native
- **Compatible Conteneurs** - Logging structuré adapté aux conteneurs
- **Compatible Kubernetes** - Sortie JSON pour les log collectors
- **Intégration CI/CD** - Support pour GitHub Actions, GitLab CI, Jenkins
- **Support Correlation ID** - Pour le tracing distribué
- **Logging Health Check** - Monitoring de santé des services
- **Format Prêt pour les Métriques** - Sortie compatible avec Prometheus
- **Configuration par Environnement** - Adaptation automatique selon l'environnement
- **Conforme 12-Factor App** - Suit les meilleures pratiques

### Fonctionnalités Avancées
- **Logging Distant** - Export vers Elasticsearch, Loki, Sentry, Datadog
- **Échantillonnage de Logs** - Gestion efficace des scénarios à haut volume
- **Limitation de Débit** - Prévention de l'inondation de logs
- **Filtrage Avancé** - Filtres par niveau, pattern ou logique personnalisée
- **Traitement par Batch** - Batching efficace pour les exports distants
- **Support Webhook** - Envoi de logs vers des endpoints personnalisés
- **Intégration Slack** - Alertes critiques dans Slack
- **Processing Asynchrone** - Non-bloquant pour les performances

---

## Installation

### Installation Basique

```bash
pip install pyloggerx
```

### Dans requirements.txt

```text
pyloggerx>=1.0.0
```

### Dans pyproject.toml (Poetry)

```toml
[tool.poetry.dependencies]
pyloggerx = "^1.0.0"
```

### Avec Support de Logging Distant

```bash
# Pour Elasticsearch
pip install pyloggerx[elasticsearch]

# Pour Sentry
pip install pyloggerx[sentry]

# Pour tous les services distants
pip install pyloggerx[all]
```

### Installation Développement

```bash
git clone https://github.com/yourusername/pyloggerx.git
cd pyloggerx
pip install -e ".[dev]"
```

---

## Quick Start

### Usage Basique

```python
from pyloggerx import log

# Logging simple
log.info("Application démarrée")
log.warning("Ceci est un avertissement")
log.error("Une erreur s'est produite")
log.debug("Informations de debug")

# Avec contexte
log.info("Utilisateur connecté", user_id=123, ip="192.168.1.1")
```

### Instance de Logger Personnalisée

```python
from pyloggerx import PyLoggerX

logger = PyLoggerX(
    name="myapp",
    level="INFO",
    console=True,
    colors=True,
    json_file="logs/app.json",
    text_file="logs/app.log"
)

logger.info("Logger personnalisé initialisé")
```

### Logger avec Export Distant

```python
logger = PyLoggerX(
    name="production-app",
    console=True,
    json_file="logs/app.json",
    
    # Export vers Elasticsearch
    elasticsearch_url="http://localhost:9200",
    elasticsearch_index="myapp-logs",
    
    # Alertes Sentry pour les erreurs
    sentry_dsn="https://xxx@sentry.io/xxx",
    
    # Notifications Slack pour les critiques
    slack_webhook="https://hooks.slack.com/services/xxx"
)

logger.info("Application démarrée")
logger.error("Erreur critique")  # Envoyé à tous les services
```

---

## Intégration DevOps

### Docker & Kubernetes

#### Application Conteneurisée

```python
# app.py
import os
from pyloggerx import PyLoggerX

# Configuration pour environnement conteneur
logger = PyLoggerX(
    name=os.getenv("APP_NAME", "myapp"),
    level=os.getenv("LOG_LEVEL", "INFO"),
    console=True,  # Logs vers stdout pour les collecteurs
    colors=False,  # Désactiver les couleurs dans les conteneurs
    json_file=None,  # Utiliser stdout uniquement
    include_caller=True,
    enrichment_data={
        "environment": os.getenv("ENVIRONMENT", "production"),
        "pod_name": os.getenv("POD_NAME", "unknown"),
        "namespace": os.getenv("NAMESPACE", "default"),
        "version": os.getenv("APP_VERSION", "1.0.0"),
        "region": os.getenv("AWS_REGION", "us-east-1")
    }
)

logger.info("Application démarrée", port=8080)
```

#### Dockerfile Optimisé

```dockerfile
FROM python:3.11-slim

WORKDIR /app

# Installation des dépendances
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Variables d'environnement pour logging
ENV LOG_LEVEL=INFO \
    APP_NAME=myapp \
    ENVIRONMENT=production \
    PYTHONUNBUFFERED=1

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD python -c "import requests; requests.get('http://localhost:8080/health')"

# Exécution
CMD ["python", "app.py"]
```

#### Déploiement Kubernetes avec Logging

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: production
  labels:
    app: myapp
    version: v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
        version: v1
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8080"
    spec:
      containers:
      - name: myapp
        image: myapp:1.0.0
        env:
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: log-level
        - name: APP_NAME
          value: "myapp"
        - name: ENVIRONMENT
          value: "production"
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: APP_VERSION
          value: "1.0.0"
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        ports:
        - containerPort: 8080
          name: http
        # Probes avec logging
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
data:
  log-level: "INFO"
```

#### Sortie JSON pour Kubernetes (Fluentd/Filebeat)

```python
# Pour les collecteurs de logs Kubernetes
logger = PyLoggerX(
    name="k8s-app",
    console=True,
    colors=False,  # IMPORTANT: désactiver pour les collecteurs
    format_string='{"timestamp":"%(asctime)s","level":"%(levelname)s","logger":"%(name)s","message":"%(message)s"}',
    enrichment_data={
        "cluster": os.getenv("CLUSTER_NAME", "prod-cluster"),
        "pod_ip": os.getenv("POD_IP", "unknown")
    }
)

logger.info("Requête traitée", 
           duration_ms=123, 
           status_code=200,
           endpoint="/api/users")
```

### Pipelines CI/CD

#### GitHub Actions

```yaml
# .github/workflows/test-and-deploy.yml
name: Test, Build & Deploy

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  LOG_LEVEL: DEBUG
  APP_NAME: myapp

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.9', '3.10', '3.11']
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      
      - name: Cache dependencies
        uses: actions/cache@v3
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
      
      - name: Install dependencies
        run: |
          pip install -e .
          pip install pytest pytest-cov pytest-xdist
      
      - name: Run tests with logging
        run: |
          python -c "
          from pyloggerx import PyLoggerX
          import os
          
          logger = PyLoggerX(
              name='ci-tests',
              level='DEBUG',
              console=True,
              json_file='test-results/logs.json',
              enrichment_data={
                  'pipeline': 'github-actions',
                  'commit': '${{ github.sha }}',
                  'branch': '${{ github.ref_name }}',
                  'actor': '${{ github.actor }}',
                  'run_id': '${{ github.run_id }}',
                  'python_version': '${{ matrix.python-version }}'
              }
          )
          logger.info('Démarrage des tests CI')
          "
          pytest -n auto --cov=pyloggerx --cov-report=xml --cov-report=html
      
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage.xml
      
      - name: Upload test logs
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: test-logs-${{ matrix.python-version }}
          path: test-results/
          retention-days: 30
  
  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      
      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            myapp:latest
            myapp:${{ github.sha }}
          cache-from: type=registry,ref=myapp:buildcache
          cache-to: type=registry,ref=myapp:buildcache,mode=max
  
  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to Kubernetes
        run: |
          echo "${{ secrets.KUBECONFIG }}" > kubeconfig
          export KUBECONFIG=kubeconfig
          kubectl set image deployment/myapp myapp=myapp:${{ github.sha }} -n production
          kubectl rollout status deployment/myapp -n production
```

#### GitLab CI

```yaml
# .gitlab-ci.yml
variables:
  LOG_LEVEL: "DEBUG"
  APP_NAME: "myapp"
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: "/certs"

stages:
  - test
  - build
  - deploy
  - monitor

# Template pour logging
.logging_template: &logging_setup
  before_script:
    - |
      python -c "
      from pyloggerx import PyLoggerX
      import os
      
      logger = PyLoggerX(
          name='gitlab-ci',
          level=os.getenv('LOG_LEVEL', 'INFO'),
          console=True,
          json_file='logs/ci.json',
          enrichment_data={
              'pipeline_id': os.getenv('CI_PIPELINE_ID'),
              'job_id': os.getenv('CI_JOB_ID'),
              'commit_sha': os.getenv('CI_COMMIT_SHA'),
              'branch': os.getenv('CI_COMMIT_REF_NAME'),
              'runner': os.getenv('CI_RUNNER_DESCRIPTION'),
              'project': os.getenv('CI_PROJECT_NAME')
          }
      )
      logger.info('Job GitLab CI démarré')
      "

test:unit:
  stage: test
  image: python:3.11
  <<: *logging_setup
  script:
    - pip install -e .[dev]
    - pytest --cov=pyloggerx --cov-report=xml --cov-report=term
  coverage: '/TOTAL.*\s+(\d+%)$/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
    paths:
      - logs/
      - htmlcov/
    expire_in: 1 week
  only:
    - merge_requests
    - main
    - develop

test:integration:
  stage: test
  image: python:3.11
  services:
    - postgres:14
    - redis:7
  variables:
    POSTGRES_DB: testdb
    POSTGRES_USER: testuser
    POSTGRES_PASSWORD: testpass
    REDIS_URL: redis://redis:6379
  script:
    - pip install -e .[dev]
    - pytest tests/integration/ -v
  only:
    - main
    - develop

build:docker:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest
  only:
    - main

deploy:production:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config use-context production
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n production
    - kubectl rollout status deployment/myapp -n production
  environment:
    name: production
    url: https://myapp.example.com
  when: manual
  only:
    - main

monitor:health:
  stage: monitor
  image: curlimages/curl:latest
  script:
    - |
      for i in {1..5}; do
        STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://myapp.example.com/health)
        if [ "$STATUS" == "200" ]; then
          echo "Health check passed"
          exit 0
        fi
        echo "Attempt $i failed, retrying..."
        sleep 10
      done
      exit 1
  only:
    - main
```

#### Jenkins Pipeline

```groovy
// Jenkinsfile
pipeline {
    agent any
    
    environment {
        LOG_LEVEL = 'DEBUG'
        APP_NAME = 'myapp'
        ENVIRONMENT = 'staging'
        DOCKER_REGISTRY = 'registry.example.com'
        KUBE_NAMESPACE = 'production'
    }
    
    options {
        buildDiscarder(logRotator(numToKeepStr: '10'))
        timeout(time: 1, unit: 'HOURS')
        timestamps()
    }
    
    stages {
        stage('Setup') {
            steps {
                script {
                    sh '''
                        python3 -m venv venv
                        . venv/bin/activate
                        pip install -e .[dev]
                    '''
                }
            }
        }
        
        stage('Test') {
            parallel {
                stage('Unit Tests') {
                    steps {
                        script {
                            sh '''
                                . venv/bin/activate
                                python -c "
from pyloggerx import PyLoggerX
logger = PyLoggerX(
    name='jenkins-tests',
    json_file='logs/unit-tests.json',
    enrichment_data={
        'build_number': '${BUILD_NUMBER}',
        'job_name': '${JOB_NAME}',
        'node_name': '${NODE_NAME}'
    }
)
logger.info('Tests unitaires démarrés')
                                "
                                pytest tests/unit/ -v --junitxml=results/unit.xml
                            '''
                        }
                    }
                }
                
                stage('Integration Tests') {
                    steps {
                        script {
                            sh '''
                                . venv/bin/activate
                                pytest tests/integration/ -v --junitxml=results/integration.xml
                            '''
                        }
                    }
                }
            }
            post {
                always {
                    junit 'results/*.xml'
                }
            }
        }
        
        stage('Build') {
            steps {
                script {
                    docker.build("${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}")
                }
            }
        }
        
        stage('Push') {
            steps {
                script {
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-credentials') {
                        docker.image("${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}").push()
                        docker.image("${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}").push('latest')
                    }
                }
            }
        }
        
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                script {
                    withKubeConfig([credentialsId: 'kube-config']) {
                        sh """
                            kubectl set image deployment/${APP_NAME} \
                                ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER} \
                                -n ${KUBE_NAMESPACE}
                            kubectl rollout status deployment/${APP_NAME} -n ${KUBE_NAMESPACE}
                        """
                    }
                }
            }
        }
        
        stage('Smoke Tests') {
            when {
                branch 'main'
            }
            steps {
                script {
                    sh '''
                        for i in {1..5}; do
                            if curl -f https://myapp.example.com/health; then
                                echo "Smoke test passed"
                                exit 0
                            fi
                            sleep 10
                        done
                        exit 1
                    '''
                }
            }
        }
    }
    
    post {
        always {
            archiveArtifacts artifacts: 'logs/*.json', allowEmptyArchive: true
            cleanWs()
        }
        success {
            slackSend(
                color: 'good',
                message: "Build #${BUILD_NUMBER} succeeded for ${JOB_NAME}"
            )
        }
        failure {
            slackSend(
                color: 'danger',
                message: "Build #${BUILD_NUMBER} failed for ${JOB_NAME}"
            )
        }
    }
}
```

### Stack d'Observabilité

#### ELK Stack (Elasticsearch, Logstash, Kibana)

```python
# Configuration pour ELK
from pyloggerx import PyLoggerX
import socket
import os

logger = PyLoggerX(
    name="elk-app",
    console=True,
    json_file="/var/log/myapp/app.json",  # Filebeat surveille ce fichier
    colors=False,
    
    # Export direct vers Elasticsearch
    elasticsearch_url="http://elasticsearch:9200",
    elasticsearch_index="myapp-logs",
    elasticsearch_username=os.getenv("ES_USERNAME"),
    elasticsearch_password=os.getenv("ES_PASSWORD"),
    
    enrichment_data={
        "service": "payment-api",
        "environment": os.getenv("ENVIRONMENT", "production"),
        "hostname": socket.gethostname(),
        "version": os.getenv("APP_VERSION", "1.0.0"),
        "datacenter": os.getenv("DATACENTER", "us-east-1")
    }
)

# Les logs sont envoyés à Elasticsearch et écrits dans un fichier
logger.info("Paiement traité", 
           transaction_id="txn_123",
           amount=99.99,
           currency="USD",
           customer_id="cust_456",
           payment_method="card")
```

**Configuration Filebeat** (`filebeat.yml`):

```yaml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/myapp/*.json
  json.keys_under_root: true
  json.add_error_key: true
  json.message_key: message
  fields:
    service: myapp
    environment: production
  fields_under_root: true

processors:
  - add_host_metadata:
      when.not.contains.tags: forwarded
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~

output.elasticsearch:
  hosts: ["elasticsearch:9200"]
  index: "myapp-logs-%{+yyyy.MM.dd}"
  username: "${ES_USERNAME}"
  password: "${ES_PASSWORD}"
  ssl.verification_mode: none

setup.kibana:
  host: "kibana:5601"

setup.ilm.enabled: true
setup.ilm.rollover_alias: "myapp-logs"
setup.ilm.pattern: "{now/d}-000001"

logging.level: info
logging.to_files: true
logging.files:
  path: /var/log/filebeat
  name: filebeat
  keepfiles: 7
  permissions: 0644
```

#### Prometheus & Grafana

```python
from pyloggerx import PyLoggerX
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import time
import functools

# Métriques Prometheus
request_counter = Counter(
    'http_requests_total', 
    'Total HTTP requests', 
    ['method', 'endpoint', 'status']
)
request_duration = Histogram(
    'http_request_duration_seconds', 
    'HTTP request duration',
    ['method', 'endpoint']
)
active_requests = Gauge(
    'http_requests_active',
    'Active HTTP requests'
)
error_counter = Counter(
    'application_errors_total',
    'Total application errors',
    ['error_type']
)

logger = PyLoggerX(
    name="metrics-app",
    json_file="logs/metrics.json",
    performance_tracking=True,
    
    # Export vers services de monitoring
    datadog_api_key=os.getenv("DATADOG_API_KEY"),
    
    enrichment_data={
        "service": "api-gateway",
        "version": "2.0.0"
    }
)

def monitor_request(func):
    """Décorateur pour monitorer les requêtes"""
    @functools.wraps(func)
    def wrapper(method, endpoint, *args, **kwargs):
        active_requests.inc()
        start_time = time.time()
        
        logger.info("Requête reçue", 
                   method=method, 
                   endpoint=endpoint)
        
        try:
            result = func(method, endpoint, *args, **kwargs)
            duration = time.time() - start_time
            
            # Mettre à jour les métriques
            request_counter.labels(
                method=method,
                endpoint=endpoint,
                status=200
            ).inc()
            request_duration.labels(
                method=method,
                endpoint=endpoint
            ).observe(duration)
            
            logger.info("Requête complétée",
                       method=method,
                       endpoint=endpoint,
                       status=200,
                       duration_ms=duration*1000)
            
            return result
            
        except Exception as e:
            duration = time.time() - start_time
            error_type = type(e).__name__
            
            request_counter.labels(
                method=method,
                endpoint=endpoint,
                status=500
            ).inc()
            error_counter.labels(error_type=error_type).inc()
            
            logger.error("Requête échouée",
                        method=method,
                        endpoint=endpoint,
                        status=500,
                        duration_ms=duration*1000,
                        error=str(e),
                        error_type=error_type)
            raise
        finally:
            active_requests.dec()
    
    return wrapper

@monitor_request
def handle_request(method, endpoint, data=None):
    # Logique de traitement
    time.sleep(0.1)  # Simulation
    return {"status": "success"}

# Démarrer le serveur de métriques Prometheus
start_http_server(8000)
logger.info("Serveur de métriques démarré", port=8000)

# Endpoint de métriques custom
def get_performance_metrics():
    stats = logger.get_performance_stats()
    return {
        "logging": {
            "total_logs": stats.get("total_operations", 0),
            "avg_duration": stats.get("avg_duration", 0),
            "max_duration": stats.get("max_duration", 0)
        },
        "requests": {
            "total": request_counter._value.sum(),
            "active": active_requests._value.get()
        }
    }
```

#### OpenTelemetry Integration

```python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from pyloggerx import PyLoggerX
import os

# Setup OpenTelemetry
resource = Resource.create({
    "service.name": "myapp",
    "service.version": "1.0.0",
    "deployment.environment": os.getenv("ENVIRONMENT", "production")
})

trace.set_tracer_provider(TracerProvider(resource=resource))
tracer = trace.get_tracer(__name__)

# Export vers OTLP collector
otlp_exporter = OTLPSpanExporter(
    endpoint="http://otel-collector:4317",
    insecure=True
)
span_processor = BatchSpanProcessor(otlp_exporter)
trace.get_tracer_provider().add_span_processor(span_processor)

logger = PyLoggerX(
    name="otel-app",
    json_file="logs/traces.json",
    enrichment_data={
        "service": "order-service"
    }
)

def process_order(order_id):
    """Traiter une commande avec tracing distribué"""
    with tracer.start_as_current_span("process_order") as span:
        span.set_attribute("order.id", order_id)
        
        # Récupérer le contexte de trace
        ctx = span.get_span_context()
        trace_id = format(ctx.trace_id, '032x')
        span_id = format(ctx.span_id, '016x')
        
        logger.info("Traitement de la commande",
                   order_id=order_id,
                   trace_id=trace_id,
                   span_id=span_id)
        
        # Étapes de traitement avec spans
        validate_order(order_id, trace_id, span_id)
        charge_payment(order_id, trace_id, span_id)
        ship_order(order_id, trace_id, span_id)
        
        logger.info("Commande complétée",
                   order_id=order_id,
                   trace_id=trace_id,
                   span_id=span_id)

def validate_order(order_id, trace_id, span_id):
    with tracer.start_as_current_span("validate_order"):
        logger.debug("Validation de la commande",
                    order_id=order_id,
                    trace_id=trace_id,
                    span_id=span_id)
        # Logique de validation
        time.sleep(0.1)

def charge_payment(order_id, trace_id, span_id):
    with tracer.start_as_current_span("charge_payment"):
        logger.info("Traitement du paiement",
                   order_id=order_id,
                   trace_id=trace_id,
                   span_id=span_id)
        # Logique de paiement
        time.sleep(0.2)

def ship_order(order_id, trace_id, span_id):
    with tracer.start_as_current_span("ship_order"):
        logger.info("Expédition de la commande",
                   order_id=order_id,
                   trace_id=trace_id,
                   span_id=span_id)
        # Logique d'expédition
        time.sleep(0.15)
```

#### Grafana Loki Integration

```python
from pyloggerx import PyLoggerX
import os

logger = PyLoggerX(
    name="loki-app",
    console=True,
    
    # Export direct vers Loki
    loki_url="http://loki:3100",
    loki_labels={
        "app": "payment-service",
        "environment": os.getenv("ENVIRONMENT", "production"),
        "region": os.getenv("AWS_REGION", "us-east-1"),
        "version": os.getenv("APP_VERSION", "1.0.0")
    },
    
    enrichment_data={
        "service": "payment-api",
        "instance": os.getenv("HOSTNAME", "unknown")
    }
)

# Les logs sont automatiquement envoyés à Loki
logger.info("Paiement initié", 
           transaction_id="txn_789",
           amount=150.00,
           currency="EUR")

logger.info("Paiement complété",
           transaction_id="txn_789",
           status="success",
           processing_time_ms=234)
```

**Configuration Promtail** (`promtail-config.yml`):

```yaml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: system
    static_configs:
      - targets:
          - localhost
        labels:
          job: varlogs
          __path__: /var/log/*log

  - job_name: containers
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        refresh_interval: 5s
    relabel_configs:
      - source_labels: ['__meta_docker_container_name']
        regex: '/(.*)'
        target_label: 'container'
      - source_labels: ['__meta_docker_container_log_stream']
        target_label: 'logstream'
      - source_labels: ['__meta_docker_container_label_logging_jobname']
        target_label: 'job'
```

### Infrastructure as Code

#### Terraform avec Logging

```python
# terraform_deploy.py
from pyloggerx import PyLoggerX
import subprocess
import json
import sys

logger = PyLoggerX(
    name="terraform",
    console=True,
    json_file="logs/terraform.json",
    performance_tracking=True,
    
    # Notifications Slack pour les déploiements
    slack_webhook=os.getenv("SLACK_WEBHOOK"),
    
    enrichment_data={
        "tool": "terraform",
        "workspace": os.getenv("TF_WORKSPACE", "default")
    }
)

def run_terraform_command(command, **kwargs):
    """Exécuter une commande Terraform avec logging"""
    logger.info(f"Exécution: terraform {command}", **kwargs)
    
    result = subprocess.run(
        ["terraform"] + command.split(),
        capture_output=True,
        text=True
    )
    
    if result.returncode == 0:
        logger.info(f"Commande réussie: terraform {command}")
    else:
        logger.error(f"Commande échouée: terraform {command}",
                    stderr=result.stderr,
                    returncode=result.returncode)
    
    return result

def terraform_deploy(workspace="production", auto_approve=False):
    """Déploiement Terraform complet avec logging détaillé"""
    logger.info("Déploiement Terraform démarré", 
               workspace=workspace,
               auto_approve=auto_approve)
    
    try:
        # Init
        with logger.timer("Terraform Init"):
            result = run_terraform_command("init -upgrade")
            if result.returncode != 0:
                raise Exception("Terraform init failed")
        
        # Workspace
        if workspace != "default":
            with logger.timer("Terraform Workspace"):
                run_terraform_command(f"workspace select {workspace}")
        
        # Plan
        with logger.timer("Terraform Plan"):
            result = run_terraform_command("plan -out=tfplan -json")
            
            # Parser la sortie JSON
            changes = {"add": 0, "change": 0, "destroy": 0}
            for line in result.stdout.split('\n'):
                if line.strip():
                    try:
                        data = json.loads(line)
                        if data.get("type") == "change_summary":
                            changes = data.get("changes", changes)
                    except:
                        pass
            
            logger.info("Plan Terraform terminé",
                       resources_to_add=changes["add"],
                       resources_to_change=changes["change"],
                       resources_to_destroy=changes["destroy"])
            
            # Alerte si destruction de ressources
            if changes["destroy"] > 0:
                logger.warning("Destruction de ressources détectée",
                             count=changes["destroy"])
        
        # Apply
        apply_cmd = "apply tfplan"
        if auto_approve:
            apply_cmd += " -auto-approve"
        
        with logger.timer("Terraform Apply"):
            result = run_terraform_command(apply_cmd)
            
            if result.returncode == 0:
                logger.info("Déploiement Terraform réussi")
            else:
                logger.error("Déploiement Terraform échoué",
                           returncode=result.returncode)
                sys.exit(1)
        
        # Statistiques finales
        stats = logger.get_performance_stats()
        logger.info("Déploiement complété",
                   total_duration=stats["total_duration"],
                   avg_duration=stats["avg_duration"])
        
    except Exception as e:
        logger.exception("Erreur lors du déploiement Terraform",
                        error=str(e))
        sys.exit(1)

if __name__ == "__main__":
    import argparse
    
    parser = argparse.ArgumentParser()
    parser.add_argument("--workspace", default="production")
    parser.add_argument("--auto-approve", action="store_true")
    args = parser.parse_args()
    
    terraform_deploy(args.workspace, args.auto_approve)
```

#### Ansible avec Logging

```python
# ansible_playbook.py
from pyloggerx import PyLoggerX
import subprocess
import json
from datetime import datetime
import os

logger = PyLoggerX(
    name="ansible",
    json_file="logs/ansible.json",
    
    # Export vers Elasticsearch pour analyse
    elasticsearch_url=os.getenv("ES_URL"),
    elasticsearch_index="ansible-logs",
    
    enrichment_data={
        "automation": "ansible",
        "run_id": datetime.now().strftime("%Y%m%d_%H%M%S"),
        "user": os.getenv("USER")
    }
)

def run_playbook(playbook_path, inventory="hosts.ini", extra_vars=None, tags=None):
    """Exécuter un playbook Ansible avec logging détaillé"""
    logger.info("Playbook Ansible démarré",
               playbook=playbook_path,
               inventory=inventory,
               extra_vars=extra_vars,
               tags=tags)
    
    cmd = [
        "ansible-playbook",
        playbook_path,
        "-i", inventory,
        "-v"  # Verbosité
    ]
    
    if extra_vars:
        cmd.extend(["--extra-vars", json.dumps(extra_vars)])
    
    if tags:
        cmd.extend(["--tags", tags])
    
    # Exécution avec capture de sortie
    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True
    )
    
    # Parser la sortie Ansible
    stats = parse_ansible_output(result.stdout)
    
    # Logger les résultats
    if stats:
        logger.info("Playbook Ansible terminé",
                   hosts_processed=len(stats),
                   total_ok=sum(s.get("ok", 0) for s in stats.values()),
                   total_changed=sum(s.get("changed", 0) for s in stats.values()),
                   total_failed=sum(s.get("failures", 0) for s in stats.values()),
                   total_unreachable=sum(s.get("unreachable", 0) for s in stats.values()))
        
        # Logger par hôte
        for host, host_stats in stats.items():
            logger.debug("Statistiques par hôte",
                        host=host,
                        ok=host_stats.get("ok", 0),
                        changed=host_stats.get("changed", 0),
                        failed=host_stats.get("failures", 0))
    
    if result.returncode != 0:
        logger.error("Playbook Ansible échoué",
                    returncode=result.returncode,
                    stderr=result.stderr)
        return False
    
    return True

def parse_ansible_output(output):
    """Parser la sortie Ansible"""
    stats = {}
    in_recap = False
    
    for line in output.split('\n'):
        if "PLAY RECAP" in line:
            in_recap = True
            continue
        
        if in_recap and ":" in line:
            parts = line.split(":")
            if len(parts) >= 2:
                host = parts[0].strip()
                stats_str = parts[1].strip()
                
                # Parser les statistiques
                host_stats = {}
                for stat in stats_str.split():
                    if "=" in stat:
                        key, value = stat.split("=")
                        try:
                            host_stats[key] = int(value)
                        except:
                            pass
                
                stats[host] = host_stats
    
    return stats

if __name__ == "__main__":
    import argparse
    
    parser = argparse.ArgumentParser()
    parser.add_argument("playbook", help="Chemin du playbook")
    parser.add_argument("-i", "--