Completed
Push — zf3-compat ( 5cee38...eea039 )
by Markus
10s
created

Module.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * cloud solutions ZendSentry
5
 *
6
 * This source file is part of the cloud solutions ZendSentry package
7
 *
8
 * @package    ZendSentry\Module
9
 * @license    New BSD License {@link /docs/LICENSE}
10
 * @copyright  Copyright (c) 2013, cloud solutions OÜ
11
 */
12
13
namespace ZendSentry;
14
15
use Zend\EventManager\EventManager;
16
use Zend\Mvc\MvcEvent;
17
use ZendSentry\Mvc\View\Http\ExceptionStrategy as SentryHttpStrategy;
18
use ZendSentry\Mvc\View\Console\ExceptionStrategy as SentryConsoleStrategy;
19
use Zend\Mvc\View\Http\ExceptionStrategy;
20
use Raven_Client as Raven;
21
use Zend\Log\Logger;
22
23
/**
24
 * Class Module
25
 *
26
 * @package ZendSentry
27
 */
28
class Module
29
{
30
    /**
31
     * Translates Zend Framework log levels to Raven log levels.
32
     */
33
    private $logLevels = array(
34
        7 => Raven::DEBUG,
35
        6 => Raven::INFO,
36
        5 => Raven::INFO,
37
        4 => Raven::WARNING,
38
        3 => Raven::ERROR,
39
        2 => Raven::FATAL,
40
        1 => Raven::FATAL,
41
        0 => Raven::FATAL,
42
    );
43
44
    /**
45
     * @var Raven $ravenClient
46
     */
47
    protected $ravenClient;
48
49
    /**
50
     * @var ZendSentry $zendSentry
51
     */
52
    protected $zendSentry;
53
54
    /**
55
     * @var $config
56
     */
57
    protected $config;
58
59
    /**
60
     * @var EventManager $eventManager
61
     */
62
    protected $eventManager;
63
64
    /**
65
     * @param MvcEvent $event
66
     */
67
    public function onBootstrap(MvcEvent $event)
68
    {
69
        // Setup RavenClient (provided by Sentry) and Sentry (provided by this module)
70
        $this->config = $event->getApplication()->getServiceManager()->get('Config');
71
72
        if (!$this->config['zend-sentry']['use-module']) {
73
            return;
74
        }
75
76
        if (isset($this->config['zend-sentry']['raven-config']) && is_array($this->config['zend-sentry']['raven-config'])) {
77
            $ravenConfig = $this->config['zend-sentry']['raven-config'];
78
        } else {
79
            $ravenConfig = array();
80
        }
81
82
        $sentryApiKey = $this->config['zend-sentry']['sentry-api-key'];
83
        $ravenClient = new Raven($sentryApiKey, $ravenConfig);
84
85
        // Register the RavenClient as a application wide service
86
        $event->getApplication()->getServiceManager()->setService('raven', $ravenClient);
87
        $this->ravenClient = $ravenClient;
88
        $this->zendSentry = new ZendSentry($ravenClient);
89
90
        // Get the eventManager and set it as a member for convenience
91
        $this->eventManager = $event->getApplication()->getEventManager();
92
93
        // If ZendSentry is configured to use the custom logger, attach the listener
94
        if ($this->config['zend-sentry']['attach-log-listener']) {
95
            $this->setupBasicLogging($event);
96
        }
97
98
        // If ZendSentry is configured to log exceptions, a few things need to be set up
99
        if ($this->config['zend-sentry']['handle-exceptions']) {
100
            $this->setupExceptionLogging($event);
101
        }
102
103
        // If ZendSentry is configured to log errors, register it as error handler
104
        if ($this->config['zend-sentry']['handle-errors']) {
105
            $errorReportingLevel = (isset($this->config['zend-sentry']['error-reporting'])) ? $this->config['zend-sentry']['error-reporting'] : -1;
106
            $this->zendSentry->registerErrorHandler($this->config['zend-sentry']['call-existing-error-handler'], $errorReportingLevel);
107
        }
108
109
        // If ZendSentry is configured to log shutdown errors, register it
110
        if ($this->config['zend-sentry']['handle-shutdown-errors']) {
111
            $this->zendSentry->registerShutdownFunction();
112
        }
113
114
        // If ZendSentry is configured to log Javascript errors, add needed scripts to the view
115
        if ($this->config['zend-sentry']['handle-javascript-errors']) {
116
            $this->setupJavascriptLogging($event);
117
        }
118
    }
119
120
    /**
121
     * @return array
122
     */
123
    public function getAutoloaderConfig()
124
    {
125
        return array('Zend\Loader\StandardAutoloader' => array('namespaces' => array(
126
            __NAMESPACE__ => __DIR__.'/src/'.__NAMESPACE__,
127
        )));
128
    }
129
130
    /**
131
     * @return mixed
132
     */
133
    public function getConfig()
134
    {
135
        return include __DIR__.'/config/module.config.php';
136
    }
137
138
    /**
139
     * Gives us the possibility to write logs to Sentry from anywhere in the application
140
     * Doesn't use the ZF compatible Log Writer because we want to return the Sentry event ID
141
     * ZF Logging doesn't provide the possibility to return values from writers
142
     *
143
     * @param MvcEvent $event
144
     */
145
    protected function setupBasicLogging(MvcEvent $event)
146
    {
147
        // Get the shared event manager and attach a logging listener for the log event on application level
148
        $sharedManager = $this->eventManager->getSharedManager();
149
        $raven = $this->ravenClient;
150
        $logLevels = $this->logLevels;
151
152
        $sharedManager->attach('*', 'log', function($event) use ($raven, $logLevels) {
153
            /** @var $event MvcEvent */
154
            if (is_object($event->getTarget())) {
155
                $target = get_class($event->getTarget());
156
            } else {
157
                $target = (string) $event->getTarget();
158
            }
159
            $message  = $event->getParam('message', 'No message provided');
160
            $priority = (int) $event->getParam('priority', Logger::INFO);
161
            $message  = sprintf('%s: %s', $target, $message);
162
            $tags     = $event->getParam('tags', array());
163
            $eventID = $raven->captureMessage($message, array(), array('tags' => $tags, 'level' => $logLevels[$priority]));
164
165
            return $eventID;
166
        }, 2);
167
    }
168
169
    /**
170
     * 1. Registers Sentry as exception handler
171
     * 2. Replaces the default ExceptionStrategy so Exception that are caught by Zend Framework can still be logged
172
     *
173
     * @param MvcEvent $event
174
     */
175
    protected function setupExceptionLogging(MvcEvent $event)
176
    {
177
        // Register Sentry as exception handler for exception that bubble up to the top
178
        $this->zendSentry->registerExceptionHandler($this->config['zend-sentry']['call-existing-exception-handler']);
179
180
        // Replace the default ExceptionStrategy with ZendSentry's strategy
181
        if ($event->getApplication()->getServiceManager()->has('HttpExceptionStrategy')) {
182
            /** @var $exceptionStrategy ExceptionStrategy */
183
            $exceptionStrategy = $event->getApplication()->getServiceManager()->get('HttpExceptionStrategy');
184
            $exceptionStrategy->detach($this->eventManager);
185
        }
186
        
187
        // Check if script is running in console
188
        $exceptionStrategy = (PHP_SAPI == 'cli') ? (new SentryConsoleStrategy()) : (new SentryHttpStrategy());
189
        $exceptionStrategy->attach($this->eventManager);
190
        $exceptionStrategy->setDisplayExceptions($this->config['zend-sentry']['display-exceptions']);
191
        $exceptionStrategy->setDefaultExceptionMessage($this->config['zend-sentry'][(PHP_SAPI == 'cli') ? 'default-exception-console-message' : 'default-exception-message']);
192
193
        $ravenClient = $this->ravenClient;
194
195
        // Attach an exception listener for the ZendSentry exception strategy, can be triggered from anywhere else too
196
        $this->eventManager->getSharedManager()->attach('*', 'logException', function($event) use ($ravenClient) {
197
            /** @var $event MvcEvent */
198
            $exception = $event->getParam('exception');
199
            $tags = $event->getParam('tags', array());
200
            $eventID = $ravenClient->captureException($exception, array('tags' => $tags));
201
            return $eventID;
202
        });
203
    }
204
205
    /**
206
     * Adds the necessary javascript, tries to prepend
207
     *
208
     * @param MvcEvent $event
209
     */
210
    protected function setupJavascriptLogging(MvcEvent $event)
211
    {
212
        $viewHelper = $event->getApplication()->getServiceManager()->get('viewhelpermanager')->get('headscript');
213
        $viewHelper->offsetSetFile(0, '//cdn.ravenjs.com/3.8.0/raven.min.js');
214
        $publicApiKey = $this->convertKeyToPublic($this->config['zend-sentry']['sentry-api-key']);
215
        $viewHelper->offsetSetScript(1, sprintf("Raven.config('%s').install()", $publicApiKey));
216
    }
217
218
    /**
219
     * @param string $key
220
     * @return string $publicKey
221
     */
222
    private function convertKeyToPublic($key)
223
    {
224
        // Find private part
225
        $start = strpos($key, ':', 6);
226
        $end = strpos($key, '@');
227
        $privatePart = substr($key, $start, $end - $start);
228
229
        // Replace it with an empty string
230
        $publicKey = str_replace($privatePart, '', $key);
231
232
        return $publicKey;
233
    }
234
}
1 ignored issue
show
As per coding style, files should not end with a newline character.

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
235