Skip to content

Commit 84538e8

Browse files
Merge pull request #43 from ElderOrb/diagnostics
Diagnositcs package
2 parents 09eff23 + 4d4e6b4 commit 84538e8

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

pkg/diagnostics/diagnostics.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Package `diagnostics` provides some tools useful for gathering and
2+
// exposing arbitrary diagnositcs information for external monitoring tools.
3+
//
4+
// Possible usage: integration nodes list into dashboard
5+
package diagnostics
6+
7+
import (
8+
"encoding/json"
9+
"io"
10+
"net/http"
11+
"strconv"
12+
"sync"
13+
14+
"github.com/ipfs/go-log"
15+
)
16+
17+
var logger = log.Logger("keep-diagnostics")
18+
19+
// Registry performs all management of diagnostic. Specifically, it allows
20+
// to registering new diagnostics sources and exposing them through the diagnostics server.
21+
type DiagnosticsRegistry struct {
22+
diagnosticsSources map[string]func() string
23+
diagnosticsMutex sync.RWMutex
24+
}
25+
26+
// NewRegistry creates a new metrics registry.
27+
func NewRegistry() *DiagnosticsRegistry {
28+
return &DiagnosticsRegistry{
29+
diagnosticsSources: make(map[string]func() string),
30+
}
31+
}
32+
33+
// EnableServer enables the diagnostics server on the given port. Data will
34+
// be exposed on `/diagnostics` path in JSON format.
35+
func (r *DiagnosticsRegistry) EnableServer(port int) {
36+
server := &http.Server{Addr: ":" + strconv.Itoa(port)}
37+
38+
http.HandleFunc("/diagnostics", func(response http.ResponseWriter, _ *http.Request) {
39+
if _, err := io.WriteString(response, r.exposeDiagnostics()); err != nil {
40+
logger.Errorf("could not write response: [%v]", err)
41+
}
42+
})
43+
44+
go func() {
45+
if err := server.ListenAndServe(); err != http.ErrServerClosed {
46+
logger.Errorf("diagnostics server error: [%v]", err)
47+
}
48+
}()
49+
}
50+
51+
// Registers diagnostics source callback with a given name.
52+
// Name will be used as a key and callback result as a value in JSON object
53+
// during composing diagnostics JSON.
54+
// Note: function will override existing diagnostics source on attempt
55+
// to register another one with the same name.
56+
func (r *DiagnosticsRegistry) RegisterSource(name string, source func() string) {
57+
r.diagnosticsMutex.Lock()
58+
defer r.diagnosticsMutex.Unlock()
59+
60+
r.diagnosticsSources[name] = source
61+
}
62+
63+
// Exposes all registered diagnostics sources in a single JSON document.
64+
func (r *DiagnosticsRegistry) exposeDiagnostics() string {
65+
r.diagnosticsMutex.RLock()
66+
defer r.diagnosticsMutex.RUnlock()
67+
68+
diagnostics := make(map[string]interface{})
69+
for sourceName, sourceGetter := range r.diagnosticsSources {
70+
var jsonString = sourceGetter()
71+
var jsonObject interface{}
72+
err := json.Unmarshal([]byte(jsonString), &jsonObject)
73+
if err == nil {
74+
diagnostics[sourceName] = jsonObject
75+
}
76+
}
77+
78+
bytes, err := json.Marshal(diagnostics)
79+
if err != nil {
80+
logger.Errorf("diagnostics JSON serialization error: [%v]", err)
81+
return ""
82+
}
83+
84+
return string(bytes)
85+
}

0 commit comments

Comments
 (0)