Flutterでのloggerの扱い方について

#### 環境

```zsh
Flutter 2.5.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 3595343e20 (6 days ago) • 2021-09-30 12:58:18 -0700
Engine • revision 6ac856380f
Tools • Dart 2.14.3
```

#### 経緯

- 機能拡張によってアプリのログが流れ過ぎているため、改善を図りたい。
- `leisim/logger`を使っていたが文字化けして一部の絵文字が見にくくなって放置状態だったが、`colors: false`にすれば問題なくなった
    - https://github.com/leisim/logger/issues/61
    - https://github.com/leisim/logger/issues/2

#### コードと作法

- [logger](https://qiita.com/quqjp/items/8e42f3479da3b8a905ee)のpub使う、printは基本コミットしない
- バグ・スローされたwarningに気付きやすくするため、残しておきたいlogと機能開発のためのlogで分ける
    - 残しておきたいlogは `Log.log('message');` で一行表示が無難
        - 変数だけログに流すと、`Log.log('message');`　どこに書いてるか分からない問題が出てくるので
        - `Log.log('message: $description');`が親切で良い
    - 機能開発時には、`logger.d('message');`とかを仕込む。
        - emojiとStackTraceが表示されて気持ちいい :fire: 
 

```dart:message.dart
final message = 'message';

Log.log(message); // 1行の方が探しやすい, printは使わない

// methodCountが2の方が扱いやすい
// エラー以外はコミットしない
logger.d(message);
logger.v(message);
logger.wtf(message);
logger.i(message);
logger.w(message);
logger.e(message);

// error, stacktraceを拾う時分かりやすくて、API仕様ミス等で気づきやすい
logger.e('$e, $s');

// loggerと併用しようかなと思ったけど、ダサめなので没
loggerTemp.d(message);
loggerTemp.v(message);
loggerTemp.wtf(message);
loggerTemp.i(message);
loggerTemp.w(message);
loggerTemp.e(message);
// ただ特定の機能カテゴリを流したい場合にありかも
loggerNotification.d(message);

// 文字化けする、つらい
loggerSimple.d(message);
loggerSimple.v(message);
loggerSimple.wtf(message);
loggerSimple.i(message);
loggerSimple.w(message);
loggerSimple.e(message);
```

![screenshot_iMac_Mini 2021-10-06 16.50.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14262/b3fee362-d906-330c-05b0-83c338a7d410.png)

```dart:log.dart
// Package imports:
import 'package:logger/logger.dart';

// Project imports:
import 'package:my_app/flavors.dart';

class Log {
  static void log(Object? obj) {
    if (F.isDev) print(obj);
  }
}

/// Simple logger
var logger = Logger(
  printer: PrefixPrinter(
    PrettyPrinter(colors: false, methodCount: 0),
  ),
);

/// For debug
/// 機能開発のDebugで使用し、コミットに入れない
var loggerTemp = Logger(
  printer: PrefixPrinterTemp(
    PrettyPrinter(colors: false),
  ),
);

var loggerSimple = Logger(
  printer: SimpleLogPrinter(''),
);
// SimpleLogPrinter

/// To modify Log color
/// - https://github.com/leisim/logger/issues/2#issuecomment-626137273
class PrefixPrinter extends LogPrinter {
  PrefixPrinter(this._realPrinter,
      {debug, verbose, wtf, info, warning, error, nothing})
      : super() {
    _prefixMap = {
      Level.debug: debug ?? '  DEBUG ',
      Level.verbose: verbose ?? 'VERBOSE ',
      Level.wtf: wtf ?? '    WTF ',
      Level.info: info ?? '   INFO ',
      Level.warning: warning ?? 'WARNING ',
      Level.error: error ?? '  ERROR ',
      Level.nothing: nothing ?? 'NOTHING',
    };
  }

  final LogPrinter _realPrinter;
  Map<Level, String>? _prefixMap;

  @override
  List<String> log(LogEvent event) {
    return _realPrinter
        .log(event)
        .map((s) => '${_prefixMap?[event.level]}$s')
        .toList();
  }
}

class PrefixPrinterTemp extends LogPrinter {
  PrefixPrinterTemp(this._realPrinter,
      {debug, verbose, wtf, info, warning, error, nothing})
      : super() {
    _prefixMap = {
      Level.debug: debug ?? '  DEBUG ',
      Level.verbose: verbose ?? 'VERBOSE ',
      Level.wtf: wtf ?? '    WTF ',
      Level.info: info ?? '   INFO ',
      Level.warning: warning ?? 'WARNING ',
      Level.error: error ?? '  ERROR ',
      Level.nothing: nothing ?? 'NOTHING',
    };
  }

  final LogPrinter _realPrinter;
  Map<Level, String>? _prefixMap;

  // TEMPだけでなく、token/notification/remote_configなどのクラスを仕込んで、特定のカテゴリのアウトプットを生やすのもあり
  @override
  List<String> log(LogEvent event) {
    return _realPrinter
        .log(event)
        .map((s) => '${_prefixMap?[event.level]} TEMP $s')
        .toList();
  }
}

class SimpleLogPrinter extends LogPrinter {
  SimpleLogPrinter(this.className);
  final String className;

  @override
  List<String> log(LogEvent event) {
    final color = PrettyPrinter.levelColors[event.level] ?? AnsiColor.none();
    final emoji = PrettyPrinter.levelEmojis[event.level];
    return [color('$emoji [$className]: ${event.message}')];
  }
}

```