-
Notifications
You must be signed in to change notification settings - Fork 76
/
endpoints_status.go
154 lines (134 loc) · 4.89 KB
/
endpoints_status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package relay
import (
"encoding/json"
"net/http"
"time"
"github.com/launchdarkly/ld-relay/v8/config"
"github.com/launchdarkly/ld-relay/v8/internal/api"
"github.com/launchdarkly/ld-relay/v8/internal/relayenv"
"github.com/launchdarkly/ld-relay/v8/internal/sdks"
"github.com/launchdarkly/go-sdk-common/v3/ldtime"
ld "github.com/launchdarkly/go-server-sdk/v7"
"github.com/launchdarkly/go-server-sdk/v7/interfaces"
)
const (
statusEnvConnected = "connected"
statusEnvDisconnected = "disconnected"
statusRelayHealthy = "healthy"
statusRelayDegraded = "degraded"
)
func statusHandler(relay *Relay) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
resp := api.StatusRep{
Environments: make(map[string]api.EnvironmentStatusRep),
Version: relay.version,
ClientVersion: ld.Version,
}
relay.lock.Lock()
fullyConfigured := relay.fullyConfigured
relay.lock.Unlock()
healthy := fullyConfigured
for _, clientCtx := range relay.getAllEnvironments() {
identifiers := clientCtx.GetIdentifiers()
status := api.EnvironmentStatusRep{
EnvKey: identifiers.EnvKey, // these will only be non-empty if we're in auto-configured mode
EnvName: identifiers.EnvName,
ProjKey: identifiers.ProjKey,
ProjName: identifiers.ProjName,
}
for _, c := range clientCtx.GetCredentials() {
switch c := c.(type) {
case config.SDKKey:
status.SDKKey = sdks.ObscureKey(string(c))
case config.MobileKey:
status.MobileKey = sdks.ObscureKey(string(c))
case config.EnvironmentID:
status.EnvID = string(c)
}
}
for _, c := range clientCtx.GetDeprecatedCredentials() {
if key, ok := c.(config.SDKKey); ok {
status.ExpiringSDKKey = sdks.ObscureKey(string(key))
}
}
client := clientCtx.GetClient()
if client == nil {
status.Status = statusEnvDisconnected
status.ConnectionStatus.State = interfaces.DataSourceStateInitializing
status.ConnectionStatus.StateSince = ldtime.UnixMillisFromTime(clientCtx.GetCreationTime())
status.DataStoreStatus.State = "INITIALIZING"
healthy = false
} else {
connected := client.Initialized()
sourceStatus := client.GetDataSourceStatus()
status.ConnectionStatus = api.ConnectionStatusRep{
State: sourceStatus.State,
StateSince: ldtime.UnixMillisFromTime(sourceStatus.StateSince),
}
if sourceStatus.LastError.Kind != "" {
status.ConnectionStatus.LastError = &api.ConnectionErrorRep{
Kind: sourceStatus.LastError.Kind,
Time: ldtime.UnixMillisFromTime(sourceStatus.LastError.Time),
}
}
if sourceStatus.State != interfaces.DataSourceStateValid &&
time.Since(sourceStatus.StateSince) >=
relay.config.Main.DisconnectedStatusTime.GetOrElse(config.DefaultDisconnectedStatusTime) {
connected = false
}
storeStatus := client.GetDataStoreStatus()
status.DataStoreStatus.State = "VALID"
status.DataStoreStatus.StateSince = ldtime.UnixMillisFromTime(storeStatus.LastUpdated)
if !storeStatus.Available {
status.DataStoreStatus.State = "INTERRUPTED"
}
if connected {
status.Status = statusEnvConnected
} else {
status.Status = statusEnvDisconnected
healthy = false
}
}
bigSegmentStore := clientCtx.GetBigSegmentStore()
if bigSegmentStore != nil {
bigSegmentStatus := api.BigSegmentStatusRep{}
synchronizedOn, err := bigSegmentStore.GetSynchronizedOn()
if err != nil {
bigSegmentStatus.Available = false
} else {
bigSegmentStatus.Available = true
bigSegmentStatus.LastSynchronizedOn = synchronizedOn
now := ldtime.UnixMillisNow()
stalenessThreshold := relay.config.Main.BigSegmentsStaleThreshold.GetOrElse(config.DefaultBigSegmentsStaleThreshold)
if !synchronizedOn.IsDefined() || now > (synchronizedOn+ldtime.UnixMillisecondTime(stalenessThreshold.Milliseconds())) {
bigSegmentStatus.PotentiallyStale = true
if relay.config.Main.BigSegmentsStaleAsDegraded {
healthy = false
}
}
}
status.BigSegmentStatus = &bigSegmentStatus
}
storeInfo := clientCtx.GetDataStoreInfo()
status.DataStoreStatus.Database = storeInfo.DBType
status.DataStoreStatus.DBServer = storeInfo.DBServer
status.DataStoreStatus.DBPrefix = storeInfo.DBPrefix
status.DataStoreStatus.DBTable = storeInfo.DBTable
statusKey := identifiers.GetDisplayName()
if relay.envLogNameMode == relayenv.LogNameIsEnvID {
// If we're identifying environments by environment ID in the log (which we do if there's any
// chance that the environment name could change) then we should also identify them that way here.
statusKey = status.EnvID
}
resp.Environments[statusKey] = status
}
if healthy {
resp.Status = statusRelayHealthy
} else {
resp.Status = statusRelayDegraded
}
data, _ := json.Marshal(resp)
_, _ = w.Write(data)
})
}