Firebase の実践的な事例を聞くため Firebase.yebisu #1 に参加してきた

昨日は Firebase.yebisu #1 に参加してきた.最近まで担当していたプロジェクトで FCM (Firebase Cloud Messaging) と Firebase Remote Config を実戦投入して良さを感じていたので,Firestore など,他の機能の話も聞きたいなと思っていた.また,チームメンバーに FCM 導入事例の LT を任せたため,その応援も兼ねていた.僕が普段参加する勉強会は AWS / Ruby / Go 関連が多いため,ネイティブエンジニアが多く集まる会にはあまり参加したことがなく,全然知ってる人がいなくて驚いた(こんなにもクラスタが違うのかぁぁぁ).

connpass.com

Firebase Dev Summit 2017 のはなし / @fumik0i

  • Firebase Dev Summit で新サービスがたくさん発表された
    • A/B Testing
    • Predictions
    • Crashlytics
  • 新サービスの発表だけじゃなく,ベストプラクティスの解説もあった
  • Vue.js + Firebase Hosting を試してみて,簡単にサンプルコードをデプロイすることができた

(資料公開待ち)

Try new Firebase A/B testing / @sgr_ksmt_dev

  • 条件に指定した複数の Remote Config を一気に変更することができる
  • 目標を設定して,コントロールグループごとに効果を見ることができる
  • ターゲットに従来のユーザー属性だけでなく,Predictions の機能を使うこともできる
  • 検証端末などを使う場合は,固定の Instance ID を条件に含めておくと便利
  • FCM と連携をすることもできる

今までも Remote Config を使って A/B のようなことは実現できていたけど,これをコントロールグループとして,統括的に管理できるようになったメリットは大きいと思う.A/B Testing 気になるなぁ!

speakerdeck.com

Way of truly serverless application / miup

  • 完全に BaaS / SaaS に依存した状態を Truly Serverless と定義した
  • Realtime Database のクエリは使いにくく,Firestore でも,まだ複雑なクエリは難しい
  • 結局,クライアントサイドジョインが必要になってしまう
  • 検索を実現するために Realm or Algolia を検討した
  • Cloud Functions を活用して,Algolia にデータを書き込む
  • モバイルエンジニアだけでサービスを作れると素早く動ける

最近個人的に試している Algolia が紹介されていたし,デモアプリも非常によくできていて,良い発表だった.「サーバレス」という言葉は解釈が曖昧で論争が起きることがあり,今回も質疑応答で定義の確認みたいな話が出ていた.

speakerdeck.com

Firebase Realtime Database Design / @1amageek

最後に Realtime Database のデモがあったり,質疑応答で出た「データスキーマのマイグレーションをどうしたら良いか?」という質問に対して「破壊的な変更があるかどうかを考えて,ある場合は,データ構造に v1 / v2 などをバージョンを付与しておく」という回答があるなど,非常に実践的な発表で勉強になった.

(資料公開待ち)

LT : Firestore で負荷試験

  • Firestore の Write は,特定の条件だと 500 per second に制限される?
  • Rocro Loadroid を使って負荷テストをしてみた
  • 実測値ではもっともっと Write はできる
  • ただ,スケールが必要なため,徐々にリクエスト数を上げないと,取りこぼしてしまう場合もあった

(資料公開待ち)

LT : 開発用途で Realtime Databaseを 導入した話

  • Realtime Database を使わないのはもったいない
  • Realtime Database にエラーログを送信し,Cloud Functions を呼び出す
  • 無料プランだと外部サービスにリクエストを飛ばすことができないため,FCM を経由して Slack にリクエストを飛ばしている

speakerdeck.com

LT : Node/SPA エンジニアにとっての富豪的 Firebase Hosting

  • 静的サイトホスティング,認証,列指向 DB があり,簡単にプロトタイピングをしたかった
  • 最近の Firebase では揃ってきた
  • AWS だとツライ
  • Node を Cloud Functions で運用するのはどうか?

speakerdeck.com

Firebase Android SDK Tasks API の直列処理について

speakerdeck.com

LT : Firebaseを利用したプッシュ通知送信基盤の実装

  • Firebase でプッシュ通知を送る場合,Firebase Notification と Firebase Cloud Messaging がある
  • API で操作でき,自由度のある Firebase Cloud Messaging を使っている
  • ただし,トピックを4個以上 & 演算できないなどの制約がある

チームメンバーに FCM 導入事例の LT を任せた.非常にうまく発表をしてて安心したけど,自分が発表するのとは桁違いに緊張した(笑)LT で話せなかった内容は以下の記事にまとめてもらっているので,是非!

