GoVector is a vector clock logging library written in Go.

GoVector.png

Build Status GoDoc Go Report Card License: MIT Coverage Status

GoVector is a vector clock logging library written in Go. The vector clock algorithm is used to order events in distributed systems in the absence of a centralized clock. GoVector implements the vector clock algorithm and provides feature-rich logging and encoding infrastructure.

Vector clock events are generated using 3 key functions, PrepareSend, UnpackReceive, and LogLocalEvent. PrepareSend encodes messages for network transport, updates GoVectors local time, and logs a sending event. UnpackReceive decodes messages from the network, merges GoVectors local clock with the received clock, and logs a receiving event. LogLocalEvent event ticks the clock, and logs a message.

This library can be added to a Go project to generate a ShiViz-compatible vector-clock timestamped log of events in a concurrent or distributed system. This library can also be used to generate TSViz-compatible log of events. GoVector is compatible with Go 1.11+ and requires support for Go modules.

  • govec/ : Contains the Library and all its dependencies
  • govec/vclock : Pure vector clock library
  • govec/vrpc : Go's rpc with GoVector integration
  • example/ : Contains some examples instrumented with different features of GoVector

Installation

To install GoVector you must have a correctly configured go development environment. See How to Write Go Code.

Once you set up your environment, GoVector can be installed with the go tool command:

$ go get -u github.com/DistributedClocks/GoVector

Usage

The following is a basic example of how this library can be used:

package main

import "github.com/DistributedClocks/GoVector/govec"

func main() {
    // Initialize GoVector logger
    logger := govec.InitGoVector("MyProcess", "LogFile", govec.GetDefaultConfig())

    // Encode message, and update vector clock
    messagePayload := []byte("sample-payload")
    vectorClockMessage := logger.PrepareSend("Sending Message", messagePayload, govec.GetDefaultLogOptions())

    // Send message
    connection.Write(vectorClockMessage)

    // In Receiving Process
    connection.Read(vectorClockMessage)

    // Decode message, and update local vector clock with received clock
    logger.UnpackReceive("Receiving Message", vectorClockMessage, &messagePayload, govec.GetDefaultLogOptions())

    // Log a local event
    logger.LogLocalEvent("Example Complete", govec.GetDefaultLogOptions())
}

For complete documentation with examples see GoVector's GoDoc.

End-to-End Examples

Generating ShiViz/TSViz compatible logs

By default, when you download the GoVector package using the go get command, the command installs a binary of the to-level file govec.go by the name of GoVector in the directory $GOPATH/bin. As long as this directory is part of your path, you can run the GoVector binary to generate a ShiViz or TSViz compatible log from all the logs in a given directory.

Note: Make sure that you are running the GoVector binary on a directory that contains log files from the same execution of the system. If it contains logs from multiple executions, then ShiViz and TSViz won't be able to interpret the log file.

Usage

To generate a ShiViz-compatible log file called hello.log from all log files in the directory path/to/logs do the following:

$ GoVector --log_type shiviz --log_dir path/to/logs --outfile hello.log

Similarly, to generate a TSViz-compatible log file called hello-ts.log from all log files in the directory path/to/logs do the following:

$ GoVector --log_type tsviz --log_dir path/to/logs --outfile hello-ts.log

Motivation

GoVector was initially developed as a pedagogical tool for UBC's computer science course on distributed systems (CPSC 416). Students new to the development of distributed systems can feed generated logs into ShiViz to visualize their program executions and reason about event orderings. Furthermore, GoVector's marshaling functionality reduces the effort needed to write networking code that is largely boilerplate.

Eventually, as a result of student requests, GoVector has been transformed into a general-purpose logging tool. Additional features include optimized IO, priority logging, TSViz compatibility, and RPC instrumentation.

Dependencies

GoVector has the following dependencies:

Contributors

  • Ivan Beschastnikh
  • Mike Fink
  • Stewart Grant
  • Clement Fung
  • Fabian Ruffy
  • Vaastav Anand

Output Example

The source code from the usage example produces the following log into a file named "LogFile.txt":

MyProcess {"MyProcess":1}
Initialization Complete
MyProcess {"MyProcess":2}
Sending Message
MyProcess {"MyProcess":3}
Receiving Message
MyProcess {"MyProcess":4}
Example Complete

Here is a sample output of the priority logger: PriorityLoggerOutput.png

Here is an example of ShiViz output generated by an RPC client server interaction: ShivizExample.png

