# JSON in JSON なログファイルビューア {{tag: jl, perl, log, stern, jq}} プログラミング処理の中で、JSON の中に JSON を入れるのは比較的簡単です。エスケープはライブラリがよしなにやってくれますから。でもその多段に JSON を突っ込まれた JSON 文字列をCLIでハンドリングするのはちょっと面倒くさいです。 例えばこんなん。 { "message": "{\"level\":\"info\",\"ts\":1557004280.5372975,\"caller\":\"zap/server_interceptors.go:40\",\"msg\":\"finished unary call with code OK\",\"grpc.start_time\":\"2019-05-04T21:11:20Z\",\"system\":\"grpc\",\"span.kind\":\"server\",\"grpc.service\":\"FooService\",\"grpc.method\":\"GetBar\",\"grpc.code\":\"OK\",\"grpc.time_ms\":248.45199584960938}\n", "namespace": "foo-service", "podName": "foo-86495899d8-m2vfl", "containerName": "foo-service" } JSON の message の value に JSON が入ってる。 昨今、石を投げればこのような多段 JSON in JSON なログに遭遇します。 この JSON in JSON 状態のエスケープされてる中身を目parseするか、なんとかCLI上で parse するか、という話。 それ、 jq の fromjson でできるよ!というのが今のところのベターアプローチだと思います。 $ stern | jq '. | {message: (.message|fromjson), namespace,podName,containerName}' { "containerName" : "foo-service", "podName" : "foo-86495899d8-m2vfl", "namespace" : "foo-service", "message" : { "grpc.service" : "FooService", "grpc.method" : "GetBar", "grpc.code" : "OK", "span.kind" : "server", "caller" : "zap/server_interceptors.go:40", "system" : "grpc", "msg" : "finished unary call with code OK", "grpc.start_time" : "2019-05-04T21:11:20Z", "grpc.time_ms" : 248.451995849609, "level" : "info", "ts" : 1557004280.5373 } } でもこれ、面倒くさくないです? というわけで、JSON in JSON を再帰的にさっといい感じにしてくれるやつ書きました。 JSON in JSON Log Viewer ということで {{cpan: jl}} じぇいえる コマンドです。 {{cpan: App::jl}} モジュールに同梱されてます。 $ stern | jl { "podName" : "foo-86495899d8-m2vfl", "message" : { "system" : "grpc", "grpc.time_ms" : 248.451995849609, "msg" : "finished unary call with code OK", "grpc.method" : "GetBar", "span.kind" : "server", "level" : "info", "grpc.start_time" : "2019-05-04T21:11:20Z", "ts" : 1557004280.5373, "grpc.code" : "OK", "caller" : "zap/server_interceptors.go:40", "grpc.service" : "FooService" }, "containerName" : "foo-service", "namespace" : "foo-service" } 超絶簡単ですね! JSON in JSON を再帰的にやっつけます。デフォルトだと最大10段ネストしててもなんとかしてくれます。 `--no-pretty` オプションをつけて再度 jq に渡すとかすると、便利かもしれません。 $ stern | jl | jq .message.msg "finished unary call with code OK" 圧倒的に覚えることが減る。 満足した。