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
Related
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.
i'm trying to do some process in an EventSubscriber listening to the request. To make it simple i want to check a header and refuse the request if i don't find it. It's almost like a Guard, but quite simpler.
In that step i might throw an Exception. And it works, except that i would like apiPlatform to manage the response and serialize it.
I have already configure ApiPlatform with packages/api_platform.yaml
api_platform:
exception_to_status:
Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException: 403
My EventSubscriber is configured like this in services.yaml
services:
app.security.api_subscriber:
class: App\Security\ApiAccessSubscriber
arguments:
- "%api.authorized.keys%"
calls:
- [setClient, ["#common-sentry-api"]]
- [setClientPerUser, ["#common-sentry-peruser"]]
My Subscriber describe itself like this:
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest', EventPriorities::POST_WRITE],
];
}
What am i doing wrong ?
I'm trying to refactor some Symfony 3 code to Symfony 4.
I am getting the following error when attempting to log:
The "monolog.logger.db" service or alias has been removed or inlined
when the container was compiled. You should either make it public, or
stop using the conta iner directly and use dependency injection
instead.
My logging code:
$logger = $container->get('monolog.logger.db');
$logger->info('Import command triggered');
Monolog config:
monolog:
channels: ['db']
handlers:
db:
channels: ['db']
type: service
id: app.monolog.db_handler
app.monolog.db_handler config (Note, I tried public: true here and it had no affect:
app.monolog.db_handler:
class: App\Util\MonologDBHandler
arguments: ['#doctrine.orm.entity_manager']
How can I get this wired up correctly in Symfony 4?
By default all services in Symfony 4 are private (and is the recommended pratice) so you need to "inject" in each Controller each needed service (personally I use a custom CommonControllerServiceClass).
You can also create a public service "alias" to continue accessing the service as you did, but it's not the best pratice to follow (also because I guess you will have many other services to fix).
mylogger.db:
alias: monolog.logger.db
public: true
then you can get the service from the container:
$logger = $container->get('mylogger.db');
Alister's answer is a good start, but you can utilise service arguments binding instead of creating a new service for each logger:
services:
_defaults:
autowire: true
bind:
$databaseLogger: '#monolog.logger.db'
Then just change the argument name in your class:
// in App\Util\MonologDBHandler.php
use Psr\Log\LoggerInterface;
public function __construct(LoggerInterface $databaseLogger = null) {...}
It appears that App\Util\MonologDBHandler may be the only thing that is actively using monolog.logger.db - via a container->get('...') call. (If not, you will want to use this technique to tag the specific sort of logger into more services).
You would be better to allow the framework to build the app.monolog.db_handler service itself, and use the container to help to build it. Normally, to inject a logger service, you will just need to type-hint it:
// in App\Util\MonologDBHandler.php
use Psr\Log\LoggerInterface;
public function __construct(LoggerInterface $logger = null) {...}
However, that will, by default, setup with the default #logger, so you need to add an extra hint in the service definition of the handler that you want a different type of logger:
services:
App\Log\CustomLogger:
arguments: ['#logger']
tags:
- { name: monolog.logger, channel: db }
Now, the logger in CustomLogger should be what you had previously known as monolog.logger.db.
You can also alias a different interface (similar to how the LoggerInterface is aliased to inject '#logger') to the allow for the tagging.
I'm trying to start sending my logs into elastic search using monolog. (I'm using Symfony2).
I've set up monolog like this:
monolog:
handlers:
elasticsearch:
elasticsearch:
host: %logger_elastic_host%
port: %logger_elastic_port%
type: elasticsearch
level: info
It worked only few minutes until it broke with this error messages(a fatal error, I removed useless stuff):
create: /monolog/logs/AVQKYsGRPmEhlo7mDfrN caused
MapperParsingException[failed to parse [context.stack.args]]; nested:
ElasticsearchIllegalArgumentException[unknown property [class]];
I've been looking with my collegue how to fix that. What we found out is:
Elastic search receive the first logs and automatically build a mapping
We send new logs with another mapping or slightly different to what was sent before and it breaks.
In this case it's breaking here: context.stack.args.
The problem is that the context will always be very different.
What we would like is:
is anyone out there using Monolog to log to Elasticsearch
How do you guys manage to avoid this issue. (How can we manage to avoid it)?
thanks guys.
This is happening because ES creates a mapping from the first document. If any document that is inserted after has the same property but with other type/format then ES will throw an error.
A solution is to create a custom monolog formatter and register it:
config.yml:
elasticsearch:
type: elasticsearch
elasticsearch:
host: elasticsearch
ignore_error: true
formatter: my_elasticsearch_formatter
This line will make Monolog\Handler\ElasticSearchHandler ignore any other errors from Ruflin's Elastica package:
ignore_error: true
Then register a service with this name: my_elasticsearch_formatter:
<service id="my_elasticsearch_formatter" class="AppBundle\Services\MyFormatter">
<argument type="string">monolog</argument>
<argument type="string">logs</argument>
</service>
first argument is the index name, second arg is the type.
And the formatter class:
<?php
namespace AppBundle\Services;
use function json_encode;
use Monolog\Formatter\ElasticaFormatter;
use function var_dump;
class MyFormatter extends ElasticaFormatter
{
/**
* #param string $index
* #param string $type
*/
public function __construct($index, $type)
{
parent::__construct($index, $type);
}
/**
* #param array $record
* #return array|\Elastica\Document|mixed|string
*/
public function format(array $record)
{
$record['context'] = json_encode($record['context']);
return parent::format($record);
}
}
The downside of this solution is that it will json_encode the context. You will not be able to filter by inner properties of the context in ES but at least you will not lose important information about your logs.
Im not sure why Im not catching exceptions from Swiftmailer in my controller. What am I doing wrong, or missing?
In a controller I have:
try {
$this->get('mailer')->send($email);
}
catch (\Swift_TransportException $e) {
$result = array(
false,
'There was a problem sending email: ' . $e->getMessage()
);
}
It seems to get caught by Symfony before it gets to my code, so instead of being able to handle the error myself I get the standard 500 page with
Swift_TransportException: Connection could not be established
If the email can't be sent there is no need for the application to halt as the email isn't critical - I just want to issue a notice.
Maybe there's a way to disable Symfonys catching of certain exceptions or for certain Controllers?
When you do $this->container->get("mailer")->send($email); the email message is not being sent at that point if you have spooling turned on. See http://symfony.com/doc/current/cookbook/email/spool.html
If you have the default setting of spool: { type: memory }, the \Swift_TransportException will be thrown during the kernel termination phase, after your controller has exited.
One way around this is to turn off the spooling (but then your users might have to wait while the email is sent), or you can make your own eventlistener to handle the exception. http://symfony.com/doc/current/cookbook/service_container/event_listener.html
You can try overriding the Twig Exception Handler in config.yml:
twig:
debug: %kernel.debug%
strict_variables: %kernel.debug%
exception_controller: MyBundleName:Exception:show
You then create an Exception class which extends:
Symfony\Bundle\TwigBundle\Controller\ExceptionController
Read the source code of that file and then override the methods to switch which template is rendered when the Exception type is Swift_TransportException
You can do that by setting a class variable in showAction() and passing it to findTemplate()
showAction:
$this->exceptionClassName = $exception->getClass();
findTemplate:
if (!$debug && $this->exceptionClassName == 'MyBundle\Exception\GenericNotFoundException') {
return 'BundleName:Exception:generic404.html.twig';
}
For more information, I recommend the KNPUniversity Symfony Screencasts.