Comments
  • Import issue

    Import issue

    I can't import GoVector into the project and keep getting error where it is looking for

    GoVector/govec/gopublisher.go:10:2: cannot find package "github.com/arcaneiceman/GoVector/broker" in any of: /usr/lib/go/src/pkg/github.com/arcaneiceman/GoVector/broker (from $GOROOT) /home/vm/gowork/src/github.com/arcaneiceman/GoVector/broker (from $GOPATH)

    And then the same thing for gopublisher.go and other components. I added GoVector as git submodule to our project and did the import from the root of the project "project/GoVector/govec" where project is root directory of our project. As far as I understand GOROOT needs to be set when you install go into a custom directory, but I haven't. GOPATH is working fine (so far) and is pointing to $HOME/gowork where the project is as well. Should GoVector be installed under $GOPATH as well for this to work? I was trying to make it self contained by having it as submodule.

    Some info:

    • GoVector cloned using git submodule init
    • project is at $GOPATH/src/project
    • GoVector is at $GOPATH/src/project/GoVector
    • the file that's importing GoVector is at $GOPATH/src/project/server
    • import statement "project/GoVector/govec"

    I would really appreciate some help. Might be something I am doing wrong. Thanks.

  • Interface reflection causes crash

    Interface reflection causes crash

    Sending an interface over vrpc causes a crash. For example the following types

    type Operation interface {
    	OperationType() OperationType
    	GetMinerID() string
    	GetFileName() string
    }
    
    type AppendOperation struct {
    	Timestamp time.Time
    	Filename  string
    	Record    Record
    	RecordNum uint16
    	MinerId   string
    }
    

    Where we are sending and expecting Operation. This causes deserialization to fail with the following message:

    panic: reflect.Set: value of type map[string]interface {} is not assignable to type blockchain.Operation
    
    goroutine 5 [running]:
    reflect.Value.assignTo(0x74a1c0, 0xc00040c2d0, 0x15, 0x7b4559, 0xb, 0x75cf60, 0xc0003ee1d0, 0xc00040c2d0, 0x0, 0x0)
    	C:/Go/src/reflect/value.go:2239 +0x453
    reflect.Value.Set(0x75cf60, 0xc0003ee1d0, 0x194, 0x74a1c0, 0xc00040c2d0, 0x15)
    	C:/Go/src/reflect/value.go:1373 +0xae
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).interfaceValue(0xc00029e700, 0x75cf60, 0xc0003ee1d0, 0x194, 0x535792, 0xc00029e700)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode_value.go:284 +0x163
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.decodeInterfaceValue(0xc00029e700, 0x75cf60, 0xc0003ee1d0, 0x194, 0xc0003ee1d0, 0x194)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode_value.go:256 +0x1ea
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.ptrDecoderFunc.func1(0xc00029e700, 0x71eb20, 0xc0003ee1d0, 0x16, 0x71eb20, 0x0)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode_value.go:124 +0xca
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).DecodeValue(0xc00029e700, 0x71eb20, 0xc0003ee1d0, 0x16, 0xc0003ee1d0, 0x16)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:224 +0x93
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.decodeInterfaceValue(0xc00029e700, 0x748420, 0xc00040c288, 0x194, 0x748420, 0x749800)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode_value.go:267 +0xaa
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).DecodeValue(0xc00029e700, 0x748420, 0xc00040c288, 0x194, 0xc00040c288, 0x194)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:224 +0x93
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).decode(0xc00029e700, 0x7216e0, 0xc00040c288, 0xc0003ea110, 0xe)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:212 +0x182
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).Decode(0xc00029e700, 0xc00006f9d0, 0x1, 0x1, 0x0, 0x763718)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:98 +0x73
    github.com/DistributedClocks/GoVector/govec.(*VClockPayload).DecodeMsgpack(0xc00040c270, 0xc00029e700, 0xc00040c270, 0x2b70338)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/govec/govec.go:184 +0xcf
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.decodeCustomValue(0xc00029e700, 0x7636e0, 0xc00040c270, 0x16, 0xc00040c270, 0x16)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode_value.go:174 +0x118
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.decodeCustomValueAddr(0xc00029e700, 0x772fe0, 0xc00040c270, 0x199, 0x772fe0, 0x452130)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode_value.go:132 +0x7c
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).DecodeValue(0xc00029e700, 0x772fe0, 0xc00040c270, 0x199, 0xc00040c270, 0x199)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:224 +0x93
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).decode(0xc00029e700, 0x7636e0, 0xc00040c270, 0x0, 0x40)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:212 +0x182
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.(*Decoder).Decode(0xc00029e700, 0xc00006fcc8, 0x1, 0x1, 0xc000036000, 0xc00006fcb8)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:98 +0x73
    github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack.Unmarshal(0xc000286060, 0x52, 0x52, 0xc00006fcc8, 0x1, 0x1, 0x30, 0x772fe0)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/vendor/github.com/vmihailenco/msgpack/decode.go:36 +0xb1
    github.com/DistributedClocks/GoVector/govec.defaultDecoder(0xc000286060, 0x52, 0x52, 0x7636e0, 0xc00040c270, 0x71eaa0, 0xc0000fe3e0)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/govec/govec.go:371 +0x85
    github.com/DistributedClocks/GoVector/govec.(*GoLog).UnpackReceive(0xc000108080, 0x7b886f, 0x14, 0xc000286060, 0x52, 0x52, 0x71eb20, 0xc0003ee1d0, 0x1)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/govec/govec.go:553 +0x102
    github.com/DistributedClocks/GoVector/govec/vrpc.(*RPCServerCodec).ReadRequestBody(0xc000202080, 0x71eb20, 0xc0003ee1d0, 0x71eb20, 0xc0003ee1d0)
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/govec/vrpc/vrpc.go:138 +0xee
    net/rpc.(*Server).readRequest(0xc0000943c0, 0x814ea0, 0xc000202080, 0xc00003c360, 0xc00003c3c0, 0xc00042df88, 0x6f897a, 0x5040408, 0xc0000524a0, 0x20, ...)
    	C:/Go/src/net/rpc/server.go:569 +0x299
    net/rpc.(*Server).ServeCodec(0xc0000943c0, 0x814ea0, 0xc000202080)
    	C:/Go/src/net/rpc/server.go:465 +0x9e
    created by github.com/DistributedClocks/GoVector/govec/vrpc.ServeRPCConn
    	C:/Users/Denis/go/src/github.com/DistributedClocks/GoVector/govec/vrpc/vrpc.go:38 +0xb6
    

    This likely because under the hood go might be serializing the interface as a map.

  • Add ability to buffer writes to the Log file

    Add ability to buffer writes to the Log file

    Currently govector Logger doesn't have the ability to buffer writes to the associated Log file and opens/writes/closes to the file at every event. File IO is expensive and this makes the govector Logger pretty much impossible to work with applications/protocols that require low latency (eg: real time game).

    This PR adds the ability to enable/disable buffered writes for the logger and passes this control to the user of the Logger.

  • RPC Codecs for automatically capturing RPC messages

    RPC Codecs for automatically capturing RPC messages

    This PR adds custom RPC Codecs and convenience functions which use a govector logger to automatically capture all RPC Calls made by the client and the responses by the server.

  • Don't Log flag?

    Don't Log flag?

    Hello,

    Say I am very pleased with the logging and believe everything works perfectly. I don't want to change my code but I now longer want to log large number of files for my system.

    Is there a method/flag in the library to disable logging completely? I see there are some to print out the logging to the screen, but none to disable.

  • Fixed bug in VClock.Compare and added tests for this method

    Fixed bug in VClock.Compare and added tests for this method

    As attributed to in the TODO comment by cfung on lines 92-96 of vclock_test.go, there was indeed a bug in the VClock.Compare method. The method as is would not detect all concurrent clocks, as it was premature to return false in lines 161-163 and 172-174 of the original code.

    I corrected the method, uncommented the test commented out by cfung and added several new tests to vclock_test.go to comprehensively check the VClock.Compare method. All tests pass.

  • Goreport

    Goreport

    I just ran gofmt and changed some variable names to make the linter happy. I figured that now that we have more than 100 stars we should try and keep the A+

  • Update example snippet in README.md

    Update example snippet in README.md

    In the example snippet available in the README.md file, the parameters passed to UnpackReceive do not seem to match the signature of the function currently available in the API (the order of buf []byte, unpack interface{} is inverted). It also looks like for all of PrepareSend,UnpackReceive and LogLocalEvent a GoLogOptions value is required in all calls.

  • nil pointer dereference when calling PrepareToSend(..)

    nil pointer dereference when calling PrepareToSend(..)

    Code I am using:

    package main
    
    import (
    	"github.com/DistributedClocks/GoVector/govec"
    )
    
    func main() {
    	LoggerClient := govec.InitGoVectorMultipleExecutions("2", "test")
    	LoggerClient.PrepareSend("Sending", "blabla")
    }
    
    

    Problem: I get the following error

    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x12dd1ad]
    
    goroutine 1 [running]:
    github.com/DistributedClocks/GoVector/govec.(*GoLog).PrepareSend(0xc420134100, 0x1393dde, 0x7, 0x1316880, 0x13d6600, 0x0, 0xc420125f70, 0x12de28e)
            /Users/annygakh/go/src/github.com/DistributedClocks/GoVector/govec/govec.go:507 +0x25d
    main.main()
            /Users/annygakh/go/src/test-shiviz/test.go:12 +0x93
    exit status 2
    

    Possible fix: It seems like there is missing initialization of private fields gv.encodingStrategy (and gv.decodingStrategy). The fields are initialized in InitGoVector, but not in InitGoVectorMultipleExecutions (which is what I am using). Attached is a proposed fix.

    patch.diff.txt

  • Bug on vclock.Compare()

    Bug on vclock.Compare()

    Method vclock have been implmented again to solve bug when comparing two concurrent vclocks. More tests for vclock.COmpare method have also been implemented for validation. The new method is more inefficient with large vectors.

  • Remove capture library.

    Remove capture library.

    This removes the circular dependency between dinv and Govector. This library should really live inside the Dinv repository as it explicitly uses Dinv's Pack and Unpack for logging vector clock timestamps and events.

  • Make ReturnVCString Deterministic

    Make ReturnVCString Deterministic

    Currently when getting the string representation for a vector clock, you will get a non-deterministic order of keys and values. The reason is that ranging over a map in Go gives you its keys in a random order. Nevertheless, the current implementation of ReturnVCString in the vclock package relies on ranging over the keys to sort the output (note that the comment is from the original code):

    //sort
    ids := make([]string, len(vc))
    i := 0
    for id := range vc {
    	ids[i] = id
    	i++
    }
    

    So I'm assuming that non-deterministic output is a bug and not intentional.
    For some use-cases (notably: my use-case πŸ™‚), this can be problematic. My proposal is to add an additional sort.Strings(ids) step before using the array of keys so that iff v1 == v2 => v1.ReturnVCString() == v2.ReturnVCString(). This should prevent any further surprises.

    There is a performance overhead but I find it negligible. For a vector clock with 100 entries (quite large):

    goos: darwin
    goarch: amd64
    pkg: github.com/DistributedClocks/GoVector/govec/vclock
    cpu: Intel(R) Core(TM) i5-8210Y CPU @ 1.60GHz
    BenchmarkVCString-4         	   28614	     40648 ns/op
    BenchmarkVCStringSorted-4   	   20901	     57339 ns/op
    PASS
    ok  	github.com/DistributedClocks/GoVector/govec/vclock	3.386s
    

    (This benchmark is not included in this PR, just illustrative.)
    0.017ms is acceptable, although that difference is grows or shrinks with the size of the clock.

  • Added support for message broadcast via RPC

    Added support for message broadcast via RPC

    Here are the changes that allow to broadcast messages via RPC with the same vector clock. An end-to-end example has been added in example/RpcBroadcast/RpcBroadcast.go and the ShiViz output of this example in .images/shiviz_broadcast.png. The example and ShiViz output has been linked from the README. Also, a quick smoke test has been added to govec_test.go.

    The changes are only really needed to enable broadcasting within the RPC framework, as if RPCs are not used, the end-user has full control to call GoLog.PrepareSend just once per several calls to conn.Write. On the other hand, when using RPCs, calls to GoLog.PrepareSend are automatically made on each RPC call and automatically tick the clock several times.

  • Little Code Error

    Little Code Error

    Hi!

    I've used this library in college for a little proyect and all the teammates I meet had the same problem I had.

    In the govec program, inside the govec folder, line 208 has a bug where you passed 3 arguments to the function dec.Decode(). An error pop up saying how it's supposed to be and, actually, in the line 183 is correctly used. So i changed it to err = dec.Decode(&d.Payload) and it works.

    I see is an easy fix, but using an IDE (for example Goland) it warns you and tries to prevent you from changing any file that is an external library. Maybe, for an even more amateur programmer than me, this could be the end of the work for a while.

  • Mocking Library for Log Outputs

    Mocking Library for Log Outputs

    We need to test the outputs written to Log files. This would involve creating a mock library that can capture and test the outputs written to the Log File.

    Something like this: https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742

  • In pubmanager.go registerPublisher should return an error

    In pubmanager.go registerPublisher should return an error

    if registerPublisher tries to register a nonce that already exists it should return an error to be dealt with in setupPubManagerTCP, otherwise the pubmanager will be shutdown for all potential new publishers.

