Skip to content

Commit ba06254

Browse files
committed
Log client and server Bolt messages
1 parent 87b152e commit ba06254

File tree

6 files changed

+150
-11
lines changed

6 files changed

+150
-11
lines changed

neo4j/internal/bolt/bolt3.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,13 @@ func NewBolt3(serverName string, conn net.Conn, log log.Logger) *bolt3 {
9090
state: bolt3_unauthorized,
9191
conn: conn,
9292
serverName: serverName,
93-
in: &incoming{buf: make([]byte, 4096)},
93+
in: &incoming{
94+
buf: make([]byte, 4096),
95+
hyd: hydrator{
96+
logger: log,
97+
logId: "S",
98+
},
99+
},
94100
birthDate: time.Now(),
95101
log: log,
96102
}
@@ -103,6 +109,8 @@ func NewBolt3(serverName string, conn net.Conn, log log.Logger) *bolt3 {
103109
}
104110
b.state = bolt3_dead
105111
},
112+
logger: log,
113+
logId: "C",
106114
}
107115
return b
108116
}
@@ -186,7 +194,10 @@ func (b *bolt3) connect(auth map[string]interface{}, userAgent string) error {
186194
}
187195

188196
b.connId = succ.connectionId
189-
b.logId = fmt.Sprintf("%s@%s", b.connId, b.serverName)
197+
connectionLogId := fmt.Sprintf("%s@%s", b.connId, b.serverName)
198+
b.logId = connectionLogId
199+
b.in.hyd.logId = fmt.Sprintf("%s %s", b.in.hyd.logId, connectionLogId)
200+
b.out.logId = fmt.Sprintf("%s %s", b.out.logId, connectionLogId)
190201
b.serverVersion = succ.server
191202

192203
// Transition into ready state

neo4j/internal/bolt/bolt4.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,20 @@ func NewBolt4(serverName string, conn net.Conn, log log.Logger) *bolt4 {
103103
birthDate: time.Now(),
104104
log: log,
105105
streams: openstreams{},
106-
in: incoming{buf: make([]byte, 4096)},
106+
in: incoming{
107+
buf: make([]byte, 4096),
108+
hyd: hydrator{
109+
logger: log,
110+
logId: "S",
111+
},
112+
},
107113
}
108114
b.out = outgoing{
109115
chunker: newChunker(),
110116
packer: packstream.Packer{},
111117
onErr: func(err error) { b.setError(err, true) },
118+
logger: log,
119+
logId: "C",
112120
}
113121

114122
return b
@@ -239,7 +247,10 @@ func (b *bolt4) connect(minor int, auth map[string]interface{}, userAgent string
239247
b.serverVersion = succ.server
240248

241249
// Construct log identity
242-
b.logId = fmt.Sprintf("%s@%s", b.connId, b.serverName)
250+
connectionLogId := fmt.Sprintf("%s@%s", b.connId, b.serverName)
251+
b.logId = connectionLogId
252+
b.in.hyd.logId = fmt.Sprintf("%s %s", b.in.hyd.logId, connectionLogId)
253+
b.out.logId = fmt.Sprintf("%s %s", b.out.logId, connectionLogId)
243254

244255
// Transition into ready state
245256
b.state = bolt4_ready

neo4j/internal/bolt/hydrator.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package bolt
2222
import (
2323
"errors"
2424
"fmt"
25+
"github.com/neo4j/neo4j-go-driver/v4/neo4j/log"
2526
"time"
2627

2728
"github.com/neo4j/neo4j-go-driver/v4/neo4j/db"
@@ -87,6 +88,8 @@ type hydrator struct {
8788
err error
8889
cachedIgnored ignored
8990
cachedSuccess success
91+
logger log.Logger
92+
logId string
9093
}
9194

9295
func (h *hydrator) setErr(err error) {
@@ -142,6 +145,7 @@ func (h *hydrator) ignored(n uint32) *ignored {
142145
if h.getErr() != nil {
143146
return nil
144147
}
148+
h.logger.Debugf(log.BoltTrace, h.logId, "IGNORED")
145149
return &h.cachedIgnored
146150
}
147151

@@ -166,6 +170,7 @@ func (h *hydrator) failure(n uint32) *db.Neo4jError {
166170
h.trash()
167171
}
168172
}
173+
h.logger.Debugf(log.BoltTrace, h.logId, "FAILURE %s", loggableFailure(dberr))
169174
return &dberr
170175
}
171176

@@ -236,6 +241,7 @@ func (h *hydrator) success(n uint32) *success {
236241
h.trash()
237242
}
238243
}
244+
h.logger.Debugf(log.BoltTrace, h.logId, "SUCCESS %s", loggableSuccess(*succ))
239245
return succ
240246
}
241247

