Bash: Automate Verbose Error Loggin in Drupal

Turning on verbose error logging in Drupal is an important tool for diagnosing any number of problems. Unless you have the PHP syntax memorized, though, it's a bit of a pain to enable. Even if you keep the $config line commented out in your settings.php file, opening a file editor every time you need to turn it on can also be a pain. Here's a short Bash script that will automatically edit your settings.php file and turn on verbose error logging..

I have a real knack for hitting the WSOD on my localhost--usually when juggling databases and code in between remote and local. As a result, I like to keep verbose error logging commented out in my settings.php. It's generally the last line in the file, somewhere after the $databases array. For privacy reasons I won't screen grab the actual file, but the commented line (for both D8 and D9) should be this:

// $config['system.logging']['error_level'] = 'verbose';

Having the line commented in my settings.php file makes it easy to toggle it on in a pinch. Although, opening the file with Nano and jumping to the last line can also be a bit of a pain. This got me recently thinking. Why waste my time opening and editing a file when Bash should be able to do it for me. I can use awk to find the line number of the commented line; afterwards, I can pass the line number to sed and use sed to rewrite the line (in effect, uncomment it). The script is simple, but definitely nothing pretty to look at. Let's have a look--I'm editing the script as error.sh--alias it, if you like, and mark it as executable:

# find line number for commented verbose error logging
line=$(awk '/error_level/{print NR}' /pathto/settings.php)

# create var to store verbose error logging w/o comments
on="\$config['system.logging']['error_level'] = 'verbose';"

# delete $line & insert $on at $line
sed -i "${line}d" /pathto/settings.php && sed -i "${line}i ${on}" /pathto/settings.php

echo "Verbose error logging is now on!"

Using AWK to Find a Line Number

# find line number for commented verbose error logging
line=$(awk '/error_level/{print NR}' /pathto/settings.php)

 My first goal is to find the line number of the existing commented line in settings.php. awk is perfect for this. I create a variable, line, and then define it as an awk command. The awk command searches the settings.php file for the phrase error_level (which is unique to verbose error logging) and then prints the line number with {print NR}. If I were to echo $line I would see the line number for my commented verbose error logging and nothing more.

A Variable for Uncommented Verbose Error Logging

# create var to store verbose error logging w/o comments
on="\$config['system.logging']['error_level'] = 'verbose';"

Next, I create a variable in which to store the verbose error logging line. I'm calling my variable "on". The only bit you need to worry about here is escaping (\) the dollar sign in $config. Without the escape, Bash will think it's a reference to another variable and try to expand it. That would, of course, fail--and, you'd wind up with either an incomplete string or mixed string (containing some sort of error output).

Using SED to Delete a Line and Write a New One

# delete $line & insert $on at $line
sed -i "${line}d" /pathto/settings.php && sed -i "${line}i ${on}" /pathto/settings.php

When conceptualizing this script, I initially thought I might need to search for the verbose error logging line, do some regex to identify the first two slashes commenting it out, and just remove the slashes. Why reinvent the wheel, though? We can just delete the line and substitute it with the string stored in our $on variable from the last step! Bringing variables into sed requires some special syntax. Instead of bringing in $line for example, I need to bring it in like this: ${line}. The line above is broken into two commands: the first one uses "${line}d"  to delete the contents of the line number stored in the $line variable; the second command uses "${line}i ${on}" to include the string stored in the $on variable in the same line number.

At this point, the script is good to go... but...

Quick Sanity Check!

I like having some kind of output to know that the script has run. This last line doesn't ensure the script has run correctly, but it does give you a sense of closure.

echo "Verbose error logging is now on!"

Running the Script

I run my script with the alias error. In the screen grab below, you'll see that I use awk to check the current status of verbose error logging in my settings.php: it's commented out. I run error, and then use awk to check the status of the line again: it's now uncommented--verbose error logging is on. I also run a quick git status just to be doubly sure. You could, of course, include git status in your script if you wanted; you could also include the check to get the state of the line (to see if commented or uncommented): i.e., awk '/error_level/{print}' /pathto/settings.php.

toggling on verbose error logging with a Bash script
Score!

Personally, I don't feel a need to create room in the script for toggling verbose error logging back off. I can just run git checkout . to remove the change from the working space. I may add that functionality later, though. It would likely use the same exact logic and commands already present in the script.