株式会社クリアコード > ククログ

ククログ


fluent-bitからGrafana Lokiに転送するには

はじめに

fluent-bitはFluentdファミリーを構成するソフトウェアの一つです。
fluent-bitはGo Pluginプロキシが提供されており、Golangにて共有ライブラリを作成することにより、プラグインとして振る舞わせることのできるインターフェースが提供されています。
この機能については、fluent-bit-go-s3とfluent-bitのGo Pluginプロキシの話でも解説しました。
FluentBitのGolang製のプラグインのDockerfileを作った話にて突然fluent-bit-go-lokiプラグインが登場してしまっていたので、そのプラグインについての解説を書きます。

Grafana Lokiとは

Lokiとは、Grafanaの新しく開発されたデータソースです。
Lokiにはログを入力するためのAPIが整備されています。

Lokiにレコードを送信するには

ログをPushするのであればPOST /api/prom/pushがAPIのエンドポイントになります。

このAPIのエンドポイントにはJSONまたはProtocol BufferでログをPushできます。
JSON形式でログをLokiに送るにはlabelsを用意するのが少々面倒だったため、fluent-bit-go-lokiではProtocol Bufferでやり取りを行うLokiのクライアントライブラリを使用することにしました。

これをGolangのコードで表現すると次のようになります。

package main

import "github.com/grafana/loki/pkg/promtail/client"
import "github.com/sirupsen/logrus"
import kit "github.com/go-kit/kit/log/logrus"
import "github.com/cortexproject/cortex/pkg/util/flagext"
import "github.com/prometheus/common/model"

import "fmt"
import "time"

func main() {
	cfg := client.Config{}
	// Init everything with default values.
	flagext.RegisterFlags(&cfg)
	var clientURL flagext.URLValue

	url := "http://localhost:3100/api/prom/push"
	// Override some of those defaults
	err := clientURL.Set(url)
	if err != nil {
		fmt.Println("Failed to parse client URL")
		return
	}
	cfg.URL = clientURL
	cfg.BatchWait = 1
	cfg.BatchSize = 10 * 1024

	log := logrus.New()

	loki, err := client.New(cfg, kit.NewLogrusLogger(log))

	line := `{"message": "Sent from Golang!"}`

	labelValue := "from-golang"
	labelSet := model.LabelSet{"lang": model.LabelValue(labelValue)}
	err = loki.Handle(labelSet, time.Now(), line)
	if err != nil {
		fmt.Println("Failed to send Loki")
	} else {
		fmt.Println("Success")
	}
	// Ensure to send record into Loki.
	time.Sleep(3 * time.Second)
}

このLoki向けのクライアントライブラリはバッチ単位で送るため、Handleを呼び出してもすぐにはLokiのAPIエンドポイントには送られないことに注意してください。

fluent-bitのGolang製のプラグインでLokiへイベントを送る

前節でLokiへアクセスするためのGolangのクライアントライブラリの使い方が分かったので、実際にfluent-bit-go-lokiへ組み込んでみます。
FLBPluginInitでLokiにアクセスするための設定を組み立て、FLBPluginFlushでLokiに一行づつイベントを送信するためのバッファに溜めています。
また、fluent-bitのレコードの情報を余さずLokiに送信するためにJSONへエンコードし直しています。

package main

import "github.com/fluent/fluent-bit-go/output"
import "github.com/grafana/loki/pkg/promtail/client"
import "github.com/sirupsen/logrus"
import kit "github.com/go-kit/kit/log/logrus"
import "github.com/prometheus/common/model"
import "github.com/cortexproject/cortex/pkg/util/flagext"
import "github.com/json-iterator/go"

import (
	"C"
	"fmt"
	"log"
	"time"
	"unsafe"
)

var loki *client.Client
var ls model.LabelSet

//export FLBPluginRegister
func FLBPluginRegister(ctx unsafe.Pointer) int {
	return output.FLBPluginRegister(ctx, "loki", "Loki GO!")
}

//export FLBPluginInit
// (fluentbit will call this)
// ctx (context) pointer to fluentbit context (state/ c code)
func FLBPluginInit(ctx unsafe.Pointer) int {
	// Example to retrieve an optional configuration parameter
	url := output.FLBPluginConfigKey(ctx, "url")
	var clientURL flagext.URLValue
	err := clientURL.Set(url)
	if err != nil {
		log.Fatalf("Failed to parse client URL")
	}
	fmt.Printf("[flb-go] plugin URL parameter = '%s'\n", url)

	cfg := client.Config{}
	// Init everything with default values.
	flagext.RegisterFlags(&cfg)

	// Override some of those defaults
	cfg.URL = clientURL
	cfg.BatchWait = 10 * time.Millisecond
	cfg.BatchSize = 10 * 1024

	log := logrus.New()

	loki, err = client.New(cfg, kit.NewLogrusLogger(log))
	if err != nil {
		log.Fatalf("client.New: %s\n", err)
	}
	ls = model.LabelSet{"job": "fluent-bit"}

	return output.FLB_OK
}

//export FLBPluginFlush
func FLBPluginFlush(data unsafe.Pointer, length C.int, tag *C.char) int {
	var ret int
	var ts interface{}
	var record map[interface{}]interface{}

	dec := output.NewDecoder(data, int(length))

	for {
		ret, ts, record = output.GetRecord(dec)
		if ret != 0 {
			break
		}

		// Get timestamp
		timestamp := ts.(output.FLBTime).Time

		js, err := createJSON(timestamp, record)
		if err != nil {
			fmt.Errorf("error creating message for Grafana Loki: %v", err)
			continue
		}

		err = loki.Handle(ls, timestamp, string(js))
		if err != nil {
			fmt.Errorf("error sending message for Grafana Loki: %v", err)
			return output.FLB_RETRY
		}
	}

	// Return options:
	//
	// output.FLB_OK    = data have been processed.
	// output.FLB_ERROR = unrecoverable error, do not try this again.
	// output.FLB_RETRY = retry to flush later.
	return output.FLB_OK
}

func createJSON(timestamp time.Time, record map[interface{}]interface{}) (string, error) {
	m := make(map[string]interface{})

	for k, v := range record {
		switch t := v.(type) {
		case []byte:
			// prevent encoding to base64
			m[k.(string)] = string(t)
		default:
			m[k.(string)] = v
		}
	}

	js, err := jsoniter.Marshal(m)
	if err != nil {
		return "{}", err
	}

	return string(js), nil
}

