Symfony 2 log command output - symfony

Is it possible to log a console command`s output to a log file ?
For example when a command has:
protected function execute(InputInterface $input, OutputInterface $output)
{
...
$output->writeln('command run');
...
}
How to log the output without modifying the execute method ?

According to Symfony2 documentation:
The Console component doesn't provide any logging capabilities out of the box. Normally, you run console commands manually and observe the output, which is why logging is not provided.
http://symfony.com/doc/2.8/console/logging.html
However you could use service container inside the command:
$logger = $this->getContainer()->get('logger');
And log some events:
$logger->info('Hello: '.$variable);
You should see the logged entries in app/logs/dev.log or app/logs/prod.log.

This is my approach to use the logger service in console commands.
First I configure the channel and handler for my logger, it is configured on config.yml
My custom channel is named as con and the handler as conlog, but you can put names you want:
# app/config/config.yml
monolog:
channels: ['con']
handlers:
conlog:
type: rotating_file
max_files: 31
path: %kernel.logs_dir%/command.log
level: debug
channels: ['con']
I use a rotating_file type because my console command is executed all days by a scheduled task and
I need to do a daily tracking of the command but you can use the type you need. More info about handler types in docs
Now you can use the logger in your console command, the important thing here is to inject monolog service using the automatically registered logger service with the name of the channel, in my sample it is:
monolog.logger.con
More info about this in docs
// src/AcmeBundle/Command/YourCommand
class YourCommand extends ContainerAwareCommand
{
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = $this->getContainer()->get('monolog.logger.con');
$myMessage = 'The first message';
$output->writeln($myMessage);
$logger->info($myMessage);
}
}
And this is all, in this sample the log is saved in log directory with file names as: command-Y-m-d.log.
Finally it is important remarks that the con channel logger messages are added to dev.log too. If you want prevent it, it will be needed to configure channels option in main handler, on config_dev.yml, and prefix with ! our custom channel name:
# app/config/config_dev.yml
monolog:
handlers:
main:
type: stream
path: %kernel.logs_dir%/%kernel.environment%.log
level: debug
channels: ['!con']

Related

How to control log level of deno/std/log module from command line?

for example, how to log out debug info Hello world for
import * as log from "https://deno.land/std#0.173.0/log/mod.ts";
// Simple default logger out of the box. You can customize it
// by overriding logger and handler named "default", or providing
// additional logger configurations. You can log any data type.
log.debug("Hello world");
log.info(123456);
log.warning(true);
log.error({ foo: "bar", fizz: "bazz" });
log.critical("500 Internal server error");
from https://deno.land/std#0.173.0/log/mod.ts
I tried deno run -A --log-level=DEBUG with no luck.
for example, how to log out debug info Hello world for...
Below is an example of how you can configure all levels of logging to the console at "DEBUG" and above.
The module at https://deno.land/std#0.174.0/log/mod.ts includes some example code that looks just like the lines in your question (on lines 97-153 in the file) — it is what I used as a basis for the code below.
so-75244033.ts:
import * as log from "https://deno.land/std#0.174.0/log/mod.ts";
// This could be read from an environment variable or parsed from a CLI argument:
const LOG_LEVEL = "DEBUG";
log.setup({
handlers: {
console: new log.handlers.ConsoleHandler(LOG_LEVEL),
},
loggers: {
default: {
level: LOG_LEVEL,
handlers: ["console"],
},
},
});
// Simple default logger out of the box. You can customize it
// by overriding logger and handler named "default", or providing
// additional logger configurations. You can log any data type.
log.debug("Hello world");
log.info(123456);
log.warning(true);
log.error({ foo: "bar", fizz: "bazz" });
log.critical("500 Internal server error");
In the terminal:
% deno --version
deno 1.30.0 (release, x86_64-apple-darwin)
v8 10.9.194.5
typescript 4.9.4
% deno run so-75244033.ts
DEBUG Hello world
INFO 123456
WARNING true
ERROR {"foo":"bar","fizz":"bazz"}
CRITICAL 500 Internal server error

Monolog handler ignoring yaml level

In Symfony 4.3 using Monolog, I have created a custom handler to push logs to AWS Firehose. Here is the constructor:
class FirehoseLogHandler extends AbstractProcessingHandler {
public function __construct(
FirehoseClient $firehoseClient,
FormatterInterface $formatter,
$streamName,
$level = Logger::INFO,
$bubble = true
) {
$this->firehoseClient = $firehoseClient;
$this->streamName = $streamName;
$this->formatter = $formatter;
parent::__construct($level, $bubble);
}
And here is my monolog.yaml config:
monolog:
handlers:
firehose_handler:
type: service
id: kinesis_stream_handler
main:
type: stream
handler: firehose_handler
level: error
channels: ["!event"]
services:
kinesis_stream_handler:
class: App\Logger\Handler\FirehoseLogHandler
arguments:
$firehoseClient: '#aws.firehose'
$formatter: '#App\Logger\Formatter\FirehoseLogFormatter'
$streamName: 'firehose-stream-test'
The problem that I am having is that the $level is always set to Logger::INFO (200), or whatever is set in the constructor. It seems to be ignoring what is set in the yaml config.
What am I doing wrong here? I know I could always add $level: 400 to the service declaration but that doesn't seem to make much sense. Appreciate any help in advance.
Handlers defined as type: service are used strictly as-is, since they are instances you have already constructed. They are not passed any arguments from the main monolog configuration; that would only apply to services it is constructing for you. So you do need to add $level as an explicit argument to your custom handler for this reason.
There may be some further confusion stemming from your main handler definition. While handler is a valid configuration key, it does not apply to a stream handler as it only makes sense for handlers that wrap others, such as filter. So that is simply being ignored.
The full list of handler types and what configuration keys actually apply to each can be found in the code here.

Symfony 4 enable logging with Monolog's Redis handler

I have a working ELK stack connected to Redis.
I also have a working stateless Symfony 4 application and I want to send all the production logs to my Redis.
I know Monolog has a Redis handler, but I don't know how I'm supposed to tweak the config/prod/monolog.yaml file to accomplish this of if there’s another approach.
This is how it looks right now:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404]
nested:
type: stream
path: "php://stderr"
level: debug
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]
deprecation:
type: stream
path: "php://stderr"
deprecation_filter:
type: filter
handler: deprecation
max_level: info
channels: ["php"]
The approach I took was, first installing the predis client:
composer require predis/predis
Then create a custom service class that extends the RedisHandler class that comes with the Monolog package:
namespace App\Service\Monolog\Handler;
use Monolog\Handler\RedisHandler;
use Monolog\Logger;
use Predis\Client as PredisClient;
class Redis extends RedisHandler
{
public function __construct( $host, $port = 6379, $level = Logger::DEBUG, $bubble = true, $capSize = false)
{
$predis = new PredisClient( "tcp://$host:$port" );
$key = 'logstash';
parent::__construct($predis, $key, $level, $bubble, $capSize);
}
}
Next, activate the service we just created on the services.yml config file:
services:
monolog.handler.redis:
class: App\Service\Monolog\Handler\Redis
arguments: [ '%redis.host%' ]
Be sure the parameter redis.host is set and points to your Redis server. In my case, my parameter value is the IP of my Redis server.
I added other parameters to the class like port and log level. You can set it at the moment of instantiating your service like with the host parameter.
Finally, configure your custom log handler service in your monolog.yaml config file. In my case, I need it only the production logs with the config as follow:
handlers:
custom:
type: service
id: monolog.handler.redis
level: debug
channels: ['!event']

How to set an config parameter from console argument?

I'm a newbie in Symfony.
I trying to change Monolog output formatter by console argument 'format=json'.
In short, I want to run any console command with the way:
app/console my_command --format=json # xml / txt / my own
...and get output of LoggerInterface in requested format.
For example, I set the default formatter in configuration:
monolog:
handlers:
console:
type: console
channels: [!event, !doctrine]
formatter: json_formatter
services:
json_formatter:
class: Monolog\Formatter\JsonFormatter
When I create the some MyEventListener::onConsoleCommand (as described here), I cannot change the parameters bag because it is already compiled: "Impossible to call set() on a frozen ParameterBag."
Up2: My services config in this case looks like this:
services:
kernel.listener.command_dispatch:
class: My\Listener\MyEventListener
autowire: true
tags:
- { name: kernel.event_listener, event: console.command }
With another way, I can register console option inside initial file:
# app/console
$loader = require __DIR__.'/autoload.php';
# ...
$application->getDefinition()->addOption(
new InputOption(
'formatter',
'f',
InputOption::VALUE_OPTIONAL,
'The logs output formatter',
'json_formatter'
)
);
But I can't find a way to change parameters bag in the Container. Because $application->getKernel()->getContainer() is still empty.
So, how to change Symfony2 parameters from console input?
Alternatively, maybe I can just use some environments parameters? But how I can get an environment variable in YAML configuration?
Thank you.
UP3:
I have achieved the goal with environments variables like this:
SYMFONY__LOG__FORMATTER=json_formatter app/console my_command
monolog:
handlers:
console:
type: console
#...
formatter: '%log.formatter%'
The only point to modify command arguments for every registered command of your application is handling CommandEvents::COMMAND that is triggered before any command has been executed. So you can modify its arguments and read them as described here. Also, at this point you have your container compiled and it is not possible to modify service's definitions at this point. But you can get any service.
So i think you can end up with following handler:
class LogFormatterEventListener
{
private $container;
private $consoleHandler;
public function __construct(ContainerInterface $container, HandlerInterface $consoleHandler)
{
$this->container = $container;
$this->consoleHandler = $consoleHandler;
}
public function onConsoleCommand(ConsoleCommandEvent $event)
{
$inputDefinition = $event->getCommand()->getApplication()->getDefinition();
$inputDefinition->addOption(
new InputOption('logformat', null, InputOption::VALUE_OPTIONAL, 'Format of your logs', null)
);
// merge the application's input definition
$event->getCommand()->mergeApplicationDefinition();
$input = new ArgvInput();
// we use the input definition of the command
$input->bind($event->getCommand()->getDefinition());
$formatter = $input->getOption('logformat');
if ($formatter /** && $this->container->has($formatter) **/) {
$this->consoleHandler->setFormatter(
$this->container->get($formatter);
);
}
}
}
Here is alternative solution (compatible with common):
Configuration:
monolog:
handlers:
console:
type: console
channels: [!event, !doctrine]
formatter: "%log.formatter%"
services:
json_formatter:
class: Monolog\Formatter\JsonFormatter
Command execution:
# colored plain text
app/console my_command
# json
SYMFONY__LOG__FORMATTER=json_formatter app/console my_command

Symfony 2.8 disable security/request.INFO logging

Symfony is logging two INFO level statements for every request in my application, inflating an apache log file very rapidly. We're not using Monolog (using an alternate solution), and I've disabled it by removing the bundle in the AppKernel.
[2016-06-23 12:11:04] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2016-06-23 12:11:06] request.INFO: Matched route "contact". {"route_parameters":{"_controller": ...
How can I disable this logging?
This happens because Monolog (which symfony will use itself even if you disable it in your app) defaults to std:error:
public function addRecord($level, $message, array $context = array())
{
if (!$this->handlers) {
$this->pushHandler(new StreamHandler('php://stderr', static::DEBUG));
}
Adding any handler in app/config/config.yml will make addRecord reject the unwanted info notice instead.
monolog:
handlers:
syslog:
type: syslog
level: error

Resources