## Instrumenting **PHP** applications --- > ability to monitor or measure performance, diagnose errors, collect and write trace information -- ## Dev ❤️ Ops --- # Logging -- ## Areas - Producing <span class="fragment">👈</span> - Collecting/Forwarding - Storing - Analysing -- <pre><code class="hljs language-php" data-line-numbers>&#x3C;?php $logger->logf('saving user %s failed: %s', $username, $err); // saving user john.doe failed: cannot connect to database </code></pre> -- <!-- .slide: data-transition="slide-in none-out" --> <pre><code class="hljs language-text" data-line-numbers>everything is very goooood everything is very goooood everything is very goooood everything is very goooood everything is very goooood everything is very goooood cannot connect to database everything is very goooood everything is very goooood everything is very goooood everything is very goooood </code></pre> -- <!-- .slide: data-transition="fade-in slide-out" --> <pre><code class="hljs language-text" data-line-numbers="7">everything is very goooood everything is very goooood everything is very goooood everything is very goooood everything is very goooood everything is very goooood cannot connect to database everything is very goooood everything is very goooood everything is very goooood everything is very goooood </code></pre> -- ## Leveled logging <pre><code class="hljs language-php" data-line-numbers>&#x3C;?php $logger->errorf('saving user %s failed: %s', $username, $err); // [ERROR] saving user john.doe failed: cannot connect to database </code></pre> -- ## Usual levels - (trace) <!-- .element: class="fragment fade-in-then-semi-out" data-fragment-index="0" --> - debug <!-- .element: class="fragment semi-fade-out" data-fragment-index="1" --> - info <!-- .element: class="fragment highlight-current-blue" data-fragment-index="1" --> - warn <!-- .element: class="fragment semi-fade-out" data-fragment-index="1" --> - error <!-- .element: class="fragment highlight-red" data-fragment-index="1" --> -- ## Structured logging <pre><code class="hljs language-php" data-line-numbers>&#x3C;?php $logger->error( 'saving user failed', [ 'user' => $username, 'reason' => $err, ] ); // [ERROR] saving user failed // user: john.doe // reason: cannot connect to database </code></pre> -- ## Correlation ID - Identifies a request - Connects log events from the same request - Works across services - PHP: shared-nothing architecture 🚀 -- ## Other considerations: GDPR <pre><code class="hljs language-php" data-line-numbers>&#x3C;?php // 👎 DON'T!!! $logger->error('saving user failed', [ 'ip' => $ip, 'credit_card' => $creditCard, ] ); // 👍 DO! $logger->error('saving user failed', ['user_id' => $userId]); </code></pre> -- ## Other considerations: Logging is expensive! <pre><code class="hljs language-php" data-line-numbers>&#x3C;?php // 👎 DON'T!!! for ($i=0; $i < 100; $i++) { $logger->info('processing details', ['id' => $i]); } // 👍 DO! $logger->info('starting batch processing', ['items' => 100]); for ($i=0; $i < 100; $i++) { // if error $logger->error('failed to process item', ['id' => $i]); } $logger->info('finished batch processing', ['errors' => 1]); </code></pre> -- ## Logging in PHP - [PSR-3](https://www.php-fig.org/psr/psr-3/) - [Monolog](https://github.com/Seldaek/monolog) --- # Metrics & monitoring -- ## Measure everything!!! -- ## ...but start with - [USE](http://www.brendangregg.com/usemethod.html) - [RED](https://twitter.com/LindsayofSF/status/692191001692237825) -- ## Telemetry models - **push:** emit metrics to an external system (eg. Graphite, Statsd) - **pull:** expose metrics at some known location (eg. Prometheus) (PHP: shared-nothing architecture 💩) -- <img src="img/prometheus.svg" alt="Prometheus" style="border: none; box-shadow: none;" class="stretch"> -- ## Prometheus - [Pushgateway](https://github.com/prometheus/pushgateway) - Redis collector -- ## Alerting - Alert user facing services first - Avoid alert fatigue 😴 --- # (Distributed) Tracing -- > Correlation ID on steroids -- ![Jaeger](img/jaeger.png) <!-- .element style="border: none; box-shadow: none;" --> -- <img src="img/opencensus.svg" alt="OpenCensus" style="border: none; box-shadow: none;" class="stretch"> -- https://github.com/census-instrumentation/opencensus-php <pre><code class="hljs language-php" data-line-numbers>&#x3C;?php // Creates a detached span $span = Tracer::startSpan(['name' => 'expensive-operation']); // Opens a scope that attaches the span to the current context $scope = Tracer::withSpan($span); try { $pi = calculatePi(1000); } finally { // Closes the scope (ends the span) $scope->close(); } </code></pre> PHP: shared-nothing architecture 🚀 --- # Thanks! --- # Looking for speakers --- <section data-background="img/hacktoberfest.png"> --- ## Further reading http://www.brendangregg.com/usemethod.html https://twitter.com/LindsayofSF/status/692191001692237825 https://peter.bourgon.org/blog/2016/02/07/logging-v-instrumentation.html --- ## Further reading https://opencensus.io https://opentelemetry.io https://prometheus.io