@@ -356,6 +362,7 @@ func (h *hydrator) record(n uint32) *db.Record {
356362
h.unp.Next()
357363
rec.Values[i] = h.value()
358364
}
365+
h.logger.Debugf(log.BoltTrace, h.logId, "RECORD %s", loggableList(rec.Values))
359366
return &rec
360367
}
361368

neo4j/internal/bolt/logging.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package bolt
2+
3+
import (
4+
"encoding/json"
5+
"github.com/neo4j/neo4j-go-driver/v4/neo4j/db"
6+
"strconv"
7+
"strings"
8+
)
9+
10+
type loggableDictionary map[string]interface{}
11+
12+
func (d loggableDictionary) String() string {
13+
if credentials, ok := d["credentials"]; ok {
14+
d["credentials"] = "<redacted>"
15+
defer func() {
16+
d["credentials"] = credentials
17+
}()
18+
}
19+
return serializeTrace(d)
20+
}
21+
22+
type loggableStringDictionary map[string]string
23+
24+
func (sd loggableStringDictionary) String() string {
25+
if credentials, ok := sd["credentials"]; ok {
26+
sd["credentials"] = "<redacted>"
27+
defer func() {
28+
sd["credentials"] = credentials
29+
}()
30+
}
31+
return serializeTrace(sd)
32+
}
33+
34+
type loggableList []interface{}
35+
36+
func (l loggableList) String() string {
37+
return serializeTrace(l)
38+
}
39+
40+
type loggableStringList []string
41+
42+
func (s loggableStringList) String() string {
43+
return serializeTrace(s)
44+
}
45+
46+
type loggableSuccess success
47+
type loggedSuccess struct {
48+
Server string `json:"server,omitempty"`
49+
ConnectionId string `json:"connection_id,omitempty"`
50+
Fields []string `json:"fields,omitempty"`
51+
TFirst string `json:"t_first,omitempty"`
52+
Bookmark string `json:"bookmark,omitempty"`
53+
TLast string `json:"t_last,omitempty"`
54+
HasMore bool `json:"has_more,omitempy"`
55+
Db string `json:"db,omitempty"`
56+
}
57+
58+
func (s loggableSuccess) String() string {
59+
return serializeTrace(loggedSuccess{
60+
Server: s.server,
61+
ConnectionId: s.connectionId,
62+
Fields: s.fields,
63+
TFirst: formatOmittingZero(s.tfirst),
64+
Bookmark: s.bookmark,
65+
TLast: formatOmittingZero(s.tlast),
66+
HasMore: s.hasMore,
67+
Db: s.db,
68+
})
69+
}
70+
71+
func formatOmittingZero(i int64) string {
72+
if i == 0 {
73+
return ""
74+
}
75+
return strconv.FormatInt(i, 10)
76+
}
77+
78+
type loggableFailure db.Neo4jError
79+
80+
func (f *loggableFailure) String() string {
81+
return serializeTrace(map[string]interface{}{
82+
"code": f.Code,
83+
"message": f.Msg,
84+
})
85+
}
86+
87+
func serializeTrace(v interface{}) string {
88+
builder := strings.Builder{}
89+
encoder := json.NewEncoder(&builder)
90+
encoder.SetEscapeHTML(false)
91+
_ = encoder.Encode(v)
92+
return strings.TrimSpace(builder.String())
93+
}
94+

neo4j/internal/bolt/outgoing.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package bolt
2020

