本日、NRQL クエリの新たな解析関数と変換関数をいくつか発表します。これにより、データが構造化されていない場合でも、必要なデータをより簡単に見つけられ、ダッシュボードやアラート設定をよりスムーズに構築できるようになります。

正直なところ、データは必ずしも整っているとは限りません。多くの場合、データは「そのまま」では使用できない状態で保存されています。タイムスタンプやエンティティ GUID、ストア ID などの重要な文字列がデータセットの奥深くに隠れている場合があります。

この問題を解決するための理想的な方法は、取り込む前にデータをクリーンアップすることですが、そもそも、データを取り込んで分析するチーム(DevOpsなど)が、データがそこに到達するまでのプロセスまでも担当しているとは限りません。

そこで、私たちはこの業務の効率化を支援するために、New Relic にアクセスできるユーザーなら誰でも使用できる New Relicクエリ言語(NRQL)に次の機能を追加しました。

それぞれのウォークスルーと使用例については以下を参照してください。

クエリ時にJSONを解析する

データにはさまざまな形式がありますが、最も一般的な形式のひとつが JSON です。このデータを解析するには、通常、複雑な正規表現またはアンカー解析を使用する必要がありますが、これは楽しい作業ではありません。ここで jparse() を使用すると、JSON データをより簡単にパースすることができます。

jparse(attribute, [path])

次の例のように、「Order response:」というテキストの後に JSON が含まれるログメッセージがあるとします。

Order response: {"timestamp":1709938901291,"status":500...

まず、アンカー解析を使用して文字列中から JSON にあたる箇所を抽出し、次に jparse() 関数を使用して、必要なフィールドを抽出します。

WITH aparse(message, 'Order response: *') AS json
FROM Log
SELECT jparse(json, 'timestamp'), jparse(json, 'status'), message
WHERE message LIKE 'Order response: {%'

jparse

この新しい機能により、JSON からタイムスタンプやステータスコードといったデータを抽出するのがはるかに簡単になります。

また、JSON 解析に適した 2 つの追加関数が追加されました。

  • mapKeys() は、マップを入力として渡すと、すべてのキーのリストを抽出します。
    • 上記の例では、['timestamp', 'status', etc.] になります。
  • mapValues() は、入力としてマップが渡されたときにすべての値のリストを抽出します。
    • ['1709938901291', '500', etc.]

詳細については、以下の各関数のドキュメントを参照してください:jparse()mapKeys()mapValues()

タイムスタンプを変換する

JSONから(ようやく)タイムスタンプを解析したとします。しかし、エポック時間「1709938901291」になっているような場合には、そのまま読み取ることは難しいでしょう。また一方で、逆のことが起こる可能性もあります。「March 08, 2024 23:01:41」のような文字列形式で日付を抽出したものの、このタイムスタンプを他のタイムスタンプと比較する方法がないようなケースです。

このような問題への対処として、タイムスタンプを任意の形式に変換する関数を追加しました。

toTimestamp(datestring [, pattern [, timezone]])

toTimestamp() または fromDateTime() は、日付文字列を受け取り、それをエポックミリ秒単位で表されるタイムスタンプに変換します。

例:
FROM Log
SELECT toTimestamp('2023-10-18 15:27', 'yyyy-MM-dd HH:mm', timezone: 'America/Los_Ang')

上記クエリの結果として、エポックタイムの値 1697668020000 が得られます。

toTimestamp

注:New Relic UI は、エポックタイム形式のタイムスタンプを、自動的に読み取り可能な日付に変換して表示します。

toDatetime(timestamp [, pattern [, timezone]])

toDatetime() または fromTimestamp() は、タイムスタンプの数値を受け取り、選択した日付文字列に変換します。出力フォーマットを指定しない場合のデフォルトの形式は yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX] です。
また、オプションでタイムゾーン値を指定することもできます。

例:
FROM Log
SELECT toDatetime(1697668020000, 'yyyy-MM-dd HH:mm', timezone: 'America/Los_Angeles')

上記のクエリは「2023-10-18 15:27」を返します。

toDatetime

詳細については、各関数のドキュメントを参照してください:toTimestamp()toDatetime()

IPアドレスをマッピングする

IP アドレスはシステム内の重要なデータポイントになる可能性があり、アドレス範囲ごとにグループ化すると、データの送信元を大まかに把握できるようになります。これまで、IP アドレスからネットワークアドレスに変換するのは手間の掛かる作業でしたが、cidrAddress() を使用すると、この問題を解決できます。

cidrAddress(<attribute> [,<number> [ ,cidrFormat:true|false]])

cidrAddress() は文字列として IP アドレスを受け取り、対応するネットワークアドレスを出力します。IP アドレス単独、または CIDR 表記のプレフィックス長を含む形式をサポートします。引数の number はプレフィックス長を表しますが、元の文字列が CIDR 表記の場合には、プレフィックス長の指定は無視されます。

以下のように、IP アドレスとポートが埋め込まれたログメッセージがあるとします。

...{id:"etcd-events-a" endpoints:"172.20.44.143:3997" }...

ここでもアンカー解析を使用して IP アドレスにあたる箇所を抽出し、今回の新しい関数を使用してそのネットワークアドレスを見つけることができます。

WITH aparse(message, '%endpoints:"*:*"%') AS (IP, Port)
FROM Log SELECT count(*) 
FACET cidrAddress(IP, 24)
WHERE message LIKE '%etcdClusterPeerInfo%'

cidrAddress

詳細については、以下のドキュメントを参照してください:cidrAddress()

Base64のエンコードとデコード

データが Base64 形式で届き、デコード後の文字列を評価したり、逆に再エンコードしたいケースがあるかもしれません。このようなケースへの対処として、encode()decode() を使用すると、いつでもデータを再フォーマットすることができます。

encode(input, encoding)

encode() は、第 2 引数で指定されたエンコード形式に従って、指定された文字列を変換します。デフォルトでは Base64 への変換になりますが、エンコードパラメータとして "base64"、"base64mime"、"base64url" をサポートしています。encode() は blob をサポートしていません。

例:
FROM Event SELECT encode('Hello World', 'base64')

上記のクエリは「SGVsbG8gV29ybGQ=」を返します。

decode(input, encoding)

decode() は 第 2 引数で指定されたエンコード形式に従って、文字列と blob に対して文字列のデコードを実行します。デフォルトでは Base64 形式からのデコードになりますが、エンコード形式として "base64"、"base64mime"、"base64url" を指定することができます。

例:

FROM Event SELECT decode(‘SGVsbG8gV29ybGQ=', ‘base64’)

上記のクエリは「Hello World」を返します。

詳細については、各関数のドキュメントを参照してください:encode()decode()

ある単位から別の単位に変換する

これは文字どおり簡単な作業です。例えば、ミリ秒単位で保存されているデータがあり、それを秒に変換したい場合は、次の関数が役立ちます。

convert(attribute, fromUnits, toUnits)

例1:
FROM Transaction
SELECT duration, convert(duration, 's', 'ms')

convert

この機能は、OpenTelemetry(OTel)メトリクスに単位が指定されていて、変換が動的になる場合に特に役立ちます。

例2:
FROM FROM Metric
SELECT average(convert(apm.service.transaction.duration, unit, 'ms')) AS 'Response time'

詳細については、以下のドキュメントを参照してください:convert()

まとめ

これらの解析および変換機能が追加されたことで、たとえデータが JSON 文字列の中に隠れていたり、エンコードされていたりする場合でも、非常に簡単に抽出して利用できるようになりました。今回ご紹介した新しい機能を是非お試し頂き、より深いインサイトを得るために活用して頂ければ幸いです。