diff --git a/webapp/backend/pkg/database/interface.go b/webapp/backend/pkg/database/interface.go index bc52475..9e50596 100644 --- a/webapp/backend/pkg/database/interface.go +++ b/webapp/backend/pkg/database/interface.go @@ -26,4 +26,5 @@ type DeviceRepo interface { SaveSmartTemperature(ctx context.Context, wwn string, deviceProtocol string, collectorSmartData collector.SmartInfo) error GetSummary(ctx context.Context) (map[string]*models.DeviceSummary, error) + GetSmartTemperatureHistory(ctx context.Context, durationKey string) (map[string][]measurements.SmartTemperature, error) } diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 6c31c83..3e2c61b 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -289,7 +289,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { smart_data = from(bucket: sourceBucket) |> range(start: rangeStart, stop: rangeEnd) |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|device_wwn|attribute_id|when_failed)/) + |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|status_reason|device_wwn|attribute_id|when_failed)/) |> last() |> yield(name: "last") @@ -514,7 +514,8 @@ func (sr *scrutinyRepository) SaveSmartTemperature(ctx context.Context, wwn stri return nil } -func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context) (map[string][]measurements.SmartTemperature, error) { +func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context, durationKey string) (map[string][]measurements.SmartTemperature, error) { + //we can get temp history for "week", "month", "year", "forever" deviceTempHistory := map[string][]measurements.SmartTemperature{} @@ -522,14 +523,15 @@ func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context) (m queryStr := fmt.Sprintf(` import "influxdata/influxdb/schema" from(bucket: "%s") - |> range(start: -1w, stop: now()) + |> range(start: %s, stop: now()) |> filter(fn: (r) => r["_measurement"] == "temp" ) |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) |> schema.fieldsAsCols() |> group(columns: ["device_wwn"]) |> yield(name: "last") `, - sr.appConfig.GetString("web.influxdb.bucket"), + sr.lookupBucketName(durationKey), + sr.lookupDuration(durationKey), ) result, err := sr.influxQueryApi.Query(ctx, queryStr) @@ -590,6 +592,7 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model |> range(start: -1y, stop: now()) |> filter(fn: (r) => r["_measurement"] == "smart" ) |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") + |> last() |> schema.fieldsAsCols() |> group(columns: ["device_wwn"]) |> yield(name: "last") @@ -630,7 +633,7 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return nil, err } - deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx) + deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx, "week") if err != nil { sr.logger.Printf("========================>>>>>>>>======================") sr.logger.Printf("========================>>>>>>>>======================") @@ -645,3 +648,44 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return summaries, nil } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Helper Methods +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func (sr *scrutinyRepository) lookupBucketName(durationKey string) string { + switch durationKey { + case "week": + //data stored in the last week + return sr.appConfig.GetString("web.influxdb.bucket") + case "month": + // data stored in the last month (after the first week) + return fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) + case "year": + // data stored in the last year (after the first month) + return fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) + case "forever": + //data stored before the last year + return fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket")) + } + return sr.appConfig.GetString("web.influxdb.bucket") +} + +func (sr *scrutinyRepository) lookupDuration(durationKey string) string { + + switch durationKey { + case "week": + //data stored in the last week + return "-1w" + case "month": + // data stored in the last month (after the first week) + return "-1mo" + case "year": + // data stored in the last year (after the first month) + return "-1y" + case "forever": + //data stored before the last year + return "-10y" + } + return "-1w" +} diff --git a/webapp/backend/pkg/web/handler/get_devices_summary_temp_history.go b/webapp/backend/pkg/web/handler/get_devices_summary_temp_history.go new file mode 100644 index 0000000..631b9ec --- /dev/null +++ b/webapp/backend/pkg/web/handler/get_devices_summary_temp_history.go @@ -0,0 +1,32 @@ +package handler + +import ( + "github.com/analogj/scrutiny/webapp/backend/pkg/database" + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "net/http" +) + +func GetDevicesSummaryTempHistory(c *gin.Context) { + logger := c.MustGet("LOGGER").(logrus.FieldLogger) + deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo) + + durationKey, exists := c.GetQuery("duration_key") + if !exists { + durationKey = "week" + } + + tempHistory, err := deviceRepo.GetSmartTemperatureHistory(c, durationKey) + if err != nil { + logger.Errorln("An error occurred while retrieving summary/temp history", err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "data": map[string]interface{}{ + "temp_history": tempHistory, + }, + }) +} diff --git a/webapp/backend/pkg/web/server.go b/webapp/backend/pkg/web/server.go index c685916..078e216 100644 --- a/webapp/backend/pkg/web/server.go +++ b/webapp/backend/pkg/web/server.go @@ -36,9 +36,10 @@ func (ae *AppEngine) Setup(logger logrus.FieldLogger) *gin.Engine { }) api.POST("/health/notify", handler.SendTestNotification) //check if notifications are configured correctly - api.POST("/devices/register", handler.RegisterDevices) //used by Collector to register new devices and retrieve filtered list - api.GET("/summary", handler.GetDevicesSummary) //used by Dashboard - api.POST("/device/:wwn/smart", handler.UploadDeviceMetrics) //used by Collector to upload data + api.POST("/devices/register", handler.RegisterDevices) //used by Collector to register new devices and retrieve filtered list + api.GET("/summary", handler.GetDevicesSummary) //used by Dashboard + api.GET("/summary/temp", handler.GetDevicesSummaryTempHistory) //used by Dashboard (Temperature history dropdown) + api.POST("/device/:wwn/smart", handler.UploadDeviceMetrics) //used by Collector to upload data api.POST("/device/:wwn/selftest", handler.UploadDeviceSelfTests) api.GET("/device/:wwn/details", handler.GetDeviceDetails) //used by Details } diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html index 4fd1574..a63f8d2 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html @@ -127,13 +127,12 @@ matTooltip="not yet implemented" mat-button [matMenuTriggerFor]="accountBalanceMenu"> - 12 months + 1 week - - - + +