//export FLBPluginExit
func FLBPluginExit() int {
	loki.Stop()
	return output.FLB_OK
}

func main() {
}

このファイルをout_loki.goとして保存します。
依存関係のパッケージを準備した後*1、以下のコマンドを実行するとfluent-bit用のLokiプラグインの振る舞いをする共有オブジェクトが作成できます。

$ go build -buildmode=c-shared -o out_loki.so .
Golang製のプラグインの動かし方

fluent-bitのGolang製の共有オブジェクトのプラグインを動かすには例えば、以下のような設定ファイルとコマンドが必要です。

[INPUT]
    Name cpu
    Tag  cpu.local
    # Interval Sec
    # ====
    # Read interval (sec) Default: 1
    Interval_Sec 1

[OUTPUT]
    Name  loki
    Match *
    Url http://localhost:3100/api/prom/push
$ fluent-bit -c /path/to/fluent-bit.conf -e /path/to/out_loki.so

fluent-bitが以下のようなログを吐き出していれば読み込みに成功して動作しています。


Fluent Bit v1.2.2
Copyright (C) Treasure Data

[2019/07/31 12:15:20] [ info] [storage] initializing...
[2019/07/31 12:15:20] [ info] [storage] in-memory
[2019/07/31 12:15:20] [ info] [storage] normal synchronization mode, checksum disabled, max_chunks_up=128
[2019/07/31 12:15:20] [ info] [engine] started (pid=13346)
[flb-go] plugin URL parameter = 'http://localhost:3100/api/prom/push'
[2019/07/31 12:15:20] [ info] [sp] stream processor started
まとめ

fluent-bitのGo製の共有オブジェクトでのプラグインについてまとまった解説を書きました。
実際のfluent-bit-go-lokiはlabelSetsが複数指定できるようになっていたり、テストが書きやすいようにfluent-bitが関わる部分をinterfaceに分離しています。*2
Golangでもfluent-bitのプラグインを書くことが出来ますからぜひ試してみてください。

*1 筆者は執筆時点ではGolangの依存関係を管理するパッケージマネージャーはdepを使用しています。depでの依存パッケージの管理の開始方法はdepのドキュメントを参照してください。

*2 実際のコードはGitHubリポジトリを参照してください。

タグ: Fluentd
2019-07-31

FluentBitのGolang製のプラグインのDockerfileを作った話

はじめに

fluent-bitはFluentdファミリーを構成するソフトウェアの一つです。
fluent-bitはGo Pluginプロキシが提供されており、Golangにて共有ライブラリを作成することにより、プラグインとして振る舞わせることのできるインターフェースが提供されています。
この機能については、fluent-bit-go-s3とfluent-bitのGo Pluginプロキシの話でも解説しました。

最近はDockerイメージ上での問題が報告される事が多くなって来たので、Dockerfileを眺めている事が多くなりました。

Golang製のツールをビルドするDockerfileの書き方

Golangはコンパイルをしなければ動作しない静的型付きの言語です。
また、Golangの実行バイナリは使用したライブラリを静的にリンクしています。*1
このことが、libcすら何もないLinuxのユーザーランドでのGolang製の実行バイナリを実行することを可能にしています。

Golangのコードをビルドするのに必要なツールチェインが揃っているDockerイメージがDockerHubで提供されています。

例えば、GolangのGOPATHを指定してビルドするDockerfileの例は次のようになります。

FROM golang:1.12.7-stretch
ENV GOOS=linux
ENV GOARCH=amd64
ENV GOPATH=/go
ADD . /go/src/path/to/githubrepo
WORKDIR /go/src/path/to/githubrepo
RUN go build .

Golang製の共有オブジェクトをDockerイメージに載せるには

Golangから作成した共有オブジェクトは基本的に共有ライブラリへの依存が少ないため、Golangのコンパイラで作成された実行ファイルや共有オブジェクトは更に別のDockerfileへコピーして載せることが容易です。
また、最近のDockerではmulti stage buildという機能が入っているため、Dockerfileを多段階に組み合わせることなく一つのDockerfileで多段階のDockerイメージのビルドができるようになっています。

では、ここまでの背景知識を元に、筆者が作成しているfluent-bit-go-lokiプラグインの実例*2を出しつつ解説します。

Golangの共有ライブラリをビルドするには前述のGolangツールチェインがインストールされているイメージを使います。また、fluent-bit-go-lokiは共有ライブラリをCGOを経由して作成するため、それに必要な環境変数も有効にしておきます。


FROM golang:1.12.7-stretch AS build-env
ENV CGO_ENABLED=1
ENV GOOS=linux
ENV GOARCH=amd64
ENV GOPATH=/go
ADD . /go/src/github.com/cosmo0920/fluent-bit-go-loki
WORKDIR /go/src/github.com/cosmo0920/fluent-bit-go-loki
RUN go build -buildmode=c-shared -o out_loki.so .

out_loki.soの作成に必要なCGO_ENABLED=1, GOOS=linux, GOARCH=amd64, GOPATH=/goの設定が完了しました。
後の三行はout_loki.soをビルドするのに必要なディレクトリ構造を整える行と、ワーキングディレクトリの設定と、実際にビルドを行う行です。

ここで、FROM golang:1.12.7-stretch AS build-envとして、このout_loki.soをビルドするイメージをbuild-envという別名をつけている事に注意してください。この名前はビルドパイプラインの後で使用する事になります。

前段のパイプラインの成果物のout_loki.soをただコピーしてfluent/fluent-bit:1.2イメージ*3から派生させています。

作成したout_loki.soのシステムの共有ライブラリの依存関係を見ると、

% ldd out_loki.so
	linux-vdso.so.1 (0x00007ffc58381000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd36a51d000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd36a35c000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fd36bc46000)

となるため、libc相当の共有ライブラリがシステムに居れば十分に動作させることができそうです。
ここでは、fluent/fluent-bit:1.2がgcr.io/distroless/ccイメージを利用しており、このイメージ内に必要なライブラリが揃っていると見做すことで問題なさそうです。

FROM fluent/fluent-bit:1.2
COPY --from=build-env /go/src/github.com/cosmo0920/fluent-bit-go-loki/out_loki.so /usr/lib/x86_64-linux-gnu/
# ...

