1<?php
2
3/*
4 * This file is part of the Silex framework.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Silex\Provider;
13
14use Pimple\Container;
15use Pimple\ServiceProviderInterface;
16use Monolog\Formatter\LineFormatter;
17use Monolog\Logger;
18use Monolog\Handler;
19use Monolog\ErrorHandler;
20use Silex\Application;
21use Silex\Api\BootableProviderInterface;
22use Symfony\Bridge\Monolog\Handler\DebugHandler;
23use Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy;
24use Symfony\Bridge\Monolog\Processor\DebugProcessor;
25use Silex\EventListener\LogListener;
26
27/**
28 * Monolog Provider.
29 *
30 * @author Fabien Potencier <fabien@symfony.com>
31 */
32class MonologServiceProvider implements ServiceProviderInterface, BootableProviderInterface
33{
34    public function register(Container $app)
35    {
36        $app['logger'] = function () use ($app) {
37            return $app['monolog'];
38        };
39
40        if ($bridge = class_exists('Symfony\Bridge\Monolog\Logger')) {
41            $app['monolog.handler.debug'] = function () use ($app) {
42                $level = MonologServiceProvider::translateLevel($app['monolog.level']);
43
44                return new DebugHandler($level);
45            };
46
47            if (isset($app['request_stack'])) {
48                $app['monolog.not_found_activation_strategy'] = function () use ($app) {
49                    return new NotFoundActivationStrategy($app['request_stack'], array('^/'), $app['monolog.level']);
50                };
51            }
52        }
53
54        $app['monolog.logger.class'] = $bridge ? 'Symfony\Bridge\Monolog\Logger' : 'Monolog\Logger';
55
56        $app['monolog'] = function ($app) use ($bridge) {
57            $log = new $app['monolog.logger.class']($app['monolog.name']);
58
59            $handler = new Handler\GroupHandler($app['monolog.handlers']);
60            if (isset($app['monolog.not_found_activation_strategy'])) {
61                $handler = new Handler\FingersCrossedHandler($handler, $app['monolog.not_found_activation_strategy']);
62            }
63
64            $log->pushHandler($handler);
65
66            if ($app['debug'] && $bridge) {
67                if (class_exists(DebugProcessor::class)) {
68                    $log->pushProcessor(new DebugProcessor());
69                } else {
70                    $log->pushHandler($app['monolog.handler.debug']);
71                }
72            }
73
74            return $log;
75        };
76
77        $app['monolog.formatter'] = function () {
78            return new LineFormatter();
79        };
80
81        $app['monolog.handler'] = $defaultHandler = function () use ($app) {
82            $level = MonologServiceProvider::translateLevel($app['monolog.level']);
83
84            $handler = new Handler\StreamHandler($app['monolog.logfile'], $level, $app['monolog.bubble'], $app['monolog.permission']);
85            $handler->setFormatter($app['monolog.formatter']);
86
87            return $handler;
88        };
89
90        $app['monolog.handlers'] = function () use ($app, $defaultHandler) {
91            $handlers = array();
92
93            // enables the default handler if a logfile was set or the monolog.handler service was redefined
94            if ($app['monolog.logfile'] || $defaultHandler !== $app->raw('monolog.handler')) {
95                $handlers[] = $app['monolog.handler'];
96            }
97
98            return $handlers;
99        };
100
101        $app['monolog.level'] = function () {
102            return Logger::DEBUG;
103        };
104
105        $app['monolog.listener'] = function () use ($app) {
106            return new LogListener($app['logger'], $app['monolog.exception.logger_filter']);
107        };
108
109        $app['monolog.name'] = 'app';
110        $app['monolog.bubble'] = true;
111        $app['monolog.permission'] = null;
112        $app['monolog.exception.logger_filter'] = null;
113        $app['monolog.logfile'] = null;
114        $app['monolog.use_error_handler'] = function ($app) {
115            return !$app['debug'];
116        };
117    }
118
119    public function boot(Application $app)
120    {
121        if ($app['monolog.use_error_handler']) {
122            ErrorHandler::register($app['monolog']);
123        }
124
125        if (isset($app['monolog.listener'])) {
126            $app['dispatcher']->addSubscriber($app['monolog.listener']);
127        }
128    }
129
130    public static function translateLevel($name)
131    {
132        // level is already translated to logger constant, return as-is
133        if (is_int($name)) {
134            return $name;
135        }
136
137        $levels = Logger::getLevels();
138        $upper = strtoupper($name);
139
140        if (!isset($levels[$upper])) {
141            throw new \InvalidArgumentException("Provided logging level '$name' does not exist. Must be a valid monolog logging level.");
142        }
143
144        return $levels[$upper];
145    }
146}
147