developers.cyberagent.co.jp

speakerdeck.com

LT : サーバサイド Swift と FCM

(資料公開待ち)

まとめ

  • Firebase 大好きなエンジニアが多く集まっていて,実践的な事例を聞けて良かった
  • Firebase と言っても機能がたくさんあるので,ちゃんと名称を言わないと「Firebase のどれ?」ってなりそう
  • Realtime Database / Firestore はデータ設計も考えつつ導入してみたい
  • A/B Testing はデモを見た感じだと,すごく良さそうだった

Fluentd / Embulk / Elasticsearch / Digdag を学ぶのに最高な「データ分析基盤構築入門」を読んだ

出版されてから少し時間がたってしまったけど,「データ分析基盤入門」を読み終えた.ページ数が多く,持ち運ぶようなサイズではないので,家でちょこちょこ読み進める感じになってしまって,想定以上に時間がかかってしまった.

データ分析基盤構築入門[Fluentd、Elasticsearch、Kibanaによるログ収集と可視化]

データ分析基盤構築入門[Fluentd、Elasticsearch、Kibanaによるログ収集と可視化]

  • 作者: 鈴木健太,吉田健太郎,大谷純,道井俊介
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/09/21
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

はじめに

目次にも書いてある通り,「データ分析基盤」というテーマで Fluentd / Elasticsearch / Kibana の解説が詳細にまとまっている.さらに付録には Embulk と Digdag の解説もあり,このあたりの技術スタックに興味がある人にとって最高な一冊なのではないかなと思う.また,Elasticsearch / Kibana に関しては Elastic Stack 5.x を前提に書かれているので,昔のバージョンで知識が止まっている人にも良いと思う.

僕自身は Fluentd も Elasticsearch も仕事で運用していて,そこそこ理解できていると思っていたけど,それでも知らないことがあって,たくさん学ぶことができた.特に Elasticsearch 5.x は使ったことがなく,試すことができたし,普段使う機会がない X-Pack を試せたのも良かった.

  • 第1部 データ分析基盤入門
  • 第2部 Fluentd入門
  • 第3部 Elasticsearch入門
  • 第4部 Kibana入門
  • 付録
    • A Fluentdプラグイン事典
    • B Embulk & Digdag入門
    • C Embulkプラグイン事典
    • D Kibanaの便利機能とその他のElastic Stackの紹介

実は Go も学べる

第1部では,Go で実装されたブログアプリケーションを題材に解説が進み,このアプリケーションのバックエンドとして Fluentd / Elasticsearch / Kibana も動いている.Docker Compose で起動をするだけなので,Go のアプリケーションをデバッグしながら学べるし,Go から fluent-logger-golang を使って直接ログを Fluentd に投げている部分も試せるし,いろいろと学べる点がある.デバッグ用途だとしても,比較的環境構築が面倒な Fluentd / Elasticsearch / Kibana をすぐに試せるので,最高すぎる.ちなみに GitHub で公開されている.

github.com

ブログアプリケーションを起動してみる

Makefile が用意されているので,最初は make run だけで良いのかなと思ったけど,僕の環境だとこれだけじゃ動かず,自分なりに手順を用意したので,参考までに載せておこうと思う.

まず Dockerfile-fluentd ファイルを以下のように修正する.

-RUN apt-get -qq update && apt-get install --no-install-recommends -y curl ca-certificates sudo
+RUN apt-get -qq update && apt-get install --no-install-recommends -y curl ca-certificates sudo build-essential libcurl4-gnutls-dev

理由は以下のエラーが出るからで,修正方法が適切かどうかは不安があるけど,ネイティブのライブラリが不足しているってことで,こういう対応をしてみた.

ERROR:  Error installing fluent-plugin-elasticsearch:
    ERROR: Failed to build gem native extension.

    current directory: /opt/td-agent/embedded/lib/ruby/gems/2.1.0/gems/strptime-0.1.9/ext/strptime
/opt/td-agent/embedded/bin/ruby -r ./siteconf20171117-8-1ft7l5r.rb extconf.rb
checking for rb_timespec_now()... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

この状態で,以下のコマンドを実行する.

$ make run

起動は成功するものの,ブラウザで http://localhost にアクセスすると 502 Bad Gateway で動かなかった.なので,Docker Compose を再起動してみると,動くようになった.

$ docker-compose restart

ただし,画面に以下のエラーが出てしまった.

no such table: articles