これらと、fluent-bit-go-lokiプラグインの実行に必要なエントリポイントについてはfluent-bit-go-lokiプラグインのDockerfileを参照してください。

まとめ

このようなイメージの作成の仕方をする事でGolangの実行バイナリや共有オブジェクトのみを載せたサイズが軽量となるイメージを作成することができます。
Golang製のツールをDockerイメージに載せるこの方法は始めはなんてまどろっこしい方法を取るんだ!と思っていたら、実行ファイルとその実行に必要な共有オブジェクトのみにしておける利点がある事がわかり腑に落ちました。
Dockerfileを書く事ができればDocker上にデプロイするのは非常に簡単なのでDocker上でもガンガンFluentdファミリーでログを収集してみてください。

*1 https://golang.org/doc/faq#Why_is_my_trivial_program_such_a_large_binary

*2 LokiはGrafanaの新しく開発されたデータソースです。

*3 fluent-bitのイメージはlibc, libgcc程度しか入っていない軽量イメージから派生しています。

タグ: Fluentd
2019-07-30

winevt_c gemを開発をした話

はじめに

Windows EventLogをRubyで取得するには元々win32-eventlog gemがありました。
このgemはWindows EventLogへ読み込みと書き込みができるものです。
ただし、文字コードに関してはCP_ACP(Windowsの初期コードページ)を使っていたため、日本語版WindowsではCP932(Windows-31J)の範囲内の文字列しか読み込むことができませんでした。

エンコーディングをより正確に扱うには?

Windows APIではchar *wchar *を相互に変換するAPIを提供しています。

どの関数も先ず変換先の文字列を長さを取得してから再度取得した変換先の文字列の長さを用いてchar *wchar *の変換を行います。

winevt_c gemでは、wchar *からRubyのUTF8の文字列を作成する関数を多用しました。

VALUE
wstr_to_rb_str(UINT cp, const WCHAR *wstr, int clen)
{
    VALUE vstr;
    CHAR *ptr;
    int len = WideCharToMultiByte(cp, 0, wstr, clen, nullptr, 0, nullptr, nullptr);
    ptr = ALLOCV_N(CHAR, vstr, len);
    WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, nullptr, nullptr);
    VALUE str = rb_utf8_str_new_cstr(ptr);
    ALLOCV_END(vstr);

    return str;
}

この関数は任意のコードページを指定できるようにしていますが、winevt_cでは基本的にCP_UTF8(UTF8のコードページ)を指定して呼び出しています。

VALUE utf8str;
// some stuff.
utf8str = wstr_to_rb_str(CP_UTF8, <Wide Char Result>, -1);

Windows EventLogの新しいAPI

Windows Vistaより、Windows EventLogを読み取る新しいAPIが提供されています。
winevt_c gemではこのAPIを用いてRubyからWindows EventLogを読み込めるように実装しました。

EvtFormatMessageを用いたEventLogのメッセージの取得方法

EvtFormatMessageを用いると、EventLogのメッセージがWindowsの組み込みの管理ツールであるイベントビューアで取得できるメッセージと同じものが取得できます。winevt_cでは、get_message関数内でEvtFormatMessageを使用しています。このEvtFormatMessage関数の引数のFlagsEvtFormatMessageEventを指定しているところがポイントです。

winevt_cの現状

winevt_cはfluent-plugin-windows-eventlogに新しく実装したin_windows_eventlog2のWindows EventLogを取得するメソッドを中心に実装しています。そのため、現状では以下の機能は実装されていません。

  • リモートにあるWindowsの認証情報を作成し、リモートのWindowsにあるWindows EventLogを取得する
  • 指定したWindows EventLogのチャンネルからevtxファイルとしてエクスポートする
  • チャンネルのメタデータや設定をRubyから取得する関数

まとめ

fluent-plugin-windows-eventlogのin_windows_eventlog2を実装するにあたって作成したwinevt_c gemについて簡単に解説しました。この記事はFluentd meetup 2019でWindows EventLogに関するプラグイン回りの発表した話では軽くしか触れられていないwinevt_cの役割と、現状を解説する目的で執筆しました。winevt_c gem単体ではWindows EventLogはXMLで取得され、中身を見るためにはXMLのパースが現状では必要になってしまいますが、RubyでWindows EventLogを扱う方法の一つとして検討してみてください。

タグ: Fluentd
2019-07-25

Fluent-bit-go-s3とfluent-bitのGo Pluginプロキシの話

はじめに

fluent-bitはFluentdファミリーを構成するソフトウェアの一つです。
fleunt-bitのWindows対応はプラグインの対応だけではなく、Go Pluginプロキシについても対応を行っています。

fluent-bitのGo Pluginプロキシはv1.1.0からWindowsでも利用可能です。

fluent-bitのGo Pluginプロキシとは

fluent-bitは共有オブジェクトファイルを読み込んでOutputプラグインとして振る舞わせることができます。

例えば、Golangを使って共有オブジェクトファイルを作成する場合のコードは以下のようになります。

package main

import "github.com/fluent/fluent-bit-go/output"

//export FLBPluginRegister
func FLBPluginRegister(def unsafe.Pointer) int {
    // Gets called only once when the plugin.so is loaded
	return output.FLBPluginRegister(ctx, "gskeleton", "Hey GO!")
}

//export FLBPluginInit
func FLBPluginInit(plugin unsafe.Pointer) int {
    // Gets called only once for each instance you have configured.
    return output.FLB_OK
}

//export FLBPluginFlushCtx
func FLBPluginFlushCtx(ctx, data unsafe.Pointer, length C.int, tag *C.char) int {
    // Gets called with a batch of records to be written to an instance.
    return output.FLB_OK
}

//export FLBPluginExit
func FLBPluginExit() int {
	return output.FLB_OK
}

func main() {
}

このコードを用いて以下のようにするとGolangで共有オブジェクトを作成することができます。

$ go build -buildmode=c-shared -o out_skeleton.so .

GolangをOutputプラグインに使う利点

Golangでfluent-bitのOutputプラグインに使う利点はC言語向けには提供されていないライブラリであり、Golang向けには提供されているライブラリが使用できることです。
例えば、Golang向けにはAWS SDKが提供されています。

このSDKを用いてfluent-bitからAWSのサービスへ直接接続することができます。

Golang製fluent-bitプラグインの例

