Dynamically changing the log level in Symfony apps – Matthias Noback

This is just a quick post sharing something I was able to figure out after doing some research.

The situation: our application throws exceptions by means of “talking back to the user”.
As developer we don’t want to be notified about all these exceptions.
They aren’t as important as any other exception that should be considered “critical”.
Still, we do want to find these exceptions in the logs, because they can sometimes provide valuable feedback about the usability of the system.

So basically we just want Symfony to log the exception, but dial the standard log level “critical” for certain types of exceptions down to “info”.
Monolog has the concept of a processor for that (represented by the optional ProcessorInterface).
The implemented process() method should return the modified log record, which is actually an array containing the different parts of a log record (the level, the message, and the context).
Since not every log record is related to an exception, we don’t have to do anything in most cases.
Here’s the code:

use Monolog\Logger;
use Monolog\Processor\ProcessorInterface;
use Symfony\Component\HttpKernel\EventListener\ErrorListener;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Throwable; final class AdjustLogLevelForExceptions implements ProcessorInterface
{ public function __invoke(array $record): array { if (!isset($record['context']['exception'])) { /** * Symfony's ErrorListener will provide a Throwable through the log message's context. * If the context has no "exception" key, we don't have to further process this log record. * * @see ErrorListener::logException() */ return $record; } $throwable = $record['context']['exception']; if (!$throwable instanceof Throwable) { // For some reason the provided value is not an actual exception, so we can't do anything with it return $record; } // Change the log level if necessary $modifiedLogLevel = $this->determineLogLevel($throwable, $record['level']); $record['level'] = $modifiedLogLevel; $record['level_name'] = Logger::getLevelName($modifiedLogLevel); return $record; } private function determineLogLevel(Throwable $throwable, int $currentLevel): int { if ($throwable instanceof UserErrorMessage) { // These are exceptions that will be rendered to the user. return Logger::INFO; } return $currentLevel; }

Now you only have to register this processor as a service and tag it as monolog.processor:

services: AdjustLogLevelForExceptions: tags: - { name: monolog.processor }

If you use auto-wiring and have set up auto-configuration for the directory where the AdjustLogLevelForExceptions is located you don’t even have to tag this service.
The MonologBundle should automatically do that for you.

PHP 8.0 feature focus: match() expressions – platform.sh

In our last episode, we discussed coming improvements to PHP’s type system. Today we look at a new construct that makes branching logic more powerful.
PHP has had a switch statement since the dawn of time, modeled on the same construct in C. You’ve surely seen it before:
<?php switch ($var) { case 'a': $message = “The variable was a.”; break; case 'b': $message = “The variable was c.”; break; case 'c': $message = “The variable was c.

PHP: file_get_contents with basic auth and redirects – Christian Weiske

I used PHP’s file_get_contents() to fetch the content of an URL:

$content = file_get_contents('https://username:password@example.org/path');

This worked fine until that URL redirected to a different path on the same domain. An error was thrown then:

PHP Warning: file_get_contents(http://…@example.org): failed to open stream: HTTP request failed! HTTP/1.1 401 Unauthorized

The solution is to use a stream context and configure the HTTP basic auth parameters into it. Those parameters are used for redirects, too.

$user = 'user';
$pass = 'pass';
$opts = [ 'http' => [ 'method' => 'GET', 'header' => 'Authorization: Basic ' . base64_encode($user . ':' . $pass) ]
file_get_contents($baUrl, false, stream_context_create($opts));

Laravel: Finding the route name – Christian Weiske

Recently at work I had to analyze a problem in a Laravel application that I was not familiar with. The problem: When calling a specific URL, it wrongly redirected to another URL.

The route that I expected to be called was not, and routes/web.php was huge; too large to find the matching route quickly.

The solution was to adjust public/index.php and add the following line before the response was sent back to the browser:

$response->header('X-Route', Route::currentRouteName());

Now I could look at the redirect’s HTTP headers to find the route that had been used:

$ curl -I http://app.example.org/en/explanatory-videos/test-510/
HTTP/1.1 302 Found
Date: Wed, 16 Sep 2020 11:45:26 GMT
Server: nginx/1.10.3 (Ubuntu)
Content-Type: text/html; charset=UTF-8
Cache-Control: no-cache, private
Location: http://app.example.org/en/products
X-Route: en_product_detail

PHP Internals News: Episode 68: Observer API – Derick Rethans

PHP Internals News: Episode 68: Observer API

In this episode of “PHP Internals News” I chat with Levi Morrison (Twitter, GitHub) and Sammy Kaye Powers (Twitter, GitHub, Website) about the new Observer API.

The RSS feed for this podcast is https://derickrethans.nl/feed-phpinternalsnews.xml, you can download this episode’s MP3 file, and it’s available on Spotify and iTunes. There is a dedicated website: https://phpinternals.news


Derick Rethans 0:15

Hi, I’m Derick, and this is PHP internals news, a weekly podcast dedicated to demystifying the development of the PHP language. This is Episode 68. Today I’m talking with Levi Morrison, and Sammy Powers, about something called the observer API, which is something that is new in PHP eight zero. Now, we’ve already passed feature freeze, of course, but this snuck in at the last possible moment. What this is observer API going to solve?

Levi Morrison 0:44

the observer API is primarily aimed at recording function calls in some way so it can also handle include, and require, and eval, and potentially in the future other things, but this is important because it allows you to write tools that automatically observe, hence the name, when a function begins or ends, or both.

Derick Rethans 1:12

What would you use that for?

Levi Morrison 1:13

So as an example, Xdebug can use this to know when functions are entered or or left, and other tools such as application performance monitoring, or APM tools like data dog, New Relic, tideways, instana so on, they can use these hooks too.

Derick Rethans 1:38

From what I understand that is the point you’re coming in from, because we haven’t actually done a proper introduction, which I forgot about. I’ve been out of this for doing this for a while. So both you and Sammy you work for data dog and work on their APM tool, which made you start doing this, I suppose.

Sammy Kaye Powers 1:54

Yeah, absolutely. One of the pain points of tying into the engine to to monitor things is that the hooks are insufficient in a number of different ways. The primary way that you would do function call interception is with a little hook called zend_execute_ex and this will hook all userland function calls. The problem is, it has an inherent stack bomb in it where if, depending on your stack size settings you, you’re going to blow up your stack. At some point if you have a very very deeply deep call stack in PHP, PHP, technically has a virtually unlimited call stack. But when you use zend_execute_ex, it actually does limit your stack size to whatever your settings are your ulimit set stack size. One of the issues that this solves is that stack overflow issue that you can run into when intercepting userland calls but the other thing that it solves is the potential JIT issues that are coming with PHP eight, where the optimizations that it does could potentially optimize out a call to zend_execute_ex where a profiling or APM tracing kind of extension would not be able to enter set that call, because of the JIT. The Observer API enables to solve multiple issues with this. Not only that, there’s more. there’s more features to this thing, because zend_execute_ex by default will intercept all userland function calls, and you have no choice but to intercept every single call, whereas, this API is designed to also allow you to choose which function calls specifically you want to intercept, so there is on the very first call of a function call. And it’ll basically send in the zend function. This is a little bit of a point we’ve been kind of going back and forth on what we actually send in on the initialis

Truncated by Planet PHP, read more at the original (another 23160 bytes)

PHP 8.0 feature focus: type improvements – platform.sh

PHP 8 is almost here, and with it a host of improvements, new functionality, and overall polish to make the web’s favorite server-side language even better. In this weekly series, leading up to the final release by the end of the year, we’ll cover what you need to know about PHP 8. It’s an exciting release, and we’re not even going to be covering all of it! There’s just that much going on.