TrafficSentinelのスクリプトクエリ機能

#スクリプト・クエリ(TrafficSentinelのスクリプトクエリ機能)
Traffic Sentinelスクリプトクエリ機能は、特殊なクエリを作成するための強力なメカニズムを提供します。ほとんどのユーザーは、スクリプトインターフェイスを使用する必要はありません。標準のレポート機能で、ほとんどの一般的なタイプのレポートを生成できます。スクリプトは通常、データを抽出してフォーマットし、他のツール（課金アプリケーションなど）にインポートできるようにするため、あるいは、複数のソースからのデータを1つのグラフまたは表に結合するような別のタイプのレポートを開発するために使用されます。

###クエリの実行
スクリプトインターフェイスは、[レポート]> [スクリプト]メニューからのアクセスです。次の図は、デフォルトのクエリスクリプトを使用したスクリプトフォームを示しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705452/8552acb2-4c4e-37ec-f60e-61b2a7e7c108.png)


スクリプトを入力するか、フォームのテキスト入力領域にスクリプトを貼り付け、[実行]ボタンをクリックしてスクリプトの結果を確認します。 [デフォルト]ボタンをクリックして、デフォルトのスクリプトに戻ります。デフォルトのスクリプトは、単純なtopNクエリを作成します。ビュー、where、interval、sort、n、format、および、headingの値を編集して、クエリを試し、結果を確認できます。

次の図は、一般的なクエリ結果を示しています。:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705452/4e45a8c5-6ac2-76c5-3603-eb06d22ff03c.png)


[戻る]ボタンをクリックして、スクリプトフォームに戻ります。

###データのインポート
クエリ結果を表示する場合：TXTボタンをクリックして、URLにエンコードされたクエリを含む単純なテキスト結果を取得します。 URLをコピーして、いつでもクエリを実行するために使用できます。 wgetやPerlなどのWeb対応ツールは、クエリURLを使用してデータを抽出できます。

注：スクリプトが長すぎてURLに渡されない場合があります。この場合、HTTP POST操作を使用してデータを取得する必要があります（wgetとPerlの両方がPOSTをサポートしています）。 IQY形式の3行目と4行目に、POSTに必要なURLと引数の両方が表示されます（以下を参照）。

IQYボタンは、クエリをMicrosoft ExcelのIQY形式で表示します。テキストテキストを切り取って貼り付け、メモ帳を使用して拡張子が.IQYのファイルを作成すると、MicrosoftExcelがそれを使用してWebクエリを実行できるようになります。

注：Excelは、CSV形式ではなくHTMLテーブルとしてデータを保持しようとします。デフォルトのクエリスクリプトでフォーマットを「html」に変更するだけで、結果をHTMLテーブルとして取得できます。

