update lol to actually work, and make this actually a go repo
This commit is contained in:
16
go.mod
Normal file
16
go.mod
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module protocol.realy.lol
|
||||||
|
|
||||||
|
go 1.23.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1
|
||||||
|
github.com/fatih/color v1.18.0
|
||||||
|
go.uber.org/atomic v1.11.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
|
)
|
||||||
19
go.sum
Normal file
19
go.sum
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
316
pkg/lol/log.go
Normal file
316
pkg/lol/log.go
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
package lol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"go.uber.org/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Off = iota
|
||||||
|
Fatal
|
||||||
|
Error
|
||||||
|
Warn
|
||||||
|
Info
|
||||||
|
Debug
|
||||||
|
Trace
|
||||||
|
)
|
||||||
|
|
||||||
|
var LevelNames = []string{
|
||||||
|
"off",
|
||||||
|
"fatal",
|
||||||
|
"error",
|
||||||
|
"warn",
|
||||||
|
"info",
|
||||||
|
"debug",
|
||||||
|
"trace",
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// LevelPrinter defines a set of terminal printing primitives that output with
|
||||||
|
// extra data, time, log logLevelList, and code location
|
||||||
|
|
||||||
|
// Ln prints lists of interfaces with spaces in between
|
||||||
|
Ln func(a ...interface{})
|
||||||
|
// F prints like fmt.Println surrounded []byte log details
|
||||||
|
F func(format string, a ...interface{})
|
||||||
|
// S prints a spew.Sdump for an enveloper slice
|
||||||
|
S func(a ...interface{})
|
||||||
|
// C accepts a function so that the extra computation can be avoided if it is
|
||||||
|
// not being viewed
|
||||||
|
C func(closure func() string)
|
||||||
|
// Chk is a shortcut for printing if there is an error, or returning true
|
||||||
|
Chk func(e error) bool
|
||||||
|
// Err is a pass-through function that uses fmt.Errorf to construct an error
|
||||||
|
// and returns the error after printing it to the log
|
||||||
|
Err func(format string, a ...interface{}) error
|
||||||
|
LevelPrinter struct {
|
||||||
|
Ln
|
||||||
|
F
|
||||||
|
S
|
||||||
|
C
|
||||||
|
Chk
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
LevelSpec struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Colorizer func(a ...interface{}) string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry is a log entry to be printed as json to the log file
|
||||||
|
Entry struct {
|
||||||
|
Time time.Time
|
||||||
|
Level string
|
||||||
|
Package string
|
||||||
|
CodeLocation string
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// sep is just a convenient shortcut for this very longwinded expression
|
||||||
|
sep = string(os.PathSeparator)
|
||||||
|
// writer can be swapped out for any io.*writer* that you want to use instead of
|
||||||
|
// stdout.
|
||||||
|
writer io.Writer = os.Stderr
|
||||||
|
// LevelSpecs specifies the id, string name and color-printing function
|
||||||
|
LevelSpecs = []LevelSpec{
|
||||||
|
{Off, "", NoSprint},
|
||||||
|
{Fatal, "FTL", color.New(color.BgRed, color.FgHiWhite).Sprint},
|
||||||
|
{Error, "ERR", color.New(color.FgHiRed).Sprint},
|
||||||
|
{Warn, "WRN", color.New(color.FgHiYellow).Sprint},
|
||||||
|
{Info, "INF", color.New(color.FgHiGreen).Sprint},
|
||||||
|
{Debug, "DBG", color.New(color.FgHiBlue).Sprint},
|
||||||
|
{Trace, "TRC", color.New(color.FgHiMagenta).Sprint},
|
||||||
|
}
|
||||||
|
NoTimeStomp atomic.Bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func NoSprint(a ...any) string { return "" }
|
||||||
|
|
||||||
|
// Log is a set of log printers for the various Level items.
|
||||||
|
type Log struct {
|
||||||
|
F, E, W, I, D, T LevelPrinter
|
||||||
|
}
|
||||||
|
|
||||||
|
type Check struct {
|
||||||
|
F, E, W, I, D, T Chk
|
||||||
|
}
|
||||||
|
type Errorf struct {
|
||||||
|
F, E, W, I, D, T Err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
*Log
|
||||||
|
*Check
|
||||||
|
*Errorf
|
||||||
|
}
|
||||||
|
|
||||||
|
var Level atomic.Int32
|
||||||
|
var Main = &Logger{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Main = &Logger{}
|
||||||
|
Main.Log, Main.Check, Main.Errorf = New(os.Stderr)
|
||||||
|
SetLoggers(Info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLoggers(level int) {
|
||||||
|
Main.Log.T.F("log level %s", LevelSpecs[level].Colorizer(LevelNames[level]))
|
||||||
|
Level.Store(int32(level))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLogLevel(level string) (i int) {
|
||||||
|
for i = range LevelNames {
|
||||||
|
if level == LevelNames[i] {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Info
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLogLevel(level string) {
|
||||||
|
for i := range LevelNames {
|
||||||
|
if level == LevelNames[i] {
|
||||||
|
SetLoggers(i)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func JoinStrings(a ...any) (s string) {
|
||||||
|
for i := range a {
|
||||||
|
s += fmt.Sprint(a[i])
|
||||||
|
if i < len(a)-1 {
|
||||||
|
s += " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var msgCol = color.New(color.FgBlue).Sprint
|
||||||
|
|
||||||
|
func GetPrinter(l int32, writer io.Writer) LevelPrinter {
|
||||||
|
return LevelPrinter{
|
||||||
|
Ln: func(a ...interface{}) {
|
||||||
|
if Level.Load() < l {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(writer,
|
||||||
|
"%s%s %s %s\n",
|
||||||
|
msgCol(Timestamper()),
|
||||||
|
LevelSpecs[l].Colorizer(LevelSpecs[l].Name),
|
||||||
|
JoinStrings(a...),
|
||||||
|
msgCol(GetLoc(2)),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
F: func(format string, a ...interface{}) {
|
||||||
|
if Level.Load() < l {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(writer,
|
||||||
|
"%s%s %s %s\n",
|
||||||
|
msgCol(Timestamper()),
|
||||||
|
LevelSpecs[l].Colorizer(LevelSpecs[l].Name),
|
||||||
|
fmt.Sprintf(format, a...),
|
||||||
|
msgCol(GetLoc(2)),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
S: func(a ...interface{}) {
|
||||||
|
if Level.Load() < l {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(writer,
|
||||||
|
"%s%s %s %s\n",
|
||||||
|
msgCol(Timestamper()),
|
||||||
|
LevelSpecs[l].Colorizer(LevelSpecs[l].Name),
|
||||||
|
spew.Sdump(a...),
|
||||||
|
msgCol(GetLoc(2)),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
C: func(closure func() string) {
|
||||||
|
if Level.Load() < l {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(writer,
|
||||||
|
"%s%s %s %s\n",
|
||||||
|
msgCol(Timestamper()),
|
||||||
|
LevelSpecs[l].Colorizer(LevelSpecs[l].Name),
|
||||||
|
closure(),
|
||||||
|
msgCol(GetLoc(2)),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Chk: func(e error) bool {
|
||||||
|
if Level.Load() < l {
|
||||||
|
return e != nil
|
||||||
|
}
|
||||||
|
if e != nil {
|
||||||
|
fmt.Fprintf(writer,
|
||||||
|
"%s%s %s %s\n",
|
||||||
|
msgCol(Timestamper()),
|
||||||
|
LevelSpecs[l].Colorizer(LevelSpecs[l].Name),
|
||||||
|
e.Error(),
|
||||||
|
msgCol(GetLoc(2)),
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
Err: func(format string, a ...interface{}) error {
|
||||||
|
if Level.Load() < l {
|
||||||
|
fmt.Fprintf(writer,
|
||||||
|
"%s%s %s %s\n",
|
||||||
|
msgCol(Timestamper()),
|
||||||
|
LevelSpecs[l].Colorizer(LevelSpecs[l].Name, " "),
|
||||||
|
fmt.Sprintf(format, a...),
|
||||||
|
msgCol(GetLoc(2)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return fmt.Errorf(format, a...)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNullPrinter() LevelPrinter {
|
||||||
|
return LevelPrinter{
|
||||||
|
Ln: func(a ...interface{}) {},
|
||||||
|
F: func(format string, a ...interface{}) {},
|
||||||
|
S: func(a ...interface{}) {},
|
||||||
|
C: func(closure func() string) {},
|
||||||
|
Chk: func(e error) bool { return e != nil },
|
||||||
|
Err: func(format string, a ...interface{}) error { return fmt.Errorf(format, a...) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(writer io.Writer) (l *Log, c *Check, errorf *Errorf) {
|
||||||
|
l = &Log{
|
||||||
|
T: GetPrinter(Trace, writer),
|
||||||
|
D: GetPrinter(Debug, writer),
|
||||||
|
I: GetPrinter(Info, writer),
|
||||||
|
W: GetPrinter(Warn, writer),
|
||||||
|
E: GetPrinter(Error, writer),
|
||||||
|
F: GetPrinter(Fatal, writer),
|
||||||
|
}
|
||||||
|
c = &Check{
|
||||||
|
F: l.F.Chk,
|
||||||
|
E: l.E.Chk,
|
||||||
|
W: l.W.Chk,
|
||||||
|
I: l.I.Chk,
|
||||||
|
D: l.D.Chk,
|
||||||
|
T: l.T.Chk,
|
||||||
|
}
|
||||||
|
errorf = &Errorf{
|
||||||
|
F: l.F.Err,
|
||||||
|
E: l.E.Err,
|
||||||
|
W: l.W.Err,
|
||||||
|
I: l.I.Err,
|
||||||
|
D: l.D.Err,
|
||||||
|
T: l.T.Err,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamper e
|
||||||
|
func Timestamper() (s string) {
|
||||||
|
if NoTimeStomp.Load() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
timeText := fmt.Sprint(time.Now().UnixNano())
|
||||||
|
lt := len(timeText)
|
||||||
|
lb := lt + 1
|
||||||
|
var timeBytes = make([]byte, lb)
|
||||||
|
copy(timeBytes[lb-9:lb], timeText[lt-9:lt])
|
||||||
|
timeBytes[lb-10] = '.'
|
||||||
|
lb -= 10
|
||||||
|
lt -= 9
|
||||||
|
copy(timeBytes[:lb], timeText[:lt])
|
||||||
|
return fmt.Sprint(string(timeBytes), " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
var wd, _ = os.Getwd()
|
||||||
|
|
||||||
|
func GetNLoc(n int) (output string) {
|
||||||
|
for ; n > 1; n-- {
|
||||||
|
output += fmt.Sprintf("%s\n", GetLoc(n))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLoc(skip int) (output string) {
|
||||||
|
_, file, line, _ := runtime.Caller(skip)
|
||||||
|
split := strings.Split(file, wd+string(os.PathSeparator))
|
||||||
|
if len(split) < 2 {
|
||||||
|
output = fmt.Sprintf("%s:%d", file, line)
|
||||||
|
} else {
|
||||||
|
output = fmt.Sprintf("%s:%d", split[1], line)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
35
pkg/lol/readme.md
Normal file
35
pkg/lol/readme.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# lol
|
||||||
|
|
||||||
|
location of log
|
||||||
|
|
||||||
|
This is a very simple, but practical library for logging in applications. Its
|
||||||
|
main feature is printing source code locations to make debugging easier.
|
||||||
|
|
||||||
|
## usage
|
||||||
|
|
||||||
|
put this somewhere in your package:
|
||||||
|
|
||||||
|
```go
|
||||||
|
var log, chk, errorf = lol.Main.Log, lol.Main.Check, lol.Main.Errorf
|
||||||
|
```
|
||||||
|
|
||||||
|
then you can invoke like this:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.I.S(spew.this.thing)
|
||||||
|
errorf.E("print and return this error")
|
||||||
|
if err = bogus; chk.E(err) { return bogus.response } // print an error at the site and return the error
|
||||||
|
```
|
||||||
|
|
||||||
|
## terminals
|
||||||
|
|
||||||
|
Due to how so few terminals actually support source location hyperlinks, pretty much tilix and intellij terminal are
|
||||||
|
the only two that really provide adequate functionality, this logging library defaults to output format that works
|
||||||
|
best with intellij. As such, the terminal is aware of the CWD and the code locations printed are relative, as
|
||||||
|
required to get the hyperlinkization from this terminal. Handling support for Tilix requires more complications and
|
||||||
|
due to advances with IntelliJ's handling it is not practical to support any other for this purpose. Users of this
|
||||||
|
library can always fall back to manually interpreting and accessing the relative file path to find the source of a log.
|
||||||
|
|
||||||
|
In addition, due to this terminal's slow rendering of long lines, long log strings are automatically broken into 80
|
||||||
|
character lines, and if there is comma separators in the line, the line is broken at the comma instead of at
|
||||||
|
column80. This works perfectly for this purpose.
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
# R.E.A.L.Y. Protocol
|
# R.E.A.L.Y. Protocol
|
||||||
|
|
||||||
> relay events and like yeah
|
> relay events and like... yeah
|
||||||
|
|
||||||
relay events and like yeah protocol
|
[](https://pkg.go.dev/protocol.realy.lol)
|
||||||
|
[](https://matrix.to/#/#realy-general:matrix.org)
|
||||||
|
|
||||||
|
zap mleku: ⚡️mleku@getalby.com
|
||||||
|
|
||||||
Inspired by the event bus architecture of [nostr](https://github.com/nostr-protocol) but redesigned to avoid the serious deficiencies of that protocol for both developers and users.
|
Inspired by the event bus architecture of [nostr](https://github.com/nostr-protocol) but redesigned to avoid the serious deficiencies of that protocol for both developers and users.
|
||||||
|
|
||||||
- [why](./why.md)
|
- [why](./why.md)
|
||||||
- [event spec](./spec.md)
|
- [event spec](./spec.md)
|
||||||
- [matrix chat](https://matrix.to/#/#realy-general:matrix.org)
|
|
||||||
- [reference relays](./relays/readme.md)
|
- [reference relays](./relays/readme.md)
|
||||||
- [reference clients](./clients/readme.md)
|
- [reference clients](./clients/readme.md)
|
||||||
- [GO libraries](./pkg/readme.md)
|
- [GO libraries](./pkg/readme.md)
|
||||||
Reference in New Issue
Block a user