Laravel Logging – How to Send Logs to a Trello Card

Laravel is a great framework for building web applications because it lays a strong foundation for building the features a modern web app needs. One such important feature is logging. While Laravel automatically creates a server logfile for you, it also lets you easily customize your applications logging to fit your needs. For one of my projects that I manage with Trello (a project management tool), I thought it would be helpful if I could log certain activities to a Trello card as well as in the log file. In this tutorial we will explore the Trello Rest API and how to use it with our custom Laravel logging.

Setting up Trello

In order to follow along with this, you’ll need to sign up for a Trello account and create an API key for your account. Instructions on getting started with the API part of it can be found here. After you get it set up, I encourage you to spend some time and play with the API using something like Postman or Curl so you can get a feeling for how the API works. Postman is a great tool for testing APIs because it allows you to save your requests, along with a lot of other useful features.

In my particular project, I wanted Laravel to log to a specific card in Trello as a comment. So, looking at the documentation, I needed the following information to make the request.

  • Card ID
  • API Key
  • API Token
  • Text to be logged

I used the rest API to find the ID for the card I wanted to log to. It took a few different requests, but it’s a good opportunity to play with the API and learn how it works. Next, I put everything into a POST request like this:

https://api.trello.com/1/cards/{card-id}/actions/comments?key={api-key}&token={api-token}&text={text}

Using something like Postman, you can easily run this request and you should see a new comment pop up in your Trello card! Now let’s set up Laravel to do the logging for us.

Setting up Laravel

For logging, Laravel uses the Monolog library under the hood and makes it relatively easy to create your own custom logging functionality. The first step in logging to our Trello card is to set up a logging channel. To do that, open your config/logging.php file in your Laravel project and add this code to the end of the channels array.

FILE: config\logging.php
'channels' => [
     ... 
     'custom' => [
            'driver' => 'custom',
            'via' => App\Logging\CustomLogger::class,
            'level' => 'info',
            'name' => 'custom',
            'path' => storage_path('logs/activities.log'),
     ]
]

The above code creates a custom driver for logging. The ‘via’ option sets the factory to be used for our new logging channel, which we will be creating next. The rest of the options listed above will be available in the $config array, which you will see in the next step. Since there is no specific place in Laravel to put the factory for our custom logging channel, I will create a “Logging” folder for it. And the code for that file looks like this:

FILE: Logging\CustomLogger.php
<?php

namespace App\Logging;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

use Monolog\Formatter\LineFormatter;
use App\Logging\TrelloHandler; //we haven't created this yet

class CustomLogger
{
    /**
     * Create a custom Monolog instance.
     *
     * @param  array  $config
     * @return \Monolog\Logger
     */
    public function __invoke(array $config)
    {
        // The $config array gives you access to the values
        // that you set in the config/logging.php file.

        // logs to the logfile set in the 'path' option
        $handler = new StreamHandler($config['path'], $config['level']);
        $handler->setFormatter(new LineFormatter());

        // handles logging to trello - we need to create this next
        $trelloHandler = new TrelloHandler();
        $trelloHandler->setFormatter(new LineFormatter());

        return new Logger($config['name'], [ $handler, $trelloHandler]);
    }
}

According to the Monolog documentation, “Every Logger instance has a channel (name) and a stack of handlers. Whenever you add a record to the logger, it traverses the handler stack.” In the above code, we specified two different handlers for our custom logger. $handler will log to the logfile set in the ‘path’ option in the config\logging.php file. setFormatter is part of the Monolog library, and I encourage you to read their documentation to learn more, since it is very thorough. But essentially what it does is format the message to be logged. For both handlers I am using the basic LineFormatter, which formats the log into a one line string.

The TrelloHandler class is what will send the log message to our Trello card, but it doesn’t exist yet. So let’s create that now.

FILE: Logging\TrelloHandler.php
<?php

namespace App\Logging;

use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;

use Illuminate\Support\Facades\Http;

class TrelloHandler extends AbstractProcessingHandler
{

    public function __construct($level = Logger::INFO, bool $bubble = true)
    {
        parent::__construct($level, $bubble);
    }

    protected function write(array $record): void
    {
        $this->send($record['formatted']);
    }

    protected function send($message){
        return Http::post('https://api.trello.com/1/cards/{card-id}/actions/comments?key='.env("TRELLOAPI").'&token'.env("TRELLOTOKEN").'=&text='.$message);
    }    

}

Once again, I encourage you to look at the Monolog docs to learn more about how this works, but I will explain the key points of what is going on here. $bubble tells the handler if it should pass the record on to the next handler in the stack or not. True will pass it on where false will not. Pretty easy stuff there.

The write method comes from the Monolog docs and the send method is one that I created which uses the Laravel’s Http Facade to send a POST request to our Trello API endpoint. And that’s it! Our logger is set up and ready to go. But how do we use it? Well that’s simple. A practical example may be that you want to create a log anytime a record is added to the database in a particular controller. This would look something like this:

FILE: App\Http\Controllers\RecordController.php
...

use Illuminate\Support\Facades\Log;

class RecordController extends Controller{

     public function store(Request $request){

         ... (regular controller logic here) ...

         $record->save();
         Log::channel('custom')->info('Record Created: '.$record);
     }
}

I understand that logging is not the most glamorous part of web development, but it is very important, especially if you manage large websites or applications. It can make a difference when it comes to debugging issues and catching problems before they get out of hand. And I can see the potential benefit of being able to send your logs to a project management tool like Trello. Especially if you work with a team and multiple people need easy access to them.

Laravel and Monolog give you a lot of power to customize your application’s logging behaviors to fit your needs, and it’s definitely worth the time to dive into the documentation and learn more about it. I know I still have a lot to learn about it.

I hope this gives you a good starting point to dive deeper into the world of Logging in Laravel. Thanks for reading!