PHP code example of andydefer / php-jsonl

1. Go to this page and download the library: Download andydefer/php-jsonl library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

andydefer / php-jsonl example snippets


use AndyDefer\PhpJsonl\Records\LogJsonlRecord;
use AndyDefer\PhpVo\ValueObjects\DateTimeVO;
use AndyDefer\DomainStructures\Utils\StrictDataObject;

$log = new LogJsonlRecord(
    time: new DateTimeVO('2026-01-15T14:35:00+00:00'),
    level: 'info',
    type: 'user_login',
    payload: new StrictDataObject(['user_id' => 123, 'username' => 'john_doe']),
);

use AndyDefer\PhpJsonl\Records\CacheJsonlRecord;

$cache = new CacheJsonlRecord(
    key: 'user_123',
    value: json_encode(['name' => 'John', 'email' => '[email protected]']),
    expires_at: new DateTimeVO('+1 hour'), // null = jamais expiré
);

use AndyDefer\PhpJsonl\Strategies\TemporalPathStrategy;

$strategy = new TemporalPathStrategy('/var/logs');
$service = new JsonlService($strategy, $fileSystem, $context);

use AndyDefer\PhpJsonl\Strategies\KeyBasedPathStrategy;

$strategy = new KeyBasedPathStrategy('/var/cache', hashLevels: 2);
$service = new JsonlService($strategy, $fileSystem, $context);

use AndyDefer\PhpJsonl\JsonlService;
use AndyDefer\PhpJsonl\Contexts\JsonlContext;
use AndyDefer\PhpJsonl\Strategies\TemporalPathStrategy;
use AndyDefer\PhpServices\Services\FileSystemService;
use AndyDefer\PhpServices\Enums\PermissionMode;

// 1. Créer la stratégie de chemin
$strategy = new TemporalPathStrategy('/var/app/logs');

// 2. Créer le service de fichiers
$fileSystem = new FileSystemService();

// 3. Créer le contexte unifié (état)
$context = new JsonlContext();

// 4. Instancier le service
$service = new JsonlService(
    pathStrategy: $strategy,
    fileSystem: $fileSystem,
    context: $context,
    defaultBufferSize: 100,              // Buffer de 100 entrées
    directoryPermission: PermissionMode::DIRECTORY  // Permissions 755
);

use AndyDefer\PhpJsonl\Strategies\KeyBasedPathStrategy;

$cacheStrategy = new KeyBasedPathStrategy(
    basePath: '/var/app/cache',
    hashLevels: 2  // 2 niveaux de hash (16² = 256 dossiers possibles)
);

$cacheService = new JsonlService($cacheStrategy, $fileSystem, $context);

public function write(AbstractRecord $entity, bool $lock = true): void

$log = new LogJsonlRecord(/* ... */);
$service->write($log);
$service->write($log, lock: false);  // Sans verrouillage

public function writeBatch(array $entities, bool $lock = true): void

$logs = [/* 100 entrées */];
$service->writeBatch($logs);

public function writeBuffered(AbstractRecord $entity): void

$service->enableBuffer(50);  // Buffer de 50 entrées

for ($i = 0; $i < 1000; $i++) {
    $service->writeBuffered($log);
    // Écriture automatique après 50 entrées
}

$service->flushBuffer();  // Écriture manuelle du reste

public function readAll(string $filePath): array

$lines = $service->readAll('/var/logs/2026-01-15/14.jsonl');
foreach ($lines as $line) {
    echo $line['level'] . ': ' . $line['type'] . "\n";
}

public function readLineByLine(string $filePath, callable $callback): void

$service->readLineByLine('/var/logs/large_file.jsonl', function ($line) {
    if ($line['level'] === 'error') {
        echo "ERREUR: " . $line['type'] . "\n";
    }
});

public function getFirstLine(string $filePath): ?array
public function getLastLine(string $filePath): ?array

$first = $service->getFirstLine('/var/logs/app.jsonl');
$last = $service->getLastLine('/var/logs/app.jsonl');

echo "Premier log: " . $first['type'] . "\n";
echo "Dernier log: " . $last['type'] . "\n";

public function search(string $filePath, callable $filter): array

