Skip to content

Commit cc4cb31

Browse files
authored
Merge pull request #3108 from itssimon/master
Add Monitoring with Apitally recipe
2 parents 30475af + 4b22a00 commit cc4cb31

File tree

5 files changed

+285
-0
lines changed

5 files changed

+285
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Here you can find the most **delicious** recipes to cook delicious meals using o
6060
- [Memgraph](./memgraph/README.md) - Using Memgraph.
6161
- [MinIO](./minio/README.md) - A simple application for uploading and downloading files from MinIO.
6262
- [MongoDB](./mongodb/README.md) - Connecting to a MongoDB database.
63+
- [Monitoring with Apitally](./monitoring-with-apitally/README.md) - A simple REST API with monitoring and request logging using Apitally.
6364
- [Multiple Ports](./multiple-ports/README.md) - Running an application on multiple ports.
6465
- [MySQL](./mysql/README.md) - Connecting to a MySQL database.
6566
- [Neo4j](./neo4j/README.md) - Connecting to a Neo4j database.

monitoring-with-apitally/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
title: Monitoring with Apitally
3+
keywords: [api, monitoring, apitally, fiber, go]
4+
description: A simple REST API with monitoring and request logging using Apitally.
5+
---
6+
7+
# Monitoring with Apitally
8+
9+
[![Github](https://img.shields.io/static/v1?label=&message=Github&color=2ea44f&style=for-the-badge&logo=github)](https://github.com/gofiber/recipes/tree/master/monitoring-with-apitally) [![StackBlitz](https://img.shields.io/static/v1?label=&message=StackBlitz&color=2ea44f&style=for-the-badge&logo=StackBlitz)](https://stackblitz.com/github/gofiber/recipes/tree/master/monitoring-with-apitally)
10+
11+
This project showcases a simple REST API built with the Fiber framework in Go, featuring monitoring and request logging via Apitally.
12+
13+
[Apitally](https://apitally.io/fiber) is a lightweight monitoring and analytics tool that helps developers track API usage, performance, and errors with minimal setup.
14+
15+
## Prerequisites
16+
17+
Ensure you have Golang installed.
18+
19+
## Setup
20+
21+
1. Clone the repository:
22+
```sh
23+
git clone https://github.com/gofiber/recipes.git
24+
cd recipes/monitoring-with-apitally
25+
```
26+
27+
2. Install dependencies:
28+
```sh
29+
go get
30+
```
31+
32+
3. Obtain a client ID from [Apitally](https://apitally.io/fiber) by signing up and creating a new app in the dashboard.
33+
34+
## Running the application
35+
36+
1. Start the application:
37+
```sh
38+
APITALLY_CLIENT_ID=your-client-id go run main.go
39+
```
40+
41+
2. Make requests to the API:
42+
```sh
43+
curl -X GET -H "Authorization: Bearer d7e123f5a2b9c4e8d6a7b2c1f5e9d3a4" http://localhost:3000/v1/books
44+
```
45+
46+
## Dashboard
47+
48+
The Apitally dashboard will show the requests you've made to the API.
49+
50+
It provides detailed insights into the API's usage, errors, and performance. Individual requests can be inspected in the request log. You can also set up custom alerts.
51+
52+
![Apitally screenshots](https://assets.apitally.io/screenshots/overview.png)
53+
54+
## References
55+
56+
- [Apitally Documentation](https://docs.apitally.io/frameworks/fiber)
57+
- [Fiber Documentation](https://docs.gofiber.io)

monitoring-with-apitally/go.mod

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module main
2+
3+
go 1.24
4+
5+
require (
6+
github.com/apitally/apitally-go/fiber v0.4.1
7+
github.com/gofiber/fiber/v2 v2.52.6
8+
)
9+
10+
require gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
11+
12+
require (
13+
github.com/andybalholm/brotli v1.1.0 // indirect
14+
github.com/apitally/apitally-go v0.4.1 // indirect
15+
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
16+
github.com/go-playground/locales v0.14.1 // indirect
17+
github.com/go-playground/universal-translator v0.18.1 // indirect
18+
github.com/go-playground/validator v9.31.0+incompatible
19+
github.com/go-playground/validator/v10 v10.16.0 // indirect
20+
github.com/google/uuid v1.6.0 // indirect
21+
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
22+
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
23+
github.com/klauspost/compress v1.17.9 // indirect
24+
github.com/leodido/go-urn v1.2.4 // indirect
25+
github.com/mattn/go-colorable v0.1.13 // indirect
26+
github.com/mattn/go-isatty v0.0.20 // indirect
27+
github.com/mattn/go-runewidth v0.0.16 // indirect
28+
github.com/rivo/uniseg v0.4.4 // indirect
29+
github.com/valyala/bytebufferpool v1.0.0 // indirect
30+
github.com/valyala/fasthttp v1.51.0 // indirect
31+
github.com/valyala/tcplisten v1.0.0 // indirect
32+
golang.org/x/crypto v0.14.0 // indirect
33+
golang.org/x/net v0.17.0 // indirect
34+
golang.org/x/sys v0.28.0 // indirect
35+
golang.org/x/text v0.13.0 // indirect
36+
)

monitoring-with-apitally/go.sum

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
2+
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
3+
github.com/apitally/apitally-go v0.4.1 h1:18tAexe2MZiWC9Jyo8td+TORotS8xf1jJJGm6hveKVE=
4+
github.com/apitally/apitally-go v0.4.1/go.mod h1:5nxehsTcKFlNHGUR4f/qWuCfCC6cK46ks59vuVVtsAE=
5+
github.com/apitally/apitally-go/fiber v0.4.1 h1:BjCcbZAXV6Y0MSqrHTzqD9roA67PqwfWq6Ebr4RtVKA=
6+
github.com/apitally/apitally-go/fiber v0.4.1/go.mod h1:Od4s1530L9r6KTNH9d67iRzszDHx3TJiL9mk2BTJMuE=
7+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
9+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10+
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
11+
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
12+
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
13+
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
14+
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
15+
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
16+
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
17+
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
18+
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
19+
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
20+
github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA=
21+
github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig=
22+
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
23+
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
24+
github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
25+
github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
26+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
27+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
28+
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
29+
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
30+
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
31+
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
32+
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
33+
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
34+
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
35+
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
36+
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
37+
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
38+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
39+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
40+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
41+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
42+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
43+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
44+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
45+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
46+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
47+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
48+
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
49+
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
50+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
51+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
52+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
53+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
54+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
55+
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
56+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
57+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
58+
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
59+
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
60+
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
61+
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
62+
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
63+
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
64+
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
65+
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
66+
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
67+
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
68+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
69+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
70+
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
71+
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
72+
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
73+
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
74+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
75+
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
76+
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
77+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
78+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
79+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

monitoring-with-apitally/main.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package main
2+
3+
import (
4+
"crypto/sha256"
5+
"crypto/subtle"
6+
"log"
7+
"os"
8+
9+
apitally "github.com/apitally/apitally-go/fiber"
10+
"github.com/go-playground/validator"
11+
"github.com/gofiber/fiber/v2"
12+
"github.com/gofiber/fiber/v2/middleware/keyauth"
13+
)
14+
15+
type apiKeyInfo struct {
16+
userID string
17+
userName string
18+
group string
19+
}
20+
21+
type Book struct {
22+
Title string `json:"title" validate:"required"`
23+
Author string `json:"author" validate:"required"`
24+
}
25+
26+
// API keys for demo purposes only
27+
// WARNING: In production applications:
28+
// - Never hardcode API keys in source code
29+
// - Use a secure database and only store hashed keys
30+
var apiKeys = map[string]apiKeyInfo{
31+
"d7e123f5a2b9c4e8d6a7b2c1f5e9d3a4": {userID: "user1", userName: "Alice", group: "admin"},
32+
"8f4e2d1c9b7a5f3e2d8c6b4a9f7e3d1c": {userID: "user2", userName: "Bob", group: "developer"},
33+
"3a9b8c7d6e5f4a2b1c9d8e7f6a5b4c3d": {userID: "user3", userName: "Charlie", group: "reader"},
34+
}
35+
36+
func validateAPIKey(c *fiber.Ctx, key string) (bool, error) {
37+
hashedKey := sha256.Sum256([]byte(key))
38+
39+
for apiKey, info := range apiKeys {
40+
hashedAPIKey := sha256.Sum256([]byte(apiKey))
41+
if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 {
42+
// Set the consumer for Apitally
43+
consumer := apitally.ApitallyConsumer{
44+
Identifier: info.userID,
45+
Name: info.userName,
46+
Group: info.group,
47+
}
48+
c.Locals("ApitallyConsumer", consumer)
49+
return true, nil
50+
}
51+
}
52+
53+
return false, keyauth.ErrMissingOrMalformedAPIKey
54+
}
55+
56+
func main() {
57+
app := fiber.New()
58+
validate := validator.New()
59+
60+
// Monitoring and request logging with Apitally
61+
apitallyConfig := &apitally.ApitallyConfig{
62+
ClientId: os.Getenv("APITALLY_CLIENT_ID"),
63+
Env: "dev",
64+
// Enable request logging (optional)
65+
RequestLoggingConfig: &apitally.RequestLoggingConfig{
66+
Enabled: true,
67+
LogQueryParams: true,
68+
LogRequestHeaders: true,
69+
LogRequestBody: true,
70+
LogResponseHeaders: true,
71+
LogResponseBody: true,
72+
LogPanic: true,
73+
},
74+
}
75+
app.Use(apitally.ApitallyMiddleware(app, apitallyConfig))
76+
77+
// API key authentication
78+
app.Use(keyauth.New(keyauth.Config{
79+
KeyLookup: "header:Authorization",
80+
AuthScheme: "Bearer",
81+
Validator: validateAPIKey,
82+
}))
83+
84+
// Routes
85+
app.Get("/v1/books", func(c *fiber.Ctx) error {
86+
books := []Book{
87+
{Title: "The Go Programming Language", Author: "Alan A. A. Donovan"},
88+
{Title: "Clean Code", Author: "Robert C. Martin"},
89+
}
90+
return c.JSON(books)
91+
})
92+
93+
app.Post("/v1/books", func(c *fiber.Ctx) error {
94+
// Parse and validate the request body
95+
var req Book
96+
if err := c.BodyParser(&req); err != nil {
97+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
98+
}
99+
if err := validate.Struct(req); err != nil {
100+
// Capture validation errors in Apitally
101+
apitally.CaptureValidationError(c, err)
102+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
103+
}
104+
105+
// Logic to create a post goes here ...
106+
107+
return c.Status(fiber.StatusCreated).Send(nil)
108+
})
109+
110+
// Start server
111+
log.Fatal(app.Listen(":3000"))
112+
}

0 commit comments

Comments
 (0)