Golang製のfluent-bitプラグインの例として、AWS S3へfluent-bitから直接接続できるようにするプラグインを実際に作成しました。
GolangはWindowsではdllを作成することが可能です。Windows向けのDLLに関してはリリースページに置いてあります。

まとめ

fluent-bitのGo Pluginプロキシとその実例を紹介しました。Golang製であれば共有オブジェクトとしてもさほど依存が含まれません。
例として、Debian 10上でGo 1.12.7でビルドした場合には以下の参照が共有オブジェクトへ含まれます。

% ldd out_s3.so
	linux-vdso.so.1 (0x00007ffd615ca000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f6e182a3000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6e180e2000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f6e19933000)

fluent-bitのGolang製のプラグインという選択肢が増えたことにより、AWS SDKを使ってAWSのサービスへ直接接続するプラグインを開発することが出来るようになりました。
依存ライブラリもGolangのみであれば一つのソースでWindowsで動くDLLの作成やLinuxで動作する共有オブジェクトの作成や、macOSでの動的ロードライブラリの作成ができます。そしてそれらをfluent-bit読み込ませて動かすことができます。ぜひ試してみてください。

タグ: Fluentd
2019-07-24

Fluent Bitプロジェクトの概要とWindows対応

2019年7月17日に3年ぶりとなるFluentd Meetupが開催されました (Webサイト)。クリアコードからは、筆者(藤本)を含めて2名がスピーカーとして参加しました。

私のパートでは、現在取り組んでいるFluent Bitプロジェクトについてお話ししました。大きなテーマは、今年の春に追加された「Fluent BitのWindows対応」ですが、そもそもFluent Bitが(まだ)それほど日本では広まっていないので、前提となるプロジェクトの基礎知識を含めてお話しました。

今回のトークのサマリーは次の通りです。

  • この数年で、アプリケーションのログ管理は格段に難しくなっています。この一つの要因には、マイクロサービスや仮想化の進展があり、監視の対象となるログの数そのものが増えているという事情があります。
  • 私たちは、この問題を解決するためにFluent Bitを開発しています。これはCで書かれた高速なログ転送デーモンで、このプログラムを使うことで、様々なサービス間で効率よくログを転送することができます。
  • このトークでは、プロジェクトの最近のサポートアーキテクチャ拡張(Windows対応)を含めて、Fluent Bitの要旨をご説明します。

全文付きのスライドはこちらに掲載しています。

http://ceptord.net/20190717-FluentdMeetup.html

とくに予備知識のないエンジニアをターゲットにトークを組み立てたので、ログ管理まわりのエコシステムに興味があればぜひご参考にどうぞ。


今回の発表にあたって、イベントに招いてくださったArm Treasure Dataの中川さんとEduardo Silvaさんに感謝いたします。

タグ: Fluentd
2019-07-19

Fluentd meetup 2019でWindows EventLogに関するプラグイン回りの発表した話

先日OSS Summitの共催イベントのFluentd meetupでWindows EventLogに関するプラグイン回りの発表をしてきた畑ケです。

関連リンク:

経緯

Windows EventLogを取得したい要望がありました。
検討した結果、例えば以下の問題があることが分かりました。

  • fluent-plugin-windows-eventlogに含まれているin_windows_eventlogが時折SEGVする問題
  • WindowsのANSIコードページを超える文字セットを扱う時に文字化けしてしまう問題

これらの問題を解決するのにはWindows Vistaから導入された新しいAPIを元にしたライブラリを作成し、それを使用するプラグインの作成が必要となりました。
今回のスライドはこれらの問題の解決策を軽く導入として話し、実際に作成したプラグインがこれらの問題を解決しているかどうかを実例を交えつつ解説しました。

イベントの内容

共催イベントということで、会場設備はとても良かったです。
Fluentdはこれから先、より動的なサービスオペレーションにより親和性の高い改良がなされていくんだろうなぁと感じました。

また、筆者は登壇は何回かしたことがあるのですが、初めて英語で発表するということもあり若干早口になっていたかもしれません。

使用した英語スクリプト

数字やバージョン番号などは読み方を迷ってしまうと考えたため、一部数字やバージョン番号などを読み間違えないようにアルファベット表記にしてあったり、括弧付きの注記にしてあります。

My name is Hiroshi Hatake. 
Working at ClearCode Inc(operated) as a software developer.
Now, OK. Today, I'm gonna talk about "Fluentd meets Unicode Windows EventLog".

So, here is today’s my talk agenda.
First, I'll talk about motivation.
Then, I'll talk about winevt_c which is the newly created gem shortly, Unicode character handling, using ANSI code page issues, Unicode testing, benchmark, 
throughput benchmark, and conclusion.

Now, let's start to talk about motivation.

in_windows_eventlog which is the old plugin has some issues.
1st. Unicode character handling. Sometimes garbage characters are generated.
2nd. Memory consumption in flood of windows event
3rd. Sometimes it causes segmentation fault
4th. CPU spike when resuming operation
5th. At least one event should exist in the listening channel on start to listen. Otherwise, nothing to be read(red).

They are caused by dependent gem which is named win thirty two-eventlog.

Next, I'm talking about winevt_c.
This gem is a solution for Unicode handling issue, but this issue is very complicated. I’ll describe it later.

Then, I show you some winevt_c itself code examples.
First, this code is querying for specified channel.
In this case, specified channel is application.

Second, displayed example code is updating bookmark for querying channel.
Bookmark is useful to resume operation.

Third, the example code subscribes specified channel.
Subscribe API is battery included. 
This API is useful for most users.

The new gem which is named winevt_c solves win thirty-two-eventlog issues

1st. Improve Unicode character handling
2nd. It doesn’t cause segmentation fault on the same situation
3rd. CPU spike when resuming operation is declined
4th. Reduce Memory consumption in flood of windows event. This issue is partially solved but declined consuming memory.
5th. At least one event should exist in the listening channel on starting to listen. Empty channel can also subscribe. The older one will be staled.

1st Issue is the hardest problem and the others are solved by new API to read Windows EventLog.

The relationship of plugins and gems in this talk.
The old plugin which is named in_windows_eventlog depends on win32-eventlog.

And

The new plugin which is named in_windows_eventlog2 depends on winevt_c gem which is the newly created one.

Next, Unicode character handling.
This part and the next part treat the hardest issues in this talk.

Then, we should consider what Unicode means.

