{"id":49866268,"url":"https://github.com/jooservices/laravel-logging","last_synced_at":"2026-05-15T03:02:26.638Z","repository":{"id":354784794,"uuid":"1225115516","full_name":"jooservices/laravel-logging","owner":"jooservices","description":"MongoDB-backed structured activity, audit, security, domain, and system logging for Laravel.","archived":false,"fork":false,"pushed_at":"2026-05-12T04:08:53.000Z","size":251,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-12T05:37:26.292Z","etag":null,"topics":["activity-log","audit-log","composer-package","jooservices","laravel","laravel12","logging","mongodb","php","php85","security-log","structured-logging"],"latest_commit_sha":null,"homepage":"https://github.com/jooservices/laravel-logging#readme","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jooservices.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-30T00:53:04.000Z","updated_at":"2026-05-06T02:26:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jooservices/laravel-logging","commit_stats":null,"previous_names":["jooservices/laravel-logging"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jooservices/laravel-logging","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jooservices%2Flaravel-logging","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jooservices%2Flaravel-logging/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jooservices%2Flaravel-logging/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jooservices%2Flaravel-logging/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jooservices","download_url":"https://codeload.github.com/jooservices/laravel-logging/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jooservices%2Flaravel-logging/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33051875,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-15T02:00:06.351Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activity-log","audit-log","composer-package","jooservices","laravel","laravel12","logging","mongodb","php","php85","security-log","structured-logging"],"created_at":"2026-05-15T03:02:25.039Z","updated_at":"2026-05-15T03:02:26.623Z","avatar_url":"https://github.com/jooservices.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Laravel Logging\n\n`jooservices/laravel-logging` stores structured activity, audit, security, domain, and system logs in MongoDB for Laravel applications.\n\nIt is not a replacement for Laravel Log, Monolog, Sentry, OpenTelemetry, Loki, ELK, or a full observability stack. It is a focused package for durable structured application records.\n\n## Requirements\n\n- PHP 8.5+\n- Laravel 12\n- `mongodb/laravel-mongodb`\n- `jooservices/dto`\n- `jooservices/laravel-repository`\n- A MongoDB connection configured in Laravel\n\n## Installation\n\n```bash\ncomposer require jooservices/laravel-logging\nphp artisan vendor:publish --tag=laravel-logging-config\nphp artisan activity-log:indexes\nphp artisan activity-log:doctor\n```\n\nUse the doctor command to validate config loading, MongoDB reachability,\ncontainer bindings, adapter resolution, retention/export config, sanitization,\npayload limits, and command registration. It does not mutate data.\n\n```bash\nphp artisan activity-log:doctor --json\nphp artisan activity-log:doctor --check-indexes\n```\n\nThe default MongoDB collection is `activity_logs`.\n\nConfigure the MongoDB connection used by the package:\n\n```env\nACTIVITY_LOG_CONNECTION=mongodb\nACTIVITY_LOG_COLLECTION=activity_logs\nMONGODB_URI=mongodb://localhost:27017\n```\n\n## Usage\n\n```php\nuse JOOservices\\LaravelLogging\\Facades\\ActivityLog;\n\nActivityLog::activity()\n    -\u003eaction('provider.disabled')\n    -\u003eby($user)\n    -\u003eon($provider)\n    -\u003esave();\n\nActivityLog::audit()\n    -\u003eaction('config.updated')\n    -\u003eby($user)\n    -\u003eon($config)\n    -\u003echangesFrom($before, $after)\n    -\u003esave();\n\nActivityLog::security()\n    -\u003eloginFailed($email)\n    -\u003ewithRequest()\n    -\u003esave();\n\nActivityLog::system()\n    -\u003ecommandStarted('crawler:run')\n    -\u003econtext(['provider' =\u003e 'onejav'])\n    -\u003esave();\n\nActivityLog::domain()\n    -\u003efromEvent($event)\n    -\u003esave();\n```\n\nTrace batch and workflow IDs through normal context fields:\n\n```php\nActivityLog::activity()\n    -\u003eaction('crawler.item.imported')\n    -\u003ebatchId($batchId)\n    -\u003eworkflowId($workflowId)\n    -\u003esave();\n```\n\nString actor, subject, and causer values are stored exactly as named identifiers. They are not parsed.\n\n```php\nActivityLog::activity()-\u003eby('system');\n// actor_type = system, actor_id = null\n\nActivityLog::activity()-\u003eonExternal('provider', 123);\n// subject_type = provider, subject_id = 123\n```\n\n## Queueing\n\n`save()` always writes synchronously and returns an `ActivityLogRecord`.\n\nFor async logging, use `queue()` with `dispatch()`:\n\n```php\nActivityLog::activity()\n    -\u003eaction('crawler.completed')\n    -\u003ebySystem()\n    -\u003equeue('logging')\n    -\u003edispatch();\n```\n\n`queue()` only selects the queue target. It does not make `save()` asynchronous.\n\nUse `sync()-\u003edispatch()` when code needs the dispatch-style API but immediate persistence.\n\n## Adapters\n\nBuilt-in adapters are registered from config:\n\n- `activity`\n- `audit`\n- `security`\n- `domain`\n- `system`\n\nCustom adapters implement `LogAdapterInterface`, usually by extending `BaseLogAdapter`.\nThe contract includes `save(): ActivityLogRecord` for synchronous persistence and\n`dispatch(): void` for dispatch-style sync or async logging.\n\n`ActivityLogRepository` remains an internal package data-access layer. Public\nrepository replacement is not a supported configuration surface in v1.\n\n```php\nActivityLog::register('crawler', CrawlerLogAdapter::class);\n\nActivityLog::crawler()\n    -\u003eaction('crawler.completed')\n    -\u003ebySystem()\n    -\u003eproperties(['items' =\u003e 120])\n    -\u003esave();\n```\n\n`ActivityLog::crawler()` is sugar for `ActivityLog::adapter('crawler')`. Magic adapter methods do not accept parameters.\n\n## Querying\n\nUse `query()` or `records()` for common reporting filters:\n\n```php\n$records = ActivityLog::query()\n    -\u003etype('audit')\n    -\u003eaction('config.updated')\n    -\u003eforSubject($config)\n    -\u003ebyActor($user)\n    -\u003ecorrelationId($id)\n    -\u003ebetween($from, $to)\n    -\u003elatest()\n    -\u003epaginate();\n```\n\nString identity filters follow logging semantics: strings are named identifiers\nunless an explicit ID is provided.\n\n## Retention And Export\n\nPrune old records with configured per-type retention:\n\n```bash\nphp artisan activity-log:prune --dry-run\nphp artisan activity-log:prune --force\nphp artisan activity-log:prune --type=system --days=30 --force\nphp artisan activity-log:prune --type=audit --before=2026-01-01 --force\n```\n\nWithout `--force`, prune runs as a dry-run. `--days` and `--before` are mutually\nexclusive, cutoffs use `occurred_at`, and future cutoffs are rejected.\n\nExport audit or security records as JSONL or CSV:\n\n```bash\nphp artisan activity-log:export --type=audit --from=2026-01-01 --format=jsonl --output=storage/app/audit.jsonl\nphp artisan activity-log:export --format=csv --output=storage/app/activity-logs.csv\n```\n\nJSONL includes the full stored document array. CSV exports stable top-level\nfields only. Export streams records and refuses to overwrite existing files\nunless `--force` is passed.\n\n## Model Audit Logging\n\nModel logging is opt-in only:\n\n```php\nuse JOOservices\\LaravelLogging\\ActivityLogOptions;\nuse JOOservices\\LaravelLogging\\Concerns\\LogsActivity;\n\nclass Setting extends Model\n{\n    use LogsActivity;\n\n    protected function activityLogOptions(): ActivityLogOptions\n    {\n        return ActivityLogOptions::make()\n            -\u003elogOnly(['name', 'value', 'enabled'])\n            -\u003elogOnlyDirty()\n            -\u003edontSubmitEmptyLogs();\n    }\n}\n```\n\nThe trait records audit logs for created, updated, deleted, and restored model\nevents when the model opts in.\n\n## Domain Event Mappers\n\n`domain()-\u003efromEvent($event)` uses registered domain mappers first, then falls\nback to the default event-class projection.\n\n```php\nActivityLog::domain()\n    -\u003efromEvent($event)\n    -\u003esave();\n```\n\n## Sanitization And Payload Limits\n\nSensitive keys are recursively redacted in `properties`, `context`, and\n`changes` before payload limits are applied. Matching is exact and\ncase-insensitive by default. Defaults include `password`, `token`,\n`access_token`, `refresh_token`, `secret`, `api_key`, `authorization`,\n`cookie`, and `x-api-key`.\n\nPayload limits truncate oversized strings, long arrays, deep nested payloads,\nand oversized approximate documents before MongoDB persistence.\n\n```php\n'retention' =\u003e [\n    'enabled' =\u003e true,\n    'default_days' =\u003e 180,\n    'chunk_size' =\u003e 500,\n    'types' =\u003e [\n        'activity' =\u003e 90,\n        'audit' =\u003e 365,\n        'security' =\u003e 365,\n        'domain' =\u003e 90,\n        'system' =\u003e 30,\n    ],\n],\n'export' =\u003e [\n    'chunk_size' =\u003e 500,\n    'formats' =\u003e ['jsonl', 'csv'],\n],\n'sanitization' =\u003e [\n    'enabled' =\u003e true,\n    'case_sensitive' =\u003e false,\n    'redacted_value' =\u003e '[redacted]',\n    'sensitive_keys' =\u003e ['password', 'token', 'authorization', 'cookie'],\n    'sensitive_patterns' =\u003e [],\n],\n'limits' =\u003e [\n    'enabled' =\u003e true,\n    'max_string_length' =\u003e 5000,\n    'max_array_items' =\u003e 200,\n    'max_depth' =\u003e 8,\n    'max_document_bytes' =\u003e 524288,\n    'truncate_marker' =\u003e '[truncated]',\n],\n```\n\n## MongoDB Schema\n\nDocuments include classification fields, actor/subject/causer references, source and trace IDs, client context, structured `properties`, `context`, `changes`, `occurred_at`, and Laravel timestamps.\n\nRun `php artisan activity-log:indexes` to create supported top-level indexes. Nested `properties`, `context`, and `changes` keys are not indexed in v1.\n\nCore fields:\n\n- `uuid`, `type`, `adapter`, `level`, `action`, `message`\n- `actor_type`, `actor_id`\n- `subject_type`, `subject_id`\n- `causer_type`, `causer_id`\n- `request_id`, `correlation_id`, `trace_id`\n- `properties`, `context`, `changes`\n- `occurred_at`, `created_at`, `updated_at`\n\n## Development\n\n`composer run check` is the local normal gate: lint plus the unit and\nintegration test suites. `composer run ci` is the coverage gate used by CI.\n\n```bash\ncomposer validate --strict\ncomposer run lint:fix\ncomposer run lint:all\ncomposer run test\ncomposer run test:coverage\ncomposer run check\ncomposer audit\ncomposer run ci\ncomposer run format:sanity\n```\n\nMongoDB integration tests require a running MongoDB server at `MONGODB_URI` or `mongodb://localhost:27017`. Without MongoDB, integration tests are skipped with a clear message.\n\nThis package tests the real persistence flow. It does not mock internal store,\nrepository, model, adapter, or DTO layers. Allowed fakes stay at Laravel\nframework boundaries such as queue dispatch, events, or temporary filesystem\noutput.\n\nRelease workflow and tagging expectations are documented in\n[`docs/02-development/05-release-process.md`](docs/02-development/05-release-process.md).\n\nAI contributors should follow `AGENTS.md` and the package-specific skills in `.github/skills/`. When code, config, tooling, workflow, architecture, or behavior changes, update the matching docs and AI guidance before committing.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjooservices%2Flaravel-logging","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjooservices%2Flaravel-logging","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjooservices%2Flaravel-logging/lists"}