AdSense

網頁

2024/3/22

React Recharts繪製AWS EC2 Instance CPUUtilization指標折線圖

React使用Recharts繪製AWS EC2 Instance CPUUtilization指標折線圖(line chart)。


事前要求

參考「React 安裝Recharts圖表函式庫」建立Raect專案。

參考「Golang 取得AWS CloudWatch metric統計資料」透過Go取得AWS指標統計資料。


Go

建立Go後端Gin web專案,提供GET| [DOMAIN]/cpu-utilization REST API給前端呼叫來取得AWS EC2 instance的CPUUtilization指標資料。

package main

import (
    "context"
    "net/http"
    "sort"
    "strconv"
    "time"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/cloudwatch"
    "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
    "github.com/samber/lo"
)

func main() {
    router := gin.Default()    // get gin engine
    router.Use(cors.Default()) // allow cors
    router.GET("/cpu-utilization", HandleCpuUtilization)
    router.Run()
}

func NewCloudWatchClient(ctx context.Context) *cloudwatch.Client {
    cfg, err := config.LoadDefaultConfig(
        ctx,
        config.WithRegion("ap-northeast-1"),
    )
    if err != nil {
        panic(err)
    }

    return cloudwatch.NewFromConfig(cfg)
}

type QueryString struct {
    StartTime *time.Time `form:"startTime" binding:"required" time_format:"2006-01-02T15:04:05" time_utc:"1"`
    EndTime   *time.Time `form:"endTime" binding:"required" time_format:"2006-01-02T15:04:05" time_utc:"1"`
}

func HandleCpuUtilization(c *gin.Context) {
    ctx := c.Request.Context()
    var q QueryString
    err := c.BindQuery(&q)
    if err != nil {
        c.Error(err)
        return
    }

    client := NewCloudWatchClient(ctx)
    output, err := client.GetMetricStatistics(ctx, &cloudwatch.GetMetricStatisticsInput{
        MetricName: aws.String("CPUUtilization"),
        StartTime:  q.StartTime,
        EndTime:    q.EndTime,
        Period:     aws.Int32(300),
        Namespace:  aws.String("AWS/EC2"),
        Statistics: []types.Statistic{types.StatisticSum},
        Dimensions: []types.Dimension{
            {
                Name:  aws.String("InstanceId"),
                Value: aws.String("i-0dbd976daa9118015"),
            },
        },
    })
    if err != nil {
        c.Error(err)
        return
    }
    points := output.Datapoints
    sort.Slice(points, func(i, j int) bool {
        return points[i].Timestamp.Before(*points[j].Timestamp)
    })

    resp := Response{
        Points: lo.Map(points, func(point types.Datapoint, i int) Point {
            return Point{
                DateTime: point.Timestamp.Format("15:04"),
                Value:    strconv.FormatFloat(*point.Sum, 'f', 2, 64),
                Unit:     string(point.Unit),
            }
        }),
    }

    c.JSON(http.StatusOK, resp)
}

type Response struct {
    Points []Point `json:"points"`
}

type Point struct {
    DateTime string `json:"dateTime"`
    Value    string `json:"value"`
    Unit     string `json:"unit"`
}

github


啟動Go專案,待稍後React專案啟動呼叫其API。


React

修改Chart.js如下。

Chart.js

import { useEffect, useState } from "react";
import * as React from 'react';
import { LineChart, Line, XAxis, YAxis, Tooltip, Legend } from 'recharts';
import axios from 'axios';

export const Chart = () => {
    const [points, setPoints] = useState([])
    useEffect(() => {
    axios.get('http://localhost:8080/cpu-utilization?startTime=2024-03-22T08%3A00%3A00&endTime=2024-03-22T10%3A00%3A00')
      .then(resp => {
        setPoints(resp.data.points)
      })
      .catch(error => {
        console.log(error)
      })
      .finally(() => {
        console.log('done')
      })
  },[])
    return (
        <LineChart width={600} height={200} data={points}>
            <Line type="monotone" dataKey="value" stroke="#ee99cc" />
            <XAxis dataKey="dateTime" />
            <YAxis />
            <Tooltip />
            <Legend />
        </LineChart>
    )
}

github


啟動React專案,Chart component會呼叫後端API,並將回應結果透過Recharts顯示折線圖如下。



沒有留言:

AdSense