【PHP】ロギングでファイルに出力しつつもSentryにもエラーログを飛ばしてWEBから見れるようにする



# わざわざログファイル見に行くのがめんどくさい

エラー起こったときにわざわざサーバーに見に行くのめんどくさいじゃないですか。
なんでライブラリ[Monolog](https://github.com/Seldaek/monolog)を使ってログファイルに書き出しつつも[Sentry](https://sentry.io/welcome/)へもその内容を飛ばしてスマホからとかでもエラー内容を確認できるようにしてみます

# Monologの導入

## `composer`でインストール

```
$ composer require monolog/monolog
```

※[composer](https://getcomposer.org/)（PHPのパッケージマネージャー）入れてない場合は先に入れてください

## 呼び出しつつ出力先とログレベルを指定する

```index.php
<?php
require_once __DIR__.'/vendor/autoload.php';

$log = new \Monolog\Logger('app');
// ここではログレベルをWARNING以上の場合にログ出すように設定
$log->pushHandler(new \Monolog\Handler\StreamHandler('/app.log', \Monolog\Logger::WARNING));
```

設定できるレベルは以下の通り

> **Log Levels**
> Monolog supports the logging levels described by [**RFC 5424**](http://tools.ietf.org/html/rfc5424).
> 
> **DEBUG** (100): Detailed debug information.
> **INFO** (200): Interesting events. Examples: User logs in, SQL logs.
> **NOTICE** (250): Normal but significant events.
> **WARNING** (300): Exceptional occurrences that are not errors. Examples: Use of deprecated APIs, poor use of an API, undesirable things that are not necessarily wrong.
> **ERROR** (400): Runtime errors that do not require immediate action but should typically be logged and monitored.
> **CRITICAL** (500): Critical conditions. Example: Application component unavailable, unexpected exception.
> **ALERT** (550): Action must be taken immediately. Example: Entire website down, database unavailable, etc. This should trigger the SMS alerts and wake you up.
> **EMERGENCY** (600): Emergency: system is unusable.

（引用：[Using Monolog | monolog](https://seldaek.github.io/monolog/doc/01-usage.html#log-levels)）

# Sentryの導入

## サイトで登録まで済ます

以下から登録する（GitHubアカウントあれば楽です）

- [Sign up for sentry to start your free 14-day trial. | Sentry](https://sentry.io/signup/)

## 発行されたURLを確認する

`https://***********************.ingest.sentry.io/*****`みたいなURLが発行されるので確認しておく

（`Projects`とかの設定も済ませておく）

## PHP SDKを`composer`でインストール

```
composer require sentry/sdk
```

この時点で`composer.json`は以下の感じになってるはず

```composer.json
{
    "require": {
        "monolog/monolog": "^2.2",
        "sentry/sdk": "^3.1",
    }
}

```

# 二つを合わせて実装してみる

上で設定した**Monolog**と**Sentry**を入れて強制的に例外発生させて動きを確認してみます

## 実装例

```index.php
<?php
require_once __DIR__.'/vendor/autoload.php';
// Sentry setup （URLはSentry登録後に発行されるやつを書く）
Sentry\init(['dsn' => 'https://***********************.ingest.sentry.io/*****']);

try {
    // Logger
    $log = new \Monolog\Logger('app');
    $log->pushHandler(new \Monolog\Handler\StreamHandler('/app.log', \Monolog\Logger::WARNING));

    throw new \Exception("テスト用のエラー"); // ここでわざと例外発生させてみます

    return;
} catch (\Throwable $exception) {
    // ログをファイルに出力しつつ
    $log->error($exception);
    // Sentryへも飛ばす
    Sentry\captureException($exception);
}
```

## ログファイルに書き込まれているか確認

↓こんな感じでログファイル（例では`app.log`）に出力される

```app.log
[2021-02-27T12:47:56.704675+09:00] app.ERROR: Exception: テスト用のエラー in C:\work\test\index.php:10 Stack trace: #0 {main} [] []
```

## Sentry上にエラー内容が送信されているか確認

うまくいくと左メニューにある`Issues`に以下のようなエラーが表示される
![c988dbab-7fb4-46c2-bbd6-6bb06618f39a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85815/1a6ff2bf-128d-bdd7-b31d-db9fbfcea483.png)

# おわり
- 自分は遊びで作ったやつに入れたんで特に設定してないですけどSlackとかにも飛ばせるみたいです
- それはそうと久しぶりにPHP書くと楽しかった（こなみかん）

# 参考URL
- [素のPHPでも最低限.envとmonologくらいは使う際の手順 - Qiita](https://qiita.com/zaburo/items/eacde522d36172d6d910)
- [Monolog - Logging for PHP | monolog](https://seldaek.github.io/monolog/)
- [Sentry Documentation | Sentry Documentation](https://docs.sentry.io/)