`github.com/prometheus/client_golang` を使って 99.9 percentileでのHTTPハンドラのメトリクスを取ってみる
github.com/prometheus/client_golang でメトリクスを取る
この記事はGoアドベントカレンダー向けの記事です。
この記事では github.com/prometheus/client_golang
を使って
基本的なメトリクスを取ると同時に、HTTPハンドラのメトリクスを追加してみます。
また、HTTPハンドラのメトリクスで、99.9 percentileのhttp_request_duration_microsecondsのメトリクスを取ってみます。
基本的なメトリクスの取得とエンドポイントの公開
github.com/prometheus/client_golang
を使えばメトリクスを取ることが出来ます。
prometheus向けのメトリクスのエンドポイントも生やせます。
下のような形で簡単にメトリクスのエンドポイントを生やす事ができます。
package main import ( "log" "net/http" "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { http.Handle("/metrics", promhttp.Handler()) log.Fatal(http.ListenAndServe(":8080", nil)) }
デフォルトでは、以下の2つのメトリクスのコレクターが登録されています。
以下の記事が詳しいです。
- Exploring Prometheus Go client metrics - https://povilasv.me/prometheus-go-metrics/
HTTPハンドラのメトリクスを取る
HTTPハンドラのメトリクスを取ってみました。 以下のようなメトリクスが取れます。
デフォルトでは、50 percentile, 90 percentile, 99 percentileのメトリクスが取れます。
http_request_duration_microseconds{handler="hello_world",quantile="0.5"} 82897.181 http_request_duration_microseconds{handler="hello_world",quantile="0.9"} 96527.057 http_request_duration_microseconds{handler="hello_world",quantile="0.99"} 98644.142 http_request_duration_microseconds_sum{handler="hello_world"} 1.0489467330000002e+06 http_request_duration_microseconds_count{handler="hello_world"}
ソースは下のようになりました。
package main import ( "time" "log" "net/http" "fmt" "math/rand" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) func main() { http.Handle("/metrics", promhttp.Handler()) http.Handle("/", prometheus.InstrumentHandlerFunc("hello_world", hello)) log.Fatal(http.ListenAndServe(":8080", nil)) } func hello(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprintln(w, "Hello World") }
簡単ですね。
99.9 percentileのメトリクスを取ってみる
99.9 percentileのメトリクスを取りたい時はどうすれば良いでしょうか。 ライブラリの中のコードを参考にすると、下のような形で取ることが出来ます。
http.Handle("/", prometheus.InstrumentHandlerFuncWithOpts( prometheus.SummaryOpts{ Subsystem: "http", ConstLabels: prometheus.Labels{"handler": "hello_world"}, Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001, 0.999: 0.0001}, }, hello))
メトリクスは以下のような形で取れます。 増えましたね。
http_request_duration_microseconds{handler="hello_world",quantile="0.5"} 50336.671
http_request_duration_microseconds{handler="hello_world",quantile="0.9"} 91294.148
http_request_duration_microseconds{handler="hello_world",quantile="0.99"} 100699.414
+ http_request_duration_microseconds{handler="hello_world",quantile="0.999"} 104040.94
まとめ
github.com/prometheus/client_golang
を使うことで簡単なメトリクスがデフォルト設定されていることを確認しました。
また、InstrumentHandlerFuncやInstrumentHandlerFuncWithOptsなどを使うことで
HTTPエンドポイントのメトリクスが自動で取得されることが分かります。
エンドポイント毎のレスポンスタイムの劣化などは非常に便利な情報です。 HTTPサーバを書いているなら、メトリクスを取って監視してみてはいかがでしょうか。
この記事では紹介しませんが 他にも自分でコードを書くことでメトリクスを取ることが可能です。
個人的に気になっていたメトリクスどうやって取るんだろうということで 調べて記事にしました。 終わり。
Spring 5.0/Spring Boot 2.0にしたらMockMvcを使ったテストが406 Not Acceptableを返してくる話
Content-Type周りの挙動で死んでしまった回
使っているSpringは5.1.0、Spring Bootは2.0.6です。
元はこんなコード。
@Before public void setUp() { this.mockMvc = MockMvcBuilders.standaloneSetup(controller) .setMessageConverters(httpMessageConverter()); } @Test public void testGetMailSuppression() throws Exception { // setup String someId = ...; // 省略 // exercise mvc.perform(get("/endpoint/{id}", someId) // verify .andExpect(status().isOk()); // なぜか406が帰ってくる }
ContentNegotiationManager周りに変更が入っているので、以下のコードを追加しました。
@Before public void setUp() { + ContentNegotiationManagerFactoryBean factoryBean = + new ContentNegotiationManagerFactoryBean(); + factoryBean.setFavorPathExtension(false); // この辺の設定はWebMvcの設定で使ってるやつ + factoryBean.afterPropertiesSet(); this.mockMvc = MockMvcBuilders.standaloneSetup(controller) + .setContentNegotiationManager(factoryBean.build()) .setMessageConverters(httpMessageConverter()); } @Test public void testGetMailSuppression() throws Exception { // setup String someId = ...; // 省略 // exercise mvc.perform(get("/endpoint/{id}", someId) // verify .andExpect(status().isOk()); // なぜか406が帰ってくる }
まとめ
よく分からず、適当なコードを書いたら直ってしまった回・・・ 挙動の違いはまた今度見てみます。
この辺が影響してそう。
Spring Boot 1.5.x を使っているプロジェクトでSpring Bootを2系にしたら @Scheduledが動かないことがある
Spring Boot 1.5.xでは動いていた @Scheduledをつけた定期処理が Spring Boot 2.xでは動かないことがあります。
EnableSchedulingを自分のアプリケーションのConfigurationクラスにつけてください。 どこにもつけてないんだと思います。
ちょっとハマったよ。
余談
じゃあ、元々なんで動いてたの?
以前はここについてた。ちなみに2.x系で対応するクラスを見つけられなかった。 spring-boot/MetricExportAutoConfiguration.java at v1.5.17.RELEASE · spring-projects/spring-boot · GitHub