Buy

Logging and Adding other Tools

Our micro-Symfony is done: go forth and use this as the starting point for new projects. It's fully-functional, it looks a lot like normal Symfony, but it's just a lot smaller. Mission accomplished.

As you build your project, you may start missing some features that you normally get out of the box with Symfony, like logging - we don't have any logging capabilities right now.

Symfony logging usually comes from MonologBundle: we can look for it in our project, but nope - we don't have MonologBundle yet. That's no problem: we just need to treat this normally-core bundle like any other third-party bundle.

Enabling and Configuring MonologBundle

So, step 1 is to install it. At your terminal, run composer require symfony/monolog-bundle:

composer require symfony/monolog-bundle

While we're waiting, Google for "symfony monologbundle". The first link is to its GitHub page, which basically just points you to read the official documentation on Symfony.

Normally, Symfony users already have this bundle installed in their project. So we need to do 3 extra steps. First, we needed to grab it with composer. Done! Second, we need to enable it in AppKernel: new MonologBundle:

50 lines AppKernel.php
... lines 1 - 6
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
... lines 12 - 14
new \Symfony\Bundle\MonologBundle\MonologBundle(),
... line 16
);
... lines 18 - 23
}
... lines 25 - 48
}

And third - if required - we need to configure the bundle. For that, go back one more time to the Standard Edition and find the app/config/config_prod.yml file. Copy most of its monolog configuration, it's good stuff! Open up our config.yml and paste it in. Change action_level to debug to log everything.

20 lines config/config.yml
... lines 1 - 9
monolog:
handlers:
main:
type: fingers_crossed
action_level: debug
handler: nested
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug

Refresh! No errors. And we suddenly have a logs directory with a dev.log file in it. Run tail -f on that to watch it:

tail -f logs/dev.log

Clear the screen and refresh. Great - it's logging a lot of things.

Controlling action_level

We'll probably not want to log everything on production like this. So, we need a way to control the action_level. Let's use a parameter: set it to %log_action_level%:

20 lines config/config.yml
... lines 1 - 9
monolog:
handlers:
main:
... line 13
action_level: %log_action_level%
... lines 15 - 20

And of course if we try it now, we see "non-existent parameter log_action_level". How can we add it? You already know: go to .env and add SYMFONY__LOG_ACTION_LEVEL: Symfony will lowercase that before making it a parameter. Set it to debug:

8 lines .env
... lines 1 - 6
SYMFONY__LOG_ACTION_LEVEL=debug

And immediately copy this line into .env.example:

8 lines .env.example
... lines 1 - 6
SYMFONY__LOG_ACTION_LEVEL=debug

Clear the logs again and refresh. They're still very verbose. Change the level to error in .env.

Clear the logs and refresh. Hey, nothing in the logs: there weren't any errors. Try a 404 page. Perfect, all the logs from the request show up as expected. That's the job of the fingers_crossed handler: don't show me any logs, unless there's at least one entry that's an error level or higher. Then I want everything.

Enabling dump()

Ok, there's one more thing I love that I'm missing. In the controller, add a dump($this->container->get('twig')):

26 lines AppBundle/Controller/MightyMouseController.php
... lines 1 - 8
class MightyMouseController extends ContainerAware
{
... lines 11 - 13
public function rescueAction()
{
... lines 16 - 20
dump($this->container);
... lines 22 - 23
}
}

That's the new awesome dump() function from Symfony 2.6. Right now, it gives us an UndefinedFunctionException:

Attempted to call function `dump()`.

Ok, this works in Symfony normally, where does it come from? It comes from a DebugBundle. Head to AppKernel and enable it in the dev environment: new DebugBundle():

51 lines AppKernel.php
... lines 1 - 6
class AppKernel extends Kernel
{
public function registerBundles()
{
... lines 11 - 18
if ($this->getEnvironment() == 'dev') {
$bundles[] = new \Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new \Symfony\Bundle\DebugBundle\DebugBundle();
}
... lines 23 - 24
}
... lines 26 - 49
}

Try it again. The page loads, and in the web debug toolbar, we see the dumped object.

This is Symfony, but it's smaller: you need to enable things when you want them. The minimum setup includes 4 files in config, 1 in web, and 3 in the root. Then, you start building like normal.

Now, take your big idea, spin it up quickly in micro-symfony, and build something amazing.

Seeya next time!

Leave a comment!

  • 2017-08-15 Mert Simsek

    Then I start the second option. This message helped, thank you :)

  • 2017-08-15 Victor Bocharsky

    Hey Mert,

    Probably, the main questions is your application runs on the same server where you want to send logs? If on the same server, then you just need to add a new stream handler and write directly to the file system. You can specify where exactly write those logs with "path" option - see "Writing Logs to different Locations" section in docs: https://symfony.com/doc/cur... .

    But, if your application runs on a different server of that where you want to send your logs - then you have a few options:
    1. You can send API requests with Guzzle or similar to that server and handle those requests with another one application. - probably not something you want as I see from your message
    2. Or, I think you can write a custom Monolog handler, so Monolog will collect all your logs and send them to another server with Guzzle or similar. For example, take a look at Loggly handler, it also sends logs with HTTP requests but using Monolog\Handler\Curl\Util helper instead of Guzzle: https://github.com/Seldaek/...

    Does it something you asking? But anyway, if we're talking about different servers, it should be a kind of HTTP request to implement interaction between them I think, but I could be wrong.

    Cheers!

  • 2017-08-15 Mert Simsek

    I want to create a log when send an http request this log to my server. I didnt use guzzle for send this log because i want to use monolog class. So i create a instance (new Monolog) and set a log; after this log go to my server. is this possible?

  • 2017-08-15 weaverryan

    Hey Mert Simsek!

    I don't think I understand your question. What do you mean by "throw logs with http request to my server"? Do you mean that you want to store the logs somewhere on your server? Or do you want to include http request information in the log message? Or something different?

    Cheers!

  • 2017-08-14 Mert Simsek

    Hello,

    I want to use a Monolog but I want to throw logs with http request to my server. Is this possible? Because i take logs with http request and i make another actions on my server.