WHAT IS UNICODE?

In Windows context, it means UTF-sixteen.

Ruby also can handle UTF-sixteen in Ruby code world, although we'll consider Ruby C extension.
Ruby C extension API does not provide convenient API to handle UTF-sixteen. 
Thus, we should say: In Ruby C extension context, it means UTF-8.

What is the difference between ANSI and Unicode?

In Windows, ANSI means current code page.
In Japanese edition Windows, it's code page nine-hundred thirty-two.
Large A suffixed API uses ANSI character encoding.

In Windows, Unicode means UTF-sixteen.
Large W suffixed API uses UTF-sixteen character encoding.
PWSTR and such Large W contained type API arguments also use UTF-sixteen character encoding.

So, we need to convert from UTF-sixteen to UTF-8 as described before.

The win thirty-two eventlog uses ANSI version of Windows API.
To handle Unicode characters correctly in win thirty-two eventlog, we need to use Unicode version of them.
 
In addition, win thirty-two eventlog gem development is inactive in recent days.
And Unicode version patch exists, but it have not been merged in.

Then, next topic is Using ANSI code page issues.

ANSI code page is lightweight encoding way for specific characters, but it causes encoding issue in some cases. 

In Japanese Edition Windows, it uses code page nine-hundred thirty-two by default.
It can handle
* Alphabets
* Greek letters
* Cyrillic alphabets
* Hiragana and Katakana
* JIS level one and two Kanji Sets

Other characters cannot handle with code page nine-hundred thirty-two.

UTF-8 contains more characters!
UTF-8 encoding can handle code page nine-hundred thirty-two characters and,
Diacritical mark such as umlaut in German
Hebrew, Arabic, Devanagari. Devanagari is the letters for Hindi.
South east asia characters such as Thai, Laotian... etsetra.
And Emoji characters.

So, we reached ANSI code page issues solution.

We decide to develop the brand-new gem which is named winevt_c.
1. It uses new Windows API that is defined in <winevt.h>
2. The new API provides bookmark which is used to resume operation
3. Unicode native API

This gem's detail was described in about winevt_c section.

This gem is written in C and C plus plus.
So, users need to build C and C plus plus extension code by themselves.
Current RubyInstaller bundles MSYS2 system. We needn't  worry about it more than necessary.

The next topic is Unicode testing.

In this section, I'm talking about Unicode testing.
This test environment is:

* Japanese edition Windows ten home nineteen-ow-three six-four bits
* Prepared writing Windows EventLog tool which is written in C-sharp
* And I used PowerShell Core six on Windows Terminal. Not command prompt and raw Powershell terminal.
'Cause command prompt and raw PowerShell terminal cannot display Thai, Devanagari, Emoji and so on. 

Here is the snippet of writing Windows EventLog code that contains...
Alphabets
Non-ASCII symbols
Japanese
Thai
Cyrillic
Greek letters
Arabic alphabets
Devanagari
Unicod-ish Kaomoji
And Emoji

Unicode testing uses benchmarking tool which is created for heavily loaded benchmark, but it accepts parameters for lightweight writing.
The shown command-line means ten events written into benchmark channel.
And sleep ten milliseconds before it displays flow rate.

This slide and the next slide describe configuration for Unicode testing.
Fluentd will use in_windows_eventlog as a source and out_forward as an output.
Note that the old plugin requests to use from_encoding and encoding parameters to handle character encoding correctly.
And also default read_interval parameter which is two-seconds is used.
But still unhandled characters exist.

Fluentd will use in_windows_eventlog2 as a source and out_forward as an output.
Note that the new plugin doesn't request to use from_encoding and encoding parameters.
And also default read_interval parameter which is two-seconds is used.
The new plugin always handles character encoding as UTF-8.
So, they needn't anymore!

Then, let's see the old plugin execution log.
Symbol, Thai, Arabic, Devanagari, Unicode contains Kaomoji, and Emoji are displayed broken. 

The other result is the new plugin execution log.
It displays Symbol, Thai, Devanagari, Unicode contains Kaomoji, and Emoji are correctly displayed.
Arabic is slightly broken but it is Windows Terminal's displaying issue.

Now, we can handle Emoji characters contaminated Windows EventLog.

So, we reached benchmark section.

In this section, I'm talking about Benchmark.

Benchmark environment has two nodes:
The collector node is Windows ten eighteen-ow-nine and has two of virtual CPUs, four gigabytes memory and standard SSD.
The aggregator node is Ubuntu eighteen point zero-four and has two virtual CPUs, four gigabytes memory and standard SSD.

The collector Fluentd process and writing EventLog tool are running on the collector node.
And the aggregator Fluentd process is running on the aggregator node.

The collector Fluentd sends events with forward protocol and the aggregator Fluentd receives with the same protocol.

1 million events will write into collector node by benchmarking tool.
Its flow rate is about ninety-one per seconds.

The shown command-line generates events and writing them into the benchmark channel.

The left side configuration is for the collector node.
In_windows_eventlog is used as a source and out_forward is used as an output.
The right side configuration is for the aggregator node.
It receives events from the collector Fluentd with forward protocol. Output is out_null or out_stdout.

The left side configuration is for the collector node.
In_windows_eventlog2 is used as a source and out_forward is used as an output.
The right side configuration is for the aggregator node.
It also receives events from collector Fluentd with forward protocol. Output is out_null or out_stdout.

Now, let's see the benchmarking results.
First, here is the old plugin benchmarking result.
This graph shows that the old plugin uses around between one-hundred ten and two-hundred forty megabytes memory.
And CPU usage sometimes spikes but around ten percent is used in the entire node. 

Second, here is the new plugin benchmarking result.
This graph shows that the new plugin uses around one-hundred twenty megabytes memory.
But CPU usage slightly higher than the previous. 

Now, we can say pros and cons for the old plugin.

Pros: 
* Low CPU usage
Cons: 
* High memory usage
* And incomplete Unicode handling

Also, we can say pros and cons for the new plugin.

Pros: 
* Low memory usage
* Unicode handling
* immediately subscribe channel event if it's empty on subscribe

Cons: 
* Slightly higher CPU usage rather than the old plugin's

The last topic is throughput benchmarking.

In this section, I’m gonna talk about Throughput Benchmark.

Benchmark environment has two nodes:
The collector node and the aggregator node.
They are the same setup at Benchmarking test which is used in the previous section.

