中間データベースを使用して、Grafana と IRIS(または Cache/Ensemble)を使用する方法を説明した非常に有益な記事がコミュニティにいくつか掲載されています。 しかし私は、IRIS 構造に直接アクセスしたいと考えていました。 特にこのリンクで説明しているように、SQL でアクセス可能なCaché履歴モニターのデータにアクセスしたかったのです。 https://community.intersystems.com/post/apm-using-cach%C3%A9-history-monitor また、データをいじりたくもありませんでした。 必要とするデータを返すクラスクエリはすでにあったので、それらを、JSON を返す REST クラスに埋め込むだけで良かったからです。 クラス Grafana.MonitorData はまだ含めていません。それでなければならないという理由があるわけではなかったためですが、要望があれば、含めることは可能です。 難しい点は 2 つだけでした。 1 つは、各ポイントで、現地時間と UTC 時間を確実に調整することでした。 もう 1 つは、Grafana は「.25」のようにゼロを省略した小数点数値を好まないため、JavaScript エラー「t.dataList.map is not a function 」が発生していたことです。$FN(tValue,,4) を使用した行があるのはそのためです。 原理を明確化するために、私の運用コードを単純化しました。 GitHub に置くことはできますが、とても単純なので、置かないかもしれません。
Class Grafana.SYSHistory Extends %CSP.REST
{
XData UrlMap
{
<Routes>
<Route Url="/" Method="GET" Call="testAvailability" Cors="true" />
<Route Url="/search" Method="POST" Call="metricFindQuery" Cors="true" />
<Route Url="/query" Method="POST" Call="query" Cors="true" />
</Routes>
}
ClassMethod testAvailability() As %Status
{
write "ok"
quit $$$OK
}
/// このメソッドは利用可能なメトリクスのリストを返します.
ClassMethod metricFindQuery() As %Status
{
do ##class(Grafana.MonitorData).GetSupportedMetrics(.metrics)
w "["
set sub=""
set firsttime=1
do {
set sub=$o(metrics(sub))
quit:sub=""
if firsttime=0 w ","
set firsttime=0
w """",sub,""""
} while sub'=""
write "]"
quit $$$OK
}
/// Grafana のデータ形式 - http://docs.grafana.org/plugins/developing/datasources/
ClassMethod query() As %Status
{
if obj="" {
write "no object found"
quit $$$OK
}
set iter=obj.targets.%GetIterator()
set tMetrics=0
while iter.%GetNext(.key,.value) {
set tMetrics=tMetrics+1
set tMetrics(tMetrics) = value.target
}
set from = obj.range.from
set to = obj.range.to
#define classname 1
#define queryname 2
set (className,queryName)=""
//どのクエリからどのクラスにもアクセスできないように、クラスをハードコードして、'NamedQuery' アイテムを使用します...
set className="Grafana.MonitorData"
set queryName="SysMonHistorySummary"
write "["
for i=1:1:tMetrics {
if i>1 w ","
w "{""target"":"""_tMetrics(i)_""",""datapoints"":["
do ..ExportJSON(className,queryName,from,to,tMetrics(i))
write "]}"
}
write "]"
quit $$$OK
}
/// 実行するクエリを判定する className と QueryName。
/// from と to は現地時間で、%Date (a.k.k. $horolog) 形式です。
/// クエリはメトリクスの値を返す必要があります。 このコードは、値が Avg_Metric と RunDate
/// として返されることを前提としていますが、それは変更可能です。
ClassMethod ExportJSON(className As %String, queryName As %String, from, to, pMetric As %String) As %Status
{
if className="" quit $$$OK
if queryName="" quit $$$OK
set rs=##class(%ResultSet).%New(className_":"_queryName)
if rs="" quit $$$ERROR($$$QueryDoesNotExist,className_":"_queryName)
// これは param 情報としてのみ使用
set sc=$classmethod(className,queryName_"GetInfo",.colinfo,.paraminfo,.idinfo,.QHandle,0,.extinfo)
//リクエストにはクエリのパラメーターに一致する名前のあるデータが含まれる必要があります。
//日付と時刻のパラメーターを文字列から $h に変換します。
set from=$e(from,1,19)
set to=$e(to,1,19)
set RunDateUTCFromH=$zdth(from,3)
set RunDateFromH=$zdth(RunDateUTCFromH,-3)
set RunDateUTCToH=$zdth(to,3)
set RunDateToH=$zdth(RunDateUTCToH,-3)
set tSc=rs.Execute(RunDateFromH,RunDateToH,"live",pMetric) //param(1),param(2))
if $$$ISERR(tSc) quit tSc
set rowcnt=0
while rs.Next() {
set rowcnt=rowcnt+1
if rowcnt>1 write ","
write "["
set tRunDate=rs.Data("RunDate")
set tUtcRunDate=$zdt(tRunDate,-3)
set tValue=rs.Data("Avg_Metric")
set tPosixTime=##class(%Library.PosixTime).OdbcToLogical($zdt(tUtcRunDate,3,3))
set tUnixTime=##class(%Library.PosixTime).LogicalToUnixTime(tPosixTime)_"000"
write $fn(tValue,,4),",",tUnixTime
write "]"
}
quit $$$OK
}
}