Completed
Branch master (e0770e)
by Markus
02:27 queued 43s
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
        /** @noinspection PhpUndefinedMethodInspection */
87
        $event->getApplication()->getServiceManager()->setService('raven', $ravenClient);
88
        $this->ravenClient = $ravenClient;
89
        $this->zendSentry = new ZendSentry($ravenClient);
90
91
        // Get the eventManager and set it as a member for convenience
92
        $this->eventManager = $event->getApplication()->getEventManager();
93
94
        // If ZendSentry is configured to use the custom logger, attach the listener
95
        if ($this->config['zend-sentry']['attach-log-listener']) {
96
            $this->setupBasicLogging($event);
97
        }
98
99
        // If ZendSentry is configured to log exceptions, a few things need to be set up
100
        if ($this->config['zend-sentry']['handle-exceptions']) {
101
            $this->setupExceptionLogging($event);
102
        }
103
104
        // If ZendSentry is configured to log errors, register it as error handler
105
        if ($this->config['zend-sentry']['handle-errors']) {
106
            $errorReportingLevel = (isset($this->config['zend-sentry']['error-reporting'])) ? $this->config['zend-sentry']['error-reporting'] : -1;
107
            $this->zendSentry->registerErrorHandler($this->config['zend-sentry']['call-existing-error-handler'], $errorReportingLevel);
108
        }
109
110
        // If ZendSentry is configured to log shutdown errors, register it
111
        if ($this->config['zend-sentry']['handle-shutdown-errors']) {
112
            $this->zendSentry->registerShutdownFunction();
113
        }
114
115
        // If ZendSentry is configured to log Javascript errors, add needed scripts to the view
116
        if ($this->config['zend-sentry']['handle-javascript-errors']) {
117
            $this->setupJavascriptLogging($event);
118
        }
119
    }
120
121
    /**
122
     * @return array
123
     */
124
    public function getAutoloaderConfig()
125
    {
126
        return array('Zend\Loader\StandardAutoloader' => array('namespaces' => array(
127
            __NAMESPACE__ => __DIR__.'/src/'.__NAMESPACE__,
128
        )));
129
    }
130
131
    /**
132
     * @return mixed
133
     */
134
    public function getConfig()
135
    {
136
        return include __DIR__.'/config/module.config.php';
137
    }/** @noinspection PhpUnusedParameterInspection */
138
    /** @noinspection PhpUnusedParameterInspection */
139
140
    /**
141
     * Gives us the possibility to write logs to Sentry from anywhere in the application
142
     * Doesn't use the ZF compatible Log Writer because we want to return the Sentry event ID
143
     * ZF Logging doesn't provide the possibility to return values from writers
144
     *
145
     * @param MvcEvent $event
146
     */
147
    protected function setupBasicLogging(MvcEvent $event)
148
    {
149
        // Suppress inspection
150
        unset($event);
151
        // Get the shared event manager and attach a logging listener for the log event on application level
152
        $sharedManager = $this->eventManager->getSharedManager();
153
        $raven = $this->ravenClient;
154
        $logLevels = $this->logLevels;
155
156
        $sharedManager->attach('*', 'log', function($event) use ($raven, $logLevels) {
157
            /** @var $event MvcEvent */
158
            if (is_object($event->getTarget())) {
159
                $target = get_class($event->getTarget());
160
            } else {
161
                $target = (string) $event->getTarget();
162
            }
163
            $message  = $event->getParam('message', 'No message provided');
164
            $priority = (int) $event->getParam('priority', Logger::INFO);
165
            $message  = sprintf('%s: %s', $target, $message);
166
            $tags     = $event->getParam('tags', array());
167
            $eventID = $raven->captureMessage($message, array(), array('tags' => $tags, 'level' => $logLevels[$priority]));
168
169
            return $eventID;
170
        }, 2);
171
    }
172
173
    /**
174
     * 1. Registers Sentry as exception handler
175
     * 2. Replaces the default ExceptionStrategy so Exception that are caught by Zend Framework can still be logged
176
     *
177
     * @param MvcEvent $event
178
     */
179
    protected function setupExceptionLogging(MvcEvent $event)
180
    {
181
        // Register Sentry as exception handler for exception that bubble up to the top
182
        $this->zendSentry->registerExceptionHandler($this->config['zend-sentry']['call-existing-exception-handler']);
183
184
        // Replace the default ExceptionStrategy with ZendSentry's strategy
185
        if ($event->getApplication()->getServiceManager()->has('HttpExceptionStrategy')) {
186
            /** @var $exceptionStrategy ExceptionStrategy */
187
            $exceptionStrategy = $event->getApplication()->getServiceManager()->get('HttpExceptionStrategy');
188
            $exceptionStrategy->detach($this->eventManager);
189
        }
190
        
191
        // Check if script is running in console
192
        $exceptionStrategy = (PHP_SAPI == 'cli') ? (new SentryConsoleStrategy()) : (new SentryHttpStrategy());
193
        $exceptionStrategy->attach($this->eventManager);
194
        $exceptionStrategy->setDisplayExceptions($this->config['zend-sentry']['display-exceptions']);
195
        $exceptionStrategy->setDefaultExceptionMessage($this->config['zend-sentry'][(PHP_SAPI == 'cli') ? 'default-exception-console-message' : 'default-exception-message']);
196
197
        $ravenClient = $this->ravenClient;
198
199
        // Attach an exception listener for the ZendSentry exception strategy, can be triggered from anywhere else too
200
        $this->eventManager->getSharedManager()->attach('*', 'logException', function($event) use ($ravenClient) {
201
            /** @var $event MvcEvent */
202
            $exception = $event->getParam('exception');
203
            $tags = $event->getParam('tags', array());
204
            $eventID = $ravenClient->captureException($exception, array('tags' => $tags));
205
            return $eventID;
206
        });
207
    }
208
209
    /**
210
     * Adds the necessary javascript, tries to prepend
211
     *
212
     * @param MvcEvent $event
213
     */
214
    protected function setupJavascriptLogging(MvcEvent $event)
215
    {
216
        $viewHelper = $event->getApplication()->getServiceManager()->get('viewhelpermanager')->get('headscript');
217
        /** @noinspection PhpUndefinedMethodInspection */
218
        $viewHelper->offsetSetFile(0, '//cdn.ravenjs.com/3.8.0/raven.min.js');
219
        $publicApiKey = $this->convertKeyToPublic($this->config['zend-sentry']['sentry-api-key']);
220
        /** @noinspection PhpUndefinedMethodInspection */
221
        $viewHelper->offsetSetScript(1, sprintf("Raven.config('%s').install()", $publicApiKey));
222
    }
223
224
    /**
225
     * @param string $key
226
     * @return string $publicKey
227
     */
228
    private function convertKeyToPublic($key)
229
    {
230
        // Find private part
231
        $start = strpos($key, ':', 6);
232
        $end = strpos($key, '@');
233
        $privatePart = substr($key, $start, $end - $start);
234
235
        // Replace it with an empty string
236
        $publicKey = str_replace($privatePart, '', $key);
237
238
        return $publicKey;
239
    }
240
}
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...
241