Search by

enuthu / api-error-logger

nuthuerick

Centralized API-call and application-error logging with duplicate detection, sanitization, and administrator notifications.

Package info

gitlab.com/nuthu.erick/api-error-logger

Issues

pkg:composer/enuthu/api-error-logger

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

dev-main 2026-09-17 14:39 UTC

This package is not auto-updated.

Last update: 2026-09-19 05:20:41 UTC


README

enuthu/api-error-logger is a reusable PHP package for centralized API-call, API-error, and application-error logging. It stores structured error records, groups duplicate failures by fingerprint, sanitizes sensitive values, and sends configurable administrator notifications without allowing logger failures to crash the host application.

Existing Implementation Review

The package follows the requested conceptual behavior:

  • capture normalized API/application error data;
  • persist structured records to a database;
  • group repeated failures by stable fingerprint;
  • increment occurrence_count and update last_occurred_at;
  • send administrator email only for configured severities;
  • throttle repeated notifications;
  • sanitize sensitive data before database or email handling;
  • isolate logging failures with an optional fallback logger.

Requirements

  • PHP >=8.0
  • PDO
  • JSON extension
  • MySQL 8+, MariaDB, PostgreSQL, or SQLite for tests/local development

Optional mail integrations:

  • symfony/mailer
  • phpmailer/phpmailer

Installation

During local development:

composer install

After publication to Packagist:

composer require enuthu/api-error-logger

From GitLab before Packagist publication:

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://gitlab.com/your-group/api-error-logger.git"
        }
    ],
    "require": {
        "enuthu/api-error-logger": "^1.0"
    }
}

Configuration

Copy or adapt config/api-error-logger.php:

$config = [
    'enabled' => true,
    'environment' => getenv('APP_ENV') ?: 'production',
    'table' => 'api_error_logs',
    'email_notifications' => true,
    'email_severities' => ['critical'],
    'email_throttle_minutes' => 10,
    'admin_emails' => ['admin@example.com'],
    'mask_fields' => ['password', 'token', 'authorization', 'cookie'],
    'fallback_log' => true,
    'fallback_log_path' => __DIR__ . '/storage/logs/api-error-logger.log',
];

Credentials should come from environment variables or the host application's secret manager. Do not commit SMTP passwords, API tokens, or application secrets.

Database Migration

Migration SQL is provided for:

  • migrations/create_api_error_logs_mysql.sql
  • migrations/create_api_error_logs_pgsql.sql
  • migrations/create_api_error_logs_sqlite.sql

Programmatic table creation:

use ENuthu\ApiErrorLogger\Config\LoggerConfig;
use ENuthu\ApiErrorLogger\Database\SchemaManager;

$pdo = new PDO($dsn, $username, $password);
$config = new LoggerConfig(['table' => 'api_error_logs']);

(new SchemaManager($pdo, $config))->createTable();

The table uses a BIGINT/BIGSERIAL style ID for production volumes, stores company_code as a string to preserve values such as 011, and stores context as JSON where the database supports it.

Basic Usage

use ENuthu\ApiErrorLogger\ApiErrorLogger;

$logger = ApiErrorLogger::createWithPdo($pdo, $config);

$logger->logError([
    'severity' => 'error',
    'error_type' => 'Timeout',
    'error_message' => 'The request timed out.',
    'api_version' => 'v3_v28',
    'api_name' => 'getCompanyList',
    'user_id' => 278,
    'username' => 'BKDeng',
    'company_id' => 4,
    'company_code' => '011',
    'platform' => 'iOS',
    'os_version' => '26.5',
    'device_type' => 'iPad',
    'device_model' => 'iPad14,6',
]);

Convenience methods are also available:

$logger->info('Health check completed.');
$logger->warning(['error_message' => 'Slow API response.', 'api_name' => 'getCompanyList']);
$logger->error(['error_message' => 'The request timed out.']);
$logger->critical(['error_message' => 'Payment API unavailable.']);

API Call Logging

$logger->logApiCall([
    'api_version' => 'v3_v28',
    'api_name' => 'getCompanyList',
    'request_id' => 'req-123',
    'http_method' => 'POST',
    'request_url' => 'https://api.example.com/company-list',
    'http_status_code' => 200,
    'response_time_ms' => 145,
    'context' => [
        'screen' => 'Company Selection',
        'network' => 'WiFi',
    ],
]);

Request bodies are not stored automatically. Pass only safe, intentional metadata through context.

Exception Logging

try {
    // application logic
} catch (Throwable $exception) {
    $logger->logException($exception, [
        'api_name' => 'getCompanyList',
        'user_id' => 278,
        'context' => [
            'screen' => 'Company Selection',
        ],
    ]);
}

The logger stores exception class, message, file, line, and trace in sanitized structured context.

Email Notifications

The package separates notification formatting from mail transport. You can provide any implementation of MailerInterface.

use ENuthu\ApiErrorLogger\ApiErrorLogger;
use ENuthu\ApiErrorLogger\Notifications\Transports\SymfonyMailerTransport;

$transport = new SymfonyMailerTransport($symfonyMailer);

$logger = ApiErrorLogger::createWithPdo($pdo, [
    'email_notifications' => true,
    'email_severities' => ['error', 'critical'],
    'email_throttle_minutes' => 10,
    'admin_emails' => ['admin@example.com'],
], $transport);

Available adapters:

  • NativeMailTransport
  • PhpMailerTransport
  • SymfonyMailerTransport

