logo
podcast Podcast
get help Get Unstuck

Why you should use placeholders in logs

A security concern you may not have considered

Joel Clermont
Joel Clermont
2025-02-26

In Laravel 11, a new logging configuration option was added called replace_placeholders. (It was technically released during the Laravel 10 cycle, but initially defaulted to false unless you manually updated your config file.)

A question came up in the Mastering Laravel community about what this option does, since it isn't explained in the docs.

Aaron shared a really helpful answer, with some broader context as to why this is important, and how to take advantage of it when writing logs in Laravel. I want to share that with you today.

First, what does this option do? It's very similar to how placeholders work in other areas of Laravel, like in validation messages or other translated text.

A quick code example will help make this clear:

// Without placeholders
Log::info("Showing the user profile for user: $id");

// With placeholders
Log::info("Showing the user profile for user: {id}", ['id' => $id]);

These seem very similar, so why would it matter which version we use?

A good analogy is to think about how you would write a SQL query in your application. It's long been known that it is insecure to pass unescaped user input directly into a SQL query.

Instead, you should use placeholders and let the database prepare the statement, safely escaping the data as part of the process. As a developer, you no longer have to remember to do this for every single query. Just stick with placeholders in prepared statements and you're safe.

The same exact logic applies to logging. We may not think of logging as a security concern, but it can be, depending on where your logs are being written.

For example, you can log to a database, a remote system, and not always just a flat file. In addition, those other log targets may have different escaping requirements based on how they will be consumed.

So even if we wanted to handle escaping ourselves, we would have to potentially do it differently for each log target, and those targets can be different per environment.

It's much better instead to use this placeholder mechanism, which is actually part of the PSR-3 logger specification, and let Laravel and the underlying Monolog library handle it for us.

Here to help,

Joel

P.S. This question was discussed months ago in the Mastering Laravel community, and I'm only sharing it as a tip now. Why wait? Join the conversation.

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼
email
No spam. Only real-world advice you can use.