次にマイグレーションを実行したら,ちゃんと動くようになった.

$ make migrate/up

今度は http://localhost/search にアクセスすると,Elasticsearch のインデックスがなく,エラーになった.ブログ記事を1件でも登録すれば動くので,注意する(本当はインデックスがなくてもエラーにならない方が良いんだけど).

elastic: Error 404 (Not Found): no such index [type=index_not_found_exception]

ということで,あとは好きなように使える!

Fluentd 関連

process_name

実は system ディレクティブで process_name の設定ができることを知らなかった.

<system>
  process_name fluentd
</system>

今まで process_name の設定をしていなかったので,Mackerel でプロセス監視をするときは,以下のように設定していた.

[plugin.checks.check_td-agent]
command = "/usr/bin/check-procs --pattern /usr/sbin/td-agent --user td-agent -C 2"

実際に td-agent.confprocess_name の設定を追加すると,以下のように ps 結果がシンプルになり,supervisor と worker を簡単に区別できるようになった.

$ ps -ef | grep td-agent
td-agent  4396     1  0 07:44 ?        00:00:00 supervisor:fluentd
td-agent  4399  4396  4 07:44 ?        00:00:00 worker:fluentd

よって Mackerel のプロセス監視設定も,以下のように修正することができた.

[plugin.checks.check_td-agent]
command = "/usr/bin/check-procs --pattern fluentd --user td-agent -C 2"

便利!

require_ack_response

Fluentd v0.12 系を運用しているのに require_ack_response を知らなかった.簡単に言えば,TCP レイヤでパケットロストがあったり,受信側を再起動したりするときに,タイミングによってはログを失う可能性があるため,それを解決してくれる.ログ転送の挙動で言えば at-least-once となる.多少のパフォーマンス劣化はあるかもしれないけど,Fluentd Aggregator を再起動することもあるし,入れておくべき設定だと思った.

docs.fluentd.org

Elasticsearch 関連

action.destructive_requires_name

