Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat(BRIDGE-122) - Support observability metrics #152

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions observability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package proton

import (
"context"

"github.com/go-resty/resty/v2"
)

func (c *Client) SendObservabilityBatch(ctx context.Context, req ObservabilityBatch) error {
return c.do(ctx, func(r *resty.Request) (*resty.Response, error) {
return r.SetHeader("Priority", "u=6").SetBody(req).Post("/data/v1/metrics")
})
}
12 changes: 12 additions & 0 deletions observability_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package proton

type ObservabilityBatch struct {
Metrics []ObservabilityMetric `json:"Metrics"`
}

type ObservabilityMetric struct {
Name string `json:"Name"`
Version int `json:"Version"`
Timestamp int64 `json:"Timestamp"` // Unix timestamp
Data interface{} `json:"Data"`
}
23 changes: 13 additions & 10 deletions server/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type unsafeBackend struct {
csTicket []string

featureFlags []proton.FeatureToggle

observabilityStatistics ObservabilityStatistics
}

func readBackendRet[T any](b *Backend, f func(b *unsafeBackend) T) T {
Expand Down Expand Up @@ -91,16 +93,17 @@ func New(authLife time.Duration, domain string, enableDedup bool) *Backend {
return &Backend{
domain: domain,
safeBackend: &unsafeBackend{
accounts: make(map[string]*account),
attachments: make(map[string]*attachment),
attData: make(map[string][]byte),
messages: make(map[string]*message),
labels: make(map[string]*label),
updates: make(map[ID]update),
maxUpdatesPerEvent: 0,
srp: make(map[string]*srp.Server),
authLife: authLife,
enableDedup: enableDedup,
accounts: make(map[string]*account),
attachments: make(map[string]*attachment),
attData: make(map[string][]byte),
messages: make(map[string]*message),
labels: make(map[string]*label),
updates: make(map[ID]update),
maxUpdatesPerEvent: 0,
srp: make(map[string]*srp.Server),
authLife: authLife,
enableDedup: enableDedup,
observabilityStatistics: NewObservabilityStatistics(),
},
}
}
Expand Down
32 changes: 32 additions & 0 deletions server/backend/observability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package backend

import (
"time"

"github.com/ProtonMail/go-proton-api"
)

type ObservabilityStatistics struct {
Metrics []proton.ObservabilityMetric
RequestTime []time.Time
}

func NewObservabilityStatistics() ObservabilityStatistics {
return ObservabilityStatistics{
Metrics: make([]proton.ObservabilityMetric, 0),
RequestTime: make([]time.Time, 0),
}
}

func (b *Backend) PushObservabilityMetrics(metrics []proton.ObservabilityMetric) {
writeBackend(b, func(b *unsafeBackend) {
b.observabilityStatistics.Metrics = append(b.observabilityStatistics.Metrics, metrics...)
b.observabilityStatistics.RequestTime = append(b.observabilityStatistics.RequestTime, time.Now())
})
}

func (b *Backend) GetObservabilityStatistics() ObservabilityStatistics {
return readBackendRet(b, func(b *unsafeBackend) ObservabilityStatistics {
return b.observabilityStatistics
})
}
19 changes: 18 additions & 1 deletion server/data.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package server

import (
"net/http"

"github.com/ProtonMail/go-proton-api"
"github.com/gin-gonic/gin"
"net/http"
)

func (s *Server) handlePostDataStats() gin.HandlerFunc {
Expand Down Expand Up @@ -51,3 +52,19 @@ func (s *Server) handlePostDataStatsMultiple() gin.HandlerFunc {
func validateSendStatReq(req *proton.SendStatsReq) bool {
return req.MeasurementGroup != ""
}

func (s *Server) handleObservabilityPost() gin.HandlerFunc {
return func(c *gin.Context) {
var req proton.ObservabilityBatch
if err := c.BindJSON(&req); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}

s.b.PushObservabilityMetrics(req.Metrics)

c.JSON(http.StatusOK, gin.H{
"Code": proton.SuccessCode,
})
}
}
2 changes: 2 additions & 0 deletions server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ func initRouter(s *Server) {
stats.POST("", s.handlePostDataStats())
stats.POST("/multiple", s.handlePostDataStatsMultiple())
}
// Observability endpoint
data.POST("/metrics", s.handleObservabilityPost())
}

// Top level auth routes don't need authentication.
Expand Down
4 changes: 4 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,7 @@ func (s *Server) PushFeatureFlag(flagName string) {
func (s *Server) DeleteFeatureFlags() {
s.b.DeleteFeatureFlags()
}

func (s *Server) GetObservabilityStatistics() backend.ObservabilityStatistics {
return s.b.GetObservabilityStatistics()
}
Loading