こんにちは。CX事業本部Delivery部のakkyです。
Grafanaはプラグインで機能を拡張することができ、さまざまなプラグインが公開されています。 パネル(フロントエンド)プラグインでは独自の可視化が可能になり、バックエンドプラグインでは独自のデータソースへの接続が可能になります。 フロンエンドの部分はReactで書き、バックエンドは基本的にはgo言語で書きます(gRPC対応であれば他の言語も対応)。
今回は、パネルプラグイン開発のチュートリアルを参考に、recharts(グラフライブラリ)を組み合わせて独自にグラフが表示できることを試してみました。
Amazon Managed Grafanaでは独自のプラグインをインストールすることはできません。
使用ソフトウェア
- Grafana 10.0.5
- Node.js 18.17.1
- @grafana/create-plugin 1.12.2
- recharts 2.8.0
Reactは17.0.2がインストールされました。
また、開発はWSL上のUbuntu22.04で行いました。
プラグインの開発
サンプルのビルド
Grafana公式のプラグイン作成チュートリアルを参考に行っていきます。
まずはテンプレートを作成します。適切な名前を付け、プラグインのタイプにpanelを選びます。
npx @grafana/create-plugin@latest
? What is going to be the name of your plugin? testpanel
? What is the organization name of your plugin? classmethod
? How would you describe your plugin?
? What type of plugin would you like? panel
? Do you want to add Github CI and Release workflows? No
? Do you want to add a Github workflow for automatically checking "Grafana API compatibility" on PRs? No
任意のパッケージマネージャー(今回はyarn)でモジュールを入れます。
cd classmethod-my-panel/
yarn install
次のコマンドでビルドします。
yarn run build
rechartsのインストールと開発
まずはrechartsを追加します。
yarn add recharts
プラグインを開発していきます。
パラメータの定義
まずは、パネルの設定に使うためのパラメータを定義していきます。今回は線の色だけ設定できるようにしてみました。
src/types.ts
export interface SimpleOptions {
linecolor: string
}
設定画面の定義
ここの詳しいドキュメントがなかったのですが、addColorPicker
などのUIコンポーネントは@grafana/ui
で定義されているものです。
Colorpickerの説明はこちらです。UIコンポーネントにパラメーターを渡すには、settings
をつくって入れる必要がありました。
今回はenableNamedColors: true
として、色の名前がそのまま渡されるようにしています。色名からカラーコードへの変更はパネル本体のコードで書きます。
src/module.ts
import { PanelPlugin } from '@grafana/data';
import { SimpleOptions } from './types';
import { SimplePanel } from './components/SimplePanel';
export const plugin = new PanelPlugin<SimpleOptions>(SimplePanel).setPanelOptions((builder) => {
return builder
.addColorPicker({
path: "linecolor",
name: "Select line name",
defaultValue: "#F00",
settings: {
enableNamedColors: true
}
});
});
次のような設定項目になります
パネル本体
Reactそのままで書くことができるので、主にrechatsの知識が必要になります。まずはシンプルな折れ線グラフを作ってみました。
Grafana特有の知識としては以下の点があります
- 設定値がoptions
に入ってくる
- 画面テーマやコンポーネントは@grafana/ui
を使う
- 表示するデータのフォーマット
データフォーマットはDataFrames形式で渡されますので、これを適宜加工して使います。
Grafanaでは、値と時刻がそれぞれの配列で渡されますが、rechatsでは値と時刻をセットにしたobjectの配列が必要なので、系列ごとのデータを分解して構成します。
設定画面で登場したカラーピッカーから渡される色名はtheme.visualization.getColorByName()
を使ってカラーコードに変換できました。
src/components/SimplePanel.tsx
import React from 'react';
import { FieldType, PanelProps } from '@grafana/data';
import { SimpleOptions } from 'types';
import { useTheme2 } from '@grafana/ui';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
interface Props extends PanelProps<SimpleOptions> {}
export const SimplePanel: React.FC<Props> = ({ options, data }) => {
const frame = data.series[0];
const timeField = frame.fields.find((field) => field.type === FieldType.time);
const valueField = frame.fields.find((field) => field.type === FieldType.number);
const filed_name = valueField!.name;
const formatted_data = [];
for (const [index, value] of timeField!.values.entries()) {
const date_str = new Date(value).toLocaleString("ja-JP");
formatted_data.push({
"time": date_str,
[valueField!.name]: valueField!.values[index]
});
}
// Convert color name to color code
const theme = useTheme2();
const colorcode = theme.visualization.getColorByName(options.linecolor);
return (
<ResponsiveContainer width="100%" height="100%">
<LineChart
data={formatted_data}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="time" />
<YAxis type='number' domain={['auto', 'auto']}/>
<Tooltip contentStyle={{backgroundColor: theme.colors.background.primary}} itemStyle={{ color: colorcode }} />
<Legend />
<Line type="linear" dataKey={filed_name} stroke={colorcode} isAnimationActive={false} dot={false}/>
</LineChart>
</ResponsiveContainer>
);
};
ビルドと実行
先ほどと同様にyarn run build
でビルドを行い、コンテナで動作テストします。
podman(dockerでも動くと思います)で実行します。GF_DEFAULT_APP_MODEを設定しないと、開発中で署名されていないプラグインを使うことができません。
podman run -d -p 3000:3000 -v ~/classmethod-test-panel:/var/lib/grafana/plugins -e GF_DEFAULT_APP_MODE=development --name=grafana docker.io/grafana/grafana:10.0.5
Grafanaを開き、今回作ったパネルを選択すると、ただしくグラフが表示できました!
なお、開発中にプラグインを更新しても、キャッシュが強く効くため、通常の更新ではうまくいきません。 Chromeの場合はSuper Reloaderを入れるとうまくいきました。
おわりに
Grafanaで独自のパネルプラグインを開発してみました。
Reactコンポーネントとして開発できるので、当初の想定より手軽に開発できました。 Grafanaを使うと、認証やDBからの接続をすべて任せてグラフの開発に集中できて便利ですね。