A simple digital clock written in go to show time in hh : mm : ss format in console

Go console clock a simple digital clock written in go to show time in "hh : mm :

Feb 3, 2022
Gomol is a library for structured, multiple-output logging for Go with extensible logging outputs

gomol Gomol (Go Multi-Output Logger) is an MIT-licensed structured logging library for Go. Gomol grew from a desire to have a structured logging libra

Sep 26, 2022
Simple text-line analog clock

anaclock anaclock prints a simple analog clock as a line of text. Demo $ anaclock 23 . : .| 00 anaclock is easy to use in CLI prompts or anywhere

Dec 31, 2021
A simple logging module for go, with a rotating file feature and console logging.

A simple logging module for go, with a rotating file feature and console logging. Installation go get github.com/jbrodriguez/mlog Usage Sample usage W

Dec 14, 2022
FactorLog is a logging infrastructure for Go that provides numerous logging functions for whatever your style may be
FactorLog is a logging infrastructure for Go that provides numerous logging functions for whatever your style may be

FactorLog FactorLog is a fast logging infrastructure for Go that provides numerous logging functions for whatever your style may be. It could easily b

Aug 3, 2022
Package logging implements a logging infrastructure for Go
Package logging implements a logging infrastructure for Go

Golang logging library Package logging implements a logging infrastructure for Go. Its output format is customizable and supports different logging ba

