-
Notifications
You must be signed in to change notification settings - Fork 145
feat (dot/telemetry): implement telemetry system.interval message #1528
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
Changes from 13 commits
d68f7f2
cfa4302
67448d7
ac28587
1c68d46
b35bb3a
cc07fdf
922ac7c
3ab3bc7
4b1ee15
a9ddf04
1cbed8d
6eab866
1292bfa
25d35e4
3caeb27
517a46c
9f60995
54b3233
8735fed
66e85c7
121c7fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,16 +24,17 @@ import ( | |
| "sync" | ||
| "time" | ||
|
|
||
| "github.com/ChainSafe/gossamer/lib/common" | ||
| "github.com/ChainSafe/gossamer/lib/genesis" | ||
| "github.com/gorilla/websocket" | ||
| log "github.com/sirupsen/logrus" | ||
| ) | ||
|
|
||
| // Handler struct for holding telemetry related things | ||
| type Handler struct { | ||
| buf bytes.Buffer | ||
| wsConn []*websocket.Conn | ||
| telemetryLogger *log.Entry | ||
| buf bytes.Buffer | ||
| wsConn []*websocket.Conn | ||
| sync.RWMutex | ||
| } | ||
|
|
||
| // MyJSONFormatter struct for defining JSON Formatter | ||
|
|
@@ -65,13 +66,16 @@ func GetInstance() *Handler { | |
| } | ||
| log.SetOutput(&handlerInstance.buf) | ||
| log.SetFormatter(new(MyJSONFormatter)) | ||
| go handlerInstance.sender() | ||
| }) | ||
| } | ||
| return handlerInstance | ||
| } | ||
|
|
||
| // AddConnections adds connections to telemetry sever | ||
| func (h *Handler) AddConnections(conns []*genesis.TelemetryEndpoint) { | ||
| h.Lock() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This lock may not be required as we are adding connections only when starting the node.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed lock. |
||
| defer h.Unlock() | ||
| for _, v := range conns { | ||
| c, _, err := websocket.DefaultDialer.Dial(v.Endpoint, nil) | ||
| if err != nil { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should continue adding connections on error.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed return. |
||
|
|
@@ -96,29 +100,87 @@ type ConnectionData struct { | |
|
|
||
| // SendConnection sends connection request message to telemetry connection | ||
| func (h *Handler) SendConnection(data *ConnectionData) { | ||
| h.Lock() | ||
| defer h.Unlock() | ||
| payload := log.Fields{"authority": data.Authority, "chain": data.Chain, "config": "", "genesis_hash": data.GenesisHash, | ||
| "implementation": data.SystemName, "msg": "system.connected", "name": data.NodeName, "network_id": data.NetworkID, "startup_time": data.StartTime, | ||
| "version": data.SystemVersion} | ||
| h.telemetryLogger = log.WithFields(log.Fields{"id": 1, "payload": payload, "ts": time.Now()}) | ||
| h.telemetryLogger.Print() | ||
| h.sendTelemtry() | ||
| telemetryLogger := log.WithFields(log.Fields{"id": 1, "payload": payload, "ts": time.Now()}) | ||
| telemetryLogger.Print() | ||
| } | ||
|
|
||
| // SendBlockImport sends block imported message to telemetry connection | ||
| func (h *Handler) SendBlockImport(bestHash string, height *big.Int) { | ||
| h.Lock() | ||
| defer h.Unlock() | ||
| payload := log.Fields{"best": bestHash, "height": height.Int64(), "msg": "block.import", "origin": "NetworkInitialSync"} | ||
| h.telemetryLogger = log.WithFields(log.Fields{"id": 1, "payload": payload, "ts": time.Now()}) | ||
| h.telemetryLogger.Print() | ||
| h.sendTelemtry() | ||
| telemetryLogger := log.WithFields(log.Fields{"id": 1, "payload": payload, "ts": time.Now()}) | ||
| telemetryLogger.Print() | ||
| } | ||
|
|
||
| func (h *Handler) sendTelemtry() { | ||
| for _, c := range h.wsConn { | ||
| err := c.WriteMessage(websocket.TextMessage, h.buf.Bytes()) | ||
| // NetworkData struct to hold network data telemetry information | ||
| type NetworkData struct { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Struct and all its fields are exported. Is it required?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, I've updated this. |
||
| peers int | ||
| rateIn float64 | ||
| rateOut float64 | ||
| } | ||
|
|
||
| // NewNetworkData creates networkData struct | ||
| func NewNetworkData(peers int, rateIn, rateOut float64) *NetworkData { | ||
| return &NetworkData{ | ||
| peers: peers, | ||
| rateIn: rateIn, | ||
| rateOut: rateOut, | ||
| } | ||
| } | ||
|
|
||
| // SendNetworkData send network data system.interval message to telemetry connection | ||
| func (h *Handler) SendNetworkData(data *NetworkData) { | ||
| h.Lock() | ||
| defer h.Unlock() | ||
| payload := log.Fields{"bandwidth_download": data.rateIn, "bandwidth_upload": data.rateOut, "msg": "system.interval", "peers": data.peers} | ||
| telemetryLogger := log.WithFields(log.Fields{"id": 1, "payload": payload, "ts": time.Now()}) | ||
| telemetryLogger.Print() | ||
| } | ||
|
|
||
| // BlockIntervalData struct to hold data for block system.interval message | ||
| type BlockIntervalData struct { | ||
| BestHash common.Hash | ||
| BestHeight *big.Int | ||
| FinalizedHash common.Hash | ||
| FinalizedHeight *big.Int | ||
| TXCount int | ||
| UsedStateCacheSize int | ||
| } | ||
|
|
||
| // SendBlockIntervalData send block data system interval information to telemetry connection | ||
| func (h *Handler) SendBlockIntervalData(data *BlockIntervalData) { | ||
| h.Lock() | ||
| defer h.Unlock() | ||
| payload := log.Fields{"best": data.BestHash.String(), "finalized_hash": data.FinalizedHash.String(), // nolint | ||
| "finalized_height": data.FinalizedHeight, "height": data.BestHeight, "msg": "system.interval", "txcount": data.TXCount, // nolint | ||
| "used_state_cache_size": data.UsedStateCacheSize} | ||
| telemetryLogger := log.WithFields(log.Fields{"id": 1, "payload": payload, "ts": time.Now()}) | ||
| telemetryLogger.Print() | ||
| } | ||
|
|
||
| func (h *Handler) sender() { | ||
| for { | ||
| h.RLock() | ||
| line, err := h.buf.ReadBytes(byte(10)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment specifying that newline delimiter is used.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added comment. |
||
| h.RUnlock() | ||
| if err != nil { | ||
| // TODO (ed) determine how to handle this error | ||
| fmt.Printf("ERROR connecting to telemetry %v\n", err) | ||
| continue | ||
| } | ||
|
|
||
| for _, c := range h.wsConn { | ||
| h.Lock() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even this lock is not required as connections are not accessed concurrently.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, removed lock. |
||
| err := c.WriteMessage(websocket.TextMessage, line) | ||
| h.Unlock() | ||
| if err != nil { | ||
| // TODO (ed) determine how to handle this error | ||
| fmt.Printf("ERROR connecting to telemetry %v\n", err) | ||
| } | ||
| } | ||
| } | ||
| h.buf.Reset() | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I added this to catch panic that happens (during testing) because stop is called twice:
in dot/core/test_helpers.go line 183:
and in dot/core/test_helpers.go line 208:
So, the service is stopped (when created as test service) in line 183, then stop is called again during test cleanup in line 208.
Please advise if I should remove one of these and remove the recover check, or if I should keep the recover check in place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can rename
doneNetworkTelemetrytocloseChto make it more generic to signal the close of service.Using the channel you can also check if the service is closed or not and return early if it's already closed. This will avoid panic on multiple close calls.
Also alternatively you can wrap the close code in
sync.Oncewhich will only be called once.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, Channel names in Golang end usually with
Ch