$errors = $service->search('/var/logs/14.jsonl', function ($line) {
    return $line['level'] === 'error';
});

foreach ($errors as $error) {
    echo $error['time'] . ': ' . $error['type'] . "\n";
}

public function searchMultiple(array $filePaths, callable $filter): array

$files = [
    '/var/logs/2026-01-15/14.jsonl',
    '/var/logs/2026-01-15/15.jsonl',
    '/var/logs/2026-01-15/16.jsonl',
];

$payments = $service->searchMultiple($files, function ($line) {
    return $line['type'] === 'payment_success';
});

echo "Nombre de paiements: " . count($payments);

public function enableBuffer(int $size = 100): void

$service->enableBuffer(200);  // Écrit toutes les 200 entrées

public function disableBuffer(): void

$service->disableBuffer();  // Écriture immédiate

public function flushBuffer(?string $filePath = null): void

$service->writeBuffered($log1);
$service->writeBuffered($log2);
$service->flushBuffer();  // Écrit les 2 entrées

public function onFlush(callable $callback): void

$service->onFlush(function (string $filePath, int $count) {
    echo "Flush: {$count} lignes écrites dans {$filePath}\n";
});

public function cleanOlderThan(int $days, string $basePath): int

$deleted = $service->cleanOlderThan(30, '/var/logs');
echo "Supprimé {$deleted} fichiers de logs de plus de 30 jours";

public function cleanExpired(string $basePath, callable $isExpired): int

$deleted = $service->cleanExpired('/var/cache', function ($line) {
    if (!isset($line['expires_at'])) {
        return false;
    }
    $expiresAt = new DateTimeVO($line['expires_at']);
    $now = new DateTimeVO();
    return $expiresAt->isBefore($now);
});

echo "Supprimé {$deleted} entrées de cache expirées";

public function cleanByPattern(string $pattern): int

$pattern = '/var/logs/2026-01-15/*.jsonl';
$deleted = $service->cleanByPattern($pattern);
echo "Supprimé {$deleted} fichiers";

public function dryRun(string $basePath, callable $filter): array

$filesToDelete = $service->dryRun('/var/logs', function ($file) {
    return filemtime($file) < strtotime('-90 days');
});

echo "Fichiers qui seraient supprimés:\n";
foreach ($filesToDelete as $file) {
    echo "  - {$file}\n";
}

if (count($filesToDelete) > 0) {
    $confirm = readline("Procéder à la suppression? (y/n): ");
    if ($confirm === 'y') {
        $deleted = $service->cleanOlderThan(90, '/var/logs');
        echo "{$deleted} fichiers supprimés\n";
    }
}

public function clear(string $basePath): int

$deleted = $service->clear('/var/cache');
echo "Cache vidé: {$deleted} fichiers supprimés";

public function acquire(string $filePath, int $timeout = 5): bool

if ($service->acquire('/var/logs/app.jsonl', timeout: 3)) {
    try {
        // Opérations exclusives
        $service->append($filePath, $data);
    } finally {
        $service->release('/var/logs/app.jsonl');
    }
}

public function release(string $filePath): void

public function executeWithLock(string $filePath, callable $callback): mixed

$result = $service->executeWithLock('/shared/data.jsonl', function () use ($service) {
    $existing = $service->readAll('/shared/data.jsonl');
    $newData = ['timestamp' => time(), 'value' => rand(1, 100)];
    $existing[] = $newData;
    
    $content = '';
    foreach ($existing as $item) {
        $content .= json_encode($item) . "\n";
    }
    file_put_contents('/shared/data.jsonl', $content);
    
    return count($existing);
});

echo "Total après opération atomique: {$result}";

public function isLocked(string $filePath): bool

if ($service->isLocked('/var/logs/app.jsonl')) {
    echo "Fichier verrouillé, réessayez plus tard";
} else {
    $service->acquire('/var/logs/app.jsonl');
    // ...
}

public function isExpired(CacheJsonlRecord $record): bool

$record = CacheJsonlRecord::fromArray($line);
if ($service->isExpired($record)) {
    echo "Cache expiré, rafraîchissement nécessaire";
} else {
    echo "Cache valide: " . $record->value;
}