Nov 10, 2021
Generate vector tiles for the entire planet on relatively low spec hardware.
Generate vector tiles for the entire planet on relatively low spec hardware.

Sequentially Generate Planet Mbtiles Sequentially generate and merge an entire planet.mbtiles vector tileset on low memory/power devices for free. com

Dec 21, 2022
The Simplest and worst logging library ever written

gologger A Simple Easy to use go logger library. Displays Colored log into console in any unix or windows platform. You can even store your logs in fi

Sep 26, 2022
a lightweight, high-performance, out-of-the-box logging library that relies solely on the Go standard library

English | δΈ­ζ–‡ olog olog is a lightweight, high-performance, out-of-the-box logging library that relies solely on the Go standard library. Support outpu

Apr 12, 2023
LogVoyage - logging SaaS written in GoLang
LogVoyage - logging SaaS written in GoLang

No longer maintained, sorry. Completely rewritten v2 is going to be released soon. Please follow http://github.com/logvoyage LogVoyage - fast and simp

Sep 26, 2022
A reusable logger module for basic logging, written in Go
A reusable logger module for basic logging, written in Go

logger A reusable logger module for basic logging, written in Go. Usage Client p

Jan 8, 2022
Simple and blazing fast lockfree logging library for golang
Simple and blazing fast lockfree logging library for golang