Elasticsearch に /* の DELETE リクエストを投げると全てのインデックスが消える件は知っていて,今まで「絶対打たないように」意識をして運用をしていたけど,それを抑止するための設定があったとは...!もしかしたら最近の Elasticsearch で追加された設定なのかなと思ったら,前に運用をしていた Elasticsearch 1.4 でも使える設定だった.僕が情弱すぎるだけだった.

action.destructive_requires_name: true

text & keyword

僕が運用をしている Elasticsearch のバージョンは 1.4 / 1.7 / 2.3 で,5.x と 6.x は使ったことがなく,リリース内容などを全然把握できていなかった.

今回知ったのは,Elasticsearch 5.x から string 型が廃止され,text 型と keyword 型に切り替わったということだった.今までだと,ログを Kibana で可視化することも考えて,完全一致と部分一致をサポートするために Multi Field などを使っていた.今後は完全一致なら text で,部分一致なら keyword を使えば良いということになる.テンプレートを考える手間が少し減るのは嬉しい.公式ブログにもちゃんと記事が出ていた.

www.elastic.co

Kibana 関連

Kibana は普段よく使っているけど,Elasticsearch 5.x の Kibana は使ったことがなく,デザインが全然違うのに驚いた.さらに,コンテナには30日間なら無料で使える X-Pack が入っているため,今まで使う機会がなかった機能を試せたのも個人的には良かった.Monitoring はあると絶対に便利だし,Elasticsearch 2.x の Kibana だとアラートの機能がなくて困る場面もあるので,Alerting も嬉しい機能だと思う.すぐにバージョンアップをしたくなった.他にも Machine Learning など,楽しそうな機能も使えるようになるので X-Pack はやはり良いなぁー.

  • Monitoring
  • Alerting (Watcher)
  • Graph
  • Machine Learning
  • などなど

Embulk & Digdag 関連

Embulk と Digdag の解説も少し入っていて,今後試そうと思っている人には良さそうだった.Embulk は多少試したことがあるけど,「Embulk プラグイン辞典」を見て,もうこんなにプラグインが出揃ってるのかぁーと驚いた.Fluentd と Embulk を用途によって適切に使い分けたり,cron を Digdag に置き換えたり,まだまだデータ分析基盤を改善できそう.

まとめ

  • Fluentd / Elasticsearch / Kibana / Embulk / Digdag を学べる本ってほぼなくて,興味がある人にとっては最高な一冊だと思う
  • Fluentd は今後だと v0.14 が主流になると思うけど,現時点だと一番メジャーな v0.12 を学べるのも良かった
  • Elasticsearch 2.x はよく使っているけど,Elasticsearch 5.x や Kibana X-Pack を試したことがなかったので,勉強になった
  • 付録も非常に価値ある情報ばかりで,非常に良かった
  • ただちょっと,全体的に誤植が多いような気がしたので,第2版などで直ると良いなぁ...
    • もしまだ出版社側にフィードバックが来てなければ,まとめて送ることもできるっす!

データ分析基盤構築入門[Fluentd、Elasticsearch、Kibanaによるログ収集と可視化]

データ分析基盤構築入門[Fluentd、Elasticsearch、Kibanaによるログ収集と可視化]

  • 作者: 鈴木健太,吉田健太郎,大谷純,道井俊介
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/09/21
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

関連記事

suzuken.hatenablog.jp

事前にデータ投入をした MySQL Docker イメージを作る場合は /docker-entrypoint-initdb.d を活用すると便利

事前にデータ投入をした MySQL Docker イメージが必要になり,最初は「Dockerfile で頑張る感じかなぁ...」なんて考えながら調査をしていたら,公式の MySQL Docker イメージに「カスタムスクリプトを実行する機能」が用意されていることを知って,全て解決した.今までも MySQL を Docker で動かす場面はあったけど,今回の機能は知らなくて勉強になった.

CI で使うためにマイグレーション実行済の MySQL Docker イメージを用意しても良いし,新メンバーのために開発用の初期データを投入した MySQL Docker イメージを用意しても良いし,ハンズオンイベントのためにテストデータを投入した MySQL Docker イメージを用意しても良いと思う.今回の仕組みを知っておくと便利な場面は多そう.

公式の Dockerfiledocker-entrypoint.sh を調べつつ,GitHub の Readme を読んでいたら,今回の機能に気付いた.

After the database is created, the entrypoint script will execute any .sh or .sql scripts found in /docker-entrypoint-initdb.d/ If you wish to execute any custom initialization scripts (e.g. for extra database or user creation), map them to this location the first time you start up the image.

github.com

github.com

動作確認

最初に動作確認をした結果を載せておこうと思う.今回まず Dockerfile と投入データが入った world.sql.gz を用意した.データは MySQL から公開されている world database にした.

.
├── Dockerfile
└── world.sql.gz

Dockerfile はシンプルで,以下のようになる.今回はサンプルとして MySQL 5.7 をベースにし,事前に world.sql.gz を投入しておくような設定にした.ファイルをコンテナ内部の /docker-entrypoint-initdb.d にコピーしている点がポイントで,ここに置いておくだけで,自動的に実行してくれる.

FROM mysql:5.7

COPY world.sql.gz /docker-entrypoint-initdb.d/world.sql.gz

実際にコンテナイメージをビルドして,コンテナを動かしてみると(オプションなどは必要に応じて),正常にデータが投入されていることを確認できた.便利!

$ docker run -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -it kakakakakku/mysql-57-world-database
$ docker exec -it xxxxxxxxxxxx /bin/sh

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| world              |
+--------------------+
5 rows in set (0.00 sec)

mysql> USE world;

mysql> SHOW TABLES;
+-----------------+
| Tables_in_world |
+-----------------+
| city            |
| country         |
| countrylanguage |
+-----------------+
3 rows in set (0.00 sec)

/docker-entrypoint-initdb.d とは?

もう少し /docker-entrypoint-initdb.d の仕組みを調べてみようと思う.まず docker-entrypoint.sh に以下のような実装があった.

for f in /docker-entrypoint-initdb.d/*; do
    case "$f" in
        *.sh)     echo "$0: running $f"; . "$f" ;;
        *.sql)    echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
        *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
        *)        echo "$0: ignoring $f" ;;
    esac
    echo
done

よって,サポートされている拡張子と動作は以下となる.

  • .sh : そのまま実行する
  • .sql : mysql コマンドに流し込む
  • .sql.gz : 解凍してから mysql コマンドに流し込む

拡張子別に試してみた

さらに grant.sqlinit.sh も追加して,全ての拡張子を試してみた.

.
├── Dockerfile
├── grant.sql
├── init.sh
└── world.sql.gz

grant.sql では,以下の通り,新規ユーザーを作成して権限を付与している.

GRANT ALL PRIVILEGES ON world.* TO 'kakakakakku'@'localhost' IDENTIFIED BY 'kakakakakku';

init.sh では,単純に MySQL のバージョンを表示している.

#!/bin/sh

mysql --version

Dockerfile は,以下の通り.

FROM mysql:5.7

COPY init.sh /docker-entrypoint-initdb.d/init.sh
COPY world.sql.gz /docker-entrypoint-initdb.d/world.sql.gz
COPY grant.sql /docker-entrypoint-initdb.d/grant.sql

この状態でコンテナを起動すると,以下のようにログが出力されていて,正常に実行されていた.

/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/grant.sql

/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/init.sh
mysql  Ver 14.14 Distrib 5.7.20, for Linux (x86_64) using  EditLine wrapper

/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/world.sql.gz

新規ユーザーも作成できていた.

mysql> SELECT Host, User FROM mysql.user;
+-----------+-------------+
| Host      | User        |
+-----------+-------------+
| %         | root        |
| localhost | kakakakakku |
| localhost | mysql.sys   |
| localhost | root        |
+-----------+-------------+
4 rows in set (0.00 sec)

実行順序に気を付ける

もし,ファイルの実行順序に依存関係がある場合,今回の仕組みではファイル名の昇順で実行されてしまうため,問題になる場合がある.その場合は Dockerfile で数字などの接頭辞を付けて COPY することで,意図した順番で実行できるようになる.マイグレーションなどは,基本的にファイル名にタイムスタンプなどが入っていると思うので,大丈夫なはず.

FROM mysql:5.7

COPY init.sh /docker-entrypoint-initdb.d/1_init.sh
COPY world.sql.gz /docker-entrypoint-initdb.d/2_world.sql.gz
COPY grant.sql /docker-entrypoint-initdb.d/3_grant.sql

まとめ

  • 事前にデータ投入をした MySQL Docker イメージが必要な場合は /docker-entrypoint-initdb.d を使う
  • .sql だけではなく .sh.sql.gz もサポートしている
  • 実行順序に依存関係がある場合,ファイル名に気を付ける

今回,検証として world database を投入した MySQL Docker イメージを作って Docker Hub に公開してみた.MySQL のハンズオンなどに活用できそう.

github.com

関連記事

2016年に作った MySQL ハンズオン資料でも world database を使ったけど,Homebrew で MySQL をインストールして,データを投入するところから始まるので,ここを Docker イメージで置き換えてあげれば,もっと簡単に進行できそう!

github.com

Jenkins ジョブにタイムアウトを設定できる Build-timeout Plugin を試した

Jenkins で実行中のバッチが,何かしらの原因によって無限ループのような状態に陥ったときに,デフォルトだとタイムアウトのような機構はなく,そのままの状態を維持してしまう.基本的にはバッチ内部で制御するべきだと思うけど,予期せぬ状態になる可能性はあるので,Jenkins 側でタイムアウトの設定ができたら良いなと思って Build-timeout Plugin を検証してみた.

最近のバージョンだと Install suggested plugins に入っている

運用している Jenkins 2.30 の Install suggested plugins に Build-timeout Plugin は入っていなかったけど,今回検証環境として Jenkins 2.73 を構築してみたら,Install suggested plugins に Build-timeout Plugin が入っていた.確かにデフォルトで入っていて良いようなプラグインだと思う.

f:id:kakku22:20171106235037p:plain

Docker で Jenkins をカジュアルに構築する

Docker を使えば,面倒な手順もなくカジュアルに Jenkins を起動できるので本当に便利.以下のコマンドで起動すれば http://localhost:8080/ でアクセスすることができる.

# Jenkins を起動する
$ docker run -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts
 
# コンテナ ID を確認して initialAdminPassword を確認しておく
$ docker ps
$ docker exec -it xxxxxxxxxxxx cat /var/jenkins_home/secrets/initialAdminPassword

タイムアウト設定

Build-timeout Plugin では,計5種類のタイムアウト設定の中から選ぶことができる.どの設定も意図が異なるため,バッチの特性に応じて適切に選ぶ必要がある.個人的にどのように使うかをまとめてみた.

  • 一定の経過時間
    • 「タイムアウト(分)」を指定して,それまでにジョブが終わらなければ,タイムアウトになる
    • 確実に異常であると判断できる時間があれば,使えそう
    • ただし,定期的に実行時間がスパイクするようなバッチの場合,より大きなタイムアウトを設定する必要がある
  • デッドライン
    • 例えば「業務的に朝9時までに終わらせる必要がある」など,時間的なデッドラインがある場合に使える
  • ビルドの予測最大時間との比較
    • カスタマイズできる設定はなく,プラグイン側で「過去の実行結果と比べて極端に長い」と判断できる場合に,タイムアウトになる
    • 実装を読んでみないと,どういうロジックなのかはわからないけど,実行時間が一定に保たれるジョブなどは相性が良さそう
  • 最後のログの出力からの経過時間
    • 「タイムアウト(秒)」を指定して,ジョブのコンソールログが出なくなった時間で,タイムアウトになる
    • ジョブの中で INFO ログなどを定期的に出す前提であれば,使えそう
  • 過去のビルド時間との比較
    • 「過去の成功ビルド」の平均時間よりも「長くなっている」場合,タイムアウトになる
    • 「過去何回か」を設定することもできる
    • 「長くなっている」を判断する設定として「150% / 200% / 250% / 300% / 350% / 400%」の中から選ぶことができる

設定例

「一定の経過時間」を設定例を以下に載せる.なお「タイムアウト時間の保存先」を設定しておくと,タイムアウト時間を環境変数から取れるようになる.ただし,単位が違って「ミリ秒」なので注意する必要がある.

f:id:kakku22:20171106235110p:plain

まとめ

  • Jenkins を使うときは,ジョブにタイムアウトを設定しておくと安心できる場合がある
  • 最近の Jenkins だと Install suggested plugins に Build-timeout Plugin が入っている
  • 計5種類のタイムアウト設定があるので,ジョブの特性によって選ぶことができる

fluent-logger-golang を使って Go で Fluentd にログを転送する

Fluentd でログを収集する場合,例えば nginx のアクセスログであれば in_tail で転送したりするけど,アプリケーションログなら選択肢として in_tail だけじゃなくて in_forward もある.アプリケーションから直接 Fluentd にログを転送できる in_forward を知らない人が案外いるなーという印象があって,知っておくと便利なので,簡単にまとめておこうと思う.

docs.fluentd.org

fluent-logger-golang

今回は Go で使える fluent-logger-golang を紹介する.

github.com

README.md にサンプルコードが載っている通り,簡単に Go から Fluentd にログを転送することができる.logger.Post() は自動的に現在時刻を設定するが,もし意図的な時刻を設定したい場合は logger.PostWithTime() を使う.また fluent.New(fluent.Config{}) はデフォルト設定にしていて,必要に応じて fluent.New(fluent.Config{FluentHost: "127.0.0.1", FluentPort: 24224}) のように設定することができる(今回はローカル環境に Fluentd を用意した).

package main

import (
    "fmt"

    "github.com/fluent/fluent-logger-golang/fluent"
)

func main() {
    logger, err := fluent.New(fluent.Config{})
    if err != nil {
        fmt.Println(err)
    }
    defer logger.Close()

    tag := "app.sample"
    var data = map[string]string{
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
    }

    // ログを転送する
    err = logger.Post(tag, data)
    if err != nil {
        fmt.Println(err)
    }
}

なお logger.Post()logger.PostWithTime() もログとしては interface{} を受けるため,struct をそのままログとして流すこともできる.アプリケーションの要件次第で使い分ければ良いかと.

package main

import (
    "fmt"

    "github.com/fluent/fluent-logger-golang/fluent"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    logger, err := fluent.New(fluent.Config{})
    if err != nil {
        fmt.Println(err)
    }
    defer logger.Close()

    tag := "app.sample"
    var data = Person{"Bob", 20}

    // ログを転送する
    err = logger.Post(tag, data)
    if err != nil {
        fmt.Println(err)
    }
}

動作確認

サクッと動作確認をする場合は,Docker で Fluentd を上げてしまうのが良いかと思う.

github.com

イメージを pull して,以下のように起動する.

$ docker run -d -p 24224:24224 -p 24224:24224/udp -v ~/fluentd:/fluentd/log fluent/fluentd

デフォルトで in_forward の設定が入っているので,アプリケーションを実行するだけで,動作確認をすることができる.

<source>
  @type  forward
  @id    input1
  @label @mainstream
  port  24224
</source>

実際に以下のように出力された.

20171103T043957+0000 app.sample  {"key1":"value1","key2":"value2","key3":"value3"}
20171103T044808+0000    app.sample  {"Name":"Bob","Age":20}

まとめ

アプリケーションログなど,ログの特性によっては in_tail よりも in_forward の方が便利な場合があるので,知っておくと便利だと思う.Go の場合は fluent-logger-golang を使うと簡単に実装することができる.今回,記事を書きながら README.md を見ていたら,サンプルコードの実装が間違っていたので,修正プルリクを出しておいた.

github.com