public function decodeCacheValue(string $encodedValue, string $typeString): StrictDataObject

$cachedData = $service->readAll('/cache/a/b/user_123.jsonl');
if (!empty($cachedData)) {
    $decoded = $service->decodeCacheValue(
        $cachedData[0]['value'],
        $cachedData[0]['value_type']
    );
    
    echo "Nom: " . $decoded->name;
    echo "Email: " . $decoded->email;
}

public function getFilePath(AbstractRecord $entity): string

$record = new LogJsonlRecord(/* ... */);
$path = $service->getFilePath($record);
echo "Le log sera stocké dans: {$path}";

public function getFilesToScan(AbstractRecord $query): array

$query = new TemporalLogQueryRecord(
    from: new DateTimeVO('2026-01-15T10:00:00+00:00'),
    to: new DateTimeVO('2026-01-15T14:00:00+00:00'),
);

$files = $service->getFilesToScan($query);
echo "Fichiers à scanner: " . count($files);

public function getContext(): JsonlContext

$context = $service->getContext();
if ($context->hasError()) {
    echo "Erreur: " . $context->getLastError();
}
echo "Total lignes traitées: " . $context->getTotalLinesProcessed();

public function resetProcessingState(): self

$service->resetProcessingState();  // Réinitialise les stats

public function setPathStrategy(JsonlPathStrategyInterface $pathStrategy): void

// Passer de logs à cache
$service->setPathStrategy($keyBasedStrategy);

$service->enableBuffer(1000);
$service->onFlush(function ($path, $count) {
    echo "[PERF] Écriture de {$count} logs dans {$path}\n";
});

for ($i = 0; $i < 100000; $i++) {
    $service->writeBuffered(new LogJsonlRecord(
        time: new DateTimeVO(),
        level: 'info',
        type: 'api_request',
        payload: new StrictDataObject(['request_id' => $i]),
    ));
}

$service->flushBuffer();

class UserCache
{
    public function __construct(private JsonlService $cache) {}
    
    public function get(int $userId): ?array
    {
        $key = "user_{$userId}";
        $path = $this->cache->getFilePath(new CacheJsonlRecord(key: $key, value: '', expires_at: null));
        
        if (!$this->cache->fileExists($path)) {
            return null;
        }
        
        $lines = $this->cache->readAll($path);
        $record = CacheJsonlRecord::fromArray($lines[0]);
        
        if ($this->cache->isExpired($record)) {
            $this->cache->delete($path);
            return null;
        }
        
        return $this->cache->decodeCacheValue($record->value, $record->value_type)->toArray();
    }
    
    public function set(int $userId, array $data, int $ttlSeconds = 3600): void
    {
        $record = new CacheJsonlRecord(
            key: "user_{$userId}",
            value: json_encode($data),
            expires_at: new DateTimeVO("+{$ttlSeconds} seconds"),
        );
        
        $this->cache->write($record);
    }
}

function analyzeLogs(JsonlService $service, string $logDir): array
{
    $stats = ['total' => 0, 'errors' => 0, 'warnings' => 0];
    
    // Parcourir tous les fichiers du dernier jour
    $today = (new DateTime())->format('Y-m-d');
    $hourFiles = [];
    
    for ($hour = 0; $hour < 24; $hour++) {
        $path = "{$logDir}/{$today}/{$hour}.jsonl";
        if ($service->fileExists($path)) {
            $hourFiles[] = $path;
        }
    }
    
    // Analyser ligne par ligne (économie mémoire)
    foreach ($hourFiles as $file) {
        $service->readLineByLine($file, function ($line) use (&$stats) {
            $stats['total']++;
            
            if ($line['level'] === 'error') {
                $stats['errors']++;
            } elseif ($line['level'] === 'warning') {
                $stats['warnings']++;
            }
        });
    }
    
    return $stats;
}

class LogRotator
{
    public function __construct(
        private JsonlService $logs,
        private JsonlService $archive,
        private int $retentionDays = 30
    ) {}
    