2121
import (
22+
"github.com/neo4j/neo4j-go-driver/v4/neo4j/log"
2223
"io"
2324
"reflect"
2425
"time"
@@ -32,6 +33,8 @@ type outgoing struct {
3233
chunker chunker
3334
packer packstream.Packer
3435
onErr func(err error)
36+
logger log.Logger
37+
logId string
3538
}
3639

3740
func (o *outgoing) begin() {
@@ -49,32 +52,37 @@ func (o *outgoing) end() {
4952
}
5053

5154
func (o *outgoing) appendHello(hello map[string]interface{}) {
55+
o.logger.Debugf(log.BoltTrace, o.logId, "HELLO %s", loggableDictionary(hello))
5256
o.begin()
5357
o.packer.StructHeader(byte(msgHello), 1)
5458
o.packMap(hello)
5559
o.end()
5660
}
5761

5862
func (o *outgoing) appendBegin(meta map[string]interface{}) {
63+
o.logger.Debugf(log.BoltTrace, o.logId, "BEGIN %s", loggableDictionary(meta))
5964
o.begin()
6065
o.packer.StructHeader(byte(msgBegin), 1)
6166
o.packMap(meta)
6267
o.end()
6368
}
6469

6570
func (o *outgoing) appendCommit() {
71+
o.logger.Debugf(log.BoltTrace, o.logId, "COMMIT")
6672
o.begin()
6773
o.packer.StructHeader(byte(msgCommit), 0)
6874
o.end()
6975
}
7076

7177
func (o *outgoing) appendRollback() {
78+
o.logger.Debugf(log.BoltTrace, o.logId, "ROLLBACK")
7279
o.begin()
7380
o.packer.StructHeader(byte(msgRollback), 0)
7481
o.end()
7582
}
7683

7784
func (o *outgoing) appendRun(cypher string, params, meta map[string]interface{}) {
85+
o.logger.Debugf(log.BoltTrace, o.logId, "RUN %q %s %s", cypher, loggableDictionary(params), loggableDictionary(meta))
7886
o.begin()
7987
o.packer.StructHeader(byte(msgRun), 3)
8088
o.packer.String(cypher)
@@ -84,6 +92,7 @@ func (o *outgoing) appendRun(cypher string, params, meta map[string]interface{})
8492
}
8593

8694
func (o *outgoing) appendPullN(n int) {
95+
o.logger.Debugf(log.BoltTrace, o.logId, "PULL %s", loggableDictionary{"n": n})
8796
o.begin()
8897
o.packer.StructHeader(byte(msgPullN), 1)
8998
o.packer.MapHeader(1)
@@ -93,6 +102,7 @@ func (o *outgoing) appendPullN(n int) {
93102
}
94103

95104
func (o *outgoing) appendPullNQid(n int, qid int64) {
105+
o.logger.Debugf(log.BoltTrace, o.logId, "PULL %s", loggableDictionary{"n": n, "qid": qid})
96106
o.begin()
97107
o.packer.StructHeader(byte(msgPullN), 1)
98108
o.packer.MapHeader(2)
@@ -104,6 +114,7 @@ func (o *outgoing) appendPullNQid(n int, qid int64) {
104114
}
105115

106116
func (o *outgoing) appendDiscardNQid(n int, qid int64) {
117+
o.logger.Debugf(log.BoltTrace, o.logId, "DISCARD %s", loggableDictionary{"n": n, "qid": qid})
107118
o.begin()
108119
o.packer.StructHeader(byte(msgDiscardN), 1)
109120
o.packer.MapHeader(2)
@@ -115,12 +126,14 @@ func (o *outgoing) appendDiscardNQid(n int, qid int64) {
115126
}
116127

117128
func (o *outgoing) appendPullAll() {
129+
o.logger.Debugf(log.BoltTrace, o.logId, "PULL ALL")
118130
o.begin()
119131
o.packer.StructHeader(byte(msgPullAll), 0)
120132
o.end()
121133
}
122134

123135
func (o *outgoing) appendRoute(context map[string]string, bookmarks []string, database string) {
136+
o.logger.Debugf(log.BoltTrace, o.logId, "ROUTE %s %s %q", loggableStringDictionary(context), loggableStringList(bookmarks), database)
124137
o.begin()
125138
o.packer.StructHeader(byte(msgRoute), 3)
126139
o.packer.MapHeader(len(context))
@@ -141,12 +154,14 @@ func (o *outgoing) appendRoute(context map[string]string, bookmarks []string, da
141154
}
142155

143156
func (o *outgoing) appendReset() {
157+
o.logger.Debugf(log.BoltTrace, o.logId, "RESET")
144158
o.begin()
145159
o.packer.StructHeader(byte(msgReset), 0)
146160
o.end()
147161
}
148162

149163
func (o *outgoing) appendGoodbye() {
164+
o.logger.Debugf(log.BoltTrace, o.logId, "GOODBYE")
150165
o.begin()
151166
o.packer.StructHeader(byte(msgGoodbye), 0)
152167
o.end()
@@ -336,4 +351,4 @@ func (o *outgoing) packX(x interface{}) {
336351
default:
337352
o.onErr(&db.UnsupportedTypeError{Type: reflect.TypeOf(x)})
338353
}
339-
}
354+
}

neo4j/log/logger.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ type Logger interface {
5151

5252
// List of component names used as parameter to logger functions.
5353
const (
54-
Bolt3 = "bolt3"
55-
Bolt4 = "bolt4"
56-
Driver = "driver"
57-
Pool = "pool"
58-
Router = "router"
59-
Session = "session"
54+
Bolt3 = "bolt3"
55+
Bolt4 = "bolt4"
56+
BoltTrace = "bolt-trace"
57+
Driver = "driver"
58+
Pool = "pool"
59+
Router = "router"
60+
Session = "session"
6061
)
6162

6263
// Last used component id

0 commit comments

Comments
 (0)