Errors and logging - phpgt/WebEngine GitHub Wiki
When a request fails, WebEngine tries to turn that failure into a useful HTTP response rather than leaving PHP to dump raw output at the browser.
Error types
Common error types include:
- missing pages
- application exceptions
- validation and user-facing failures
- configuration problems
Not all of these should be shown to the user in the same way, which is why WebEngine distinguishes them while handling the request.
Error rendering
WebEngine first tries to render an application-specific error page. If that fails too, it falls back to a simpler built-in error response.
Development and production should behave differently here. Development needs detail. Production needs safety and clarity.
Custom error pages
Custom error pages live in the directory configured by app.error_page_dir, which defaults to page/_error.
Create one HTML file per HTTP status code you want to handle, for example:
page/_error/404.htmlpage/_error/500.htmlpage/_error/403.html
When an exception resolves to one of those status codes, WebEngine will try to render the matching page. If no matching template exists, it falls back to the built-in error response.
In development mode, fallback 404 responses include a hint showing the missing error page path. In production mode, that extra detail is suppressed.
See Configuration reference#Config section: app for the error_page_dir setting.
Logging and diagnosis
Errors are logged as part of the request lifecycle. When diagnosing a problem, usually start by checking:
- the request path
- the matching page files
- recent configuration changes
- the application logs
Avoid leaking sensitive stack details to the browser in production responses.
Using the logger
The main logger settings live under the logger config section.
logger.typeselects destinations:stdout,sentry, orsentry,stdout.logger.levelcontrols the minimum level: one shared value, or one comma-separated value per destination inlogger.typeorder.logger.stderr_levelcontrols when local messages go tostderrinstead ofstdout.logger.log_all_requestsenables request logging for normal responses.logger.log_redirectsenables logging for redirect responses.logger.log_404_to_error_logwrites 404 responses to the error log.logger.debug_to_javascriptcontrols whether buffered debug output is exposed to browser-side JavaScript tooling.
To log a message in application code, import GT\Logger\Log and call the method matching the level you want:
use GT\Logger\Log;
Log::debug("Starting import");
Log::info("User signed in");
Log::notice("Request took longer than expected");
Log::warning("Configured fallback was used");
Log::error("Payment provider request failed");
You can also attach context data to the log entry:
use GT\Logger\Log;
Log::info("Order created", [
"orderId" => 4821,
"userId" => 19,
]);
Log::error("Database query failed", [
"query" => "select * from invoice where id = ?",
"invoiceId" => 4821,
]);
In practice:
- use
debugfor development detail - use
infofor normal application events - use
noticefor unusual but expected situations - use
warningwhen something degraded but the request can continue - use
errorwhen part of the request failed - use higher levels such as
critical,alert, oremergencyonly for severe operational failures
By default, WebEngine logs to standard output and sends higher-severity messages to standard error. That default fits container and process-manager environments well, because log collection is usually already wired to those streams.
For application failures, 5xx exceptions are logged automatically. Client-side failures are treated more quietly: 404s are only logged when logger.log_404_to_error_log is enabled, and other handled client errors are not treated as server errors.
For the full list of logger defaults, see Configuration reference#Config section: logger.
Optional Sentry error reporting
Install sentry/sentry in your application (the sentry/sdk meta-package also
provides it), then configure your project's config.ini:
[sentry]
dsn=https://[email protected]/YOUR_PROJECT
environment=production
The DSN can point to Sentry or a compatible service such as GlitchTip.
The optional sentry.environment is trimmed and included with reported errors.
If missing, empty or whitespace-only, the SDK's default behavior applies:
SENTRY_ENVIRONMENT if supplied by the server, otherwise production.
WebEngine initializes an SDK client in Application::start() when both the SDK
and a nonempty DSN are available. No Sentry initialization in setup.php is necessary. Leave the
DSN empty in environments that should not report errors.
Exceptions escaping request logic are reported before the normal error page or custom error script runs. Failures escaping error-page rendering are also reported. Expected HTTP responses below 500 are excluded. Reporting failures do not replace the application's error response. Exceptions caught and handled by application code still require explicit reporting if desired.
The reporter uses an injected Sentry\ClientInterface and PSR-7 request, without
the SDK's global hub or default integrations. WebEngine reports fatal errors
through its shutdown handler once the reporter is initialized. Errors before
initialization are not captured. Performance tracing is not enabled.
Request context includes only the HTTP method and URL without credentials, query parameters or fragments. Headers, cookies and request bodies are omitted. Exception messages may still contain sensitive data; review what your application throws.
Sending logs to Sentry or GlitchTip
Use the existing logger configuration to choose destinations and minimum severities. To send only error-level and more severe logs remotely:
[logger]
type=sentry
level=ERROR
Use type=sentry,stdout to also retain the existing local stdout/stderr output.
logger.stderr_level still controls the local stdout/stderr split; it does not
change the Sentry threshold. Destination names and levels are case-insensitive.
The levels, in ascending severity, are debug, info, notice, warning,
error, critical, alert and emergency. Surrounding whitespace is ignored.
ERROR includes ERROR, CRITICAL, ALERT and EMERGENCY, but excludes
WARNING, NOTICE, INFO and DEBUG. Existing request-logging switches still
control which messages are generated.
One level value applies to every destination. To send errors and above to
Sentry while retaining debug and above locally, set one level per destination:
[logger]
type=sentry,stdout
level=error,debug
stderr_level=error
Values are matched by position: reversing type to stdout,sentry requires
level=debug,error for the same result. If the number of levels is neither one
nor the number of destinations, WebEngine throws LoggerConfigurationException
during configuration. Repeated destinations use one handler at the lowest of
their configured thresholds.
This uses sentry.dsn and sentry.environment above and requires a Sentry PHP SDK
with structured logs support (tested with 4.31.0). Logs appear in GlitchTip's Logs
view, not as additional exception issues. Exception reporting remains independent
of logger.type and logger.level.
Logs are batched in groups of up to 100, flushed at request completion and again at shutdown for any remaining messages. Messages are limited to 8 KiB. Arbitrary log context is not forwarded, to avoid exposing request data or credentials; messages themselves must still be safe to send. If the SDK or DSN is unavailable, or delivery fails, pending messages fall back to PHP's error log without changing the application response. No global Sentry hub or superglobal access is required for log delivery.
The final reference page is project structure reference.