Notifications include useful debugging fields such as error ID, severity, API name, request ID, user, company, device, HTTP status, occurrence count, environment, and exception details when available.

Severity

Built-in severities are:

  • info
  • warning
  • error
  • critical

Severity names are normalized to lowercase strings. The notification list is fully configurable:

'email_severities' => ['critical'],

Duplicate Handling And Throttling

Errors are grouped by a SHA-256 fingerprint built from stable values:

  • API name
  • error type
  • normalized error message
  • exception class
  • source file and line

Volatile values such as timestamps and request IDs are excluded. Repeated fingerprints update one record by incrementing occurrence_count, updating last_occurred_at, and preserving first_occurred_at.

This grouped-record approach scales better for high-volume repeated failures than writing thousands of identical rows. If a host application needs per-occurrence analytics later, a second occurrence table can be added behind ErrorLogRepositoryInterface without changing the public logger API.

Email throttling is controlled by:

'email_throttle_minutes' => 10,

When the same fingerprint repeats inside the throttle window, the database record is updated but no duplicate email is sent.

Sensitive Data

The sanitizer masks common sensitive keys before persistence or notification:

  • password
  • passwd
  • token
  • access_token
  • refresh_token
  • authorization
  • cookie
  • session
  • session_id
  • secret
  • api_key
  • pin

Extend the list through mask_fields:

'mask_fields' => ['password', 'authorization', 'customer_pin'],

Failure Isolation

All logger operations catch internal failures. A database outage, invalid notification transport, or fallback logging failure will not crash the host application.

For file fallback logging:

'fallback_log' => true,
'fallback_log_path' => __DIR__ . '/storage/logs/api-error-logger.log',

To use a PSR-3 logger as fallback:

use ENuthu\ApiErrorLogger\Support\PsrFallbackLogger;

$fallback = new PsrFallbackLogger($psrLogger);

Yii2 Integration

Register the logger as an application component without making Yii2 a package dependency:

use ENuthu\ApiErrorLogger\ApiErrorLogger;
use ENuthu\ApiErrorLogger\Config\LoggerConfig;
use ENuthu\ApiErrorLogger\Database\PdoErrorLogRepository;
use ENuthu\ApiErrorLogger\Notifications\EmailNotifier;

'components' => [
    'apiErrorLogger' => function () {
        $config = new LoggerConfig(require Yii::getAlias('@app/config/api-error-logger.php'));

        $pdo = Yii::$app->db->pdo;
        $repository = new PdoErrorLogRepository($pdo, $config);

        $mailer = new class (Yii::$app->mailer, $config) implements \ENuthu\ApiErrorLogger\Contracts\MailerInterface {
            private $yiiMailer;
            private $config;

            public function __construct($yiiMailer, $config)
            {
                $this->yiiMailer = $yiiMailer;
                $this->config = $config;
            }

            public function send(\ENuthu\ApiErrorLogger\Models\MailMessage $message): void
            {
                $this->yiiMailer->compose()
                    ->setFrom([$message->fromAddress() => $message->fromName()])
                    ->setTo($message->to())
                    ->setSubject($message->subject())
                    ->setTextBody($message->textBody())
                    ->send();
            }
        };

        return new ApiErrorLogger(
            $config,
            $repository,
            new EmailNotifier($config, $mailer)
        );
    },
],

Controller usage:

Yii::$app->apiErrorLogger->logException($exception, [
    'api_name' => Yii::$app->controller->action->id,
    'user_id' => Yii::$app->user->id,
]);

Global error handler integration:

try {
    Yii::$app->apiErrorLogger->logException($exception, [
        'request_url' => Yii::$app->request->absoluteUrl,
        'http_method' => Yii::$app->request->method,
    ]);
} catch (Throwable $ignored) {
    // The package already isolates failures; this is only extra protection.
}

Testing And Quality

composer validate --strict
composer test
composer analyse
composer check-style
composer check

Tests use SQLite in memory and fake mail transports. They do not send real email.

Versioning

Initial development version:

0.1.0

First production release:

1.0.0

Release checklist:

  • tests passing;
  • static analysis passing;
  • Composer validation passing;
  • README completed;
  • CHANGELOG updated;
  • Git tag created;
  • GitLab release created;
  • Packagist synchronization confirmed.

GitLab Release

git remote add origin git@gitlab.com:your-group/api-error-logger.git
git push -u origin main
git tag 1.0.0
git push origin 1.0.0

Create a GitLab release from tag 1.0.0 and include the CHANGELOG entry.

Packagist Publication

  1. Push the package to GitLab.
  2. Ensure composer.json uses the final package name enuthu/api-error-logger.
  3. Create and push tag 1.0.0.
  4. Log in to Packagist and submit the GitLab repository URL.
  5. Configure GitLab/Packagist synchronization or webhook.
  6. Confirm Packagist lists version 1.0.0.
  7. Install in another project:
composer require enuthu/api-error-logger:^1.0

Troubleshooting

  • No emails are sent: confirm email_notifications, email_severities, admin_emails, and the host mail transport.
  • Duplicate errors do not create new rows: this is expected; grouped fingerprints increment occurrence_count.
  • Company code loses leading zeros: pass it as a string, for example '011'.
  • Logger returns null: logging may be disabled or the repository failed; check the fallback log.
  • Migration fails: confirm the configured database driver is one of mysql, pgsql, or sqlite.