###スクリプトの記述
Traffic Sentinelで使用されるスクリプト言語は、E4X拡張機能を備えたJavaScript1.6です。 Javascriptは、Webページ内で一般的に使用される単純なスクリプト言語（Visual Basicライク）です。 Javascriptには無料のチュートリアルがたくさんあります（Googleで「javascriptチュートリアル」を検索してください）。書籍であれば、「[Javascript：The DefinitiveGuide](https://www.oreilly.com/library/view/javascript-the-definitive/0596101996/)」が優れたリファレンスです。

このチュートリアルの残りの部分では、スクリプトがネットワークトポロジとトラフィック情報にアクセスし、計算を実行して結果を出力し、他のツールに簡単にインポートできるようにする方法の例を示します。

注：これらのサンプルスクリプトを切り取ってスクリプトフォームに貼り付け、自分で試すことができます。自身のTraffic Sentinelにアクセスできない場合は、[demo.inmon.com](https://demo.inmon.com/inmsf/Query) でこれらのスクリプトを試用できます。

####プリント
印刷機能は、Javascript言語の標準機能ではありません。次の2つのグローバル関数が追加され、スクリプトからテキスト出力を返すことができるようになりました。print()は結果を出力し、println()は結果を出力して改行します。

```
print("hello");
println(" world");
println("one plus one equals " + (1 + 1));
```
印刷機能は、スクリプトのテストに非常に役立ちます。期待する結果が得られていることを確認するために、printステートメントを含めましょう。

####Network
[Network](https://inmon.com/sentinel_help/8.0/help/en/report/query.shtml#network) クラスは、現在のネットワーク・ステートへのインターフェイスです。エージェントとインターフェイス、ネットワークトポロジ、およびアドレスマッピングに関する情報を提供します。

次の例では、新しいネットワークオブジェクトを作成し、すべてのエージェントのリストを要求してから、エージェントのIPアドレスとシステム説明(sysDescr)を出力するエージェントをリピート処理します。

クラスは、現在のネットワーク・ステートへのインターフェイスです。エージェントとインターフェイス、ネットワークトポロジ、およびアドレスマッピングに関する情報を提供します。

次の例では、新しいネットワークオブジェクトを作成し、すべてのエージェントのリストを要求してから、エージェントのIPアドレスとシステム説明(sysDescr)を出力するエージェントをリピート処理します。

```
var n = Network.current();
var agents = n.agents();
for(var i = 0; i < agents.length; i++) {
  n.path = agents[i];
  println("ip=" + n.agentIP() + " sysDescr=" + n.sysDescr());
};
```

path属性は、設定で指定されたネットワークデバイスの階層グループを参照します（ネットワーク階層の詳細については、[TrafficSentinelの設定](https://qiita.com/Shinya_IDENO/items/bcdd6c04f3d9e6c02463)
を参照してください）。パスを設定すると、後続のクエリの範囲が制限されます。前の例では、エージェントへのパスを設定すると、エージェント固有のデータを照会できます。

ネットワークオブジェクトには、引数の配列を受け取り、結果の配列を返す多数のMap関数もあります。次の例では、vendorMap（）関数を使用して、MACアドレスの配列に関連付けられているベンダー名を検索します。

```
var n = Network.current();
var macs = ["000480F54600","001321B21CE1","0002556F2F78"];
var vendors = n.vendorMap(macs);
for(var i = 0; i < macs.length; i++) println(macs[i] + " " + vendors[i]);
```

####クエリ
[Query](https://inmon.com/sentinel_help/8.0/help/en/report/query.shtml#query) クラスは、トラフィックデータベースにインターフェイスカウンタデータとトラフィックフロー情報を照会するために使用されます。トラフィックデータベースは、特定の属性セットを持つビューに編成されています。:

[traffic](https://inmon.com/sentinel_help/8.0/help/en/report/api_view_traffic.shtml) ：このビューは、トラフィックフローをクエリするために使用されます（たとえば、先月の上位のWebサーバー）。
[ifcounters](https://inmon.com/sentinel_help/8.0/help/en/report/api_view_ifcounters.shtml) ：このビューは、インターフェイスカウンターの傾向を照会するために使用されます（たとえば、先月のリンクでの使用率の傾向）。
[host](https://inmon.com/sentinel_help/8.0/help/en/report/api_view_host.shtml) ：このビューは、ホストパフォーマンスカウンター（CPU、メモリ、IOなど）を照会するために使用されます。
[application](https://inmon.com/sentinel_help/8.0/help/en/report/api_view_application.shtml) ：このビューは、アプリケーションのトランザクション情報（URL、応答時間など）を照会するために使用されます。
[events](https://inmon.com/sentinel_help/8.0/help/en/report/api_view_events.shtml) ：このビューは、イベントログをクエリするために使用されます（たとえば、危機的なイベントの上位タイプを識別します）。
注：このリストのリンクをクリックして、各ビューのすべての属性の詳細を取得してください。

ビュー内では、属性は2つの主要なタイプに分類されます。集計時にカテゴリを形成するキーと、累積される統計値です。たとえば、ipsourceはカテゴリで、bytesは統計値です。ipsource属性とbytes属性を指定するクエリは、各送信元IPアドレスのバイトを合計した結果を生成します。

クエリを作成するには、ビューを指定し、属性を選択し、時間間隔を選択して、結果の並べ替え方法を指定する必要があります。次の例では、簡単なクエリを作成します。

```
var q = new Query();
q.view     = "traffic";
q.select   = "ipsource,bytes";
q.where    = "sourcezone != EXTERNAL";
q.interval = "today";
q.sort     = "bytes";
q.truncate = 5;
var t = q.run();
t.printCSV(true);
```

このスクリプトは、バイトでソートされた上位5つのローカルの送信元IPアドレスのクエリを作成します。 q.run()ステートメントはクエリを評価し、結果としてテーブルを返します。

同じクエリを作成する簡単な方法は、Query.topN()関数を使用することです。次のスクリプトは、上記とまったく同じクエリを実行します

```
var q = Query.topN("traffic",
                   "ipsource,bytes",
                   "sourcezone != EXTERNAL",
                   "today",
                   "bytes",
                   5);
var t = q.run();
t.printCSV(true);
```

この例では、データはビューの値属性の1つでソートされています。代わりに、キー属性の1つの一意の値の数をカウントし、それを値として使用すると便利な場合があります。このタイプのクエリは、スキャン動作（インターネットワームやポートスキャンに関連することが多い）を特定するのに特に役立ちます。次の例は、count()関数をクエリに適用する方法を示しています。

```
var q = Query.topN("traffic",
                   "ipsource,count(ipdestination)",
                   "destinationport = TCP:80 & sourcezone != EXTERNAL",
                   "today",
                   "count(ipdestination)",
                   5);
var t = q.run();
t.printCSV(true);
```

クエリは、ポートTCP:80を使用してローカルネットワーク上のホストによってスキャンされたアドレスの数をカウントし、スキャンされたアドレスの数による上位ホストを一覧表示します。

もう1つの一般的なタイプのクエリは、時間の経過に伴う変化を示す傾向を生成することです。次のスクリプトは、Query.trend()関数を使用してクエリを作成します。

```
var q = Query.trend("traffic",
                   "time,bytes",
                   "protocol = TCP",
                   "yesterday",
                   "hour");
var t = q.run();
t.printCSV(true);
```

スクリプトは、TCPトラフィックの合計バイト数を時間ごとの傾向を表示します。合計ではなくバイトレートが必要な場合（つまり、各間隔の1秒あたりの平均バイト数）、次のようにrate(bytes)をbytesの代わりに使用できます。


```
var q = Query.trend("traffic",
                   "time,rate(bytes)",
                   "protocol = TCP",
                   "yesterday",
                   "hour");
var t = q.run();
t.printCSV(true);
```

####テーブル
[Table](https://inmon.com/sentinel_help/8.0/help/en/report/query.shtml#table) クラスは、クエリ結果を表すために使用されます。テーブルは、テーブルの列（列の名前とタイプを含む）とデータの行数に関する情報で構成されます。

前の例では、1秒あたりのバイト数で測定された値を表示するクエリを作成しました。結果をビット/秒で表示する場合は、8倍にスケーリングする必要があります。テーブルscaleColumn（）関数は、このタスクを実行できます。

```
var q = Query.trend(“traffic”,

                   "time,rate(bytes)",
                   "protocol = TCP",
                   "yesterday",
                   "hour");
var t = q.run();
t.scaleColumn(1,8);
t.printCSV(true);
```

次の例は、追加データを使用してテーブルを拡張する方法を示しています。

```
var q = Query.topN("traffic",
                   "ipsource,bytes",
                   "sourcezone != EXTERNAL",
                   "today",
                   "bytes",
                   5);
var t = q.run();
var n = Network.current();
var addresses = t.column(0);
var locations = n.locationMap(addresses);
t.insertColumn("location","interface",locations,1);
t.printCSV(true);
```

スクリプトは、アドレスを含むテーブル列（列0）にアクセスし、Network locationMap（）関数を使用して、ネットワークに接続しているスイッチインターフェイスへの各アドレスを見つけます。 insertColumn関数は、テーブル内のアドレスの直後に位置情報を挿入するために使用されます（列の位置に名前を付け、そのタイプをインターフェースとして宣言します）。

####SNMP
[SNMP](https://inmon.com/sentinel_help/8.0/help/en/report/query.shtml#snmp) クラスは、ネットワーク内のデバイスにSNMP（Simple Network Management Protocol）要求を行うために使用されます。多くの標準SNMP変数は、Network クラスを使用してすでに使用可能です（例：sysName（）、ifName（）など）。可能な場合は、Networkクラスから情報を取得する方がはるかに効率的です。通常、SNMPクラスは、Traffice Sentinelが定期的に監視しないデバイスからデータを取得するため、またはベンダー固有の情報を取得するために使用されます。

次のスクリプトは、ベンダー固有の変数を取得する方法を示しています。この場合、FoundryNetworks機器からの温度の取得です。

```
var selectedAgents = [];
var n = Network.current();
for each (var agent in n.agents()) {
  n.path = agent;
  var id = n.sysObjectID();
  if(id && id.indexOf(".1.3.6.1.4.1.1991.") == 0) selectedAgents.push(agent);
}

var s = new SNMP();
s.oid = ".1.3.6.1.4.1.1991.1.1.1.1.18.0";
var t = Table.create(["Agent","Name","Degrees C"],
                     ["agent","string","integer"]);
for each(var agent in selectedAgents) {
  n.path = agent;
  s.host = agent;
  try {
    var val = s.get();
    if(val[0]) t.addRow([agent, n.sysName(), parseInt(val[0]) / 2]);
  } catch(ex) {};
}
t.printCSV(true);
```

スクリプトの最初の部分では、Networkオブジェクトを使用してすべてのエージェントを列挙します。 Foundry Networksエージェントは、各エージェントのsysObjectIDをチェックして、FoundryNetworksプレフィックス「.1.3.6.1.4.1.1991」で始まるかどうかを確認することで識別されます。スクリプトの2番目の部分は、選択した各エージェントに現在のシャーシ温度の要求を送信し、結果をテーブルにまとめます。

####readurl
readurl関数は、データをスクリプトにインポートするために使用されます。次の例は、readurlを使用してオンライン情報ソースにアクセスする方法を示しています。

```
var addr = "64.151.76.40";
var url = "http://www.radb.net/cgi-bin/radb/advanced-query.cgi"
url +=  "?submit=Query&searchstr=" + addr;
var res = readurl(url);
var match = /descr:[\s]+([^\n]+)/.exec(res);
println(match[1]);
```

このスクリプトは、Merit Routing Asset Database（RADb）にIPアドレスに関する情報を照会するURLを作成します。結果のテキストは正規表現を使用して解析され、descr：フィールドの値が出力されます。

次の例では、XMLファイルをインポートし、それを使用して情報を検索します。

```
var url = "https://inmon.com/tutorials3/db.xml";
var db = new XML(readurl(url));
println(db.server.(name=="Web").address);
```

[db.xml](https://inmon.com/tutorials8/db.xml) ドキュメントには、それぞれに名前とアドレスを持つ多数のサーバーのレコードが含まれています。 javascriptのE4X拡張機能は、XMLのネイティブサポートを提供し、XMLドキュメントのクエリ、作成、変更、および印刷のためのメカニズムを提供します。

最後に、readurlを使用して、スクリプトの開始時にjavascript関数と値のライブラリをロードできます。

```
var initscript = readurl("https://inmon.com/tutorials3/init.js");
eval(initscript);
println(descr("64.151.76.40"));
```

init.jsスクリプトには、前に示したRADbルックアップ関数を実装するdescr（）関数が含まれています。

###スクリプトの使用
スクリプトを使用するには、主に3つの方法があります。クエリURLを使用するWebベースのクエリ、クエリコマンド、またはTrafficSentinelレポートツールで使用するためにそれらをxmlテンプレートに組み込むことです。

####URL
クエリURLの形式は次のとおりです。

```
/inmsf/Query?script=script&authenticate=basic&resultFormat=txt
```

ここで、scriptはjavascriptソースです。

URLを介してスクリプトに追加の引数を渡すこともできます。フォームの任意の属性:

```
input_name=value
```

URL内に、フォームの割り当てとしてスクリプトに渡されます

```
var name = value;
```

次のスクリプトは、この手法を示しています。

```
var addrs = [];
if(typeof(address) != 'undefined') addrs = address.split(",");
var n = Network.current();
var locations = n.locationMap(addrs);
for(var i = 0; i < addrs.length; i++) {
  n.path = locations[i];
  print(addrs[i]+ " " + n.sysName() + " " + n.ifName()); 
};
```

スクリプトは、アドレスパラメータが定義されているかどうか（つまり、スクリプトに渡されているかどうか）をテストします。アドレス文字列が定義されている場合、それはコンマ区切りのリストとして扱われ、アドレスの配列に分割されます。locationMap関数は、各アドレスをネットワークに接続するインターフェイスを識別し、結果のエージェントとインターフェイスの情報が出力されます。

次のフォームは、このスクリプトをWebフォームに埋め込む方法を示しています。
以下のような表示です。：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705452/78e2e489-0e32-3657-81ee-5612c3f62ad0.png)
フォームのソースコードを以下に示します。

```
<form action="http://demo.inmon.com/inmsf/Query" method="get">
<input name="input_address" value="10.0.0.238" type="text" />
<input type="submit" />
<input type="hidden" name="authenticate" value="basic" />
<input type="hidden" name="resultFormat" value="txt" />
<input type="hidden" name="script" value="var addrs = [];
if(typeof(address) != 'undefined') addrs = address.split(',');
var n = Network.current();
var locations = n.locationMap(addrs);
for(var i = 0; i &lt; addrs.length; i++) {
  n.path = locations[i];
  print(addrs[i]+ ' ' + n.agent() + ' ' + n.ifName());
};" />
</form>
```

注：スクリプトをフォームフィールドとして含めることができるように、スクリプト内の文字列を区切るため区切り文字を使用しました。 「<」記号は「＆lt;」としてエスケープする必要がありました。 （通常、スクリプトをhtml属性として使用する場合は、通常、文字「<」、「>」、「＆」をそれぞれ「＆lt;」、「＆gt;」、「＆amp;」としてエスケープする必要があります。）。

####コマンドライン
コマンドラインクエリ機能は、TrafficSentinelの標準インストールの一部です。このコマンドは/usr/local/inmsf/bin/queryにあります。queryコマンドは、スクリプトを標準入力として受け取ることができます。:

```
echo "println('hello world');" | /usr/local/inmsf/bin/query
```

またはスクリプトファイルから：

```
/usr/local/inmsf/bin/query hello.js
```

コマンドラインクエリ機能は、標準のLinuxツールを使用してトラフィックデータにアクセスするための便利な方法を提供します。コマンドラインクエリは、Webサーバーとネットワークをバイパスするため、URLベースのクエリよりも信頼性が高くなります。コマンドラインクエリの最も一般的なアプリケーションの1つは、課金のためのトラフィックアカウンティングデータを定期的に抽出することです。 Linux cronサービスは、クエリを使用して、課金システムの課金レコードを更新するために使用される使用状況データを取得するスクリプトを定期的に実行できます。

####XMLテンプレート
チュートリアル「[レポートテンプレートの作成](https://inmon.com/tutorials8/reporttemplate.php)」では、クエリスクリプトに基づいてレポートテンプレートを作成する方法について説明しています。スクリプトを拡張して、レポートにカスタマイズされたグラフや表を作成できます。レポートテンプレートが作成されると、オンデマンドで実行することも、レポートを作成してイベントを生成するようにスケジュールすることもできます。

チュートリアル「[ウィジェットテンプレートの作成](https://inmon.com/tutorials8/widgettemplate.php)」では、クエリスクリプトに基づいてウィジェットテンプレートを作成する方法について説明します。スクリプトを拡張して、ウィジェットにグラフまたは表を表示できます。ウィジェットテンプレートが作成されると、ダッシュボードに含めることができます。