Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Github Monolog Laravel Package

naoray/laravel-github-monolog

Laravel package that connects Monolog to GitHub, letting your application automatically create GitHub issues from logged errors and exceptions. Useful for tracking production errors directly in your repository's issue tracker with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the handler and publish its config:

composer require naoray/laravel-github-monolog
php artisan vendor:publish --provider="Naoray\LaravelGithubMonolog\ServiceProvider"

Set the minimum viable environment:

LOG_CHANNEL=stack
LOG_STACK=single,github
LOG_GITHUB_TOKEN=ghp_xxx           # fine-grained PAT with Issues: Read & Write
LOG_GITHUB_REPOSITORY=org/repo
LOG_GITHUB_LEVEL=error

Wire the channel into a stack so logs still land locally even when the GitHub API is unavailable:

// config/logging.php
'stack' => [
    'driver' => 'stack',
    'channels' => ['single', 'github'],
    'ignore_exceptions' => false,
],

Where to look first:

  1. config/github-monolog.php — token/repo, level, labels, and the signature generator (the thing that decides whether an exception opens a new issue or comments on an existing one).
  2. The signature generator class bound in that config — this is the single most important knob for issue volume, and it changed in 3.11.
  3. The published comment stub view, if you publish it — it must keep its <!-- Signature: {signature} --> marker (see Gotchas).

First use case: point the channel at a scratch repository, LOG_GITHUB_LEVEL=debug, then php artisan tinker and throw a known exception a few times. You should get exactly one issue with multiple comments. If you get N issues, your signature generator is too specific — that is the primary daily-use behaviour to verify before shipping.

Implementation Patterns

Stack it, don't replace it. Use stack with single/daily + github. The GitHub channel is your triage/alerting surface; the file channel is your forensic record and your fallback when the API is rate-limited or the token expires.

Tune level per channel. error for GitHub, debug locally. Set LOG_GITHUB_LEVEL per environment so staging exercises the pipeline without spamming the production repo.

Treat the signature generator as your grouping policy. This is the core operational lever:

  • Too coarse → unrelated bugs collapse into one thread and get closed prematurely.
  • Too fine (exception message with IDs, UUIDs, timestamps, tenant names) → one issue per request.

The default generator hashes the error into a stable signature; the practical move is to extend/bind your own and normalise volatile fragments out of the message before hashing, while deliberately keeping structural context (e.g. tenant class, not tenant ID) if you want per-segment issues.

Queued jobs changed behaviour in 3.11 — build around it. Errors thrown inside jobs are now grouped by job class + queue, not by the route that dispatched them. That is usually a big noise reduction for apps that dispatch the same job from many endpoints. If you relied on route-level granularity, encode your discriminator explicitly into the signature rather than relying on the old behaviour, which no longer exists.

Use labels as your triage automation hook. Set labels in config (e.g. bug, auto-reported, needs-triage) and let GitHub Actions, Projects, or on-call rotations take it from there. This is what turns the package from "an issue tracker" into a lightweight incident workflow.

Attach context that survives the jump. Push app version, environment, request ID, and queue name into the issue body via Monolog context processors on the channel. Without it, every issue body looks identical and you cannot tell a v2.4 regression from a v2.5 one.

Write against the API, not the network. In tests, Http::fake(['api.github.com/*' => Http::response([], 201)]) and assert on the recorded request payload — issue title, labels, and whether it hit POST /issues versus POST /issues/{n}/comments. That assertion is the cheapest regression test you can have for signature-generator changes.

Guard the channel by environment. Disable in local/testing via the logging config (or a token-less channel) so a stray report() on a laptop doesn't file issues on the shared board.

Gotchas and Tips

Duplicate issues after the 3.11 upgrade are expected, and only partly auto-healed. v3.11.0's new grouping opened fresh issues for job errors that previously had route-keyed threads. 3.11.1 adds a one-time lookup for the issue v3.10 would have used (default signature generator only) and comments there instead. Practically:

  • After upgrading, expect a short burst of continuation comments on old route-derived issues.
  • Close the stale siblings manually — v3.10 opened one per dispatching route; only the first route's thread is continued.
  • If you use a custom signature generator, this compatibility lookup does not apply to you. Plan for the migration yourself.

The compat lookup is removed in the next major. Do not build tooling that depends on legacy issue resolution; verify your custom generator and archive/close legacy threads before v4.

Do not strip the signature marker from the comment stub. Comments on existing issues now embed <!-- Signature: {signature} -->, which is how subsequent occurrences match an open issue. If you published the stub and rewrote it as friendly prose, you will silently re-introduce duplicates. Keep that HTML comment exactly as-is — it is invisible in rendered markdown but load-bearing.

Silent failure is the default failure mode. The handler talks to the network from inside your error path. Wrap the channel so a GitHub outage, a revoked token, or a rate-limit 403 never escalates into a 500. Check ignore_exceptions on the stack and consider WhatFailureGroupHandler semantics for anything non-critical.

Never route the handler's own failures back into itself. Logging a 401 from the GitHub channel through the same channel is an infinite issue-spam loop. Exclude api.github.com / GuzzleHttp exceptions from this handler explicitly.

Rate limits and issue flood are real. Authenticated PATs get ~5,000 requests/hour, and every issue/comment costs at least one. A single bad loop can burn the hourly budget and open thousands of issues. Mitigate: sane level (error, not debug), a coarser signature for high-volume job classes, and your own throttle (cache-key per signature) ahead of Log::channel('github').

Job grouping collapses tenants. Grouping by job class + queue means a job failing for 100 customers becomes one issue with 100 comments. That is usually right; if you need per-tenant visibility, put the tenant class into the custom signature — but budget for issue count accordingly.

Scrub before you ship. Issue bodies and stack traces go to GitHub, where they persist and, on public repos, are public and indexable. Strip credentials, request payloads, PII, and customer identifiers via a context processor rather than hoping exceptions are tidy. Also beware GitHub markdown: leading @ in a username or email auto-mentions real accounts; backtick-escape log lines.

Token hygiene. Use a dedicated bot account or machine user so issue attribution isn't muddled with a human's account, and scope the fine-grained PAT to Issues only on the single target repo.

When it misbehaves, debug in this order: (1) is the channel actually in the stack for that environment, (2) does the token have Issues write on the repo, (3) what does your signature hash resolve to for the failing exception — log it locally, (4) did you publish and then modify the comment stub, (5) is something swallowing handler exceptions. The signature value is the answer to almost every "duplicate issue" report.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo