2
2

More than 3 years have passed since last update.

JSONからフィールドを抽出する。

Last updated at Posted at 2020-03-01

Splunk>Answersの質問はなんか放置されてたけど、自分で納得できたので投稿します。

大体.confの資料に何故だかは書いてあった。

課題

invalidJson.spl
 | makeresults 
 | eval _raw="Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"global\", \"origin\": \"dynstats\", \"values\": { } }
  Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"imuxsock\", \"origin\": \"imuxsock\", \"submitted\": 0, \"ratelimit.discarded\": 0, \"ratelimit.numratelimiters\": 0 }
  Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"action 0\", \"origin\": \"core.action\", \"processed\": 50996, \"failed\": 0, \"suspended\": 0, \"suspended.duration\": 0, \"resumed\": 0 }
  Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"action 1\", \"origin\": \"core.action\", \"processed\": 50996, \"failed\": 0, \"suspended\": 0, \"suspended.duration\": 0, \"resumed\": 0 }" 
 | makemv delim="
  " _raw 
 | stats count by _raw 
 | rex "(?<json>{.*)" 
 | spath input=json

JSONが途中から出てくるログをどうやったらprops.confで抽出できるのかを質問してみた。
この段階では、抽出したフィールドからINDEXED_EXTRACTIONSとか使えると思っていた。

解決方法

props.conf
 [json_sed]
 TIME_FORMAT = %B %d %T
 SEDCMD = s/.*?({.*)/\1/g
 KV_MODE = json
 LINE_BREAKER = ([\r\n]+)
 NO_BINARY_CHECK = true

一番危惧していたのは、 SEDCMDでログを加工してしまうとログの情報が取れなくなること。
でも順番で処理してくれるみたいで、最初に時刻情報の抽出をした後
SEDCMDでログを加工してしまえばいいらしい。
transforms.confではなくprops.confでフィールド抽出はEXTRACTです。
これはrexの構文をそのまま使える。

今回はLINE_BREAKERをデフォルトにしている。
通常のJSONだと LINE_BREAKER = }(,) あたりがだいたい使えるかも。ここはログ次第

sed_check.spl
| makeresults 
| eval _raw="Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"global\", \"origin\": \"dynstats\", \"values\": { } }
  Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"imuxsock\", \"origin\": \"imuxsock\", \"submitted\": 0, \"ratelimit.discarded\": 0, \"ratelimit.numratelimiters\": 0 }
  Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"action 0\", \"origin\": \"core.action\", \"processed\": 50996, \"failed\": 0, \"suspended\": 0, \"suspended.duration\": 0, \"resumed\": 0 }
  Nov 14 03:23:42 hostname rsyslogd-pstats:{ \"name\": \"action 1\", \"origin\": \"core.action\", \"processed\": 50996, \"failed\": 0, \"suspended\": 0, \"suspended.duration\": 0, \"resumed\": 0 }" 
| makemv delim="
  " _raw 
| stats count by _raw 
| rex mode=sed "s/^.*?({.*})/\1/g"

こういった形で確認して、そのままSEDCMDの引数に持っていけばいい。
|spathが効くならKV_MODE=jsonも使える。
なお、LINE_BREAKERrex "(?<line_breaker>なにか)"してsplit(_raw,"なにか")が使えるところと考えるといいと思います
:sweat:わかりずらいですね

JSONのJSON

json_json.spl
 | makeresults 
 | eval _raw="{
 @timestamp: 2020-02-05T09:41:19.486+00:00
 domain: capem
 environment: sit
 level: INFO
 logger_name: com.test.dna.evthub.sse.impl.EventEncrypter
 message: {\"data\":{\"errorDetails\":[{\"system\":\"OCS\",\"responseCode\":404,\"request\":{\"url\":\"https://slot4.org008.t-dev.test.net/application/ocsia/v1/ocs-provisioning/service/61474817171/products\",\"body\":[\"fb92a747-1cf7-09c8-33fc-0da0d0c16d80\"]},\"response\":{\"statusCode\":404,\"error\":{\"error\":10004,\"message\":\"Service not found in OCS\"}}}],\"transactionDetails\":{\"id\":\"30d49584-76fe-4e9e-b7b4-0c3a819e432e\",\"groupId\":\"6e2d25f3-6e77-90a2-689d-1e1476e79c8b\",\"parentId\":\"fb92a747-1cf7-09c8-33fc-0da0d0c16d80\",\"serviceId\":\"61474817171\",\"downstreams\":[{\"name\":\"OCS\",\"status\":\"FAILED\",\"statusCode\":404,\"error\":{\"error\":10004,\"message\":\"Service not found in OCS\"}}],\"orderItemId\":\"5065705155871632216\",\"actionStatus\":\"FAILED\",\"dependencies\":[],\"chargingSpecId\":\"CS_SVCLSUB_001\",\"chargingSpecType\":\"SERVICE_SUBSCRIPTION\",\"productActionCode\":\"CEASE\",\"productActionType\":\"cease\",\"productInstanceId\":\"fb92a747-1cf7-09c8-33fc-0da0d0c16d80\",\"chargingSpecSubType\":\"HANDSET_CONNECTION\",\"customerAccountUuid\":\"6b1b147c-2b98-2489-cf92-cefab92a77cf\",\"orderItemActionType\":\"Create\",\"effectiveDate\":\"2020-02-05T09:40:14+00:00\",\"sourceSystem\":\"B2C-Vlocity\",\"orderId\":\"B20052034417634\"}},\"correlationId\":\"30d49584-76fe-4e9e-b7b4-0c3a819e432e\",\"eventName\":\"WTC_SubscriptionLineItemCompletion_Failed\",\"timestamp\":\"2020-02-05T09:40:14+00:00\",\"eventPublisher\":\"WTC\"}
 thread_name: main
 }" 
 | rex "message: (?<message>{.*})" 
 | spath input=message

通常であれば、messageだけ取り出すところ

むりやりJSON

props.conf
SEDCMD-trim1 = (\S+)\:\s(\w\S+)/\"\1\":\s\"\2\",/g
SEDCMD-trim2 = message:\s({.*})/\"message\": \1,/
KV_MODE = json
rex
 | rex mode=sed "s/(\S+)\: (\w\S+)/\"\1\": \"\2\",/g"
 | rex mode=sed "s/message: ({.*})/\"message\": \1,/"
 | spath

が効くので、そのままSEDCMDに移植。

まとめ

JSONなログはLINE_BREAKERを気をつけないといけなかったり、まずは|spathが効くかどうか確認しないとフィールドが抽出できない。
ネストが深くなければREGEXで抽出もありだけど、自動抽出が便利すぎて、無理やりJSONのほうがいいです。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2