From 3ed599aae82b68aead551b82a0accda4d80caee5 Mon Sep 17 00:00:00 2001 From: Hans Moog <hm@mkjc.net> Date: Sat, 31 Aug 2019 03:00:35 +0200 Subject: [PATCH] Feat: started adding a stringify package for debugging purposes To make debugging of the heartbeats a bit easier, this commit adds a stringify package which can show even very complex objects in a nice readable format like: Heartbeat { nodeId: "c0a2918db00514d655f2b82199c6aedda234f807" mainStatement: OpinionStatement { previousStatementHash: <nil> nodeId: "c0a2918db00514d655f2b82199c6aedda234f807" time: 1567213114 toggledTransactions: [ ToggledTransaction { transactionId: 0x29f54622b0df47c864ceca1a5bb4ed84fb7dbbc1b4a6d9a029f79572b86f4d3c68bcca30b08953ac9d217a667facac7d4aa0 initialStatement: true finalStatement: false }, ToggledTransaction { transactionId: 0x774f74040c249b73ec4c390352e3191438899c166863b86765e1ef8546ea735bd0ff28dea6e35c9b7d66b35a5703b0c7fe63 initialStatement: true finalStatement: false }, ] signature: 0x57fa4ba799a2312b4e8561b144d9386703fce7f128c30c9ec2eeec73693878704d0a176cd4563f5afa8f5ceabdd2552f42bd17cd82363fc0bd1c1386edf914d401 } neighborStatements: map{} signature: <nil> } --- go.mod | 2 + go.sum | 2 + packages/ca/heartbeat/heartbeat.go | 13 ++++- packages/ca/heartbeat/opinion_statement.go | 18 +++---- packages/ca/heartbeat/toggled_transaction.go | 10 ++++ packages/ca/heartbeat_manager_test.go | 6 ++- packages/stringify/bool.go | 9 ++++ packages/stringify/constants.go | 5 ++ packages/stringify/int.go | 9 ++++ packages/stringify/interface.go | 50 ++++++++++++++++++++ packages/stringify/map.go | 31 ++++++++++++ packages/stringify/map_test.go | 15 ++++++ packages/stringify/slice.go | 41 ++++++++++++++++ packages/stringify/slice_of_bytes.go | 13 +++++ packages/stringify/string.go | 5 ++ packages/stringify/struct.go | 31 ++++++++++++ packages/stringify/struct_field.go | 17 +++++++ 17 files changed, 266 insertions(+), 11 deletions(-) create mode 100644 packages/stringify/bool.go create mode 100644 packages/stringify/constants.go create mode 100644 packages/stringify/int.go create mode 100644 packages/stringify/interface.go create mode 100644 packages/stringify/map.go create mode 100644 packages/stringify/map_test.go create mode 100644 packages/stringify/slice.go create mode 100644 packages/stringify/slice_of_bytes.go create mode 100644 packages/stringify/string.go create mode 100644 packages/stringify/struct.go create mode 100644 packages/stringify/struct_field.go diff --git a/go.mod b/go.mod index 31b7140a..8e94e41a 100644 --- a/go.mod +++ b/go.mod @@ -12,12 +12,14 @@ require ( github.com/gorilla/websocket v1.4.0 github.com/iotaledger/iota.go v1.0.0-beta.7 github.com/kr/pretty v0.1.0 // indirect + github.com/kr/text v0.1.0 github.com/labstack/echo v3.3.10+incompatible github.com/labstack/gommon v0.2.9 // indirect github.com/pkg/errors v0.8.1 github.com/rivo/tview v0.0.0-20190721135419-23dc8a0944e4 github.com/rivo/uniseg v0.1.0 // indirect github.com/stretchr/testify v1.3.0 + github.com/tonnerre/golang-text v0.0.0-20130925195846-048ed3d792f7 // indirect golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e // indirect diff --git a/go.sum b/go.sum index 3190f6cf..4321f8c8 100644 --- a/go.sum +++ b/go.sum @@ -100,6 +100,8 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/tonnerre/golang-text v0.0.0-20130925195846-048ed3d792f7 h1:E4pdTAo1tqctAfTr2tkxcX+JkDeJP84bQfjC3ONwoXQ= +github.com/tonnerre/golang-text v0.0.0-20130925195846-048ed3d792f7/go.mod h1:J5H/d3ZVtRUjmP4Zf87sPSIUSCGFXorzn3hQtdODORQ= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= diff --git a/packages/ca/heartbeat/heartbeat.go b/packages/ca/heartbeat/heartbeat.go index 6087afd8..dd2d3da8 100644 --- a/packages/ca/heartbeat/heartbeat.go +++ b/packages/ca/heartbeat/heartbeat.go @@ -3,6 +3,8 @@ package heartbeat import ( "sync" + "github.com/iotaledger/goshimmer/packages/stringify" + "github.com/iotaledger/goshimmer/packages/errors" "github.com/iotaledger/goshimmer/packages/marshaling" @@ -28,7 +30,7 @@ func NewHeartbeat() *Heartbeat { func (heartbeat *Heartbeat) GetNodeId() string { heartbeat.nodeIdMutex.RLock() - defer heartbeat.nodeIdMutex.RLock() + defer heartbeat.nodeIdMutex.RUnlock() return heartbeat.nodeId } @@ -126,3 +128,12 @@ func (heartbeat *Heartbeat) MarshalBinary() ([]byte, errors.IdentifiableError) { func (heartbeat *Heartbeat) UnmarshalBinary(data []byte) (err errors.IdentifiableError) { return marshaling.Unmarshal(heartbeat, data, &heartbeatProto.HeartBeat{}) } + +func (heartbeat *Heartbeat) String() string { + return stringify.Struct("Heartbeat", + stringify.StructField("nodeId", heartbeat.nodeId), + stringify.StructField("mainStatement", heartbeat.mainStatement), + stringify.StructField("neighborStatements", heartbeat.neighborStatements), + stringify.StructField("signature", heartbeat.signature), + ) +} diff --git a/packages/ca/heartbeat/opinion_statement.go b/packages/ca/heartbeat/opinion_statement.go index 8071114d..95819a48 100644 --- a/packages/ca/heartbeat/opinion_statement.go +++ b/packages/ca/heartbeat/opinion_statement.go @@ -1,10 +1,10 @@ package heartbeat import ( - "encoding/hex" - "strconv" "sync" + "github.com/iotaledger/goshimmer/packages/stringify" + "github.com/iotaledger/goshimmer/packages/errors" "github.com/iotaledger/goshimmer/packages/marshaling" @@ -157,11 +157,11 @@ func (opinionStatement *OpinionStatement) UnmarshalBinary(data []byte) (err erro } func (opinionStatement *OpinionStatement) String() string { - return "OpinionStatement {\n" + - " previousStatementHash: 0x" + hex.EncodeToString(opinionStatement.previousStatementHash) + "\n" + - " nodeId: " + opinionStatement.nodeId + "\n" + - " time: " + strconv.Itoa(int(opinionStatement.time)) + "\n" + - " toggledTransactions: [" + "" + "]\n" + - " signature: 0x" + hex.EncodeToString(opinionStatement.signature) + "\n" + - "}" + return stringify.Struct("OpinionStatement", + stringify.StructField("previousStatementHash", opinionStatement.previousStatementHash), + stringify.StructField("nodeId", opinionStatement.nodeId), + stringify.StructField("time", opinionStatement.time), + stringify.StructField("toggledTransactions", opinionStatement.toggledTransactions), + stringify.StructField("signature", opinionStatement.signature), + ) } diff --git a/packages/ca/heartbeat/toggled_transaction.go b/packages/ca/heartbeat/toggled_transaction.go index a6fb4bb9..8d81371c 100644 --- a/packages/ca/heartbeat/toggled_transaction.go +++ b/packages/ca/heartbeat/toggled_transaction.go @@ -3,6 +3,8 @@ package heartbeat import ( "sync" + "github.com/iotaledger/goshimmer/packages/stringify" + "github.com/iotaledger/goshimmer/packages/errors" "github.com/iotaledger/goshimmer/packages/marshaling" @@ -89,3 +91,11 @@ func (toggledTransaction *ToggledTransaction) MarshalBinary() ([]byte, errors.Id func (toggledTransaction *ToggledTransaction) UnmarshalBinary(data []byte) (err errors.IdentifiableError) { return marshaling.Unmarshal(toggledTransaction, data, &heartbeatProto.ToggledTransaction{}) } + +func (toggledTransaction *ToggledTransaction) String() string { + return stringify.Struct("ToggledTransaction", + stringify.StructField("transactionId", toggledTransaction.transactionId), + stringify.StructField("initialStatement", toggledTransaction.initialStatement), + stringify.StructField("finalStatement", toggledTransaction.finalStatement), + ) +} diff --git a/packages/ca/heartbeat_manager_test.go b/packages/ca/heartbeat_manager_test.go index 9c5bc1a5..42b82105 100644 --- a/packages/ca/heartbeat_manager_test.go +++ b/packages/ca/heartbeat_manager_test.go @@ -12,8 +12,12 @@ func TestHeartbeatManager_GenerateHeartbeat(t *testing.T) { transactionId1 := make([]byte, 50) rand.Read(transactionId1) + transactionId2 := make([]byte, 50) + rand.Read(transactionId2) + heartbeatManager := NewHeartbeatManager(identity.GenerateRandomIdentity()) heartbeatManager.SetInitialOpinion(transactionId1) + heartbeatManager.SetInitialOpinion(transactionId2) result, err := heartbeatManager.GenerateHeartbeat() if err != nil { @@ -22,5 +26,5 @@ func TestHeartbeatManager_GenerateHeartbeat(t *testing.T) { return } - fmt.Println(result.GetMainStatement()) + fmt.Println(result) } diff --git a/packages/stringify/bool.go b/packages/stringify/bool.go new file mode 100644 index 00000000..0cd7045e --- /dev/null +++ b/packages/stringify/bool.go @@ -0,0 +1,9 @@ +package stringify + +func Bool(value bool) string { + if value { + return "true" + } else { + return "false" + } +} diff --git a/packages/stringify/constants.go b/packages/stringify/constants.go new file mode 100644 index 00000000..798bff37 --- /dev/null +++ b/packages/stringify/constants.go @@ -0,0 +1,5 @@ +package stringify + +const ( + INDENTATION_SIZE = 4 +) diff --git a/packages/stringify/int.go b/packages/stringify/int.go new file mode 100644 index 00000000..0a98f381 --- /dev/null +++ b/packages/stringify/int.go @@ -0,0 +1,9 @@ +package stringify + +import ( + "strconv" +) + +func Int(value int) string { + return strconv.Itoa(value) +} diff --git a/packages/stringify/interface.go b/packages/stringify/interface.go new file mode 100644 index 00000000..bbf4f198 --- /dev/null +++ b/packages/stringify/interface.go @@ -0,0 +1,50 @@ +package stringify + +import ( + "fmt" + "reflect" + "strconv" +) + +func Interface(value interface{}) string { + switch value.(type) { + case bool: + return Bool(value.(bool)) + case string: + return String(value.(string)) + case []byte: + return SliceOfBytes(value.([]byte)) + case int: + return Int(value.(int)) + case uint64: + return strconv.FormatUint(value.(uint64), 10) + case reflect.Value: + typeCastedValue := value.(reflect.Value) + switch typeCastedValue.Kind() { + case reflect.Slice: + return sliceReflect(typeCastedValue) + case reflect.String: + return String(typeCastedValue.String()) + case reflect.Int: + return Int(int(typeCastedValue.Int())) + case reflect.Uint8: + return Int(int(typeCastedValue.Uint())) + case reflect.Ptr: + return Interface(typeCastedValue.Interface()) + default: + panic("undefined reflect type: " + typeCastedValue.Kind().String()) + } + case fmt.Stringer: + return value.(fmt.Stringer).String() + default: + value := reflect.ValueOf(value) + switch value.Kind() { + case reflect.Slice: + return sliceReflect(value) + case reflect.Map: + return mapReflect(value) + default: + panic("undefined type: " + value.Kind().String()) + } + } +} diff --git a/packages/stringify/map.go b/packages/stringify/map.go new file mode 100644 index 00000000..b81741e2 --- /dev/null +++ b/packages/stringify/map.go @@ -0,0 +1,31 @@ +package stringify + +import ( + "reflect" + "strings" + + "github.com/kr/text" +) + +func Map(value interface{}) string { + return mapReflect(reflect.ValueOf(value)) +} + +func mapReflect(value reflect.Value) (result string) { + result = "map{" + + mapKeys := value.MapKeys() + if len(mapKeys) >= 1 { + result += "\n" + } + + for _, mapKey := range mapKeys { + item := value.MapIndex(mapKey) + + result += text.Indent("["+Interface(mapKey)+"]: "+Interface(item)+",\n", strings.Repeat(" ", INDENTATION_SIZE)) + } + + result += "}" + + return +} diff --git a/packages/stringify/map_test.go b/packages/stringify/map_test.go new file mode 100644 index 00000000..b1fb2740 --- /dev/null +++ b/packages/stringify/map_test.go @@ -0,0 +1,15 @@ +package stringify + +import ( + "fmt" + "testing" +) + +func TestMap(t *testing.T) { + testMap := make(map[string][]byte) + + testMap["huhu"] = []byte{1, 2} + testMap["haha"] = []byte{1, 2, 3, 4} + + fmt.Println(Map(testMap)) +} diff --git a/packages/stringify/slice.go b/packages/stringify/slice.go new file mode 100644 index 00000000..21c5ffb9 --- /dev/null +++ b/packages/stringify/slice.go @@ -0,0 +1,41 @@ +package stringify + +import ( + "reflect" + "strings" + + "github.com/kr/text" +) + +func Slice(value []interface{}) string { + return sliceReflect(reflect.ValueOf(value)) +} + +func sliceReflect(value reflect.Value) (result string) { + result += "[" + + newLineVersion := false + for i := 0; i < value.Len(); i++ { + item := value.Index(i) + + valueString := Interface(item) + if strings.Contains(valueString, "\n") { + if !newLineVersion { + result += "\n" + + newLineVersion = true + } + result += text.Indent(Interface(item)+",\n", strings.Repeat(" ", INDENTATION_SIZE)) + } else { + result += Interface(item) + ", " + } + } + + if !newLineVersion { + result = result[:len(result)-2] + } + + result += "]" + + return +} diff --git a/packages/stringify/slice_of_bytes.go b/packages/stringify/slice_of_bytes.go new file mode 100644 index 00000000..558a2576 --- /dev/null +++ b/packages/stringify/slice_of_bytes.go @@ -0,0 +1,13 @@ +package stringify + +import "encoding/hex" + +func SliceOfBytes(value []byte) string { + if value == nil { + return "<nil>" + } else if len(value) == 0 { + return "<empty>" + } else { + return "0x" + hex.EncodeToString(value) + "" + } +} diff --git a/packages/stringify/string.go b/packages/stringify/string.go new file mode 100644 index 00000000..e25c63f5 --- /dev/null +++ b/packages/stringify/string.go @@ -0,0 +1,5 @@ +package stringify + +func String(value string) string { + return "\"" + value + "\"" +} diff --git a/packages/stringify/struct.go b/packages/stringify/struct.go new file mode 100644 index 00000000..9d1a50a6 --- /dev/null +++ b/packages/stringify/struct.go @@ -0,0 +1,31 @@ +package stringify + +import ( + "strings" + + "github.com/kr/text" +) + +func Struct(name string, fields ...*structField) string { + return structBuilder{ + name: name, + fields: fields, + }.String() +} + +type structBuilder struct { + name string + fields []*structField +} + +func (stringifyStruct structBuilder) String() (result string) { + result = stringifyStruct.name + " {\n" + + for _, field := range stringifyStruct.fields { + result += text.Indent(field.String()+"\n", strings.Repeat(" ", INDENTATION_SIZE)) + } + + result += "}" + + return result +} diff --git a/packages/stringify/struct_field.go b/packages/stringify/struct_field.go new file mode 100644 index 00000000..d4190b22 --- /dev/null +++ b/packages/stringify/struct_field.go @@ -0,0 +1,17 @@ +package stringify + +type structField struct { + name string + value interface{} +} + +func StructField(name string, value interface{}) *structField { + return &structField{ + name: name, + value: value, + } +} + +func (structField *structField) String() (result string) { + return structField.name + ": " + Interface(structField.value) +} -- GitLab