    public function rotate(): void
    {
        // Simuler pour voir ce qui serait supprimé
        $toDelete = $this->logs->dryRun('/var/logs', function ($file) {
            return filemtime($file) < strtotime("-{$this->retentionDays} days");
        });
        
        if (empty($toDelete)) {
            echo "Aucun log à archiver\n";
            return;
        }
        
        echo "Fichiers à archiver ({$this->retentionDays} jours):\n";
        foreach ($toDelete as $file) {
            echo "  - {$file}\n";
        }
        
        $confirm = readline("Archiver ces fichiers? (y/n): ");
        if ($confirm !== 'y') {
            echo "Opération annulée\n";
            return;
        }
        
        // Archiver avant suppression
        foreach ($toDelete as $file) {
            $content = $this->logs->readAll($file);
            $archiveFile = str_replace('/logs/', '/archive/', $file);
            
            $this->archive->writeBatch($content);
            echo "Archivé: {$file} → {$archiveFile}\n";
        }
        
        // Supprimer les originaux
        $deleted = $this->logs->cleanOlderThan($this->retentionDays, '/var/logs');
        echo "Supprimé {$deleted} fichiers\n";
    }
}

class CounterService
{
    public function __construct(private JsonlService $storage) {}
    
    public function increment(string $counterName): int
    {
        $filePath = "/counters/{$counterName}.jsonl";
        
        return $this->storage->executeWithLock($filePath, function () use ($filePath, $counterName) {
            $value = 0;
            
            if ($this->storage->fileExists($filePath)) {
                $lastLine = $this->storage->getLastLine($filePath);
                $value = $lastLine['value'] ?? 0;
            }
            
            $newValue = $value + 1;
            
            $record = new LogJsonlRecord(
                time: new DateTimeVO(),
                level: 'info',
                type: 'counter_increment',
                payload: new StrictDataObject([
                    'counter' => $counterName,
                    'value' => $newValue,
                    'increment' => 1,
                ]),
            );
            
            $this->storage->write($record, lock: false); // Déjà locké
            
            return $newValue;
        });
    }
}

$service->write($record);
$context = $service->getContext();

if ($context->hasError()) {
    echo "Erreur: " . $context->getLastError() . "\n";
    echo "Opération: " . $context->getCurrentOperation()->value . "\n";
    echo "Fichiers traités: " . implode(', ', $context->getProcessedFiles()->toArray()) . "\n";
    echo "Lignes traitées: " . $context->getTotalLinesProcessed() . "\n";
}

// Réinitialiser pour la prochaine opération
$service->resetProcessingState();

   $service->enableBuffer(1000);  // 1000 logs avant écriture disque
   

   $service->readLineByLine($path, $callback);  // Pas de chargement mémoire
   

   $toDelete = $service->dryRun($path, $filter);  // Vérifier avant de supprimer
   

   $service->write($record, lock: false);  // Pas de lock si écriture unique
   

// Initialisation
$strategy = new TemporalPathStrategy('/var/logs');
$context = new JsonlContext();
$service = new JsonlService($strategy, new FileSystemService(), $context);

// Écrire un log
$service->write(new LogJsonlRecord(
    time: new DateTimeVO(),
    level: 'info',
    type: 'user_login',
    payload: new StrictDataObject(['user_id' => 123]),
));

// Lire les logs
$logs = $service->readAll('/var/logs/2026-01-15/14.jsonl');

// Rechercher des erreurs
$errors = $service->search('/var/logs/14.jsonl', fn($line) => $line['level'] === 'error');

// Nettoyer les vieux logs
$service->cleanOlderThan(30, '/var/logs');

// Accéder au contexte
$context = $service->getContext();
echo "Total lignes: " . $context->getTotalLinesProcessed();

// Réinitialiser l'état
$service->resetProcessingState();
bash
composer 
jsonl
{"time":"2026-01-15T14:35:00+00:00","level":"info","type":"user_login"}
{"time":"2026-01-15T14:36:00+00:00","level":"info","type":"user_login"}
{"time":"2026-01-15T14:37:00+00:00","level":"error","type":"payment_failed"}

/var/logs/
├── 2026-01-15/
│   ├── 00.jsonl
│   ├── 01.jsonl
│   └── ...
│   └── 23.jsonl
├── 2026-01-16/
│   └── ...