-
-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api): Expose uptime data as text via API (#758)
* Expose Raw Uptime Data via API Signed-off-by: James Hillyard <[email protected]> * Add Test for Raw Uptime Data API Endpoint Signed-off-by: James Hillyard <[email protected]> * Document Raw Uptime Data API Endpoint Signed-off-by: James Hillyard <[email protected]> * Fix Test after #759 Core Refactor Signed-off-by: James Hillyard <[email protected]> * Update Raw Data Content Type Signed-off-by: James Hillyard <[email protected]> * Support 30d Data from Raw Uptime Endpoint Signed-off-by: James Hillyard <[email protected]> * Update README.md * Update README.md --------- Signed-off-by: James Hillyard <[email protected]> Co-authored-by: TwiN <[email protected]>
- Loading branch information
1 parent
e88f47f
commit c44d998
Showing
4 changed files
with
155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package api | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/TwiN/gatus/v5/storage/store" | ||
"github.com/TwiN/gatus/v5/storage/store/common" | ||
"github.com/gofiber/fiber/v2" | ||
) | ||
|
||
func UptimeRaw(c *fiber.Ctx) error { | ||
duration := c.Params("duration") | ||
var from time.Time | ||
switch duration { | ||
case "30d": | ||
from = time.Now().Add(-30 * 24 * time.Hour) | ||
case "7d": | ||
from = time.Now().Add(-7 * 24 * time.Hour) | ||
case "24h": | ||
from = time.Now().Add(-24 * time.Hour) | ||
case "1h": | ||
from = time.Now().Add(-2 * time.Hour) // Because uptime metrics are stored by hour, we have to cheat a little | ||
default: | ||
return c.Status(400).SendString("Durations supported: 30d,7d, 24h, 1h") | ||
} | ||
key := c.Params("key") | ||
uptime, err := store.Get().GetUptimeByKey(key, from, time.Now()) | ||
if err != nil { | ||
if errors.Is(err, common.ErrEndpointNotFound) { | ||
return c.Status(404).SendString(err.Error()) | ||
} else if errors.Is(err, common.ErrInvalidTimeRange) { | ||
return c.Status(400).SendString(err.Error()) | ||
} | ||
return c.Status(500).SendString(err.Error()) | ||
} | ||
|
||
c.Set("Content-Type", "text/plain") | ||
c.Set("Cache-Control", "no-cache, no-store, must-revalidate") | ||
c.Set("Expires", "0") | ||
return c.Status(200).Send([]byte(fmt.Sprintf("%f", uptime))) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package api | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
"time" | ||
|
||
"github.com/TwiN/gatus/v5/config" | ||
"github.com/TwiN/gatus/v5/config/endpoint" | ||
"github.com/TwiN/gatus/v5/config/endpoint/ui" | ||
"github.com/TwiN/gatus/v5/storage/store" | ||
"github.com/TwiN/gatus/v5/watchdog" | ||
) | ||
|
||
func TestRawDataEndpoint(t *testing.T) { | ||
defer store.Get().Clear() | ||
defer cache.Clear() | ||
cfg := &config.Config{ | ||
Metrics: true, | ||
Endpoints: []*endpoint.Endpoint{ | ||
{ | ||
Name: "frontend", | ||
Group: "core", | ||
}, | ||
{ | ||
Name: "backend", | ||
Group: "core", | ||
}, | ||
}, | ||
} | ||
|
||
cfg.Endpoints[0].UIConfig = ui.GetDefaultConfig() | ||
cfg.Endpoints[1].UIConfig = ui.GetDefaultConfig() | ||
|
||
watchdog.UpdateEndpointStatuses(cfg.Endpoints[0], &endpoint.Result{Success: true, Connected: true, Duration: time.Millisecond, Timestamp: time.Now()}) | ||
watchdog.UpdateEndpointStatuses(cfg.Endpoints[1], &endpoint.Result{Success: false, Connected: false, Duration: time.Second, Timestamp: time.Now()}) | ||
api := New(cfg) | ||
router := api.Router() | ||
type Scenario struct { | ||
Name string | ||
Path string | ||
ExpectedCode int | ||
Gzip bool | ||
} | ||
scenarios := []Scenario{ | ||
{ | ||
Name: "raw-uptime-1h", | ||
Path: "/api/v1/endpoints/core_frontend/uptimes/1h", | ||
ExpectedCode: http.StatusOK, | ||
}, | ||
{ | ||
Name: "raw-uptime-24h", | ||
Path: "/api/v1/endpoints/core_backend/uptimes/24h", | ||
ExpectedCode: http.StatusOK, | ||
}, | ||
{ | ||
Name: "raw-uptime-7d", | ||
Path: "/api/v1/endpoints/core_frontend/uptimes/7d", | ||
ExpectedCode: http.StatusOK, | ||
}, | ||
{ | ||
Name: "raw-uptime-30d", | ||
Path: "/api/v1/endpoints/core_frontend/uptimes/30d", | ||
ExpectedCode: http.StatusOK, | ||
}, | ||
{ | ||
Name: "raw-uptime-with-invalid-duration", | ||
Path: "/api/v1/endpoints/core_backend/uptimes/3d", | ||
ExpectedCode: http.StatusBadRequest, | ||
}, | ||
{ | ||
Name: "raw-uptime-for-invalid-key", | ||
Path: "/api/v1/endpoints/invalid_key/uptimes/7d", | ||
ExpectedCode: http.StatusNotFound, | ||
}, | ||
} | ||
for _, scenario := range scenarios { | ||
t.Run(scenario.Name, func(t *testing.T) { | ||
request := httptest.NewRequest("GET", scenario.Path, http.NoBody) | ||
if scenario.Gzip { | ||
request.Header.Set("Accept-Encoding", "gzip") | ||
} | ||
response, err := router.Test(request) | ||
if err != nil { | ||
return | ||
} | ||
if response.StatusCode != scenario.ExpectedCode { | ||
t.Errorf("%s %s should have returned %d, but returned %d instead", request.Method, request.URL, scenario.ExpectedCode, response.StatusCode) | ||
} | ||
}) | ||
} | ||
} |