glg is simple golang logging library Requirement Go 1.11 Installation go get github.com/kpango/glg Example package main import ( "net/http" "time"

Nov 28, 2022
Logging library for Golang

GLO Logging library for Golang Inspired by Monolog for PHP, severity levels are identical Install go get github.com/lajosbencz/glo Severity levels Deb

Sep 26, 2022
Minimalistic logging library for Go.
Minimalistic logging library for Go.

logger Minimalistic logging library for Go. Blog Post Features: Advanced output filters (package and/or level) Attributes Timers for measuring perform

Nov 16, 2022
Seelog is a native Go logging library that provides flexible asynchronous dispatching, filtering, and formatting.

Seelog Seelog is a powerful and easy-to-learn logging framework that provides functionality for flexible dispatching, filtering, and formatting log me

Jan 3, 2023
A pure Go contextual logging library with "batteries included"

Cue Overview Cue implements contextual logging with "batteries included". It has thorough test coverage and supports logging to stdout/stderr, file, s

Sep 16, 2019
Golang logging library
Golang logging library

Golang logging library Package logging implements a logging infrastructure for Go. Its output format is customizable and supports different logging ba

Dec 27, 2022
Hierarchical, leveled, and structured logging library for Go

spacelog Please see http://godoc.org/github.com/spacemonkeygo/spacelog for info License Copyright (C) 2014 Space Monkey, Inc. Licensed under the Apach

Apr 27, 2021
Minimal structured logging library for Go
Minimal structured logging library for Go

slog slog is a minimal structured logging library for Go. Install go get cdr.dev/slog Features Minimal API First class context.Context support First c

Dec 29, 2022