Throughput Benchmark setup is as follows:
Writing five-hundred-thousand events
Increase flow rate of events step by step
* around one-hundred-sixty events per second
* around two-hundred-ninety events per second
* around three-hundred-ten events per second
* around three-hundred-twenty events per second
* And the last case is stuck.
  (Chunk bytes limit exceeds for an emitted event stream warning is generated from Fluentd...)

The left side configuration is for collector node.
In_windows_eventlog2 is used as a source and out_forward is used as an output.
The right side configuration is for the aggregator node.
This configuration is same as the previous benchmarking test.

Here is around one-hundred-sixty events per second case. The new plugin can consume benchmark channel events.

The next is around two-hundred-ninety events per second case. The new plugin also can consume benchmark channel events.

Third is around three-hundred-ten events per second case. The new plugin also can consume benchmark channel events.
But it is slightly growing up memory consumption.

The last normal case is around three-hundred-twenty events per second case. The new plugin also can consume benchmark channel events.
But it is also slightly growing up memory consumption.

Finally, here is the conclusion.

The new plugin which is named in_windows_eventlog2 does...
* Improve Unicode handling. Thanks to winevt_c gem!
* Reduce memory consumption
* Solve CPU spike after resuming operation

But still there is an issue in the new plugin:
* Slightly higher CPU usage than the old one

From throughput benchmarking result, the new plugin can handle about three-hundred event per second with default read_interval parameter.

The new plugin which is named in_windows_eventlog2’s status is…

included fluent-plugin-windows-eventlog2 version zero-point-three-point-ow.
We wanna to hear more user voices and use cases
Note that installation is a bit of harder than the older one

Let's enjoy Monitoring Windows EventLog! 

Thank you for listening!
(Any questions?)

ふむ、こうして改めて眺めてみると中々長いですね。スライドの枚数が増えてしまったので20分の持ち時間でデモは難しそうということで当日はデモを見送りました。

まとめ

Fluentd meetupが久々に東京で開催されるということで登壇しました。
Windows EventLogのEventDataへはUTF-16でValidな文字であれば、どのような文字でも入れることができます。
現代では、UTF-16の文字セットの範囲内にアルファベットやキリル文字・ギリシャ文字だけでなく、東南アジア系の文字や、ヘブライ文字・アラビア文字といったものまで入っています。
また、扱いが手ごわそうな絵文字ですらも扱うことが出来たので、in_windows_eventlog2プラグインが動き始めた時には衝撃を受けました。

文字コードをうまく扱うのは大変ですし地味ですけれども、絵文字の登場によって文字コードの話題が実例を見せた時に見た目が賑やかになることで実際に扱えていることが視覚的に分かりやすくなったのは喜ばしいですね。

タグ: Fluentd
2019-07-18

fluent-plugin-elasticsearchのSnifferクラスについて

はじめに

fluent-plugin-elasticsearchはよく使われているプラグインの一つです。 このプラグインをメンテナンスするためには、Fluentdの知識だけでなく、Elasticsearchが今後どのようになっていくかも知っておく必要があります。 また、このプラグインはRed Hat社がメンテナンスしているOpenShiftのログコンポーネントの一部としても使われています。

elasticsearch-transportのSnifferクラスとは

elasticsearch-transportには定期的にクラスタの状況を監視するSnifferクラスがあります。このクラスではGET _nodes/httpというクラスタの状況を返答するAPIを叩いており、大抵の場合はこのAPIを叩いておけばElasticsearchクラスタの状況がfluent-plugin-elasticsearchが使っているelasticsearchクライアントに通知されます。 そのため、X-Packを用いない通常の使用方法では問題になりません。

k8sサービス化されたElasticsearchクラスタに接続する

k8sのサービスとはPodから生成したノードを一まとめにしたアクセス手段を提供します。k8sの世界観ではサービスのアクセス先は一定です。しかし、サービスを構成するノードの構成要素はある時は起動していますが、またある時は停止または破棄されています。このノード一つ一つにElasticsearchが立っていても通知速度よりも起動・破棄のサイクルが速ければGET _nodes/httpを使用しても欠点が目立つようになります。 そのため、k8sのサービス化されたElasticsearchクラスタには新たなSnifferクラスの実装が必要になります。

そこで、元々のSnifferクラスのhostsメソッドの実装を見てみると、以下のようになっています。

        # Retrieves the node list from the Elasticsearch's
        # [_Nodes Info API_](http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-info/)
        # and returns a normalized Array of information suitable for passing to transport.
        #
        # Shuffles the collection before returning it when the `randomize_hosts` option is set for transport.
        #
        # @return [Array<Hash>]
        # @raise  [SnifferTimeoutError]
        #
        def hosts
          Timeout::timeout(timeout, SnifferTimeoutError) do
            nodes = transport.perform_request('GET', '_nodes/http').body

            hosts = nodes['nodes'].map do |id,info|
              if info[PROTOCOL]
                host, port = info[PROTOCOL]['publish_address'].split(':')

                { :id =>      id,
                  :name =>    info['name'],
                  :version => info['version'],
                  :host =>    host,
                  :port =>    port,
                  :roles =>   info['roles'],
                  :attributes => info['attributes'] }
              end
            end.compact

            hosts.shuffle! if transport.options[:randomize_hosts]
            hosts
          end
        end

nodes = transport.perform_request('GET', '_nodes/http').body の行でElasticsearchクラスタの情報を取りに行き、取りに行った情報から再度クラスタの情報を再構築しています。

もし、接続先のURLやIPアドレスが固定であれば、以下のようなSnifferクラスを作成し、ホスト情報を使い回す振る舞いをさせた方が良いです。

require 'elasticsearch'

class Fluent::Plugin::ElasticsearchIdempotenceSniffer < Elasticsearch::Transport::Transport::Sniffer
  def hosts
    @transport.hosts
  end
end

elasticsearchクライアントは独自Snifferを渡してそのクラスを元にクラスタ情報を再構築するようなカスタマイズをすることができます。

@sniffer = options[:sniffer_class] ? options[:sniffer_class].new(self) : Sniffer.new(self)

これらの変更をfluent-plugin-elasticsearchで扱うには以下のようにすると独自のSnifferクラスを用いてElasticsearchクラスタとやりとりできるようになります。

     config_param :pipeline, :string, :default => nil
     config_param :with_transporter_log, :bool, :default => false
     config_param :emit_error_for_missing_id, :bool, :default => false
