Fluentdを利用してS3にPythonログを収集する
Fluentd のインストール
td-agent をインストールするか、または Ruby gem(pip に似ている)で fluentd という gem をインストールします。
td-agent は Fluentd の配布パッケージです。Fluentd gem 以外、fluent-plugin-s3 などのいくつかのプラグインもあらかじめインストールされています。
- Amazon Linux 2 で td-agent をインストール:
    $ curl -L https://toolbelt.treasuredata.com/sh/install-amazon2-td-agent4.sh | sh
- 起動:
    $ sudo systemctl start td-agent.service詳細については、公式ドキュメント を参照してください。 
Python アプリから Fluentd にログを送信するには、fluent-logger-python ライブラリをインストールします。
$ pip install fluent-logger
Fluentd 側の設定
Fluentd の設定ファイル /etc/td-agent/td-agent.conf を編集します。
- source ディレクティブ:入力ソースを指定します
- match ディレクティブ:出力先を指定します
入力ソースは in_forward プラグインを指定し、TCP ソケットをリッスンして Python のログイベントを受信します。
出力先は out_s3 プラグインを利用して、ログをS3に集約します。
tag が webapi.* パターンに一致するタグが出力対象となります。
<source>
  @type forward
  @id input_forward
  bind 127.0.0.1
  port 24224
</source>
<match webapi.*>
  @type s3
  s3_bucket BUCKET_NAME
  s3_region ap-northeast-1
  path logs/%Y/%m/%d/${tag[0]}/${tag[1]}_
  <buffer tag,time>
    @type file
    path /var/log/td-agent/s3/webapi
    timekey 10m  # write in chunks every 10mins
    timekey_wait 3m  # flush delay
    timekey_zone Asia/Tokyo
    chunk_limit_size 256m
  </buffer>
  time_slice_format %H%M
</match>Pythonアプリ側の設定
fluent-logger-python は FluentHandler というロギングハンドラーを提供しています。
以下は YAML で記述された logging 設定ファイルの例です。
version: 1
formatters:
  standard:
    format: '%(asctime)0.19s %(name)s [%(levelname)s]: %(message)s'
  fluent_fmt:
    '()': fluent.handler.FluentRecordFormatter
    format:
      name: '%(name)s'
      level: '%(levelname)s'
      hostname: '%(hostname)s'
handlers:
  console:
    class: logging.StreamHandler
    level: INFO
    formatter: standard
    stream: ext://sys.stdout
  webapi_fluentd_handler:
    class: fluent.handler.FluentHandler
    host: 127.0.0.1  # ホストを指定します
    port: 24224  # ポート番号を指定します
    tag: webapi.test  # Fluentd がマッチできるようなタグを付けます
    formatter: fluent_fmt
    level: INFO
root:
  level: INFO
  handlers: [console]
  propagate: no
loggers:
  webapi:
    level: INFO
    handlers: [console, webapi_fluentd_handler]
    propagate: no以上の設定を読み込んで logging.config.dictConfig() に渡します。
import yaml
import logging
import logging.config
def custom_logger(name, yml_fp):
    with open(yml_fp) as f:
        config = yaml.safe_load(f)
    try:
        logging.config.dictConfig(config)
    except Exception as e:
        raise e
    logger = logging.getLogger(name)
    return logger