watchlog/laravel-apm

Lightweight APM integration for Laravel apps using Watchlog

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

pkg:composer/watchlog/laravel-apm

0.2.0 2025-11-22 21:12 UTC

This package is not auto-updated.

Last update: 2025-12-20 21:33:06 UTC


README

๐ŸŽฏ Lightweight, production-ready Application Performance Monitoring (APM) middleware for Laravel apps, designed for Watchlog.

Tracks request duration, memory usage, and status codes โ€” stores metrics in a buffer file, and automatically flushes them to your Watchlog Agent every 10 seconds.

๐Ÿš€ Features

  • โœ… Compatible with Laravel 10 & 12+
  • ๐Ÿง  Smart file-based metric buffering (no database or queue needed)
  • ๐Ÿ” Aggregates metrics per route (e.g. /users/{id})
  • ๐Ÿ“Š Tracks duration, memory, and status codes
  • ๐Ÿ”’ Safe and non-blocking โ€” doesn't slow down your requests
  • ๐ŸŒ Sends data automatically every 10 seconds to your Watchlog Agent
  • ๐Ÿท๏ธ Auto-detects service name from .env (WATCHLOG_APM_SERVICE or fallback to APP_NAME)

๐Ÿ“ฆ Installation

1. Link local package (for development)

composer config repositories.watchlog-apm path ../laravel-watchlog-apm
composer require "watchlog/laravel-apm:*"

Adjust the path to match your local project structure.

โš™๏ธ Usage (Laravel 12+)

In your bootstrap/app.php, register the middleware:

use Watchlog\LaravelAPM\Middleware\WatchlogAPM;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(...)
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->append(WatchlogAPM::class);
    })
    ->create();

๐Ÿ› ๏ธ Configuration

Service Identification

You can define your service name explicitly in .env:

WATCHLOG_APM_SERVICE=orders-api

If not set, it will fallback to:

APP_NAME=laravel-app

Agent URL Configuration

The package automatically detects the agent endpoint, but you can override it for Docker:

Option 1: Environment Variable (Recommended for Docker)

WATCHLOG_APM_AGENT_URL=http://watchlog-agent:3774/apm

Option 2: Config File

Publish the config file (if available) or add to your config/services.php:

'watchlog' => [
    'apm' => [
        'agent_url' => env('WATCHLOG_APM_AGENT_URL', ''),
    ],
],

Option 3: Direct Usage

use Watchlog\LaravelAPM\Sender;

$sender = new Sender('http://watchlog-agent:3774/apm');
$sender->flush();

If not provided, the package will auto-detect:

  • Local / non-K8s: http://127.0.0.1:3774/apm
  • Kubernetes: http://watchlog-node-agent.monitoring.svc.cluster.local:3774/apm

๐Ÿ“ค How it works

During each request:

  • The middleware tracks route, status code, duration, and memory.
  • The data is written to a file: storage/logs/apm-buffer.json

After the request ends:

  • A shutdown function checks if 10 seconds have passed since the last flush.
  • If yes, it:
    • Reads all pending metrics from apm-buffer.json
    • Aggregates them by route/method
    • Sends them to your Watchlog Agent as a JSON payload
    • Clears the buffer

๐Ÿ“ฆ What gets sent?

{
  "collected_at": "2025-05-18T12:00:00Z",
  "platformName": "laravel",
  "metrics": [
    {
      "type": "aggregated_request",
      "service": "orders-api",
      "path": "hello/{id}",
      "method": "GET",
      "request_count": 3,
      "error_count": 0,
      "avg_duration": 6.1,
      "max_duration": 8.2,
      "avg_memory": {
        "rss": 18432000,
        "heapUsed": 23998464,
        "heapTotal": 25600000
      }
    }
  ]
}

๐Ÿ“ File structure

laravel-watchlog-apm/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ Middleware/
โ”‚   โ”‚   โ””โ”€โ”€ WatchlogAPM.php
โ”‚   โ”œโ”€โ”€ Collector.php
โ”‚   โ””โ”€โ”€ Sender.php
โ”œโ”€โ”€ composer.json
โ”œโ”€โ”€ README.md

๐Ÿงช Debugging & Testing

You can manually flush metrics via tinker:

php artisan tinker
>>> (new \Watchlog\LaravelAPM\Sender())->flush();

๐Ÿ“ Recommended .gitignore

Add the following to your Laravel app's .gitignore:

/storage/logs/apm-buffer.json
/storage/logs/apm-debug.log
/storage/framework/cache/watchlog-apm.lock

๐Ÿณ Docker Setup

When running your Laravel app in Docker, configure the agent URL:

Docker Compose Example:

version: '3.8'

services:
  watchlog-agent:
    image: watchlog/agent:latest
    container_name: watchlog-agent
    ports:
      - "3774:3774"
    environment:
      - WATCHLOG_APIKEY=your-api-key
      - WATCHLOG_SERVER=https://log.watchlog.ir
    networks:
      - app-network

  laravel-app:
    build: .
    container_name: laravel-app
    ports:
      - "8000:8000"
    environment:
      - WATCHLOG_APM_AGENT_URL=http://watchlog-agent:3774/apm
      - WATCHLOG_APM_SERVICE=my-laravel-app
    depends_on:
      - watchlog-agent
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Docker Run Example:

# 1. Create network
docker network create app-network

# 2. Run Watchlog Agent
docker run -d \
  --name watchlog-agent \
  --network app-network \
  -p 3774:3774 \
  -e WATCHLOG_APIKEY="your-api-key" \
  -e WATCHLOG_SERVER="https://log.watchlog.ir" \
  watchlog/agent:latest

# 3. Run Laravel app (set WATCHLOG_APM_AGENT_URL in your .env or docker run)
docker run -d \
  --name laravel-app \
  --network app-network \
  -p 8000:8000 \
  -e WATCHLOG_APM_AGENT_URL="http://watchlog-agent:3774/apm" \
  my-laravel-app

Important Notes:

  • When using Docker, use the container name as the hostname (e.g., watchlog-agent)
  • Both containers must be on the same Docker network
  • The agent must be running before your app starts
  • Set WATCHLOG_APM_AGENT_URL in your .env file or as an environment variable
  • If WATCHLOG_APM_AGENT_URL is not provided, auto-detection will be used (local or Kubernetes)

โœ… Notes

  • The route path is captured via $request->route()?->uri() for correct dynamic segment grouping (/users/{id})
  • Multiple requests within 10 seconds are buffered, then aggregated and sent in a single payload
  • The flush lock uses a simple file timestamp (watchlog-apm.lock) to prevent oversending
  • The middleware is safe: flush failures won't crash your app

๐Ÿ“ License

MIT ยฉ Mohammadreza
Built for Watchlog.io