+    config_param :sniffer_class_name, :string, :default => nil
     config_param :content_type, :enum, list: [:"application/json", :"application/x-ndjson"], :default => :"application/js
on",
                  :deprecated => <<EOC
 elasticsearch gem v6.0.2 starts to use correct Content-Type. Please upgrade elasticserach gem and stop to use this option
.

#...
     def client
       @_es ||= begin
         adapter_conf = lambda {|f| f.adapter @http_backend, @backend_options }
         transport = Elasticsearch::Transport::Transport::HTTP::Faraday.new(get_connection_options.merge(
                                                                             options: {
                                                                               reload_connections: @reload_connections,
                                                                               reload_on_failure: @reload_on_failure,
                                                                               resurrect_after: @resurrect_after,
                                                                               retry_on_failure: 5,
@@ -287,7 +300,8 @@ EOC
                                                                               http: {
                                                                                 user: @user,
                                                                                 password: @password
-                                                                              }
+                                                                              },
+                                                                              sniffer_class: @sniffer_class,
                                                                             }), &adapter_conf)
         es = Elasticsearch::Client.new transport: transport
 

まとめ

fluent-plugin-elasticsearchのElasticsearchへのリクエストに関わるelasticsearch-transportのSnifferに関するお話を書きました。 記事と同様の働きをするパッチはfluent-plugin-elasticsearchのv2.11.5に取り込んでリリース済みです。 fluent-plugin-elasticsearchでk8sやnginxのプロキシを設置していて接続のリロード時に正常なElasticsearchクラスタの情報が取得できずに困っている場合はsniffer_class_nameの設定項目を初期値から変えてみたり、独自のSnifferクラスを定義したりしてみてください。

タグ: Fluentd
2018-08-22

fluent-plugin-elasticsearchのHTTPバックエンドを切り替えられるようにするには

はじめに

fluent-plugin-elasticsearchはよく使われているプラグインの一つです。 このプラグインをメンテナンスするためには、Fluentdの知識だけでなく、Elasticsearchが今後どのようになっていくかも知っておく必要があります。 取り掛かりとして、fluent-plugin-elasticsearchの構造をまず軽く説明します。fluent-plugin-elasticsearchのElasticsearchのAPIリクエストは自前で実装しているのではなく、elasticsearch, elasticsearch-api, elasticsearch-transportというgemに依存しています。それぞれ、ElasticsearchのRubyクライアントライブラリをカプセル化して共通のインターフェースで使用できるようにgem化したもの、APIリクエストをgem化したもの、HTTPリクエストの方式をgem化したものです。

elasticsearch-transport

この中で、今回はelasticsearch-transportについて取り上げます。elasticsearch-transportは複数のHTTPバックエンドを切り替えて使用することができます。

fluent-plugin-elasticsearchでは、これまで以下のようにHTTPリクエストのバックエンドライブラリとしてexconが固定で使われていました。

    def client
      @_es ||= begin
        excon_options = { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass }
        adapter_conf = lambda {|f| f.adapter :excon, excon_options } # f.adaptorに ':excon' 固定
        transport = Elasticsearch::Transport::Transport::HTTP::Faraday.new(get_connection_options.merge(
                                                                            options: {
                                                                              reload_connections: @reload_connections,
                                                                               reload_on_failure: @reload_on_failure,
                                                                               resurrect_after: @resurrect_after,
                                                                               retry_on_failure: 5,
                                                                               logger: @transport_logger,
                                                                               transport_options: {
                                                                                 headers: { 'Content-Type' => @content_type.to_s },
                                                                                 request: { timeout: @request_timeout },
                                                                                 ssl: { verify: @ssl_verify, ca_file: @ca_file, version: @ssl_version }
                                                                               },
                                                                               http: {
                                                                                 user: @user,
                                                                                 password: @password
                                                                               }
                                                                             }), &adapter_conf)
      es = Elasticsearch::Client.new transport: transport
# ...

exconの問題点

exconはHTTPのバックエンドライブラリとしては申し分がないのですが、keepaliveがデフォルトで有効にならないという問題がありました。 nginxなどのproxy配下ではkeepaliveが有効でないと接続が頻繁に切れ、効率的な転送が行えないという問題が報告されました。

elasticsearch-transportでFaradyアダプターのHTTPバックエンドを切り替えられるようにする

elasticsearch-transportはいくつかのHTTPバックエンドを使用することができます。その一つがFaradayアダプターを使用するものです。 Faradayはそれ単体ではHTTPを扱う統一的なインターフェースを提供するだけですが、実際のHTTPリクエストはHTTPを扱うライブラリに担当させます。 例えば、exconを使ってHTTPリクエストを出すには以下のようにします。

require 'excon'

client = Elasticsearch::Client.new(host: 'localhost', port: '9200') do |f|
  f.response :logger
  f.adapter  :excon
end

この状態では、exconのみしかHTTPのバックエンドに使用することができません。

例えば、typhoeus を使ってHTTPリクエストを投げるようにするには、

require 'typhoeus'
require 'typhoeus/adapters/faraday'

client = Elasticsearch::Client.new(host: 'localhost', port: '9200') do |f|
  f.response :logger
  f.adapter  :typhoeus
end

のようにすると、HTTPのリクエストはTyphoeusを使って投げられるようになります。

実際のプラグインに適用する

実際のfluent-plugin-elasticsearchにHTTPバックエンドを変更できるようにしたパッチは以下の通りです。 (out_elasticsearch部分のみ示します。)

diff --git a/lib/fluent/plugin/out_elasticsearch.rb b/lib/fluent/plugin/out_elasticsearch.rb
index 42e1a16..cb5f1c0 100644
--- a/lib/fluent/plugin/out_elasticsearch.rb
+++ b/lib/fluent/plugin/out_elasticsearch.rb
@@ -107,6 +107,7 @@ elasticsearch gem v6.0.2 starts to use correct Content-Type. Please upgrade elas
 see: https://github.com/elastic/elasticsearch-ruby/pull/514
 EOC
     config_param :include_index_in_url, :bool, :default => false
+    config_param :http_backend, :enum, list: [:excon, :typhoeus], :default => :excon
 
     config_section :buffer do
       config_set_default :@type, DEFAULT_BUFFER_TYPE
