mirror of https://github.com/vacp2p/nim-libp2p.git
adding chronicles logging
This commit is contained in:
parent
5bc8e7e7b1
commit
435c69633f
|
@ -1,77 +0,0 @@
|
|||
## Nim-LibP2P
|
||||
## Copyright (c) 2018 Status Research & Development GmbH
|
||||
## Licensed under either of
|
||||
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
## at your option.
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
## Small debug module that's only runs in non release builds.
|
||||
## It's inspired by the Nodejs ``debug`` module which allows printing
|
||||
## colorized output based on matched patterns. This module is powered
|
||||
## by the standard ``nre`` module and as such it supports the same set
|
||||
## of regexp expressions.
|
||||
##
|
||||
## The output is controled through two environment variables ``DEBUG``
|
||||
## and ``DEBUG_COLOR``. By default, it will print everything to stderr
|
||||
## but if only some output is of interested, ``DEBUG`` accepts a coma
|
||||
## separated list of regexp expressions to match the output against.
|
||||
## Each match gets assigned a different color to help differentiate
|
||||
## the output lines.
|
||||
##
|
||||
## Colorization is done with 256 ANSI colors, and each run gets a random
|
||||
## color, if more than one match is specified, each one gets a random color
|
||||
## to disable this behavior use ``DEBUG_COLOR`` with a valid ANSI color code.
|
||||
## This will also disable individual colorization for each matched line.
|
||||
##
|
||||
|
||||
when not defined(release):
|
||||
import random,
|
||||
tables,
|
||||
nre,
|
||||
strutils,
|
||||
times,
|
||||
terminal,
|
||||
sequtils,
|
||||
os
|
||||
|
||||
type
|
||||
Match = object
|
||||
pattern: Regex
|
||||
color: string
|
||||
|
||||
# if isTrueColorSupported():
|
||||
# system.addQuitProc(resetAttributes)
|
||||
# enableTrueColors()
|
||||
|
||||
var context {.threadvar.} : OrderedTableRef[string, Match]
|
||||
proc initDebugCtx() =
|
||||
let debugout = getEnv("DEBUG", ".*")
|
||||
let debugColor = getEnv("DEBUG_COLOR")
|
||||
let isDebugColor = debugColor.len > 0
|
||||
context = newOrderedTable[string, Match]()
|
||||
var patrns: seq[string] = @[]
|
||||
patrns = debugout.split(re"[,\s]").filterIt(it.len > 0)
|
||||
|
||||
randomize()
|
||||
for p in patrns:
|
||||
context[p] = Match(pattern: re(p), color: if isDebugColor: debugColor else: $rand(0..272)) # 256 ansi colors
|
||||
|
||||
proc doDebug(data: string, line: string): void {.gcsafe.} =
|
||||
if isNil(context):
|
||||
initDebugCtx()
|
||||
for m in context.values:
|
||||
if data.contains(m.pattern):
|
||||
stderr.writeLine("\u001b[38;5;" & m.color & "m " & alignLeft(line & data, 4) & "\e[0m")
|
||||
return
|
||||
|
||||
template debug*(data: string) =
|
||||
let module = instantiationInfo()
|
||||
let line = "$# $#:$# - " %
|
||||
[now().format("yyyy-MM-dd HH:mm:ss:fffffffff"),
|
||||
module.filename[0..^5],
|
||||
$module.line]
|
||||
doDebug(data, line)
|
||||
else:
|
||||
template debug*(data: string) = discard
|
|
@ -8,12 +8,11 @@
|
|||
## those terms.
|
||||
|
||||
import sequtils, strutils, strformat
|
||||
import chronos
|
||||
import chronos, chronicles
|
||||
import connection,
|
||||
varint,
|
||||
vbuffer,
|
||||
protocols/protocol,
|
||||
helpers/debug
|
||||
protocols/protocol
|
||||
|
||||
const MsgSize* = 64*1024
|
||||
const Codec* = "/multistream/1.0.0"
|
||||
|
@ -46,37 +45,37 @@ proc select*(m: MultisteamSelect,
|
|||
conn: Connection,
|
||||
proto: seq[string]):
|
||||
Future[string] {.async.} =
|
||||
debug &"select: initiating handshake"
|
||||
debug "select: initiating handshake"
|
||||
## select a remote protocol
|
||||
await conn.write(m.codec) # write handshake
|
||||
if proto.len() > 0:
|
||||
debug &"select: selecting proto {proto}"
|
||||
debug "select: selecting proto", proto = proto
|
||||
await conn.writeLp((proto[0] & "\n")) # select proto
|
||||
|
||||
result = cast[string](await conn.readLp()) # read ms header
|
||||
result.removeSuffix("\n")
|
||||
if result != Codec:
|
||||
debug &"select: handshake failed"
|
||||
debug "select: handshake failed"
|
||||
return ""
|
||||
|
||||
if proto.len() == 0: # no protocols, must be a handshake call
|
||||
return
|
||||
|
||||
result = cast[string](await conn.readLp()) # read the first proto
|
||||
debug &"select: reading first requested proto"
|
||||
debug "select: reading first requested proto"
|
||||
result.removeSuffix("\n")
|
||||
if result == proto[0]:
|
||||
debug &"select: succesfully selected {proto}"
|
||||
debug "select: succesfully selected ", proto = proto
|
||||
return
|
||||
|
||||
if not result.len > 0:
|
||||
debug &"select: selecting one of several protos"
|
||||
debug "select: selecting one of several protos"
|
||||
for p in proto[1..<proto.len()]:
|
||||
await conn.writeLp((p & "\n")) # select proto
|
||||
result = cast[string](await conn.readLp()) # read the first proto
|
||||
result.removeSuffix("\n")
|
||||
if result == p:
|
||||
debug &"select: selected {result}"
|
||||
debug "select: selected protocol", protocol = result
|
||||
break
|
||||
|
||||
proc select*(m: MultisteamSelect,
|
||||
|
@ -107,25 +106,25 @@ proc list*(m: MultisteamSelect,
|
|||
result = list
|
||||
|
||||
proc handle*(m: MultisteamSelect, conn: Connection) {.async, gcsafe.} =
|
||||
debug &"select: starting multistream handling"
|
||||
debug "handle: starting multistream handling"
|
||||
while not conn.closed:
|
||||
block main:
|
||||
var ms = cast[string](await conn.readLp())
|
||||
ms.removeSuffix("\n")
|
||||
|
||||
debug &"select: got request for {ms}"
|
||||
debug "handle: got request for ", ms
|
||||
if ms.len() <= 0:
|
||||
debug &"select: invalid proto"
|
||||
debug "handle: invalid proto"
|
||||
await conn.write(m.na)
|
||||
|
||||
if m.handlers.len() == 0:
|
||||
debug &"select: {ms} is na"
|
||||
debug "handle: sending `na` for protocol ", protocol = ms
|
||||
await conn.write(m.na)
|
||||
continue
|
||||
|
||||
case ms:
|
||||
of "ls":
|
||||
debug &"select: listing protos"
|
||||
debug "handle: listing protos"
|
||||
var protos = ""
|
||||
for h in m.handlers:
|
||||
protos &= (h.proto & "\n")
|
||||
|
@ -135,14 +134,14 @@ proc handle*(m: MultisteamSelect, conn: Connection) {.async, gcsafe.} =
|
|||
else:
|
||||
for h in m.handlers:
|
||||
if (not isNil(h.match) and h.match(ms)) or ms == h.proto:
|
||||
debug &"select: found handler for {ms}"
|
||||
debug "handle: found handler for", protocol = ms
|
||||
await conn.writeLp((h.proto & "\n"))
|
||||
try:
|
||||
await h.protocol.handler(conn, ms)
|
||||
break main
|
||||
except Exception as exc:
|
||||
debug exc.msg # TODO: Logging
|
||||
debug &"select: no handlers for {ms}"
|
||||
debug "handle: exception while handling ", msg = exc.msg # TODO: Logging
|
||||
debug "handle: no handlers for ", protocol = ms
|
||||
await conn.write(m.na)
|
||||
|
||||
proc addHandler*[T: LPProtocol](m: MultisteamSelect,
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
import chronos, strformat
|
||||
import strformat
|
||||
import chronos, chronicles
|
||||
import types,
|
||||
coder,
|
||||
nimcrypto/utils,
|
||||
../../stream/bufferstream,
|
||||
../../stream/lpstream,
|
||||
../../connection,
|
||||
../../helpers/debug
|
||||
../../connection
|
||||
|
||||
const DefaultChannelSize* = DefaultBufferSize * 64 # 64kb
|
||||
|
||||
|
@ -52,7 +52,7 @@ proc newChannel*(id: uint,
|
|||
proc writeHandler(data: seq[byte]): Future[void] {.async, gcsafe.} =
|
||||
# writes should happen in sequence
|
||||
await chan.asyncLock.acquire()
|
||||
debug &"writeHandler: sending data {data} from {chan.id}"
|
||||
debug "writeHandler: sending data ", data, id = chan.id
|
||||
await conn.writeMsg(chan.id, chan.msgCode, data) # write header
|
||||
chan.asyncLock.release()
|
||||
|
||||
|
|
|
@ -8,13 +8,12 @@
|
|||
## those terms.
|
||||
|
||||
import chronos, options, sequtils, strformat
|
||||
import types,
|
||||
import nimcrypto/utils, chronicles
|
||||
import types,
|
||||
../../connection,
|
||||
../../varint,
|
||||
../../vbuffer,
|
||||
../../stream/lpstream,
|
||||
nimcrypto/utils,
|
||||
../../helpers/debug
|
||||
../../stream/lpstream
|
||||
|
||||
type
|
||||
Msg* = tuple
|
||||
|
@ -38,7 +37,7 @@ proc readMplexVarint(conn: Connection): Future[Option[uint]] {.async, gcsafe.} =
|
|||
if res != VarintStatus.Success:
|
||||
buffer.setLen(0)
|
||||
return
|
||||
except TransportIncompleteError, AsyncStreamIncompleteError:
|
||||
except LPStreamIncompleteError:
|
||||
buffer.setLen(0)
|
||||
|
||||
proc readMsg*(conn: Connection): Future[Option[Msg]] {.async, gcsafe.} =
|
||||
|
@ -46,12 +45,12 @@ proc readMsg*(conn: Connection): Future[Option[Msg]] {.async, gcsafe.} =
|
|||
if headerVarint.isNone:
|
||||
return
|
||||
|
||||
debug &"readMsg: read header varint {$headerVarint}"
|
||||
debug "readMsg: read header varint ", varint = headerVarint
|
||||
|
||||
let dataLenVarint = await conn.readMplexVarint()
|
||||
var data: seq[byte]
|
||||
if dataLenVarint.isSome and dataLenVarint.get() > 0.uint:
|
||||
debug &"readMsg: read size varint {$dataLenVarint}"
|
||||
debug "readMsg: read size varint ", varint = dataLenVarint
|
||||
data = await conn.read(dataLenVarint.get().int)
|
||||
|
||||
let header = headerVarint.get()
|
||||
|
|
|
@ -17,16 +17,15 @@
|
|||
## here to not forget that this needs to be fixed ASAP.
|
||||
|
||||
import tables, sequtils, options, strformat
|
||||
import chronos
|
||||
import chronos, chronicles
|
||||
import coder, types, channel,
|
||||
../muxer,
|
||||
../../varint,
|
||||
../../connection,
|
||||
../../vbuffer,
|
||||
../../protocols/protocol,
|
||||
../../stream/bufferstream,
|
||||
../../stream/lpstream,
|
||||
../muxer,
|
||||
../../helpers/debug
|
||||
../../stream/lpstream
|
||||
|
||||
type
|
||||
Mplex* = ref object of Muxer
|
||||
|
@ -35,9 +34,6 @@ type
|
|||
currentId*: uint
|
||||
maxChannels*: uint
|
||||
|
||||
proc newMplexNoSuchChannel(id: uint, msgType: MessageType): ref MplexNoSuchChannel =
|
||||
result = newException(MplexNoSuchChannel, &"No such channel id {$id} and message {$msgType}")
|
||||
|
||||
proc newMplexUnknownMsgError(): ref MplexUnknownMsgError =
|
||||
result = newException(MplexUnknownMsgError, "Unknown mplex message type")
|
||||
|
||||
|
@ -71,7 +67,7 @@ method handle*(m: Mplex) {.async, gcsafe.} =
|
|||
if MessageType(msgType) != MessageType.New:
|
||||
let channels = m.getChannelList(initiator)
|
||||
if not channels.contains(id):
|
||||
debug &"handle: Channel with id {id} message type {msgType} not found"
|
||||
# debug "handle: Channel with id and msg type ", id = id, msg = msgType
|
||||
continue
|
||||
channel = channels[id]
|
||||
|
||||
|
@ -79,7 +75,7 @@ method handle*(m: Mplex) {.async, gcsafe.} =
|
|||
of MessageType.New:
|
||||
let name = cast[string](data)
|
||||
channel = await m.newStreamInternal(false, id, name)
|
||||
debug &"handle: created channel with id {$id} and name {name}"
|
||||
# debug "handle: created channel ", id = id, name = name
|
||||
if not isNil(m.streamHandler):
|
||||
let handlerFut = m.streamHandler(newConnection(channel))
|
||||
|
||||
|
@ -91,19 +87,19 @@ method handle*(m: Mplex) {.async, gcsafe.} =
|
|||
proc(udata: pointer) =
|
||||
# TODO: is waitFor() OK here?
|
||||
channel.cleanUp()
|
||||
.addCallback(proc(udata: pointer)
|
||||
= debug &"handle: cleaned up channel {$id}"))
|
||||
handlerFut.addCallback(cleanUpChan)
|
||||
.addCallback(proc(udata: pointer) =
|
||||
debug "handle: cleaned up channel ", id = id))
|
||||
handlerFut.addCallback(cleanUpChan)
|
||||
continue
|
||||
of MessageType.MsgIn, MessageType.MsgOut:
|
||||
debug &"handle: pushing data to channel {$id} type {msgType}"
|
||||
debug "handle: pushing data to channel ", id = id, msgType = msgType
|
||||
await channel.pushTo(data)
|
||||
of MessageType.CloseIn, MessageType.CloseOut:
|
||||
debug &"handle: closing channel {$id} type {msgType}"
|
||||
debug "handle: closing channel ", id = id, msgType = msgType
|
||||
await channel.closedByRemote()
|
||||
m.getChannelList(initiator).del(id)
|
||||
of MessageType.ResetIn, MessageType.ResetOut:
|
||||
debug &"handle: resetting channel {$id} type {msgType}"
|
||||
debug "handle: resetting channel ", id = id
|
||||
await channel.resetByRemote()
|
||||
break
|
||||
else: raise newMplexUnknownMsgError()
|
||||
|
|
|
@ -8,15 +8,14 @@
|
|||
## those terms.
|
||||
|
||||
import options, strformat
|
||||
import chronos
|
||||
import chronos, chronicles
|
||||
import ../protobuf/minprotobuf,
|
||||
../peerinfo,
|
||||
../connection,
|
||||
../peer,
|
||||
../crypto/crypto,
|
||||
../multiaddress,
|
||||
../protocols/protocol,
|
||||
../helpers/debug
|
||||
../protocols/protocol
|
||||
|
||||
const IdentifyCodec* = "/ipfs/id/1.0.0"
|
||||
const IdentifyPushCodec* = "/ipfs/id/push/1.0.0"
|
||||
|
@ -108,7 +107,7 @@ proc identify*(p: Identify,
|
|||
"Invalid or empty message received!")
|
||||
|
||||
result = decodeMsg(message)
|
||||
debug &"identify: Identify for remote peer succeded"
|
||||
debug "identify: Identify for remote peer succeded"
|
||||
if remotePeerInfo.isSome and
|
||||
remotePeerInfo.get().peerId.publicKey != result.pubKey:
|
||||
debug "identify: Peer's remote public key doesn't match"
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
## those terms.
|
||||
|
||||
import tables, sequtils, options, strformat
|
||||
import chronos
|
||||
import chronos, chronicles
|
||||
import connection,
|
||||
transports/transport,
|
||||
stream/lpstream,
|
||||
multistream,
|
||||
protocols/protocol,
|
||||
protocols/secure,
|
||||
protocols/secure/secure, # for plain text
|
||||
protocols/secure/secio,
|
||||
peerinfo,
|
||||
multiaddress,
|
||||
protocols/identify,
|
||||
muxers/muxer,
|
||||
peer,
|
||||
helpers/debug
|
||||
peer
|
||||
|
||||
type
|
||||
Switch* = ref object of RootObj
|
||||
|
@ -33,13 +33,13 @@ type
|
|||
ms*: MultisteamSelect
|
||||
identity*: Identify
|
||||
streamHandler*: StreamHandler
|
||||
secureManager*: Secure
|
||||
secureManagers*: seq[Secure]
|
||||
|
||||
proc secure(s: Switch, conn: Connection): Future[Connection] {.async, gcsafe.} =
|
||||
## secure the incoming connection
|
||||
|
||||
# plaintext for now, doesn't do anything
|
||||
if not (await s.ms.select(conn, s.secureManager.codec)):
|
||||
if (await s.ms.select(conn, s.secureManagers.mapIt(it.codec))).len == 0:
|
||||
raise newException(CatchableError, "Unable to negotiate a secure channel!")
|
||||
|
||||
result = conn
|
||||
|
@ -61,11 +61,11 @@ proc identify(s: Switch, conn: Connection) {.async, gcsafe.} =
|
|||
peerInfo.peerId = PeerID.init(info.pubKey) # we might not have a peerId at all
|
||||
peerInfo.addrs = info.addrs
|
||||
peerInfo.protocols = info.protos
|
||||
debug &"identify: identified remote peer {peerInfo.peerId.pretty}"
|
||||
debug "identify: identified remote peer ", peer = peerInfo.peerId.pretty
|
||||
except IdentityInvalidMsgError as exc:
|
||||
debug exc.msg
|
||||
debug "identify: invalid message", msg = exc.msg
|
||||
except IdentityNoMatchError as exc:
|
||||
debug exc.msg
|
||||
debug "identify: peer's public keys don't match ", msg = exc.msg
|
||||
|
||||
proc mux(s: Switch, conn: Connection): Future[void] {.async, gcsafe.} =
|
||||
## mux incoming connection
|
||||
|
@ -87,7 +87,7 @@ proc mux(s: Switch, conn: Connection): Future[void] {.async, gcsafe.} =
|
|||
handlerFut.addCallback(
|
||||
proc(udata: pointer = nil) {.gcsafe.} =
|
||||
if handlerFut.finished:
|
||||
debug &"Muxer handler completed for peer {conn.peerInfo.get().peerId.pretty}"
|
||||
debug "mux: Muxer handler completed for peer ", peer = conn.peerInfo.get().peerId.pretty
|
||||
)
|
||||
await s.identify(stream)
|
||||
await stream.close() # close idenity stream
|
||||
|
@ -141,9 +141,9 @@ proc dial*(s: Switch,
|
|||
if s.muxed.contains(peer.peerId.pretty):
|
||||
result = await s.muxed[peer.peerId.pretty].newStream()
|
||||
|
||||
debug &"dial: attempting to select remote proto {proto}"
|
||||
debug "dial: attempting to select remote ", proto = proto
|
||||
if not (await s.ms.select(result, proto)):
|
||||
debug &"dial: Unable to select protocol: {proto}"
|
||||
debug "dial: Unable to select protocol: ", proto = proto
|
||||
raise newException(CatchableError,
|
||||
&"Unable to select protocol: {proto}")
|
||||
|
||||
|
@ -177,7 +177,8 @@ proc stop*(s: Switch) {.async.} =
|
|||
proc newSwitch*(peerInfo: PeerInfo,
|
||||
transports: seq[Transport],
|
||||
identity: Identify,
|
||||
muxers: Table[string, MuxerProvider]): Switch =
|
||||
muxers: Table[string, MuxerProvider],
|
||||
secureManagers: seq[Secure] = @[]): Switch =
|
||||
new result
|
||||
result.peerInfo = peerInfo
|
||||
result.ms = newMultistream()
|
||||
|
@ -199,5 +200,10 @@ proc newSwitch*(peerInfo: PeerInfo,
|
|||
val.streamHandler = result.streamHandler
|
||||
result.mount(val)
|
||||
|
||||
result.secureManager = Secure(newPlainText())
|
||||
result.mount(result.secureManager)
|
||||
for s in secureManagers:
|
||||
result.secureManagers.add(s)
|
||||
result.mount(s)
|
||||
|
||||
if result.secureManagers.len == 0:
|
||||
# use plain text if no secure managers are provided
|
||||
result.mount(Secure(newPlainText()))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import unittest, sequtils, sugar, strformat, options
|
||||
import chronos, nimcrypto/utils
|
||||
import unittest, sequtils, sugar, strformat, options, strformat
|
||||
import chronos, nimcrypto/utils, chronicles
|
||||
import ../libp2p/connection,
|
||||
../libp2p/stream/lpstream,
|
||||
../libp2p/stream/bufferstream,
|
||||
|
@ -10,8 +10,7 @@ import ../libp2p/connection,
|
|||
../libp2p/muxers/mplex/mplex,
|
||||
../libp2p/muxers/mplex/coder,
|
||||
../libp2p/muxers/mplex/types,
|
||||
../libp2p/muxers/mplex/channel,
|
||||
../libp2p/helpers/debug
|
||||
../libp2p/muxers/mplex/channel
|
||||
|
||||
suite "Mplex":
|
||||
test "encode header with channel id 0":
|
||||
|
|
|
@ -2,4 +2,4 @@ import unittest
|
|||
import testvarint, testbase32, testbase58, testbase64
|
||||
import testrsa, testecnist, tested25519, testsecp256k1, testcrypto
|
||||
import testmultibase, testmultihash, testmultiaddress, testcid, testpeer
|
||||
import testidentify, testtransport, testmultistream, testbufferstream, testmplex
|
||||
import testidentify, testtransport, testmultistream, testbufferstream, testmplex, testswitch
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import unittest, tables
|
||||
import chronos
|
||||
import chronos, chronicles
|
||||
import ../libp2p/switch,
|
||||
../libp2p/multistream,
|
||||
../libp2p/protocols/identify,
|
||||
|
@ -12,8 +12,7 @@ import ../libp2p/switch,
|
|||
../libp2p/protocols/protocol,
|
||||
../libp2p/muxers/muxer,
|
||||
../libp2p/muxers/mplex/mplex,
|
||||
../libp2p/muxers/mplex/types,
|
||||
../libp2p/helpers/debug
|
||||
../libp2p/muxers/mplex/types
|
||||
|
||||
const TestCodec = "/test/proto/1.0.0"
|
||||
|
||||
|
|
Loading…
Reference in New Issue