@@ -128,6 +129,7 @@ EOC
       raise Fluent::ConfigError, "'tag' in chunk_keys is required." if not @chunk_key_tag
 
       @time_parser = create_time_parser
+      @backend_options = backend_options
 
       if @remove_keys
         @remove_keys = @remove_keys.split(/\s*,\s*/)
@@ -207,6 +209,18 @@ EOC
       end
     end
 
+    def backend_options
+      case @http_backend
+      when :excon
+        { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass }
+      when :typhoeus
+        require 'typhoeus'
+        { sslkey: @client_key, sslcert: @client_cert, keypasswd: @client_key_pass }
+      end
+    rescue LoadError
+      raise Fluent::ConfigError, "You must install #{@http_backend} gem."
+    end
+
     def detect_es_major_version
       @_es_info ||= client.info
       @_es_info["version"]["number"].to_i
@@ -257,8 +271,7 @@ EOC
 
     def client
       @_es ||= begin
-        excon_options = { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass }
-        adapter_conf = lambda {|f| f.adapter :excon, excon_options }
+        adapter_conf = lambda {|f| f.adapter @http_backend, @backend_options }
         transport = Elasticsearch::Transport::Transport::HTTP::Faraday.new(get_connection_options.merge(
                                                                             options: {
                                                                               reload_connections: @reload_connections,

前述の通り、f.adapter の部分へ切り替えたいHTTPバックエンドのgem名のシンボルを渡してあげれば良いことになります。 この記事では解説していませんが、バックエンドによってはTLSの設定方法に違いがある場合があるので新しいバックエンドを追加した際には無効なハッシュキーを渡さないように注意してください。

まとめ

fluent-plugin-elasticsearchのHTTPバックエンドをexconだけではなくtyphoeusも扱えるように改修したお話を書きました。 記事で引用したパッチはfluent-plugin-elasticsearchのv2.11.4に取り込んでリリース済みです。 fluent-plugin-elasticsearchでkeepaliveが有効にならず、困っている場合はtyphoeus gemをインストールした後、http_backend typhoeusの設定値を加えてkeepaliveが有効になるHTTPバックエンドをぜひ試してみてください。

タグ: Fluentd
2018-08-21

Fluentd UIのFluentd v1対応のロードマップ

fluentd-uiというFluentdの設定を管理できるWebアプリケーションがあります。 Fluentd v1 がリリースされる前から機能の追加やFluentdの新しい機能への対応はされていませんでした。

手を入れる前は、以下のような状態でした。

  • Rails 4.2.8
  • Fluentd v0.12
  • Vue.js v0.11.4
  • sb-admin-v2
  • filter非対応
  • label feature非対応
  • systemd非対応
  • reload非対応
  • Fluentd v1に対応していないプラグインがおすすめプラグインに載っている

2018年4月中旬から手を入れ始めて、新しいバージョンをいくつかリリースしました。

  • v0.4.5
    • 約一年ぶりのリリース
    • Rails 4.2.10に更新
    • 使用しているgemを一通り更新
    • poltergeistからheadless chromeに移行
  • v1.0.0-alpha.1
    • Rails 5.2.0に更新
    • Fluentd v1のサポートを開始し、Fluentd v0.12以前のサポートをやめた
    • Vue.js v2.5.16 に更新
    • startbootstrap-sb-admin 4.0.0 に更新
    • JavaScript まわりを sprockets から webpacker に移行 *1
  • v1.0.0-alpha.2
    • v1.0.0-aplha.1で動かない箇所があったのを修正した

今後の予定は以下の通りです。

  1. Fluent::Config::ConfigureProxy#dump_config_definitionで得られる情報を利用して、設定UIを構築する
  2. 複雑な設定を持つプラグインは個別にフォームを作成し、使いやすくする
  3. owned plugin (parserやformatterなど)の設定方法について検討し、実装する
  4. テストの修正
  5. filterサポート
  6. label featureサポート
  7. おすすめプラグインの更新
  8. issuesの対応

3まで完了したらalpha.3かbeta.1をリリースする予定です。

*1 CSSはsprocketsのまま

タグ: Fluentd
2018-06-08

fluent-plugin-elasticsearch v2.8.6/v1.13.4からのX-Pack向けの認証情報の設定方法の注意点

はじめに

fluent-plugin-elasticsearchはよく使われているプラグインの一つです。 このプラグインをメンテナンスするためには、Fluentdの知識だけでなく、Elasticsearchのエコシステムも知っておく必要があります。 Elasticsearch 5.xからnginxのリバースプロキシの認証だけでなく、Elastic Stack自体で認証をコントロールする仕組みがプラグインとして提供されています。

X-Packには、旧Shieldの機能であるBasic認証などの認証の仕組みがあります。 この認証の仕組みへの対応はElasticsearchのRubyクライアントであるelasticsearch-rubyも提供しています。

認証情報の設定方法の注意点

fluent-plugin-elasticsearchのこれまでの挙動はhost毎に認証情報を紐付ける形で設定していました。 v2.8.6/v1.13.4以降ではクラスタ毎に設定する設定ファイルの書き方が推奨されるようになります。*1 そのため、以下の設定方法は推奨されなくなることに注意してください。 X-Packを設定せずに運用している場合は設定変更の必要はありません。

hosts https://username:password@host-custom.com:443

という設定は推奨されなくなり、

hosts https://host-custom.com:443
user username
password password

という書き方が推奨されます。 前者の書き方ではElasticsearchのクラスタの情報の再読み込み時に認証情報が抜け落ちてしまうということが起きるためです。 後者の書き方では、クラスタの情報の再読み込み時に認証情報が抜け落ちてしまうということを防ぐ対策が動作するようになります。

まとめ

fluent-plugin-elasticsearch v2.8.6/v1.13.4 では、再読み込み時に接続先のElasticsearchの認証情報を保持することが可能となる対策が入っています。 X-PackでElasticsearchクラスタのBasic認証を有効化していて、リロード時に接続情報が失われて困っている運用者の方は是非バージョンアップしてみてください。

*1 これまで困っている方々が結構いたようです。例として https://github.com/uken/fluent-plugin-elasticsearch/issues/307 https://github.com/uken/fluent-plugin-elasticsearch/issues/257 などが報告されていました。

タグ: Fluentd
2018-04-10

タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|