diff --git a/.gitignore b/.gitignore
index d091be8..e2798b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
-data/config.json
-data/settings_db/**
-aleesa-jabber-go
+/data/Config.json
+/data/config.json
+/data/settings_db/**
+/aleesa-jabber-go
+/aleesa-jabber-go.exe
diff --git a/.golangci.yml b/.golangci.yml
index 2cae5e9..4135c21 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,11 +1,8 @@
run:
tests: false
- skip-dirs:
- - data
- - vendor
modules-download-mode: readonly
allow-parallel-runners: true
- go: '1.22'
+ go: '1.25'
output:
sort-results: true
linters-settings:
@@ -14,6 +11,9 @@ linters-settings:
# Оно не используется для повышения безопасности или каких-то таких секъюрых вещей, оно используется для выборки
# произвольного элемента из массива, так что ИДИ НАХУЙ с этой проверкой и не еби мозги липовой безопасностью.
- G404 # Insecure random number source (rand)
+issues.exclude-dirs:
+ - data
+ - vendor
linters:
disable-all: true
enable:
@@ -28,19 +28,18 @@ linters:
- bodyclose
- containedctx
- contextcheck
+ - copyloopvar
- decorder
- durationcheck
- errchkjson
- errorlint
- exhaustive
- exhaustruct
- - exportloopref
- - gci
- ginkgolinter
- gocheckcompilerdirectives
- gocritic
- godot
- - goerr113
+ - err113
- gofmt
- goimports
- gosec
diff --git a/Makefile b/Makefile
index 9362b85..b00d0b4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,34 @@
#!/usr/bin/env gmake -f
-BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath
-FILELIST=collection.go commands.go event_parser.go globals.go lib.go main.go read_config.go redis.go types.go \
- settings-db-util.go
+GOOPTS=CGO_ENABLED=0
+BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath -buildvcs=false
+MYNAME=aleesa-jabber-go
+BINARY=${MYNAME}
+UNIX_BINARY=${MYNAME}
+WINDOWS_BINARY=${MYNAME}.exe
+RMCMD=rm -rf
-BINARY=aleesa-jabber-go
+# На windows имя бинарника может зависеть не только от платформы, но и от выбранной цели, для linux-а суффикс .exe
+# не нужен
+ifeq ($(OS),Windows_NT)
+ifdef GOOS
+ifeq ($(GOOS),windows)
+BINARY=${WINDOWS_BINARY}
+else # not ifeq ($(GOOS),windows)
+BINARY=${MYNAME}
+endif # ifeq ($(GOOS),windows)
+else # not ifdef GOOS
+BINARY=${WINDOWS_BINARY}
+endif # ifdef GOOS
+ifeq ($(SHELL), sh.exe)
+RMCMD=DEL /Q /F
+endif
+endif
+
+# Явно определяем символ новой строки, чтобы избежать неоднозначности на windows
+define IFS
+
+endef
all: clean build
@@ -12,38 +36,41 @@ all: clean build
build:
ifeq ($(OS),Windows_NT)
-# powershell
-ifeq ($(SHELL),sh.exe)
- SET CGO_ENABLED=0
- go build ${BUILDOPTS} -o ${BINARY} ${FILELIST}
-else
-# jetbrains golang
- CGO_ENABLED=0
- go build ${BUILDOPTS} -o ${BINARY} ${FILELIST}
-endif
-# bash/git bash
-else
- CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY} ${FILELIST}
-endif
+# Looks like on windows gnu make explicitly set SHELL to sh.exe, if it was not set.
+ifeq ($(SHELL), sh.exe)
+# # Vanilla cmd.exe / powershell.
+ SET "CGO_ENABLED=0"
+ go build ${BUILDOPTS} -o ${BINARY} ./cmd/${MYNAME}
+else ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
+# # git-bash
+ CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY} ./cmd/${MYNAME}
+else # not ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
+# # Some other shell.
+# # TODO: handle it.
+ $(info "-- Dunno how to handle this shell: ${SHELL}")
+endif # ifeq (,$(findstring(Git/usr/bin/sh.exe, $(SHELL))))
+else # not ($(OS),Windows_NT)
+ CGO_ENABLED=0 go build ${BUILDOPTS} -o ${BINARY} ./cmd/${MYNAME}
+endif # ifeq ($(OS),Windows_NT)
clean:
- go clean
+ifeq ($(OS),Windows_NT)
+ifeq ($(SHELL),sh.exe)
+# # Vanilla cmd.exe / powershell.
+ if exist ${WINDOWS_BINARY} ${RMCMD} ${WINDOWS_BINARY}
+ if exist ${UNIX_BINARY} ${RMCMD} ${UNIX_BINARY}
+else # not ifeq ($(SHELL),sh.exe)
+ ${RMCMD} ./${WINDOWS_BINARY}
+ ${RMCMD} ./${UNIX_BINARY}
+endif # ifeq ($(SHELL),sh.exe)
+else # not ifeq ($(OS),Windows_NT)
+ ${RMCMD} ./${BINARY}
+endif
upgrade:
-ifeq ($(OS),Windows_NT)
-# jetbrains golang, powershell
-ifeq ($(SHELL),sh.exe)
- if exist vendor del /F /S /Q vendor >nul
-# git bash case
-else
- $(RM) -r vendor
-endif
-else
- $(RM) -r vendor
-endif
- go get -d -u -t ./...
+ go get -u ./...
go mod tidy
go mod vendor
diff --git a/README.md b/README.md
index e14c7fb..561ca97 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ pubsub.
make
```
-в итоге получится бинарник **aleesa-jabber-go**. После создания data/config.json из data/config_sample.json, можно
+в итоге получится бинарник **aleesa-jabber-go**. После создания data/Config.json из data/config_sample.json, можно
запускать приложение.
Предполагается, что конфиг написан в формате [human json](https://hjson.github.io), который допускает коментарии и
@@ -28,12 +28,12 @@ make
~/.aleesa-jabber-go.json
~/aleesa-jabber-go.json
/etc/aleesa-jabber-go.json
-data/config.json
+data/Config.json
```
В каталоге **contrib** находится скрипт для _alpine linux_, системы инициализации _openrc_. Этот скрипт достаточно
положить в **/etc/init.d/aleesa-jabber-go**. После чего скопировать бинарник в каталог **/var/lib/aleesa-jabber-go**,
-положить конфиг в одну из дефолтных локаций (тестировалась /var/lib/aleesa-jabber-go/data/config.json) и после этого
+положить конфиг в одну из дефолтных локаций (тестировалась /var/lib/aleesa-jabber-go/data/Config.json) и после этого
сервис запускается командой:
```bash
diff --git a/cmd/aleesa-jabber-go/main.go b/cmd/aleesa-jabber-go/main.go
new file mode 100644
index 0000000..6c41c0f
--- /dev/null
+++ b/cmd/aleesa-jabber-go/main.go
@@ -0,0 +1,190 @@
+package main
+
+import (
+ "crypto/tls"
+ "fmt"
+ "os"
+ "os/signal"
+ "path/filepath"
+ "time"
+
+ "aleesa-jabber-go/internal/anycollection"
+ "aleesa-jabber-go/internal/jabber"
+ "aleesa-jabber-go/internal/log"
+
+ "github.com/eleksir/go-xmpp"
+ "github.com/go-redis/redis/v8"
+ "gopkg.in/tomb.v2"
+)
+
+func main() {
+ var (
+ err error
+ logfile *os.File
+ logVebosity string
+ verboseClient = false
+ )
+
+ // Добавим динамически формируемый путь до конфига в список возможных положений конфига в системе.
+ executablePath, err := os.Executable()
+
+ if err != nil {
+ log.Errorf("unable to get current executable path: %s", err)
+
+ os.Exit(1)
+ }
+
+ configJSONPath := fmt.Sprintf("%s/data/config.json", filepath.Dir(executablePath))
+ jabber.ConfigLocations = append(jabber.ConfigLocations, configJSONPath)
+
+ if err := jabber.ReadConfig(); err != nil {
+ log.Errorf("%s", err)
+
+ os.Exit(1)
+ }
+
+ // Откроем лог и скормим его логгеру
+ if jabber.Config.Log == "" {
+ logfile = os.Stderr
+ } else {
+ logfile, err = os.OpenFile(jabber.Config.Log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
+
+ if err != nil {
+ log.Errorf("Unable to open log file %s: %s", jabber.Config.Log, err)
+ os.Exit(1)
+ }
+ }
+
+ log.Init(jabber.Config.Loglevel, logfile)
+ logVebosity = log.GetLevel()
+ log.Warnf("Loglevel set to %v", logVebosity)
+
+ for {
+ jabber.SigChan = make(chan os.Signal, 1)
+ jabber.Talk = new(xmpp.Client)
+ jabber.Options = new(xmpp.Options)
+
+ // Через tomb попробуем сделать выход горутинок управляемым.
+ jabber.GTomb = tomb.Tomb{}
+
+ // Иницализируем redis-клиента.
+ jabber.RedisClient = redis.NewClient(&redis.Options{ //nolint:exhaustruct
+ Addr: fmt.Sprintf("%s:%d", jabber.Config.Redis.Server, jabber.Config.Redis.Port),
+ })
+
+ log.Debugf("Lazy connect() to redis at %s:%d", jabber.Config.Redis.Server, jabber.Config.Redis.Port)
+ jabber.Subscriber = jabber.RedisClient.Subscribe(jabber.Ctx, jabber.Config.Redis.MyChannel)
+
+ if logVebosity == "debug" {
+ verboseClient = true
+ }
+
+ // github.com/mattn/go-xmpp пишет в stdio, нам этого не надо, ловим выхлоп его в logrus с уровнем trace.
+ xmpp.DebugWriter = log.Writer
+
+ // Хэндлер сигналов не надо трогать, он нужен для завершения программы целиком.
+ jabber.GTomb.Go(jabber.SigHandler)
+ signal.Notify(jabber.SigChan, os.Interrupt)
+
+ jabber.GTomb.Go(func() error { return jabber.RedisLoop(jabber.Subscriber.Channel()) })
+
+ jabber.Options = &xmpp.Options{ //nolint:exhaustruct
+ Host: fmt.Sprintf("%s:%d", jabber.Config.Jabber.Server, jabber.Config.Jabber.Port),
+ User: jabber.Config.Jabber.User,
+ Password: jabber.Config.Jabber.Password,
+ Resource: jabber.Config.Jabber.Resource,
+ NoTLS: !jabber.Config.Jabber.Ssl,
+ StartTLS: jabber.Config.Jabber.StartTLS,
+ TLSConfig: &tls.Config{ //nolint:exhaustruct
+ ServerName: jabber.Config.Jabber.Server,
+ InsecureSkipVerify: !jabber.Config.Jabber.SslVerify, //nolint:gosec
+ },
+ InsecureAllowUnencryptedAuth: jabber.Config.Jabber.InsecureAllowUnencryptedAuth,
+ Debug: verboseClient,
+ Session: false,
+ Status: "xa",
+ StatusMessage: jabber.RandomPhrase(jabber.Config.Jabber.StartupStatus),
+ DialTimeout: time.Duration(jabber.Config.Jabber.ConnectionTimeout) * time.Second,
+ }
+
+ // Устанавливаем соединение и гребём события, посылаемые сервером.
+ jabber.GTomb.Go(myLoop)
+
+ // Ловим первый же kill и не дождаемся остальных, хотя формально надо бы.
+ <-jabber.GTomb.Dying()
+
+ time.Sleep(time.Duration(jabber.Config.Jabber.ReconnectDelay) * time.Second)
+ }
+}
+
+func myLoop() error {
+ for {
+ // Зададим начальное значение глобальным переменным.
+ jabber.ServerPingTimestampRx = 0
+ jabber.ServerPingTimestampTx = 0
+ jabber.RoomsConnected = make([]string, 1)
+ jabber.LastActivity = 0
+ jabber.LastServerActivity = 0
+ jabber.LastMucActivity = anycollection.NewCollection()
+ jabber.ServerCapsQueried = false
+ jabber.ServerCapsList = anycollection.NewCollection()
+ jabber.MucCapsList = anycollection.NewCollection()
+ jabber.RoomPresences = anycollection.NewCollection()
+
+ // Установим коннект.
+ if err := jabber.EstablishConnection(); err != nil {
+ log.Errorf("%s", err)
+
+ return err
+ }
+
+ jabber.ServerPingTimestampRx = time.Now().Unix() // Считаем, что если коннект запустился, то первый пинг успешен.
+
+ // Тыкаем сервер палочкой, проверяем, что коннект жив и вываливаемся из mainLoop, если он не жив.
+ jabber.GTomb.Go(
+ func() error {
+ err := jabber.ProbeServerLiveness()
+ log.Errorf("%s", err)
+
+ return err
+ },
+ )
+
+ // Тыкаем muc-и палочкой, проверяем, что они живы и пере-заходим в них, если пинги пропали.
+ // Если пинги до комнаты пропали, то это фактически значит, что либо сервер потерял связь с MUC-компонентом,
+ // либо у нас какой-то wire error.
+ // GTomb.Go() тут зовётся внутри на каждую комнату, если у нас ошибка, эта горутинка рано или поздно выйдет.
+ go jabber.ProbeMUCLiveness()
+
+ // Гребём сообщения...
+ for {
+ // Стриггерилось завершение работы приложения, или соединение не установлено (порвалось, например).
+ // грести не надо.
+ if jabber.Shutdown {
+ break
+ }
+
+ if !jabber.IsConnected {
+ // Tight loop - это наверно не очень хорошо, думаю, ничего страшного не будет, если мы поспим 100мс.
+ time.Sleep(100 * time.Millisecond)
+
+ continue
+ }
+
+ // Вынимаем ивент из "провода".
+ chat, err := jabber.Talk.Recv()
+
+ if err != nil {
+ log.Errorf("Unable to get recieve data from socket: %s", err)
+
+ return err
+ }
+
+ jabber.ParseEvent(chat)
+ }
+
+ return nil
+ }
+}
+
+/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
diff --git a/go.mod b/go.mod
index d5e07ac..c18bd92 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module aleesa-jabber-go
-go 1.22
+go 1.25.1
require (
github.com/cockroachdb/errors v1.11.3
@@ -9,7 +9,6 @@ require (
github.com/eleksir/go-xmpp v1.6.0
github.com/go-redis/redis/v8 v8.11.5
github.com/hjson/hjson-go v3.3.0+incompatible
- github.com/sirupsen/logrus v1.9.3
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
)
diff --git a/go.sum b/go.sum
index 4aa7ef0..14ae07d 100644
--- a/go.sum
+++ b/go.sum
@@ -19,7 +19,6 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
@@ -76,10 +75,6 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
-github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -107,7 +102,6 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -124,13 +118,11 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/collection.go b/internal/anycollection/anycollection.go
similarity index 78%
rename from collection.go
rename to internal/anycollection/anycollection.go
index 9ec783a..2d6efaa 100644
--- a/collection.go
+++ b/internal/anycollection/anycollection.go
@@ -1,4 +1,4 @@
-package main
+package anycollection
import (
"sync"
@@ -12,12 +12,13 @@ type Collection struct {
// Item представляет собой интерфейс для хранения произвольных данных.
type item struct {
- data interface{}
+ data any
}
// NewCollection создаёт инстанс коллекции.
func NewCollection() *Collection {
- c := &Collection{ //nolint:exhaustruct
+ c := &Collection{
+ items: sync.Map{},
close: make(chan struct{}),
}
@@ -25,7 +26,7 @@ func NewCollection() *Collection {
}
// Get достаёт данные по заданному ключу из коллекции.
-func (collection *Collection) Get(key interface{}) (interface{}, bool) {
+func (collection *Collection) Get(key any) (any, bool) {
obj, exists := collection.items.Load(key)
if !exists {
@@ -38,15 +39,15 @@ func (collection *Collection) Get(key interface{}) (interface{}, bool) {
}
// Set сохраняет данные с заданным ключом в коллекцию.
-func (collection *Collection) Set(key interface{}, value interface{}) {
+func (collection *Collection) Set(key any, value any) {
collection.items.Store(key, item{
data: value,
})
}
// Range применяет функцию f ко всем ключам в коллекции.
-func (collection *Collection) Range(f func(key, value interface{}) bool) {
- fn := func(key, value interface{}) bool {
+func (collection *Collection) Range(f func(key, value any) bool) {
+ fn := func(key, value any) bool {
item := value.(item)
return f(key, item.data)
@@ -56,7 +57,7 @@ func (collection *Collection) Range(f func(key, value interface{}) bool) {
}
// Delete удаляет ключ и значение из коллекции данных.
-func (collection *Collection) Delete(key interface{}) {
+func (collection *Collection) Delete(key any) {
collection.items.Delete(key)
}
diff --git a/commands.go b/internal/jabber/commands.go
similarity index 80%
rename from commands.go
rename to internal/jabber/commands.go
index ffe6306..8f76dc3 100644
--- a/commands.go
+++ b/internal/jabber/commands.go
@@ -1,4 +1,4 @@
-package main
+package jabber
import (
"encoding/json"
@@ -7,8 +7,9 @@ import (
"slices"
"strings"
+ "aleesa-jabber-go/internal/log"
+
"github.com/eleksir/go-xmpp"
- log "github.com/sirupsen/logrus"
)
func cmd(v xmpp.Chat) error {
@@ -18,10 +19,10 @@ func cmd(v xmpp.Chat) error {
data []byte
)
- message.From = config.Redis.MyChannel
+ message.From = Config.Redis.MyChannel
message.Threadid = "" // Тредиков в jabber-е нету, поэтому это поле отправляем пустым
message.Message = v.Text
- message.Plugin = config.Redis.MyChannel
+ message.Plugin = Config.Redis.MyChannel
// Список команд, публично доступных, без каких-то специальных настроек
cmds := []string{"ping", "пинг", "пинх", "pong", "понг", "понх", "coin", "монетка", "roll", "dice", "кости",
@@ -58,7 +59,7 @@ func cmd(v xmpp.Chat) error {
message.Misc.Answer = 0
message.Misc.Fwdcnt = 0
- message.Misc.Csign = config.CSign
+ message.Misc.Csign = Config.CSign
message.Misc.Username = userNick
message.Misc.Botnick = getBotNickFromRoomConfig(message.Chatid)
message.Misc.Msgformat = 0
@@ -66,9 +67,9 @@ func cmd(v xmpp.Chat) error {
msgLen := len(v.Text)
// TODO: а вот тут надо впилить парсер команд
- if (msgLen > len(config.CSign)) && (v.Text[:len(config.CSign)] == config.CSign) {
+ if (msgLen > len(Config.CSign)) && (v.Text[:len(Config.CSign)] == Config.CSign) {
var (
- cmd = v.Text[len(config.CSign):]
+ cmd = v.Text[len(Config.CSign):]
room = message.Chatid
answer string
)
@@ -76,55 +77,55 @@ func cmd(v xmpp.Chat) error {
// И таких кейсов у нас минимум на команды !help и семейство команд !admin, а также на те команды, которые не всегда работают
switch {
case cmd == "help" || cmd == "помощь":
- answer += fmt.Sprintf("%shelp | %sпомощь - это сообщение\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru\n", config.CSign, config.CSign, config.CSign)
- answer += fmt.Sprintf("%sbuni - комикс-стрип hapi buni\n", config.CSign)
- answer += fmt.Sprintf("%sbunny - кролик\n", config.CSign)
- answer += fmt.Sprintf("%srabbit | %sкролик - кролик\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%scat | %sкис - кошечка\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sdice | %sroll | %sкости - бросить кости\n", config.CSign, config.CSign, config.CSign)
- answer += fmt.Sprintf("%sdig | %sкопать - заняться археологией\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sdrink | %sпраздник - какой сегодня праздник?\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sfish | %sfisher - порыбачить\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sрыба | %sрыбка | %sрыбалка - порыбачить\n", config.CSign, config.CSign, config.CSign)
- answer += fmt.Sprintf("%sf | %sф - рандомная фраза из сборника цитат fortune_mod\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sfortune | %sфортунка - рандомная фраза из сборника цитат fortune_mod\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sfox | %sлис - лисичка\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sfriday | %sпятница - а не пятница ли сегодня?\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sfrog | %sлягушка - лягушка\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%shorse | %sлошадь | %sлошадка - лошадка\n", config.CSign, config.CSign, config.CSign)
- answer += fmt.Sprintf("%skarma фраза - посмотреть карму фразы\n", config.CSign)
- answer += fmt.Sprintf("%sкарма фраза - посмотреть карму фразы\n", config.CSign)
+ answer += fmt.Sprintf("%shelp | %sпомощь - это сообщение\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru\n", Config.CSign, Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sbuni - комикс-стрип hapi buni\n", Config.CSign)
+ answer += fmt.Sprintf("%sbunny - кролик\n", Config.CSign)
+ answer += fmt.Sprintf("%srabbit | %sкролик - кролик\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%scat | %sкис - кошечка\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sdice | %sroll | %sкости - бросить кости\n", Config.CSign, Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sdig | %sкопать - заняться археологией\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sdrink | %sпраздник - какой сегодня праздник?\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sfish | %sfisher - порыбачить\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sрыба | %sрыбка | %sрыбалка - порыбачить\n", Config.CSign, Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sf | %sф - рандомная фраза из сборника цитат fortune_mod\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sfortune | %sфортунка - рандомная фраза из сборника цитат fortune_mod\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sfox | %sлис - лисичка\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sfriday | %sпятница - а не пятница ли сегодня?\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sfrog | %sлягушка - лягушка\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%shorse | %sлошадь | %sлошадка - лошадка\n", Config.CSign, Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%skarma фраза - посмотреть карму фразы\n", Config.CSign)
+ answer += fmt.Sprintf("%sкарма фраза - посмотреть карму фразы\n", Config.CSign)
answer += fmt.Sprintln("фраза++ | фраза-- - повысить или понизить карму фразы")
- answer += fmt.Sprintf("%slat | %sлат - сгенерировать фразу из крылатого латинского выражения\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%smonkeyuser - комикс-стрип MonkeyUser\n", config.CSign)
- answer += fmt.Sprintf("%sowl | %sсова - сова\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sping | %sпинг - попинговать бота\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sproverb | %sпословица - рандомная русская пословица\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%ssnail | %sулитка - улитка\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%ssome_brew - выдать соответствующий напиток, бармен может налить rum, ром, vodka, водку, tequila, текила\n", config.CSign)
- answer += fmt.Sprintf("%sver | %sversion - написать что-то про версию ПО\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sверсия - написать что-то про версию ПО\n", config.CSign)
- answer += fmt.Sprintf("%sw <город> | %sп <город> - погода в городе\n", config.CSign, config.CSign)
- answer += fmt.Sprintf("%sxkcd - комикс-стрип с xkcb.ru\n", config.CSign)
+ answer += fmt.Sprintf("%slat | %sлат - сгенерировать фразу из крылатого латинского выражения\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%smonkeyuser - комикс-стрип MonkeyUser\n", Config.CSign)
+ answer += fmt.Sprintf("%sowl | %sсова - сова\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sping | %sпинг - попинговать бота\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sproverb | %sпословица - рандомная русская пословица\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%ssnail | %sулитка - улитка\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%ssome_brew - выдать соответствующий напиток, бармен может налить rum, ром, vodka, водку, tequila, текила\n", Config.CSign)
+ answer += fmt.Sprintf("%sver | %sversion - написать что-то про версию ПО\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sверсия - написать что-то про версию ПО\n", Config.CSign)
+ answer += fmt.Sprintf("%sw <город> | %sп <город> - погода в городе\n", Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sxkcd - комикс-стрип с xkcb.ru\n", Config.CSign)
// Для овнера или админа надо показывать команду admin
if isMucAdmin(v.Remote) {
- answer += fmt.Sprintf("%sadmin - настройки некоторых плагинов бота для комнаты\n", config.CSign)
+ answer += fmt.Sprintf("%sadmin - настройки некоторых плагинов бота для комнаты\n", Config.CSign)
}
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
case cmd == "admin":
if isMucAdmin(v.Remote) {
- answer += fmt.Sprintf("%sadmin oboobs # - где 1 - вкл, 0 - выкл плагина oboobs\n", config.CSign)
- answer += fmt.Sprintf("%sadmin oboobs - показываем ли сисечки по просьбе участников чата (команды %stits, %stities, %sboobs, %sboobies, %sсиси, %sсисечки)\n", config.CSign, config.CSign, config.CSign, config.CSign, config.CSign, config.CSign, config.CSign)
- answer += fmt.Sprintf("%sadmin obutts # - где 1 - вкл, 0 - выкл плагина obutts\n", config.CSign)
- answer += fmt.Sprintf("%sadmin obutts - показываем ли попки по просьбе участников чата (команды %sass, %sbutt, %sbooty, %sпопа, %sпопка)\n", config.CSign, config.CSign, config.CSign, config.CSign, config.CSign, config.CSign)
+ answer += fmt.Sprintf("%sadmin oboobs # - где 1 - вкл, 0 - выкл плагина oboobs\n", Config.CSign)
+ answer += fmt.Sprintf("%sadmin oboobs - показываем ли сисечки по просьбе участников чата (команды %stits, %stities, %sboobs, %sboobies, %sсиси, %sсисечки)\n", Config.CSign, Config.CSign, Config.CSign, Config.CSign, Config.CSign, Config.CSign, Config.CSign)
+ answer += fmt.Sprintf("%sadmin obutts # - где 1 - вкл, 0 - выкл плагина obutts\n", Config.CSign)
+ answer += fmt.Sprintf("%sadmin obutts - показываем ли попки по просьбе участников чата (команды %sass, %sbutt, %sbooty, %sпопа, %sпопка)\n", Config.CSign, Config.CSign, Config.CSign, Config.CSign, Config.CSign, Config.CSign)
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -145,7 +146,7 @@ func cmd(v xmpp.Chat) error {
answer = "Плагин oboobs выключен"
}
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -160,7 +161,7 @@ func cmd(v xmpp.Chat) error {
answer = "Плагин oboobs включен"
}
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -170,7 +171,7 @@ func cmd(v xmpp.Chat) error {
_ = saveSetting(room, "oboobs", "0")
answer = "Плагин oboobs выключен"
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -189,7 +190,7 @@ func cmd(v xmpp.Chat) error {
answer = "Плагин obutts выключен"
}
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -204,7 +205,7 @@ func cmd(v xmpp.Chat) error {
answer = "Плагин obutts включен"
}
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -214,7 +215,7 @@ func cmd(v xmpp.Chat) error {
_ = saveSetting(room, "obutts", "0")
answer = "Плагин obutts выключен"
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -289,7 +290,7 @@ func cmd(v xmpp.Chat) error {
} else {
answer := fmt.Sprintf("Я тут не вижу участника с ником %s", userNick)
- _, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
+ _, err = Talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
@@ -351,9 +352,9 @@ func cmd(v xmpp.Chat) error {
message.Misc.Answer = 1
message.Misc.Fwdcnt = 0
- message.Misc.Csign = config.CSign
+ message.Misc.Csign = Config.CSign
message.Misc.Username = message.Userid
- message.Misc.Botnick = config.Jabber.Nick
+ message.Misc.Botnick = Config.Jabber.Nick
message.Misc.Msgformat = 0
data, err = json.Marshal(message)
@@ -364,11 +365,11 @@ func cmd(v xmpp.Chat) error {
}
// Заталкиваем наш json в редиску
- if err := redisClient.Publish(ctx, config.Redis.Channel, data).Err(); err != nil {
- return fmt.Errorf("unable to send data to redis channel %s: %w", config.Redis.Channel, err)
+ if err := RedisClient.Publish(Ctx, Config.Redis.Channel, data).Err(); err != nil {
+ return fmt.Errorf("unable to send data to redis channel %s: %w", Config.Redis.Channel, err)
}
- log.Debugf("Sent msg to redis channel %s: %s", config.Redis.Channel, string(data))
+ log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
return err
}
diff --git a/event_parser.go b/internal/jabber/event_parser.go
similarity index 86%
rename from event_parser.go
rename to internal/jabber/event_parser.go
index c31f192..03ce197 100644
--- a/event_parser.go
+++ b/internal/jabber/event_parser.go
@@ -1,4 +1,4 @@
-package main
+package jabber
import (
"encoding/json"
@@ -8,15 +8,16 @@ import (
"strings"
"time"
+ "aleesa-jabber-go/internal/log"
+
"github.com/davecgh/go-spew/spew"
"github.com/eleksir/go-xmpp"
- log "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
)
-// parseEvent парсит ивенты, прилетающие из модуля xmpp (изменения presence, фразы участников, ошибки).
-func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
- lastServerActivity = time.Now().Unix()
+// ParseEvent парсит ивенты, прилетающие из модуля xmpp (изменения presence, фразы участников, ошибки).
+func ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
+ LastServerActivity = time.Now().Unix()
switch v := e.(type) {
// Сообщение в чяти
@@ -43,15 +44,15 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
if err := cmd(v); err != nil {
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
- lastActivity = lastServerActivity
+ LastActivity = LastServerActivity
if muc, _ := strings.CutSuffix(v.Remote, "/"); muc != "" {
- lastMucActivity.Set(muc, lastServerActivity)
+ LastMucActivity.Set(muc, LastServerActivity)
}
// Приватный чятик.
@@ -62,12 +63,12 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
log.Debugf("Private message: %s", v.Text)
if err := cmd(v); err != nil {
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
- lastActivity = lastServerActivity
+ LastActivity = LastServerActivity
// Внезапно, ошибки. По идее они должны ассоциироваться с отправляемыми сообщениями, но по ходу это
// не реализовано, поэтому мы получаем ошибки в форме отдельного чятика.
@@ -92,8 +93,8 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
log.Debug("Looks like IQ get query")
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
- if slices.Contains(roomsConnected, muc) {
- lastMucActivity.Set(muc, lastServerActivity)
+ if slices.Contains(RoomsConnected, muc) {
+ LastMucActivity.Set(muc, LastServerActivity)
}
}
@@ -109,7 +110,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
case "jabber:iq:version":
log.Infof("Got IQ get request for version from %s", v.From)
- if id, err := talk.IqVersionResponse(
+ if id, err := Talk.IqVersionResponse(
v,
"aleesa-jabber-go",
"4.с_чем-то",
@@ -121,7 +122,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -132,14 +133,14 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
case "urn:xmpp:ping":
log.Infof("Got IQ get request for pong from %s", v.From)
- if id, err := talk.PingResponse(v); err != nil {
+ if id, err := Talk.PingResponse(v); err != nil {
err := fmt.Errorf(
"unable to send pong to jabber server: id=%s, err=%w",
id,
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -151,14 +152,14 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
case "jabber:iq:last":
log.Infof("Got IQ get last activity time request from %s", v.From)
- if id, err := talk.JabberIqLastResponse(v, lastActivity); err != nil {
+ if id, err := Talk.JabberIqLastResponse(v, LastActivity); err != nil {
err := fmt.Errorf(
"unable to send last activity time to jabber server: id=%s, err=%w",
id,
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -177,7 +178,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
answer += ""
answer += ""
- if id, err := talk.RawInformation(
+ if id, err := Talk.RawInformation(
v.To,
v.From,
v.ID,
@@ -190,7 +191,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -201,7 +202,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
case xmpp.XMPPNS_DISCO_ITEMS:
log.Infof("Got IQ get disco#items request from %s, answer service unavailable", v.From)
- if _, err := talk.ErrorServiceUnavailable(
+ if _, err := Talk.ErrorServiceUnavailable(
v,
"http://jabber.org/protocol/disco#info",
"http://jabber.org/protocol/commands",
@@ -212,7 +213,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -239,14 +240,14 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
case "urn:xmpp:time":
log.Infof("Got IQ get time request from %s", v.From)
- if id, err := talk.UrnXMPPTimeResponse(v, "+00:00"); err != nil {
+ if id, err := Talk.UrnXMPPTimeResponse(v, "+00:00"); err != nil {
err := fmt.Errorf(
"unable to send urn:xmpp:time to jabber server: id=%s, err=%w",
id,
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -273,7 +274,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
case xmpp.XMPPNS_PUBSUB:
log.Infof("Got IQ get pubsub request from %s, answer feature unimplemented", v.From)
- if id, err := talk.ErrorNotImplemented(
+ if id, err := Talk.ErrorNotImplemented(
v,
"http://jabber.org/protocol/pubsub#errors",
"subscribe",
@@ -283,7 +284,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -309,14 +310,14 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
if err := xml.Unmarshal(v.Query, &iqStruct); err == nil {
log.Debugf("Got IQ get request (actually, response) for MUC Self-Ping from %s", v.From)
- if id, err := talk.PingResponse(v); err != nil {
+ if id, err := Talk.PingResponse(v); err != nil {
err := fmt.Errorf(
"unable to send pong to jabber server: id=%s, err=%w",
id,
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -333,27 +334,27 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
case xmpp.IQTypeResult:
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
- if slices.Contains(roomsConnected, muc) {
- lastMucActivity.Set(muc, lastServerActivity)
+ if slices.Contains(RoomsConnected, muc) {
+ LastMucActivity.Set(muc, LastServerActivity)
}
}
switch {
// Похоже на pong от сервера (по стандарту в ответе нету query, но go-xmpp нам подсовывает это)
- case v.From == config.Jabber.Server && v.To == talk.JID() && string(v.Query) == "":
+ case v.From == Config.Jabber.Server && v.To == Talk.JID() && string(v.Query) == "":
log.Debugf("Got S2C pong answer from %s to %s", v.From, v.To)
- serverPingTimestampRx = time.Now().Unix() //nolint:wsl
+ ServerPingTimestampRx = time.Now().Unix() //nolint:wsl
// Похоже на понг второй стадии xep-0410 MUC-Ping-а, который у нас не реализован
- case v.To == talk.JID() && string(v.Query) == "":
- mucNameMatch := slices.Contains(roomsConnected, v.From)
+ case v.To == Talk.JID() && string(v.Query) == "":
+ mucNameMatch := slices.Contains(RoomsConnected, v.From)
if mucNameMatch {
log.Debugf("Got server-optimized MUC pong answer (xep-0410) from %s to %s", v.From, v.To)
} else {
mucNickMatch := false
- for _, room := range roomsConnected {
+ for _, room := range RoomsConnected {
mucNick := fmt.Sprintf("%s/%s", room, getBotNickFromRoomConfig(room))
if v.From == mucNick {
@@ -379,14 +380,14 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// Этот бот не управляется со стороны сервера, поэтому все попытки порулить игнорируем.
case xmpp.IQTypeSet:
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
- if slices.Contains(roomsConnected, muc) {
- lastMucActivity.Set(muc, lastServerActivity)
+ if slices.Contains(RoomsConnected, muc) {
+ LastMucActivity.Set(muc, LastServerActivity)
}
}
log.Info("Got an IQ request for set something. Answer not implemented")
- if id, err := talk.ErrorNotImplemented(
+ if id, err := Talk.ErrorNotImplemented(
v,
"http://jabber.org/protocol/commands",
xmpp.IQTypeSet,
@@ -397,7 +398,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -415,12 +416,12 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
if err := xml.Unmarshal(v.Query, &iqPingStruct); err == nil {
if iqPingStruct.Xmlns == "urn:xmpp:ping" {
- if v.From == config.Jabber.Server {
+ if v.From == Config.Jabber.Server {
msg := "Server announced that it can answer c2s ping, but gives us an error to such query, "
msg += "fallback to keepalive whitespace pings"
log.Error(msg)
- serverCapsList.Set("urn:xmpp:ping", false)
+ ServerCapsList.Set("urn:xmpp:ping", false)
} else {
log.Errorf("Got 'ping unsupported' message from: %s to: %s", v.From, v.To)
}
@@ -437,27 +438,27 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
var iqErrorCancelNotAcceptable jabberIqErrorCancelNotAcceptable
if err := xml.Unmarshal(v.Query, &iqErrorCancelNotAcceptable); err == nil {
- if v.To == talk.JID() {
+ if v.To == Talk.JID() {
var (
room = strings.SplitN(v.From, "/", 2)[0]
nick = strings.SplitN(v.From, "/", 2)[1]
)
- if slices.Contains(roomsConnected, iqErrorCancelNotAcceptable.By) && nick == getBotNickFromRoomConfig(room) {
+ if slices.Contains(RoomsConnected, iqErrorCancelNotAcceptable.By) && nick == getBotNickFromRoomConfig(room) {
log.Errorf(
"Got Iq error message from: %s to: %s. Looks like i'm not in MUC anymore",
v.From, v.To,
)
- time.Sleep(time.Duration(config.Jabber.MucRejoinDelay) * time.Second)
+ time.Sleep(time.Duration(Config.Jabber.MucRejoinDelay) * time.Second)
- if _, err := talk.JoinMUCNoHistory(iqErrorCancelNotAcceptable.By, nick); err != nil {
+ if _, err := Talk.JoinMUCNoHistory(iqErrorCancelNotAcceptable.By, nick); err != nil {
err := fmt.Errorf(
"looks like connection to server also lost err=%w",
err,
)
- gTomb.Kill(err)
+ GTomb.Kill(err)
return
}
@@ -493,8 +494,8 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// Смена статуса участника
case xmpp.Presence:
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
- if slices.Contains(roomsConnected, muc) {
- lastMucActivity.Set(muc, lastServerActivity)
+ if slices.Contains(RoomsConnected, muc) {
+ LastMucActivity.Set(muc, LastServerActivity)
}
}
@@ -506,12 +507,12 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// Однако, это не значит, что такую ситуацию мы не должны корректным образом обрабатывать.
if v.Type == "unavailable" {
// Считаем, что мы больше не в комнате, поэтому не знаем, кто там есть.
- roomPresences.Delete(v.From)
+ RoomPresences.Delete(v.From)
log.Error("Presence notification - looks like another instance of client leaves room")
- if slices.Contains(roomsConnected, v.From) {
- go joinMuc(v.From)
+ if slices.Contains(RoomsConnected, v.From) {
+ go joinMuc(v.From) //nolint: errcheck
}
} else {
log.Errorf("Presence notification, Type: %s, From: %s, Show: %s, Status: %s",
@@ -535,18 +536,18 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// Это наш собственный Presence
if v.Show == "" && v.Status == "" {
- if nick == config.Jabber.Nick {
- roomsConnected = append(roomsConnected, room)
+ if nick == Config.Jabber.Nick {
+ RoomsConnected = append(RoomsConnected, room)
// На всякий случай дедуплицируем список комнат, к которым мы заджойнились.
- sort.Strings(roomsConnected)
- slices.Compact(roomsConnected)
+ sort.Strings(RoomsConnected)
+ slices.Compact(RoomsConnected)
}
}
switch v.Role {
// Участник ушёл
case "none":
- if presenceJSONInterface, present := roomPresences.Get(room); present {
+ if presenceJSONInterface, present := RoomPresences.Get(room); present {
presenceJSONStrings := interfaceToStringSlice(presenceJSONInterface)
var newPresenceJSONStrings []string
@@ -562,7 +563,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
newPresenceJSONStrings = append(newPresenceJSONStrings, presenceJSONstring)
}
- roomPresences.Set(room, newPresenceJSONStrings)
+ RoomPresences.Set(room, newPresenceJSONStrings)
}
// Участник пришёл
default:
@@ -572,7 +573,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
presenceJSONBytes []byte
)
- if presenceJSONInterface, present := roomPresences.Get(room); present {
+ if presenceJSONInterface, present := RoomPresences.Get(room); present {
presenceJSONStrings = interfaceToStringSlice(presenceJSONInterface)
}
@@ -591,15 +592,15 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
presenceJSONBytes, _ = json.Marshal(v) //nolint:errchkjson
newPresenceJSONStrings = append(newPresenceJSONStrings, string(presenceJSONBytes))
- roomPresences.Set(room, newPresenceJSONStrings)
+ RoomPresences.Set(room, newPresenceJSONStrings)
}
}
// Ответ на запрос поддерживаемых фич, который "http://jabber.org/protocol/disco#info"
case xmpp.DiscoResult:
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
- if slices.Contains(roomsConnected, muc) {
- lastMucActivity.Set(muc, lastServerActivity)
+ if slices.Contains(RoomsConnected, muc) {
+ LastMucActivity.Set(muc, LastServerActivity)
}
}
@@ -611,10 +612,10 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// Конкретно сейчас нас интересует только поддержка c2s ping
for _, feature := range v.Features {
log.Debugf("Server %s announced that it supports feature: %s", v.From, feature)
- serverCapsList.Set(feature, true)
+ ServerCapsList.Set(feature, true)
}
- serverCapsQueried = true
+ ServerCapsQueried = true
case "conference":
mucCaps := make(map[string]bool)
@@ -624,7 +625,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
mucCaps[feature] = true //nolint:wsl
}
- mucCapsList.Set(v.From, mucCaps)
+ MucCapsList.Set(v.From, mucCaps)
case "pubsub":
log.Debugf("PubSub component %s reply to disco#info, skipping", v.From)
diff --git a/globals.go b/internal/jabber/globals.go
similarity index 78%
rename from globals.go
rename to internal/jabber/globals.go
index 78b1d93..87691da 100644
--- a/globals.go
+++ b/internal/jabber/globals.go
@@ -1,6 +1,7 @@
-package main
+package jabber
import (
+ "aleesa-jabber-go/internal/anycollection"
"context"
"os"
@@ -11,79 +12,79 @@ import (
)
// Config - это у нас глобальная штука :) .
-var config myConfig
+var Config myConfig
// Статичные пути, по которым у нас лежат конфиги. При запуске сюда дописываются и динамические пути тоже.
-var configLocations = []string{
+var ConfigLocations = []string{
"~/.aleesa-jabber-go.json",
"~/aleesa-jabber-go.json",
"/etc/aleesa-jabber-go.json",
}
-// To break circular message forwarding we must set some sane default, it can be overridden via config.
+// To break circular message forwarding we must set some sane default, it can be overridden via Config.
var forwardMax int64 = 5
// Ставится в true, если мы получили сигнал на выключение.
-var shutdown = false
+var Shutdown = false
// Чтобы не организовывать драку за установку коннекта.
var connecting = false
// Глобальное состояние соединения.
-var isConnected = false
+var IsConnected = false
// Канал, в который приходят уведомления для хэндлера сигналов от траппера сигналов.
-var sigChan chan os.Signal
+var SigChan chan os.Signal
// Основной инстанс xmpp-клиента.
-var talk *xmpp.Client
+var Talk *xmpp.Client
// Опции подключения к xmpp-серверу.
-var options *xmpp.Options
+var Options *xmpp.Options
// Список комнат, в которых находится бот.
-var roomsConnected []string
+var RoomsConnected []string
// Время последней активности, нужно для jabber:iq:last.
-var lastActivity int64
+var LastActivity int64
// Время последней активности, нужно для c2s пингов - посылаем пинги, только если давненько ничего не приходило с
// сервера.
-var lastServerActivity int64
+var LastServerActivity int64
// Время последней активности MUC-ов, нужно для пингов - посылаем пинги, только если давненько ничего не приходило из
// muc-ов.
-var lastMucActivity *Collection
+var LastMucActivity *anycollection.Collection
// Получен ли ответ на запрос disco#info к серверу.
-var serverCapsQueried bool
+var ServerCapsQueried bool
// sync.Map-ка с капабилити сервера.
-var serverCapsList *Collection
+var ServerCapsList *anycollection.Collection
// sync.Map-ка с комнатами и их capability.
-var mucCapsList *Collection
+var MucCapsList *anycollection.Collection
// Время, когда был отправлен c2s ping.
-var serverPingTimestampTx int64
+var ServerPingTimestampTx int64
// Время, когда был принят s2c pong.
-var serverPingTimestampRx int64
+var ServerPingTimestampRx int64
// Объектик для хранения стейта утилизатора горутинок.
-var gTomb tomb.Tomb
+var GTomb tomb.Tomb
// sync.Map-ка со списком участников конференций (в json-формате, согласно структуре xmpp.Presence, "room".[]json).
-var roomPresences *Collection
+var RoomPresences *anycollection.Collection
// Объектики клиента-редиски.
-var redisClient *redis.Client
-var subscriber *redis.PubSub
+var RedisClient *redis.Client
+var Subscriber *redis.PubSub
// Мапка с открытыми дескрипторами баз с настройками.
var settingsDB = make(map[string]*pebble.DB)
// Main context.
-var ctx = context.Background()
+var Ctx = context.Background()
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
diff --git a/lib.go b/internal/jabber/lib.go
similarity index 57%
rename from lib.go
rename to internal/jabber/lib.go
index 49d84b5..9f04218 100644
--- a/lib.go
+++ b/internal/jabber/lib.go
@@ -1,138 +1,63 @@
-package main
+package jabber
import (
"encoding/json"
"fmt"
"math/rand"
- "os"
"reflect"
"strings"
- "syscall"
"time"
+ "aleesa-jabber-go/internal/log"
+
"github.com/eleksir/go-xmpp"
- log "github.com/sirupsen/logrus"
+
"golang.org/x/exp/slices"
)
-// sigHandler Хэндлер сигналов закрывает все бд, все сетевые соединения и сваливает из приложения.
-func sigHandler() error {
- log.Debug("Installing signal handler")
-
- for s := range sigChan {
- switch s {
- case syscall.SIGINT:
- log.Infoln("Got SIGINT, quitting")
- case syscall.SIGTERM:
- log.Infoln("Got SIGTERM, quitting")
- case syscall.SIGQUIT:
- log.Infoln("Got SIGQUIT, quitting")
-
- // Заходим на новую итерацию, если у нас "неинтересный" сигнал.
- default:
- continue
- }
-
- var err error
-
- // Чтобы не срать в логи ошибками, проставим shutdown state приложения в true.
- shutdown = true
-
- // Отпишемся от всех каналов и закроем коннект к редиске
- if err = subscriber.Unsubscribe(ctx); err != nil {
- log.Errorf("Unable to unsubscribe from redis channels cleanly: %s", err)
- } else {
- log.Debug("Unsubscribe from all redis channels")
- }
-
- if err = subscriber.Close(); err != nil {
- log.Errorf("Unable to close redis connection cleanly: %s", err)
- } else {
- log.Debug("Close redis connection")
- }
-
- if isConnected && !shutdown {
- log.Debug("Try to set our presence to Unavailable and status to Offline")
-
- // Вот тут понадобится коллекция известных пользователей, чтобы им разослать presence, что бот свалил в offline
- // Пока за неимением лучшего сообщим об этом самим себе.
- for _, room := range roomsConnected {
- if _, err := talk.SendPresence(
- xmpp.Presence{ //nolint:exhaustruct
- To: room,
- Status: "Offline",
- Type: "unavailable",
- },
- ); err != nil {
- log.Infof("Unable to send presence to jabber server: %s", err)
- }
- }
-
- // И закрываем соединение.
- log.Infoln("Closing connection to jabber server")
-
- if err := talk.Close(); err != nil {
- log.Infof("Unable to close connection to jabber server: %s", err)
- }
- }
-
- if len(settingsDB) > 0 {
- log.Debug("Closing runtime jabber room settings db")
-
- for _, db := range settingsDB {
- _ = db.Close()
- }
- }
-
- os.Exit(0)
- }
-
- return nil
-}
-
-// establishConnection устанавливает соединение с jabber-сервером.
-func establishConnection() error {
+// EstablishConnection устанавливает соединение с jabber-сервером.
+func EstablishConnection() error {
var err error
- if connecting && !isConnected {
+ if connecting && !IsConnected {
return nil
}
// Проставляем глобальные переменные.
connecting = true
- isConnected = false
- roomsConnected = make([]string, 0)
+ IsConnected = false
+ RoomsConnected = make([]string, 0)
- talk, err = options.NewClient()
+ Talk, err = Options.NewClient()
if err != nil {
- return fmt.Errorf("Unable to connect to %s: %w", options.Host, err)
+ return fmt.Errorf("unable to connect to %s: %w", Options.Host, err)
}
// По идее keepalive должен же проходить только, если мы уже на сервере, так?
- if _, err := talk.SendKeepAlive(); err != nil {
- return fmt.Errorf("Try to send initial KeepAlive, got error: %w", err)
+ if _, err := Talk.SendKeepAlive(); err != nil {
+ return fmt.Errorf("try to send initial KeepAlive, got error: %w", err)
}
log.Info("Connected")
// Джойнимся к чятикам, но делаем это в фоне, чтобы не блочиться на ошибках, например, если бота забанили
- for _, room := range config.Jabber.Channels {
- gTomb.Go(func() error { return joinMuc(room.Name) })
+ for _, room := range Config.Jabber.Channels {
+ GTomb.Go(func() error { return joinMuc(room.Name) })
}
- gTomb.Go(func() error { return RotateStatus("") })
+ GTomb.Go(func() error { return RotateStatus("") })
- lastActivity = time.Now().Unix()
+ LastActivity = time.Now().Unix()
connecting = false
- isConnected = true
+ IsConnected = true
- log.Debugf("Sending disco#info to %s", config.Jabber.Server)
+ log.Debugf("Sending disco#info to %s", Config.Jabber.Server)
- _, err = talk.DiscoverInfo(talk.JID(), config.Jabber.Server)
+ _, err = Talk.DiscoverInfo(Talk.JID(), Config.Jabber.Server)
if err != nil {
- return fmt.Errorf("Unable to send disco#info to jabber server: %s", err)
+ return fmt.Errorf("unable to send disco#info to jabber server: %w", err)
}
return nil
@@ -140,14 +65,14 @@ func establishConnection() error {
// joinMu джойнится к конференциям/каналам/комнатам в джаббере.
func joinMuc(room string) error {
- log.Debugf("Sending disco#info from %s to %s", talk.JID(), room)
+ log.Debugf("Sending disco#info from %s to %s", Talk.JID(), room)
- if _, err := talk.DiscoverInfo(talk.JID(), room); err != nil {
- return fmt.Errorf("Unable to send disco#info to MUC %s: %s", room, err)
+ if _, err := Talk.DiscoverInfo(Talk.JID(), room); err != nil {
+ return fmt.Errorf("unable to send disco#info to MUC %s: %w", room, err)
}
// Ждём, пока muc нам вернёт список фичей.
- for i := 0; i < (20 * int(config.Jabber.ConnectionTimeout)); i++ {
+ for i := 0; i < (20 * int(Config.Jabber.ConnectionTimeout)); i++ {
var (
myRoom interface{}
supported bool
@@ -156,7 +81,7 @@ func joinMuc(room string) error {
time.Sleep(50 * time.Millisecond)
- if myRoom, exist = mucCapsList.Get(room); !exist {
+ if myRoom, exist = MucCapsList.Get(room); !exist {
// Пока не задискаверилась
continue
}
@@ -173,8 +98,8 @@ func joinMuc(room string) error {
}
// Пытаемся зайти в комнату
- if _, err := talk.JoinMUCNoHistory(room, getBotNickFromRoomConfig(room)); err != nil {
- return fmt.Errorf("Unable to join to MUC: %s, %w", room, err)
+ if _, err := Talk.JoinMUCNoHistory(room, getBotNickFromRoomConfig(room)); err != nil {
+ return fmt.Errorf("unable to join to MUC: %s, %w", room, err)
}
log.Infof("Joining to MUC: %s", room)
@@ -182,10 +107,10 @@ func joinMuc(room string) error {
// Ждём, когда прилетит presence из комнаты, тогда мы точно знаем, что мы вошли.
entered := false
- for i := 0; i < (20 * int(config.Jabber.ConnectionTimeout)); i++ {
+ for i := 0; i < (20 * int(Config.Jabber.ConnectionTimeout)); i++ {
time.Sleep(50 * time.Millisecond)
- if slices.Contains(roomsConnected, room) {
+ if slices.Contains(RoomsConnected, room) {
entered = true
break
@@ -196,7 +121,7 @@ func joinMuc(room string) error {
log.Errorf(
"Unable to enter to MUC %s, join timeout after %d seconds (server does not return my presence for this room)",
room,
- 20*int(config.Jabber.ConnectionTimeout)+1,
+ 20*int(Config.Jabber.ConnectionTimeout)+1,
)
return nil
@@ -205,54 +130,54 @@ func joinMuc(room string) error {
// Вот теперь точно можно слать статус.
log.Infof("Joined to MUC: %s", room)
- gTomb.Go(func() error { return RotateStatus(room) })
+ GTomb.Go(func() error { return RotateStatus(room) })
return nil
}
-// probeServerLiveness проверяет живость соединения с сервером. Для многих серверов обязательная штука, без которой
+// ProbeServerLiveness проверяет живость соединения с сервером. Для многих серверов обязательная штука, без которой
// они выкидывают клиента через некоторое время неактивности.
-func probeServerLiveness() error { //nolint:gocognit
+func ProbeServerLiveness() error { //nolint:gocognit
for {
for {
- if shutdown {
+ if Shutdown {
return nil
}
- sleepTime := time.Duration(config.Jabber.ServerPingDelay) * 1000 * time.Millisecond
- sleepTime += time.Duration(rand.Int63n(1000*config.Jabber.PingSplayDelay)) * time.Millisecond
+ sleepTime := time.Duration(Config.Jabber.ServerPingDelay) * 1000 * time.Millisecond
+ sleepTime += time.Duration(rand.Int63n(1000*Config.Jabber.PingSplayDelay)) * time.Millisecond
time.Sleep(sleepTime)
- if !isConnected {
+ if !IsConnected {
continue
}
- // Пингуем, только если не было никакой активности в течение > config.Jabber.ServerPingDelay,
- // в худшем случе это будет ~ (config.Jabber.PingSplayDelay * 2) + config.Jabber.PingSplayDelay
- // if (time.Now().Unix() - lastServerActivity) < (config.Jabber.ServerPingDelay + config.Jabber.PingSplayDelay) {
+ // Пингуем, только если не было никакой активности в течение > Config.Jabber.ServerPingDelay,
+ // в худшем случе это будет ~ (Config.Jabber.PingSplayDelay * 2) + Config.Jabber.PingSplayDelay
+ // if (time.Now().Unix() - lastServerActivity) < (Config.Jabber.ServerPingDelay + Config.Jabber.PingSplayDelay) {
// continue
// }
- if serverCapsQueried { // Сервер ответил на disco#info
+ if ServerCapsQueried { // Сервер ответил на disco#info
var (
value interface{}
exist bool
)
- value, exist = serverCapsList.Get("urn:xmpp:ping")
+ value, exist = ServerCapsList.Get("urn:xmpp:ping")
switch {
// Сервер анонсировал, что умеет в c2s пинги
case exist && value.(bool):
// Таймаут c2s пинга. Возьмём сумму задержки между пингами, добавим таймаут коннекта и добавим
// максимальную корректировку разброса.
- txTimeout := config.Jabber.ServerPingDelay + config.Jabber.ConnectionTimeout
- txTimeout += config.Jabber.PingSplayDelay
+ txTimeout := Config.Jabber.ServerPingDelay + Config.Jabber.ConnectionTimeout
+ txTimeout += Config.Jabber.PingSplayDelay
rxTimeout := txTimeout
- rxTimeAgo := time.Now().Unix() - serverPingTimestampRx
+ rxTimeAgo := time.Now().Unix() - ServerPingTimestampRx
- if serverPingTimestampTx > 0 { // Первая пуля от нас ушла...
+ if ServerPingTimestampTx > 0 { // Первая пуля от нас ушла...
switch {
// Давненько мы не получали понгов от сервера, вероятно, соединение с сервером утеряно?
case rxTimeAgo > (rxTimeout * 2):
@@ -265,36 +190,36 @@ func probeServerLiveness() error { //nolint:gocognit
// По-умолчанию, мы отправляем c2s пинг
default:
- log.Debugf("Sending c2s ping from %s to %s", talk.JID(), config.Jabber.Server)
+ log.Debugf("Sending c2s ping from %s to %s", Talk.JID(), Config.Jabber.Server)
- if err := talk.PingC2S(talk.JID(), config.Jabber.Server); err != nil {
+ if err := Talk.PingC2S(Talk.JID(), Config.Jabber.Server); err != nil {
return err
}
- serverPingTimestampTx = time.Now().Unix()
+ ServerPingTimestampTx = time.Now().Unix()
}
} else { // Первая пуля пока не вылетела, отправляем
- log.Debugf("Sending first c2s ping from %s to %s", talk.JID(), config.Jabber.Server)
+ log.Debugf("Sending first c2s ping from %s to %s", Talk.JID(), Config.Jabber.Server)
- if err := talk.PingC2S(talk.JID(), config.Jabber.Server); err != nil {
+ if err := Talk.PingC2S(Talk.JID(), Config.Jabber.Server); err != nil {
return err
}
- serverPingTimestampTx = time.Now().Unix()
+ ServerPingTimestampTx = time.Now().Unix()
}
// Сервер не анонсировал, что умеет в c2s пинги
default:
log.Debug("Sending keepalive whitespace ping")
- if _, err := talk.SendKeepAlive(); err != nil {
+ if _, err := Talk.SendKeepAlive(); err != nil {
return err
}
}
} else { // Сервер не ответил на disco#info
log.Debug("Sending keepalive whitespace ping")
- if _, err := talk.SendKeepAlive(); err != nil {
+ if _, err := Talk.SendKeepAlive(); err != nil {
return err
}
}
@@ -302,31 +227,31 @@ func probeServerLiveness() error { //nolint:gocognit
}
}
-// probeMUCLiveness Пингует MUC-и, нужно для проверки, что клиент ещё находится в MUC-е.
-func probeMUCLiveness() error { //nolint:gocognit
+// ProbeMUCLiveness Пингует MUC-и, нужно для проверки, что клиент ещё находится в MUC-е.
+func ProbeMUCLiveness() { //nolint:gocognit
for {
for {
- for _, room := range roomsConnected {
+ for _, room := range RoomsConnected {
var (
exist bool
lastActivityTS interface{}
)
// Если записи про комнату нету, то пинговать её бессмысленно.
- if lastActivityTS, exist = lastMucActivity.Get(room); !exist {
+ if lastActivityTS, exist = LastMucActivity.Get(room); !exist {
continue
}
// Если время последней активности в чятике не превысило
- // config.Jabber.ServerPingDelay + config.Jabber.PingSplayDelay, ничего не пингуем.
- if (time.Now().Unix() - lastActivityTS.(int64)) < (config.Jabber.ServerPingDelay + config.Jabber.PingSplayDelay) {
+ // Config.Jabber.ServerPingDelay + Config.Jabber.PingSplayDelay, ничего не пингуем.
+ if (time.Now().Unix() - lastActivityTS.(int64)) < (Config.Jabber.ServerPingDelay + Config.Jabber.PingSplayDelay) {
continue
}
/* Пинг MUC-а по сценарию без серверной оптимизации мы реализовывать не будем. Это как-то не надёжно.
go func(room string) {
// Небольшая рандомная задержка перед пингом комнаты
- sleepTime := time.Duration(rand.Int63n(1000*config.Jabber.PingSplayDelay)) * time.Millisecond //nolint:gosec
+ sleepTime := time.Duration(rand.Int63n(1000*Config.Jabber.PingSplayDelay)) * time.Millisecond //nolint:gosec
time.Sleep(sleepTime)
if err := talk.PingS2S(talk.JID(), room+"/"+getBotNickFromRoomConfig(room)); err != nil {
@@ -338,21 +263,21 @@ func probeMUCLiveness() error { //nolint:gocognit
var roomMap interface{}
- roomMap, exist = mucCapsList.Get(room)
+ roomMap, exist = MucCapsList.Get(room)
// Пинги комнаты проводим, только если она записана, как прошедшая disco#info и поддерживающая
// Server Optimization.
if exist && roomMap.(map[string]bool)["http://jabber.org/protocol/muc#self-ping-optimization"] {
- gTomb.Go(
+ GTomb.Go(
func() error {
// Небольшая рандомная задержка перед пингом комнаты.
- sleepTime := time.Duration(rand.Int63n(1000*config.Jabber.PingSplayDelay)) * time.Millisecond
+ sleepTime := time.Duration(rand.Int63n(1000*Config.Jabber.PingSplayDelay)) * time.Millisecond
time.Sleep(sleepTime)
- log.Debugf("Sending MUC ping from %s to %s", talk.JID(), room)
+ log.Debugf("Sending MUC ping from %s to %s", Talk.JID(), room)
- if err := talk.PingS2S(talk.JID(), room); err != nil {
- return fmt.Errorf("unable to ping MUC %s: %w", room, err)
+ if err := Talk.PingS2S(Talk.JID(), room); err != nil {
+ log.Errorf("unable to ping MUC %s: %s", room, err)
}
return nil
@@ -361,7 +286,7 @@ func probeMUCLiveness() error { //nolint:gocognit
}
}
- time.Sleep(time.Duration(config.Jabber.MucPingDelay) * time.Second)
+ time.Sleep(time.Duration(Config.Jabber.MucPingDelay) * time.Second)
}
}
}
@@ -370,11 +295,11 @@ func probeMUCLiveness() error { //nolint:gocognit
func RotateStatus(room string) error {
for {
// TODO: Переделать на ticker-ы
- totalSleepTime := time.Duration(config.Jabber.RuntimeStatus.RotationTime) * time.Second
- totalSleepTime += time.Duration(config.Jabber.RuntimeStatus.RotationSplayTime) * time.Second
+ totalSleepTime := time.Duration(Config.Jabber.RuntimeStatus.RotationTime) * time.Second
+ totalSleepTime += time.Duration(Config.Jabber.RuntimeStatus.RotationSplayTime) * time.Second
for {
- status := randomPhrase(config.Jabber.RuntimeStatus.Text)
+ status := RandomPhrase(Config.Jabber.RuntimeStatus.Text)
log.Debugf("Set status for MUC: %s to: %s", room, status)
var p xmpp.Presence
@@ -390,12 +315,12 @@ func RotateStatus(room string) error {
}
}
- if _, err := talk.SendPresence(p); err != nil {
- return fmt.Errorf("Unable to send presence to MUC %s: %s", room, err)
+ if _, err := Talk.SendPresence(p); err != nil {
+ return fmt.Errorf("unable to send presence to MUC %s: %w", room, err)
}
// Если мы не хотим ротировать, то цикл нам тут не нужен, просто выходим.
- if config.Jabber.RuntimeStatus.RotationTime == 0 {
+ if Config.Jabber.RuntimeStatus.RotationTime == 0 {
return nil
}
@@ -404,8 +329,8 @@ func RotateStatus(room string) error {
}
}
-// randomPhrase Выдаёт одну рандомную фразу из даденного списка фраз.
-func randomPhrase(list []string) string {
+// RandomPhrase Выдаёт одну рандомную фразу из даденного списка фраз.
+func RandomPhrase(list []string) string {
phrase := ""
if listLen := len(list); listLen > 0 {
@@ -441,7 +366,7 @@ func getRealJIDfromNick(fullNick string) string {
room := (strings.SplitN(fullNick, "/", 2))[0]
// Достанем presence участника
- presenceJSONInterface, present := roomPresences.Get(room)
+ presenceJSONInterface, present := RoomPresences.Get(room)
// Никого нет дома
if !present {
@@ -467,8 +392,8 @@ func isMucAdmin(fullNick string) bool {
room := (strings.SplitN(fullNick, "/", 2))[0]
- // Достанем presence участника
- presenceJSONInterface, present := roomPresences.Get(room)
+ // Достанем presence участника.
+ presenceJSONInterface, present := RoomPresences.Get(room)
// Никого нет дома
if !present {
@@ -498,7 +423,7 @@ func getMucNames(room string) []string {
)
// Достанем presence участников
- presenceJSONInterface, present := roomPresences.Get(room)
+ presenceJSONInterface, present := RoomPresences.Get(room)
if !present {
return names
@@ -516,15 +441,15 @@ func getMucNames(room string) []string {
return names
}
-// getBotNickFromRoomConfig достаёт (короткий) ник бота из настроек чата
+// getBotNickFromRoomConfig достаёт (короткий) ник бота из настроек чата.
func getBotNickFromRoomConfig(room string) string {
- for _, roomStruct := range config.Jabber.Channels {
+ for _, roomStruct := range Config.Jabber.Channels {
if roomStruct.Name == room {
return roomStruct.Nick
}
}
- return config.Jabber.Nick
+ return Config.Jabber.Nick
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
diff --git a/read_config.go b/internal/jabber/read_config.go
similarity index 96%
rename from read_config.go
rename to internal/jabber/read_config.go
index 9fdb6e8..4c55d66 100644
--- a/read_config.go
+++ b/internal/jabber/read_config.go
@@ -1,4 +1,4 @@
-package main
+package jabber
import (
"encoding/json"
@@ -6,19 +6,20 @@ import (
"fmt"
"os"
+ "aleesa-jabber-go/internal/log"
+
"github.com/hjson/hjson-go"
- log "github.com/sirupsen/logrus"
)
-// readConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
+// ReadConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
// нет.
-func readConfig() error { //nolint:gocognit,gocyclo
+func ReadConfig() error { //nolint:gocognit,gocyclo
var (
err error
configLoaded = false
)
- for _, location := range configLocations {
+ for _, location := range ConfigLocations {
fileInfo, err := os.Stat(location)
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём.
@@ -189,7 +190,7 @@ func readConfig() error { //nolint:gocognit,gocyclo
for n, channel := range sampleConfig.Jabber.Channels {
if channel.Name == "" {
- return fmt.Errorf("no \"name\" entry in jabber channel config")
+ return fmt.Errorf("no \"name\" entry in jabber channel config") //nolint: err113
}
if channel.Nick == "" {
@@ -232,7 +233,7 @@ func readConfig() error { //nolint:gocognit,gocyclo
// sampleConfig.Log = "" if not set
- config = sampleConfig
+ Config = sampleConfig
configLoaded = true
log.Infof("Using %s as config file", location)
diff --git a/redis.go b/internal/jabber/redis.go
similarity index 91%
rename from redis.go
rename to internal/jabber/redis.go
index 901a82c..43c4233 100644
--- a/redis.go
+++ b/internal/jabber/redis.go
@@ -1,23 +1,25 @@
-package main
+package jabber
import (
"encoding/json"
"fmt"
+ "aleesa-jabber-go/internal/log"
+
"github.com/eleksir/go-xmpp"
"github.com/go-redis/redis/v8"
- log "github.com/sirupsen/logrus"
)
-func redisLoop(redisMsgChan <-chan *redis.Message) error {
+// RedisLoop вычитывает сообщения из редиски.
+func RedisLoop(redisMsgChan <-chan *redis.Message) error {
// Обработчик событий от редиски
for msg := range redisMsgChan {
- if shutdown {
+ if Shutdown {
return nil
}
if err := redisMsgParser(msg.Payload); err != nil {
- log.Warn(err)
+ log.Warnf("%s", err)
}
}
@@ -28,7 +30,7 @@ func redisLoop(redisMsgChan <-chan *redis.Message) error {
func redisMsgParser(msg string) error {
var err error
- if shutdown {
+ if Shutdown {
// Если мы завершаем работу программы, то нам ничего обрабатывать не надо.
return err
}
@@ -90,7 +92,7 @@ func redisMsgParser(msg string) error {
// j.Misc.BotNick тоже можно не передавать, тогда будет записана пустая строка
// j.Misc.CSign если нам его не передали, возьмём значение из конфига
if exist := j.Misc.Csign; exist == "" {
- j.Misc.Csign = config.CSign
+ j.Misc.Csign = Config.CSign
}
// j.Misc.FwdCnt если нам его не передали, то будет 0
@@ -107,7 +109,7 @@ func redisMsgParser(msg string) error {
switch j.Mode {
case "public":
// Отправляем сообщение в чятик, а не тому, кто прислал нам исходное сообщение
- if _, err := talk.Send(
+ if _, err := Talk.Send(
xmpp.Chat{ //nolint:exhaustruct
Remote: j.Chatid,
Type: "groupchat",
@@ -121,7 +123,7 @@ func redisMsgParser(msg string) error {
case "private":
// Отправляем сообщение тому, кто прислал сообщение
- if _, err := talk.Send(
+ if _, err := Talk.Send(
xmpp.Chat{ //nolint:exhaustruct
Remote: j.From,
Type: "chat",
diff --git a/settings-db-util.go b/internal/jabber/settings-db-util.go
similarity index 95%
rename from settings-db-util.go
rename to internal/jabber/settings-db-util.go
index 0652ee6..19f2bd5 100644
--- a/settings-db-util.go
+++ b/internal/jabber/settings-db-util.go
@@ -1,4 +1,4 @@
-package main
+package jabber
import (
"crypto/sha256"
@@ -6,9 +6,10 @@ import (
"fmt"
"io/fs"
+ "aleesa-jabber-go/internal/log"
+
"github.com/cockroachdb/errors/oserror"
"github.com/cockroachdb/pebble"
- log "github.com/sirupsen/logrus"
)
// StoreKV сохраняет в указанной бд ключ и значение.
@@ -58,7 +59,7 @@ func getSetting(chatID string, setting string) string {
// настройками порождается огромное количество файлов. Умолчальное ограничение на количество файлов - 500 штук,
// что нас не устраивает, поэтому немного снизим эту цифру до более приемлемых значений
options.L0CompactionFileThreshold = 8
- settingsDB[database], err = pebble.Open(config.DataDir+"/"+database, &options)
+ settingsDB[database], err = pebble.Open(Config.DataDir+"/"+database, &options)
if err != nil {
log.Errorf("Unable to open settings db, %s: %s\n", database, err)
@@ -107,7 +108,7 @@ func saveSetting(chatID string, setting string, value string) error {
// что нас не устраивает, поэтому немного снизим эту цифру до более приемлемых значений
options.L0CompactionFileThreshold = 8
- settingsDB[database], err = pebble.Open(config.DataDir+"/"+database, &options)
+ settingsDB[database], err = pebble.Open(Config.DataDir+"/"+database, &options)
if err != nil {
log.Errorf("Unable to open settings db, %s: %s\n", database, err)
diff --git a/internal/jabber/sighandler.go b/internal/jabber/sighandler.go
new file mode 100644
index 0000000..b1cdf93
--- /dev/null
+++ b/internal/jabber/sighandler.go
@@ -0,0 +1,86 @@
+package jabber
+
+import (
+ "aleesa-jabber-go/internal/log"
+ "os"
+ "syscall"
+
+ "github.com/eleksir/go-xmpp"
+)
+
+// SigHandler Хэндлер сигналов закрывает все бд, все сетевые соединения и сваливает из приложения.
+func SigHandler() error {
+ log.Debug("Installing signal handler")
+
+ for s := range SigChan {
+ switch s {
+ case syscall.SIGINT:
+ log.Info("Got SIGINT, quitting")
+ case syscall.SIGTERM:
+ log.Info("Got SIGTERM, quitting")
+ case syscall.SIGQUIT:
+ log.Info("Got SIGQUIT, quitting")
+
+ // Заходим на новую итерацию, если у нас "неинтересный" сигнал.
+ default:
+ continue
+ }
+
+ var err error
+
+ // Чтобы не срать в логи ошибками, проставим shutdown state приложения в true.
+ Shutdown = true
+
+ // Отпишемся от всех каналов и закроем коннект к редиске
+ if err = Subscriber.Unsubscribe(Ctx); err != nil {
+ log.Errorf("Unable to unsubscribe from redis channels cleanly: %s", err)
+ } else {
+ log.Debug("Unsubscribe from all redis channels")
+ }
+
+ if err = Subscriber.Close(); err != nil {
+ log.Errorf("Unable to close redis connection cleanly: %s", err)
+ } else {
+ log.Debug("Close redis connection")
+ }
+
+ if IsConnected && !Shutdown {
+ log.Debug("Try to set our presence to Unavailable and status to Offline")
+
+ // Вот тут понадобится коллекция известных пользователей, чтобы им разослать presence, что бот свалил в offline
+ // Пока за неимением лучшего сообщим об этом самим себе.
+ for _, room := range RoomsConnected {
+ if _, err := Talk.SendPresence(
+ xmpp.Presence{ //nolint:exhaustruct
+ To: room,
+ Status: "Offline",
+ Type: "unavailable",
+ },
+ ); err != nil {
+ log.Infof("Unable to send presence to jabber server: %s", err)
+ }
+ }
+
+ // И закрываем соединение.
+ log.Info("Closing connection to jabber server")
+
+ if err := Talk.Close(); err != nil {
+ log.Infof("Unable to close connection to jabber server: %s", err)
+ }
+ }
+
+ if len(settingsDB) > 0 {
+ log.Debug("Closing runtime jabber room settings db")
+
+ for _, db := range settingsDB {
+ _ = db.Close()
+ }
+ }
+
+ os.Exit(0)
+ }
+
+ return nil
+}
+
+/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
diff --git a/types.go b/internal/jabber/types.go
similarity index 99%
rename from types.go
rename to internal/jabber/types.go
index 2a05674..ecd250c 100644
--- a/types.go
+++ b/internal/jabber/types.go
@@ -1,4 +1,4 @@
-package main
+package jabber
import (
"encoding/xml"
diff --git a/internal/log/log.go b/internal/log/log.go
new file mode 100644
index 0000000..b10e667
--- /dev/null
+++ b/internal/log/log.go
@@ -0,0 +1,158 @@
+package log
+
+import (
+ "bufio"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "log/slog"
+ "os"
+ "time"
+)
+
+// Handler exposes slog handler struct.
+var Handler slog.Handler
+var Ctx = context.Background()
+var Writer io.Writer
+var reader io.Reader
+
+// Init setup logger stuff.
+// level can be error, warn, info, debug if something other supplied info level selected.
+// fileDescriptor should be opened before supplying it to Init().
+func Init(level string, fileDescriptor *os.File) {
+ var loglevel slog.Level
+
+ // no panic, no trace.
+ switch level {
+ case "debug":
+ loglevel = slog.LevelDebug
+
+ case "info":
+ loglevel = slog.LevelInfo
+
+ case "warn":
+ loglevel = slog.LevelWarn
+
+ case "error":
+ loglevel = slog.LevelError
+
+ default:
+ loglevel = slog.LevelInfo
+ }
+
+ opts := &slog.HandlerOptions{ //nolint: exhaustruct
+ // Use the ReplaceAttr function on the handler options
+ // to be able to replace any single attribute in the log output
+ ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { //nolint: revive
+ // check that we are handling the time key
+ if a.Key != slog.TimeKey {
+ return a
+ }
+
+ t := a.Value.Time()
+
+ // change the value from a time.Time to a String
+ // where the string has the correct time format.
+ a.Value = slog.StringValue(t.Format(time.DateTime))
+
+ return a
+ },
+
+ Level: loglevel,
+ }
+
+ Handler = slog.NewTextHandler(fileDescriptor, opts)
+
+ slog.SetDefault(
+ slog.New(Handler),
+ )
+
+ reader, Writer = io.Pipe()
+
+ go readIoPipe()
+}
+
+// readIoPipe reads pipe and writes it to slog.
+func readIoPipe() {
+ scanner := bufio.NewScanner(reader)
+
+ for {
+ for scanner.Scan() {
+ line := scanner.Text() // Get the current line as a string
+ slog.Debug(line)
+ }
+
+ if err := scanner.Err(); err != nil {
+ // io.EOF is expected when done reading, e.g. on exit.
+ if errors.Is(err, io.EOF) {
+ return
+ }
+
+ // something weird happen, we should it log to guess later what it was.
+ Errorf("Error during scanning log writer pipe: %v\n", err)
+ }
+ }
+}
+
+// GetLevel returns current loglevel.
+func GetLevel() string {
+ switch {
+ case Handler.Enabled(Ctx, slog.LevelDebug):
+ return "debug"
+
+ case Handler.Enabled(Ctx, slog.LevelInfo):
+ return "info"
+
+ case Handler.Enabled(Ctx, slog.LevelWarn):
+ return "warn"
+
+ case Handler.Enabled(Ctx, slog.LevelError):
+ return "error"
+
+ default:
+ return "unknown"
+ }
+}
+
+// Error passes message directly to slog.Error().
+func Error(message string) {
+ slog.Error(message)
+}
+
+// Errorf logs message on error log level and allows to supply arguments in printf() style.
+func Errorf(format string, a ...any) {
+ slog.Error(fmt.Sprintf(format, a...))
+}
+
+// Warn passes message directly to slog.Warn().
+func Warn(message string) {
+ slog.Warn(message)
+}
+
+// Warnf logs message on warn log level and allows to supply arguments in printf() style.
+func Warnf(format string, a ...any) {
+ slog.Warn(fmt.Sprintf(format, a...))
+}
+
+// Info passes message directly to slog.Info().
+func Info(message string) {
+ slog.Info(message)
+}
+
+// Infof logs message on info log level and allows to supply arguments in printf() style.
+func Infof(format string, a ...any) {
+ slog.Info(fmt.Sprintf(format, a...))
+}
+
+// Debug passes message directly to slog.Debug().
+func Debug(message string) {
+ slog.Debug(message)
+}
+
+// Debugf logs message on debug log level and allows to supply arguments in printf() style.
+func Debugf(format string, a ...any) {
+ slog.Debug(fmt.Sprintf(format, a...))
+}
+
+/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
diff --git a/main.go b/main.go
deleted file mode 100644
index 011588b..0000000
--- a/main.go
+++ /dev/null
@@ -1,207 +0,0 @@
-package main
-
-import (
- "crypto/tls"
- "fmt"
- "os"
- "os/signal"
- "path/filepath"
- "time"
-
- "github.com/eleksir/go-xmpp"
- "github.com/go-redis/redis/v8"
- log "github.com/sirupsen/logrus"
- "gopkg.in/tomb.v2"
-)
-
-func main() {
- log.SetFormatter(&log.TextFormatter{ //nolint:exhaustruct
- DisableQuote: true,
- DisableLevelTruncation: false,
- DisableColors: true,
- FullTimestamp: true,
- TimestampFormat: "2006-01-02 15:04:05",
- })
-
- // Добавим динамически формируемый путь до конфига в список возможных положений конфига в системе.
- executablePath, err := os.Executable()
-
- if err != nil {
- log.Errorf("unable to get current executable path: %s", err)
-
- os.Exit(1)
- }
-
- for {
- sigChan = make(chan os.Signal, 1)
- talk = new(xmpp.Client)
- options = new(xmpp.Options)
-
- configJSONPath := fmt.Sprintf("%s/data/config.json", filepath.Dir(executablePath))
- configLocations = append(configLocations, configJSONPath)
-
- if err := readConfig(); err != nil {
- log.Error(err)
-
- os.Exit(1)
- }
-
- // no panic
- switch config.Loglevel {
- case "fatal":
- log.SetLevel(log.FatalLevel)
- case "error":
- log.SetLevel(log.ErrorLevel)
- case "warn":
- log.SetLevel(log.WarnLevel)
- case "info":
- log.SetLevel(log.InfoLevel)
- case "debug":
- log.SetLevel(log.DebugLevel)
- case "trace":
- log.SetLevel(log.TraceLevel)
- default:
- log.SetLevel(log.InfoLevel)
- }
-
- // Откроем лог и скормим его логгеру
- if config.Log != "" {
- logfile, err := os.OpenFile(config.Log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
-
- if err != nil {
- log.Fatalf("Unable to open log file %s: %s", config.Log, err)
- }
-
- log.SetOutput(logfile)
- }
-
- myLogLevel := log.GetLevel()
- log.Warnf("Loglevel set to %v", myLogLevel)
-
- // Через tomb попробуем сделать выход горутинок управляемым.
- gTomb := tomb.Tomb{}
-
- // Иницализируем redis-клиента.
- redisClient = redis.NewClient(&redis.Options{ //nolint:exhaustruct
- Addr: fmt.Sprintf("%s:%d", config.Redis.Server, config.Redis.Port),
- })
-
- log.Debugf("Lazy connect() to redis at %s:%d", config.Redis.Server, config.Redis.Port)
- subscriber = redisClient.Subscribe(ctx, config.Redis.MyChannel)
-
- verboseClient := false
-
- if myLogLevel == log.TraceLevel {
- verboseClient = true
- }
-
- // github.com/mattn/go-xmpp пишет в stdio, нам этого не надо, ловим выхлоп его в logrus с уровнем trace.
- xmpp.DebugWriter = log.WithFields(log.Fields{"logger": "stdlib"}).WriterLevel(log.TraceLevel)
-
- // Хэндлер сигналов не надо трогать, он нужен для завершения программы целиком.
- gTomb.Go(func() error { return sigHandler() })
- signal.Notify(sigChan, os.Interrupt)
-
- gTomb.Go(func() error { return redisLoop(subscriber.Channel()) })
-
- options = &xmpp.Options{ //nolint:exhaustruct
- Host: fmt.Sprintf("%s:%d", config.Jabber.Server, config.Jabber.Port),
- User: config.Jabber.User,
- Password: config.Jabber.Password,
- Resource: config.Jabber.Resource,
- NoTLS: !config.Jabber.Ssl,
- StartTLS: config.Jabber.StartTLS,
- TLSConfig: &tls.Config{ //nolint:exhaustruct
- ServerName: config.Jabber.Server,
- InsecureSkipVerify: !config.Jabber.SslVerify, //nolint:gosec
- },
- InsecureAllowUnencryptedAuth: config.Jabber.InsecureAllowUnencryptedAuth,
- Debug: verboseClient,
- Session: false,
- Status: "xa",
- StatusMessage: randomPhrase(config.Jabber.StartupStatus),
- DialTimeout: time.Duration(config.Jabber.ConnectionTimeout) * time.Second,
- }
-
- // Устанавливаем соединение и гребём события, посылаемые сервером.
- gTomb.Go(func() error { return myLoop() })
-
- // Ловим первый же kill и не дождаемся остальных, хотя формально надо бы.
- _ = <-gTomb.Dying()
-
- time.Sleep(time.Duration(config.Jabber.ReconnectDelay) * time.Second)
- }
-}
-
-func myLoop() error {
- for {
- // Зададим начальное значение глобальным переменным.
- serverPingTimestampRx = 0
- serverPingTimestampTx = 0
- roomsConnected = make([]string, 1)
- lastActivity = 0
- lastServerActivity = 0
- lastMucActivity = NewCollection()
- serverCapsQueried = false
- serverCapsList = NewCollection()
- mucCapsList = NewCollection()
- serverPingTimestampTx = 0
- serverPingTimestampRx = 0
- roomPresences = NewCollection()
-
- // Установим коннект.
- if err := establishConnection(); err != nil {
- log.Error(err)
-
- return err
- }
-
- serverPingTimestampRx = time.Now().Unix() // Считаем, что если коннект запустился, то первый пинг успешен.
-
- // Тыкаем сервер палочкой, проверяем, что коннект жив и вываливаемся из mainLoop, если он не жив.
- gTomb.Go(
- func() error {
- err := probeServerLiveness()
- log.Error(err)
- return err
- },
- )
-
- // Тыкаем muc-и палочкой, проверяем, что они живы и пере-заходим в них, если пинги пропали.
- // Если пинги до комнаты пропали, то это фактически значит, что либо сервер потерял связь с MUC-компонентом,
- // либо у нас какой-то wire error.
- // gTomb.Go() тут зовётся внутри на каждую комнату, если у нас ошибка, эта горутинка рано или поздно выйдет.
- go probeMUCLiveness()
-
- // Гребём сообщения...
- for {
- // Стриггерилось завершение работы приложения, или соединение не установлено (порвалось, например).
- // грести не надо.
- if shutdown {
- break
- }
-
- if !isConnected {
- // Tight loop - это наверно не очень хорошо, думаю, ничего страшного не будет, если мы поспим 100мс.
- time.Sleep(100 * time.Millisecond)
-
- continue
- }
-
- // Вынимаем ивент из "провода".
- chat, err := talk.Recv()
-
- if err != nil {
- log.Errorf("Unable to get recieve data from socket: %s", err)
-
- return err
- }
-
- parseEvent(chat)
- }
-
- return nil
- }
-}
-
-/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
diff --git a/vendor/github.com/sirupsen/logrus/.gitignore b/vendor/github.com/sirupsen/logrus/.gitignore
deleted file mode 100644
index 1fb13ab..0000000
--- a/vendor/github.com/sirupsen/logrus/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-logrus
-vendor
-
-.idea/
diff --git a/vendor/github.com/sirupsen/logrus/.golangci.yml b/vendor/github.com/sirupsen/logrus/.golangci.yml
deleted file mode 100644
index 65dc285..0000000
--- a/vendor/github.com/sirupsen/logrus/.golangci.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-run:
- # do not run on test files yet
- tests: false
-
-# all available settings of specific linters
-linters-settings:
- errcheck:
- # report about not checking of errors in type assetions: `a := b.(MyStruct)`;
- # default is false: such cases aren't reported by default.
- check-type-assertions: false
-
- # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
- # default is false: such cases aren't reported by default.
- check-blank: false
-
- lll:
- line-length: 100
- tab-width: 4
-
- prealloc:
- simple: false
- range-loops: false
- for-loops: false
-
- whitespace:
- multi-if: false # Enforces newlines (or comments) after every multi-line if statement
- multi-func: false # Enforces newlines (or comments) after every multi-line function signature
-
-linters:
- enable:
- - megacheck
- - govet
- disable:
- - maligned
- - prealloc
- disable-all: false
- presets:
- - bugs
- - unused
- fast: false
diff --git a/vendor/github.com/sirupsen/logrus/.travis.yml b/vendor/github.com/sirupsen/logrus/.travis.yml
deleted file mode 100644
index c1dbd5a..0000000
--- a/vendor/github.com/sirupsen/logrus/.travis.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-language: go
-go_import_path: github.com/sirupsen/logrus
-git:
- depth: 1
-env:
- - GO111MODULE=on
-go: 1.15.x
-os: linux
-install:
- - ./travis/install.sh
-script:
- - cd ci
- - go run mage.go -v -w ../ crossBuild
- - go run mage.go -v -w ../ lint
- - go run mage.go -v -w ../ test
diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md
deleted file mode 100644
index 7567f61..0000000
--- a/vendor/github.com/sirupsen/logrus/CHANGELOG.md
+++ /dev/null
@@ -1,259 +0,0 @@
-# 1.8.1
-Code quality:
- * move magefile in its own subdir/submodule to remove magefile dependency on logrus consumer
- * improve timestamp format documentation
-
-Fixes:
- * fix race condition on logger hooks
-
-
-# 1.8.0
-
-Correct versioning number replacing v1.7.1.
-
-# 1.7.1
-
-Beware this release has introduced a new public API and its semver is therefore incorrect.
-
-Code quality:
- * use go 1.15 in travis
- * use magefile as task runner
-
-Fixes:
- * small fixes about new go 1.13 error formatting system
- * Fix for long time race condiction with mutating data hooks
-
-Features:
- * build support for zos
-
-# 1.7.0
-Fixes:
- * the dependency toward a windows terminal library has been removed
-
-Features:
- * a new buffer pool management API has been added
- * a set of `Fn()` functions have been added
-
-# 1.6.0
-Fixes:
- * end of line cleanup
- * revert the entry concurrency bug fix whic leads to deadlock under some circumstances
- * update dependency on go-windows-terminal-sequences to fix a crash with go 1.14
-
-Features:
- * add an option to the `TextFormatter` to completely disable fields quoting
-
-# 1.5.0
-Code quality:
- * add golangci linter run on travis
-
-Fixes:
- * add mutex for hooks concurrent access on `Entry` data
- * caller function field for go1.14
- * fix build issue for gopherjs target
-
-Feature:
- * add an hooks/writer sub-package whose goal is to split output on different stream depending on the trace level
- * add a `DisableHTMLEscape` option in the `JSONFormatter`
- * add `ForceQuote` and `PadLevelText` options in the `TextFormatter`
-
-# 1.4.2
- * Fixes build break for plan9, nacl, solaris
-# 1.4.1
-This new release introduces:
- * Enhance TextFormatter to not print caller information when they are empty (#944)
- * Remove dependency on golang.org/x/crypto (#932, #943)
-
-Fixes:
- * Fix Entry.WithContext method to return a copy of the initial entry (#941)
-
-# 1.4.0
-This new release introduces:
- * Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
- * Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter` (#909, #911)
- * Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
-
-Fixes:
- * Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
- * Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
- * Fix infinite recursion on unknown `Level.String()` (#907)
- * Fix race condition in `getCaller` (#916).
-
-
-# 1.3.0
-This new release introduces:
- * Log, Logf, Logln functions for Logger and Entry that take a Level
-
-Fixes:
- * Building prometheus node_exporter on AIX (#840)
- * Race condition in TextFormatter (#468)
- * Travis CI import path (#868)
- * Remove coloured output on Windows (#862)
- * Pointer to func as field in JSONFormatter (#870)
- * Properly marshal Levels (#873)
-
-# 1.2.0
-This new release introduces:
- * A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
- * A new trace level named `Trace` whose level is below `Debug`
- * A configurable exit function to be called upon a Fatal trace
- * The `Level` object now implements `encoding.TextUnmarshaler` interface
-
-# 1.1.1
-This is a bug fix release.
- * fix the build break on Solaris
- * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
-
-# 1.1.0
-This new release introduces:
- * several fixes:
- * a fix for a race condition on entry formatting
- * proper cleanup of previously used entries before putting them back in the pool
- * the extra new line at the end of message in text formatter has been removed
- * a new global public API to check if a level is activated: IsLevelEnabled
- * the following methods have been added to the Logger object
- * IsLevelEnabled
- * SetFormatter
- * SetOutput
- * ReplaceHooks
- * introduction of go module
- * an indent configuration for the json formatter
- * output colour support for windows
- * the field sort function is now configurable for text formatter
- * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater
-
-# 1.0.6
-
-This new release introduces:
- * a new api WithTime which allows to easily force the time of the log entry
- which is mostly useful for logger wrapper
- * a fix reverting the immutability of the entry given as parameter to the hooks
- a new configuration field of the json formatter in order to put all the fields
- in a nested dictionnary
- * a new SetOutput method in the Logger
- * a new configuration of the textformatter to configure the name of the default keys
- * a new configuration of the text formatter to disable the level truncation
-
-# 1.0.5
-
-* Fix hooks race (#707)
-* Fix panic deadlock (#695)
-
-# 1.0.4
-
-* Fix race when adding hooks (#612)
-* Fix terminal check in AppEngine (#635)
-
-# 1.0.3
-
-* Replace example files with testable examples
-
-# 1.0.2
-
-* bug: quote non-string values in text formatter (#583)
-* Make (*Logger) SetLevel a public method
-
-# 1.0.1
-
-* bug: fix escaping in text formatter (#575)
-
-# 1.0.0
-
-* Officially changed name to lower-case
-* bug: colors on Windows 10 (#541)
-* bug: fix race in accessing level (#512)
-
-# 0.11.5
-
-* feature: add writer and writerlevel to entry (#372)
-
-# 0.11.4
-
-* bug: fix undefined variable on solaris (#493)
-
-# 0.11.3
-
-* formatter: configure quoting of empty values (#484)
-* formatter: configure quoting character (default is `"`) (#484)
-* bug: fix not importing io correctly in non-linux environments (#481)
-
-# 0.11.2
-
-* bug: fix windows terminal detection (#476)
-
-# 0.11.1
-
-* bug: fix tty detection with custom out (#471)
-
-# 0.11.0
-
-* performance: Use bufferpool to allocate (#370)
-* terminal: terminal detection for app-engine (#343)
-* feature: exit handler (#375)
-
-# 0.10.0
-
-* feature: Add a test hook (#180)
-* feature: `ParseLevel` is now case-insensitive (#326)
-* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
-* performance: avoid re-allocations on `WithFields` (#335)
-
-# 0.9.0
-
-* logrus/text_formatter: don't emit empty msg
-* logrus/hooks/airbrake: move out of main repository
-* logrus/hooks/sentry: move out of main repository
-* logrus/hooks/papertrail: move out of main repository
-* logrus/hooks/bugsnag: move out of main repository
-* logrus/core: run tests with `-race`
-* logrus/core: detect TTY based on `stderr`
-* logrus/core: support `WithError` on logger
-* logrus/core: Solaris support
-
-# 0.8.7
-
-* logrus/core: fix possible race (#216)
-* logrus/doc: small typo fixes and doc improvements
-
-
-# 0.8.6
-
-* hooks/raven: allow passing an initialized client
-
-# 0.8.5
-
-* logrus/core: revert #208
-
-# 0.8.4
-
-* formatter/text: fix data race (#218)
-
-# 0.8.3
-
-* logrus/core: fix entry log level (#208)
-* logrus/core: improve performance of text formatter by 40%
-* logrus/core: expose `LevelHooks` type
-* logrus/core: add support for DragonflyBSD and NetBSD
-* formatter/text: print structs more verbosely
-
-# 0.8.2
-
-* logrus: fix more Fatal family functions
-
-# 0.8.1
-
-* logrus: fix not exiting on `Fatalf` and `Fatalln`
-
-# 0.8.0
-
-* logrus: defaults to stderr instead of stdout
-* hooks/sentry: add special field for `*http.Request`
-* formatter/text: ignore Windows for colors
-
-# 0.7.3
-
-* formatter/\*: allow configuration of timestamp layout
-
-# 0.7.2
-
-* formatter/text: Add configuration option for time format (#158)
diff --git a/vendor/github.com/sirupsen/logrus/LICENSE b/vendor/github.com/sirupsen/logrus/LICENSE
deleted file mode 100644
index f090cb4..0000000
--- a/vendor/github.com/sirupsen/logrus/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Simon Eskildsen
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md
deleted file mode 100644
index d1d4a85..0000000
--- a/vendor/github.com/sirupsen/logrus/README.md
+++ /dev/null
@@ -1,515 +0,0 @@
-# Logrus
[](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [](https://travis-ci.org/sirupsen/logrus) [](https://pkg.go.dev/github.com/sirupsen/logrus)
-
-Logrus is a structured logger for Go (golang), completely API compatible with
-the standard library logger.
-
-**Logrus is in maintenance-mode.** We will not be introducing new features. It's
-simply too hard to do in a way that won't break many people's projects, which is
-the last thing you want from your Logging library (again...).
-
-This does not mean Logrus is dead. Logrus will continue to be maintained for
-security, (backwards compatible) bug fixes, and performance (where we are
-limited by the interface).
-
-I believe Logrus' biggest contribution is to have played a part in today's
-widespread use of structured logging in Golang. There doesn't seem to be a
-reason to do a major, breaking iteration into Logrus V2, since the fantastic Go
-community has built those independently. Many fantastic alternatives have sprung
-up. Logrus would look like those, had it been re-designed with what we know
-about structured logging in Go today. Check out, for example,
-[Zerolog][zerolog], [Zap][zap], and [Apex][apex].
-
-[zerolog]: https://github.com/rs/zerolog
-[zap]: https://github.com/uber-go/zap
-[apex]: https://github.com/apex/log
-
-**Seeing weird case-sensitive problems?** It's in the past been possible to
-import Logrus as both upper- and lower-case. Due to the Go package environment,
-this caused issues in the community and we needed a standard. Some environments
-experienced problems with the upper-case variant, so the lower-case was decided.
-Everything using `logrus` will need to use the lower-case:
-`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
-
-To fix Glide, see [these
-comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
-For an in-depth explanation of the casing issue, see [this
-comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
-
-Nicely color-coded in development (when a TTY is attached, otherwise just
-plain text):
-
-
-
-With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
-or Splunk:
-
-```text
-{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
-ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
-
-{"level":"warning","msg":"The group's number increased tremendously!",
-"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
-
-{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
-"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
-
-{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
-"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
-
-{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
-"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
-```
-
-With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
-attached, the output is compatible with the
-[logfmt](http://godoc.org/github.com/kr/logfmt) format:
-
-```text
-time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
-time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
-time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
-time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
-time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
-time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
-```
-To ensure this behaviour even if a TTY is attached, set your formatter as follows:
-
-```go
- log.SetFormatter(&log.TextFormatter{
- DisableColors: true,
- FullTimestamp: true,
- })
-```
-
-#### Logging Method Name
-
-If you wish to add the calling method as a field, instruct the logger via:
-```go
-log.SetReportCaller(true)
-```
-This adds the caller as 'method' like so:
-
-```json
-{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
-"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
-```
-
-```text
-time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
-```
-Note that this does add measurable overhead - the cost will depend on the version of Go, but is
-between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
-environment via benchmarks:
-```
-go test -bench=.*CallerTracing
-```
-
-
-#### Case-sensitivity
-
-The organization's name was changed to lower-case--and this will not be changed
-back. If you are getting import conflicts due to case sensitivity, please use
-the lower-case import: `github.com/sirupsen/logrus`.
-
-#### Example
-
-The simplest way to use Logrus is simply the package-level exported logger:
-
-```go
-package main
-
-import (
- log "github.com/sirupsen/logrus"
-)
-
-func main() {
- log.WithFields(log.Fields{
- "animal": "walrus",
- }).Info("A walrus appears")
-}
-```
-
-Note that it's completely api-compatible with the stdlib logger, so you can
-replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
-and you'll now have the flexibility of Logrus. You can customize it all you
-want:
-
-```go
-package main
-
-import (
- "os"
- log "github.com/sirupsen/logrus"
-)
-
-func init() {
- // Log as JSON instead of the default ASCII formatter.
- log.SetFormatter(&log.JSONFormatter{})
-
- // Output to stdout instead of the default stderr
- // Can be any io.Writer, see below for File example
- log.SetOutput(os.Stdout)
-
- // Only log the warning severity or above.
- log.SetLevel(log.WarnLevel)
-}
-
-func main() {
- log.WithFields(log.Fields{
- "animal": "walrus",
- "size": 10,
- }).Info("A group of walrus emerges from the ocean")
-
- log.WithFields(log.Fields{
- "omg": true,
- "number": 122,
- }).Warn("The group's number increased tremendously!")
-
- log.WithFields(log.Fields{
- "omg": true,
- "number": 100,
- }).Fatal("The ice breaks!")
-
- // A common pattern is to re-use fields between logging statements by re-using
- // the logrus.Entry returned from WithFields()
- contextLogger := log.WithFields(log.Fields{
- "common": "this is a common field",
- "other": "I also should be logged always",
- })
-
- contextLogger.Info("I'll be logged with common and other field")
- contextLogger.Info("Me too")
-}
-```
-
-For more advanced usage such as logging to multiple locations from the same
-application, you can also create an instance of the `logrus` Logger:
-
-```go
-package main
-
-import (
- "os"
- "github.com/sirupsen/logrus"
-)
-
-// Create a new instance of the logger. You can have any number of instances.
-var log = logrus.New()
-
-func main() {
- // The API for setting attributes is a little different than the package level
- // exported logger. See Godoc.
- log.Out = os.Stdout
-
- // You could set this to any `io.Writer` such as a file
- // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
- // if err == nil {
- // log.Out = file
- // } else {
- // log.Info("Failed to log to file, using default stderr")
- // }
-
- log.WithFields(logrus.Fields{
- "animal": "walrus",
- "size": 10,
- }).Info("A group of walrus emerges from the ocean")
-}
-```
-
-#### Fields
-
-Logrus encourages careful, structured logging through logging fields instead of
-long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
-to send event %s to topic %s with key %d")`, you should log the much more
-discoverable:
-
-```go
-log.WithFields(log.Fields{
- "event": event,
- "topic": topic,
- "key": key,
-}).Fatal("Failed to send event")
-```
-
-We've found this API forces you to think about logging in a way that produces
-much more useful logging messages. We've been in countless situations where just
-a single added field to a log statement that was already there would've saved us
-hours. The `WithFields` call is optional.
-
-In general, with Logrus using any of the `printf`-family functions should be
-seen as a hint you should add a field, however, you can still use the
-`printf`-family functions with Logrus.
-
-#### Default Fields
-
-Often it's helpful to have fields _always_ attached to log statements in an
-application or parts of one. For example, you may want to always log the
-`request_id` and `user_ip` in the context of a request. Instead of writing
-`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
-every line, you can create a `logrus.Entry` to pass around instead:
-
-```go
-requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
-requestLogger.Info("something happened on that request") # will log request_id and user_ip
-requestLogger.Warn("something not great happened")
-```
-
-#### Hooks
-
-You can add hooks for logging levels. For example to send errors to an exception
-tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
-multiple places simultaneously, e.g. syslog.
-
-Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
-`init`:
-
-```go
-import (
- log "github.com/sirupsen/logrus"
- "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
- logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
- "log/syslog"
-)
-
-func init() {
-
- // Use the Airbrake hook to report errors that have Error severity or above to
- // an exception tracker. You can create custom hooks, see the Hooks section.
- log.AddHook(airbrake.NewHook(123, "xyz", "production"))
-
- hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
- if err != nil {
- log.Error("Unable to connect to local syslog daemon")
- } else {
- log.AddHook(hook)
- }
-}
-```
-Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
-
-A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
-
-
-#### Level logging
-
-Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
-
-```go
-log.Trace("Something very low level.")
-log.Debug("Useful debugging information.")
-log.Info("Something noteworthy happened!")
-log.Warn("You should probably take a look at this.")
-log.Error("Something failed but I'm not quitting.")
-// Calls os.Exit(1) after logging
-log.Fatal("Bye.")
-// Calls panic() after logging
-log.Panic("I'm bailing.")
-```
-
-You can set the logging level on a `Logger`, then it will only log entries with
-that severity or anything above it:
-
-```go
-// Will log anything that is info or above (warn, error, fatal, panic). Default.
-log.SetLevel(log.InfoLevel)
-```
-
-It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
-environment if your application has that.
-
-Note: If you want different log levels for global (`log.SetLevel(...)`) and syslog logging, please check the [syslog hook README](hooks/syslog/README.md#different-log-levels-for-local-and-remote-logging).
-
-#### Entries
-
-Besides the fields added with `WithField` or `WithFields` some fields are
-automatically added to all logging events:
-
-1. `time`. The timestamp when the entry was created.
-2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
- the `AddFields` call. E.g. `Failed to send event.`
-3. `level`. The logging level. E.g. `info`.
-
-#### Environments
-
-Logrus has no notion of environment.
-
-If you wish for hooks and formatters to only be used in specific environments,
-you should handle that yourself. For example, if your application has a global
-variable `Environment`, which is a string representation of the environment you
-could do:
-
-```go
-import (
- log "github.com/sirupsen/logrus"
-)
-
-func init() {
- // do something here to set environment depending on an environment variable
- // or command-line flag
- if Environment == "production" {
- log.SetFormatter(&log.JSONFormatter{})
- } else {
- // The TextFormatter is default, you don't actually have to do this.
- log.SetFormatter(&log.TextFormatter{})
- }
-}
-```
-
-This configuration is how `logrus` was intended to be used, but JSON in
-production is mostly only useful if you do log aggregation with tools like
-Splunk or Logstash.
-
-#### Formatters
-
-The built-in logging formatters are:
-
-* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
- without colors.
- * *Note:* to force colored output when there is no TTY, set the `ForceColors`
- field to `true`. To force no colored output even if there is a TTY set the
- `DisableColors` field to `true`. For Windows, see
- [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
- * When colors are enabled, levels are truncated to 4 characters by default. To disable
- truncation set the `DisableLevelTruncation` field to `true`.
- * When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
- * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
-* `logrus.JSONFormatter`. Logs fields as JSON.
- * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
-
-Third party logging formatters:
-
-* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
-* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
-* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
-* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
-* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo.
-* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
-* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Sava log to files.
-* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added.
-
-You can define your formatter by implementing the `Formatter` interface,
-requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
-`Fields` type (`map[string]interface{}`) with all your fields as well as the
-default ones (see Entries section above):
-
-```go
-type MyJSONFormatter struct {
-}
-
-log.SetFormatter(new(MyJSONFormatter))
-
-func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
- // Note this doesn't include Time, Level and Message which are available on
- // the Entry. Consult `godoc` on information about those fields or read the
- // source of the official loggers.
- serialized, err := json.Marshal(entry.Data)
- if err != nil {
- return nil, fmt.Errorf("Failed to marshal fields to JSON, %w", err)
- }
- return append(serialized, '\n'), nil
-}
-```
-
-#### Logger as an `io.Writer`
-
-Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
-
-```go
-w := logger.Writer()
-defer w.Close()
-
-srv := http.Server{
- // create a stdlib log.Logger that writes to
- // logrus.Logger.
- ErrorLog: log.New(w, "", 0),
-}
-```
-
-Each line written to that writer will be printed the usual way, using formatters
-and hooks. The level for those entries is `info`.
-
-This means that we can override the standard library logger easily:
-
-```go
-logger := logrus.New()
-logger.Formatter = &logrus.JSONFormatter{}
-
-// Use logrus for standard log output
-// Note that `log` here references stdlib's log
-// Not logrus imported under the name `log`.
-log.SetOutput(logger.Writer())
-```
-
-#### Rotation
-
-Log rotation is not provided with Logrus. Log rotation should be done by an
-external program (like `logrotate(8)`) that can compress and delete old log
-entries. It should not be a feature of the application-level logger.
-
-#### Tools
-
-| Tool | Description |
-| ---- | ----------- |
-|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will be generated with different configs in different environments.|
-|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
-
-#### Testing
-
-Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
-
-* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook
-* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
-
-```go
-import(
- "github.com/sirupsen/logrus"
- "github.com/sirupsen/logrus/hooks/test"
- "github.com/stretchr/testify/assert"
- "testing"
-)
-
-func TestSomething(t*testing.T){
- logger, hook := test.NewNullLogger()
- logger.Error("Helloerror")
-
- assert.Equal(t, 1, len(hook.Entries))
- assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
- assert.Equal(t, "Helloerror", hook.LastEntry().Message)
-
- hook.Reset()
- assert.Nil(t, hook.LastEntry())
-}
-```
-
-#### Fatal handlers
-
-Logrus can register one or more functions that will be called when any `fatal`
-level message is logged. The registered handlers will be executed before
-logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need
-to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
-
-```
-...
-handler := func() {
- // gracefully shutdown something...
-}
-logrus.RegisterExitHandler(handler)
-...
-```
-
-#### Thread safety
-
-By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
-If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
-
-Situation when locking is not needed includes:
-
-* You have no hooks registered, or hooks calling is already thread-safe.
-
-* Writing to logger.Out is already thread-safe, for example:
-
- 1) logger.Out is protected by locks.
-
- 2) logger.Out is an os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing)
-
- (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
diff --git a/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/sirupsen/logrus/alt_exit.go
deleted file mode 100644
index 8fd189e..0000000
--- a/vendor/github.com/sirupsen/logrus/alt_exit.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package logrus
-
-// The following code was sourced and modified from the
-// https://github.com/tebeka/atexit package governed by the following license:
-//
-// Copyright (c) 2012 Miki Tebeka .
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of
-// this software and associated documentation files (the "Software"), to deal in
-// the Software without restriction, including without limitation the rights to
-// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-// the Software, and to permit persons to whom the Software is furnished to do so,
-// subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-import (
- "fmt"
- "os"
-)
-
-var handlers = []func(){}
-
-func runHandler(handler func()) {
- defer func() {
- if err := recover(); err != nil {
- fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
- }
- }()
-
- handler()
-}
-
-func runHandlers() {
- for _, handler := range handlers {
- runHandler(handler)
- }
-}
-
-// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
-func Exit(code int) {
- runHandlers()
- os.Exit(code)
-}
-
-// RegisterExitHandler appends a Logrus Exit handler to the list of handlers,
-// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
-// any Fatal log entry is made.
-//
-// This method is useful when a caller wishes to use logrus to log a fatal
-// message but also needs to gracefully shutdown. An example usecase could be
-// closing database connections, or sending a alert that the application is
-// closing.
-func RegisterExitHandler(handler func()) {
- handlers = append(handlers, handler)
-}
-
-// DeferExitHandler prepends a Logrus Exit handler to the list of handlers,
-// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
-// any Fatal log entry is made.
-//
-// This method is useful when a caller wishes to use logrus to log a fatal
-// message but also needs to gracefully shutdown. An example usecase could be
-// closing database connections, or sending a alert that the application is
-// closing.
-func DeferExitHandler(handler func()) {
- handlers = append([]func(){handler}, handlers...)
-}
diff --git a/vendor/github.com/sirupsen/logrus/appveyor.yml b/vendor/github.com/sirupsen/logrus/appveyor.yml
deleted file mode 100644
index df9d65c..0000000
--- a/vendor/github.com/sirupsen/logrus/appveyor.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-version: "{build}"
-platform: x64
-clone_folder: c:\gopath\src\github.com\sirupsen\logrus
-environment:
- GOPATH: c:\gopath
-branches:
- only:
- - master
-install:
- - set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- - go version
-build_script:
- - go get -t
- - go test
diff --git a/vendor/github.com/sirupsen/logrus/buffer_pool.go b/vendor/github.com/sirupsen/logrus/buffer_pool.go
deleted file mode 100644
index c7787f7..0000000
--- a/vendor/github.com/sirupsen/logrus/buffer_pool.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package logrus
-
-import (
- "bytes"
- "sync"
-)
-
-var (
- bufferPool BufferPool
-)
-
-type BufferPool interface {
- Put(*bytes.Buffer)
- Get() *bytes.Buffer
-}
-
-type defaultPool struct {
- pool *sync.Pool
-}
-
-func (p *defaultPool) Put(buf *bytes.Buffer) {
- p.pool.Put(buf)
-}
-
-func (p *defaultPool) Get() *bytes.Buffer {
- return p.pool.Get().(*bytes.Buffer)
-}
-
-// SetBufferPool allows to replace the default logrus buffer pool
-// to better meets the specific needs of an application.
-func SetBufferPool(bp BufferPool) {
- bufferPool = bp
-}
-
-func init() {
- SetBufferPool(&defaultPool{
- pool: &sync.Pool{
- New: func() interface{} {
- return new(bytes.Buffer)
- },
- },
- })
-}
diff --git a/vendor/github.com/sirupsen/logrus/doc.go b/vendor/github.com/sirupsen/logrus/doc.go
deleted file mode 100644
index da67aba..0000000
--- a/vendor/github.com/sirupsen/logrus/doc.go
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
-
-
-The simplest way to use Logrus is simply the package-level exported logger:
-
- package main
-
- import (
- log "github.com/sirupsen/logrus"
- )
-
- func main() {
- log.WithFields(log.Fields{
- "animal": "walrus",
- "number": 1,
- "size": 10,
- }).Info("A walrus appears")
- }
-
-Output:
- time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
-
-For a full guide visit https://github.com/sirupsen/logrus
-*/
-package logrus
diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go
deleted file mode 100644
index 71cdbbc..0000000
--- a/vendor/github.com/sirupsen/logrus/entry.go
+++ /dev/null
@@ -1,442 +0,0 @@
-package logrus
-
-import (
- "bytes"
- "context"
- "fmt"
- "os"
- "reflect"
- "runtime"
- "strings"
- "sync"
- "time"
-)
-
-var (
-
- // qualified package name, cached at first use
- logrusPackage string
-
- // Positions in the call stack when tracing to report the calling method
- minimumCallerDepth int
-
- // Used for caller information initialisation
- callerInitOnce sync.Once
-)
-
-const (
- maximumCallerDepth int = 25
- knownLogrusFrames int = 4
-)
-
-func init() {
- // start at the bottom of the stack before the package-name cache is primed
- minimumCallerDepth = 1
-}
-
-// Defines the key when adding errors using WithError.
-var ErrorKey = "error"
-
-// An entry is the final or intermediate Logrus logging entry. It contains all
-// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
-// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
-// reused and passed around as much as you wish to avoid field duplication.
-type Entry struct {
- Logger *Logger
-
- // Contains all the fields set by the user.
- Data Fields
-
- // Time at which the log entry was created
- Time time.Time
-
- // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
- // This field will be set on entry firing and the value will be equal to the one in Logger struct field.
- Level Level
-
- // Calling method, with package name
- Caller *runtime.Frame
-
- // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
- Message string
-
- // When formatter is called in entry.log(), a Buffer may be set to entry
- Buffer *bytes.Buffer
-
- // Contains the context set by the user. Useful for hook processing etc.
- Context context.Context
-
- // err may contain a field formatting error
- err string
-}
-
-func NewEntry(logger *Logger) *Entry {
- return &Entry{
- Logger: logger,
- // Default is three fields, plus one optional. Give a little extra room.
- Data: make(Fields, 6),
- }
-}
-
-func (entry *Entry) Dup() *Entry {
- data := make(Fields, len(entry.Data))
- for k, v := range entry.Data {
- data[k] = v
- }
- return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, Context: entry.Context, err: entry.err}
-}
-
-// Returns the bytes representation of this entry from the formatter.
-func (entry *Entry) Bytes() ([]byte, error) {
- return entry.Logger.Formatter.Format(entry)
-}
-
-// Returns the string representation from the reader and ultimately the
-// formatter.
-func (entry *Entry) String() (string, error) {
- serialized, err := entry.Bytes()
- if err != nil {
- return "", err
- }
- str := string(serialized)
- return str, nil
-}
-
-// Add an error as single field (using the key defined in ErrorKey) to the Entry.
-func (entry *Entry) WithError(err error) *Entry {
- return entry.WithField(ErrorKey, err)
-}
-
-// Add a context to the Entry.
-func (entry *Entry) WithContext(ctx context.Context) *Entry {
- dataCopy := make(Fields, len(entry.Data))
- for k, v := range entry.Data {
- dataCopy[k] = v
- }
- return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
-}
-
-// Add a single field to the Entry.
-func (entry *Entry) WithField(key string, value interface{}) *Entry {
- return entry.WithFields(Fields{key: value})
-}
-
-// Add a map of fields to the Entry.
-func (entry *Entry) WithFields(fields Fields) *Entry {
- data := make(Fields, len(entry.Data)+len(fields))
- for k, v := range entry.Data {
- data[k] = v
- }
- fieldErr := entry.err
- for k, v := range fields {
- isErrField := false
- if t := reflect.TypeOf(v); t != nil {
- switch {
- case t.Kind() == reflect.Func, t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Func:
- isErrField = true
- }
- }
- if isErrField {
- tmp := fmt.Sprintf("can not add field %q", k)
- if fieldErr != "" {
- fieldErr = entry.err + ", " + tmp
- } else {
- fieldErr = tmp
- }
- } else {
- data[k] = v
- }
- }
- return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
-}
-
-// Overrides the time of the Entry.
-func (entry *Entry) WithTime(t time.Time) *Entry {
- dataCopy := make(Fields, len(entry.Data))
- for k, v := range entry.Data {
- dataCopy[k] = v
- }
- return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context}
-}
-
-// getPackageName reduces a fully qualified function name to the package name
-// There really ought to be to be a better way...
-func getPackageName(f string) string {
- for {
- lastPeriod := strings.LastIndex(f, ".")
- lastSlash := strings.LastIndex(f, "/")
- if lastPeriod > lastSlash {
- f = f[:lastPeriod]
- } else {
- break
- }
- }
-
- return f
-}
-
-// getCaller retrieves the name of the first non-logrus calling function
-func getCaller() *runtime.Frame {
- // cache this package's fully-qualified name
- callerInitOnce.Do(func() {
- pcs := make([]uintptr, maximumCallerDepth)
- _ = runtime.Callers(0, pcs)
-
- // dynamic get the package name and the minimum caller depth
- for i := 0; i < maximumCallerDepth; i++ {
- funcName := runtime.FuncForPC(pcs[i]).Name()
- if strings.Contains(funcName, "getCaller") {
- logrusPackage = getPackageName(funcName)
- break
- }
- }
-
- minimumCallerDepth = knownLogrusFrames
- })
-
- // Restrict the lookback frames to avoid runaway lookups
- pcs := make([]uintptr, maximumCallerDepth)
- depth := runtime.Callers(minimumCallerDepth, pcs)
- frames := runtime.CallersFrames(pcs[:depth])
-
- for f, again := frames.Next(); again; f, again = frames.Next() {
- pkg := getPackageName(f.Function)
-
- // If the caller isn't part of this package, we're done
- if pkg != logrusPackage {
- return &f //nolint:scopelint
- }
- }
-
- // if we got here, we failed to find the caller's context
- return nil
-}
-
-func (entry Entry) HasCaller() (has bool) {
- return entry.Logger != nil &&
- entry.Logger.ReportCaller &&
- entry.Caller != nil
-}
-
-func (entry *Entry) log(level Level, msg string) {
- var buffer *bytes.Buffer
-
- newEntry := entry.Dup()
-
- if newEntry.Time.IsZero() {
- newEntry.Time = time.Now()
- }
-
- newEntry.Level = level
- newEntry.Message = msg
-
- newEntry.Logger.mu.Lock()
- reportCaller := newEntry.Logger.ReportCaller
- bufPool := newEntry.getBufferPool()
- newEntry.Logger.mu.Unlock()
-
- if reportCaller {
- newEntry.Caller = getCaller()
- }
-
- newEntry.fireHooks()
- buffer = bufPool.Get()
- defer func() {
- newEntry.Buffer = nil
- buffer.Reset()
- bufPool.Put(buffer)
- }()
- buffer.Reset()
- newEntry.Buffer = buffer
-
- newEntry.write()
-
- newEntry.Buffer = nil
-
- // To avoid Entry#log() returning a value that only would make sense for
- // panic() to use in Entry#Panic(), we avoid the allocation by checking
- // directly here.
- if level <= PanicLevel {
- panic(newEntry)
- }
-}
-
-func (entry *Entry) getBufferPool() (pool BufferPool) {
- if entry.Logger.BufferPool != nil {
- return entry.Logger.BufferPool
- }
- return bufferPool
-}
-
-func (entry *Entry) fireHooks() {
- var tmpHooks LevelHooks
- entry.Logger.mu.Lock()
- tmpHooks = make(LevelHooks, len(entry.Logger.Hooks))
- for k, v := range entry.Logger.Hooks {
- tmpHooks[k] = v
- }
- entry.Logger.mu.Unlock()
-
- err := tmpHooks.Fire(entry.Level, entry)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
- }
-}
-
-func (entry *Entry) write() {
- entry.Logger.mu.Lock()
- defer entry.Logger.mu.Unlock()
- serialized, err := entry.Logger.Formatter.Format(entry)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
- return
- }
- if _, err := entry.Logger.Out.Write(serialized); err != nil {
- fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
- }
-}
-
-// Log will log a message at the level given as parameter.
-// Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit.
-// For this behaviour Entry.Panic or Entry.Fatal should be used instead.
-func (entry *Entry) Log(level Level, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(level) {
- entry.log(level, fmt.Sprint(args...))
- }
-}
-
-func (entry *Entry) Trace(args ...interface{}) {
- entry.Log(TraceLevel, args...)
-}
-
-func (entry *Entry) Debug(args ...interface{}) {
- entry.Log(DebugLevel, args...)
-}
-
-func (entry *Entry) Print(args ...interface{}) {
- entry.Info(args...)
-}
-
-func (entry *Entry) Info(args ...interface{}) {
- entry.Log(InfoLevel, args...)
-}
-
-func (entry *Entry) Warn(args ...interface{}) {
- entry.Log(WarnLevel, args...)
-}
-
-func (entry *Entry) Warning(args ...interface{}) {
- entry.Warn(args...)
-}
-
-func (entry *Entry) Error(args ...interface{}) {
- entry.Log(ErrorLevel, args...)
-}
-
-func (entry *Entry) Fatal(args ...interface{}) {
- entry.Log(FatalLevel, args...)
- entry.Logger.Exit(1)
-}
-
-func (entry *Entry) Panic(args ...interface{}) {
- entry.Log(PanicLevel, args...)
-}
-
-// Entry Printf family functions
-
-func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(level) {
- entry.Log(level, fmt.Sprintf(format, args...))
- }
-}
-
-func (entry *Entry) Tracef(format string, args ...interface{}) {
- entry.Logf(TraceLevel, format, args...)
-}
-
-func (entry *Entry) Debugf(format string, args ...interface{}) {
- entry.Logf(DebugLevel, format, args...)
-}
-
-func (entry *Entry) Infof(format string, args ...interface{}) {
- entry.Logf(InfoLevel, format, args...)
-}
-
-func (entry *Entry) Printf(format string, args ...interface{}) {
- entry.Infof(format, args...)
-}
-
-func (entry *Entry) Warnf(format string, args ...interface{}) {
- entry.Logf(WarnLevel, format, args...)
-}
-
-func (entry *Entry) Warningf(format string, args ...interface{}) {
- entry.Warnf(format, args...)
-}
-
-func (entry *Entry) Errorf(format string, args ...interface{}) {
- entry.Logf(ErrorLevel, format, args...)
-}
-
-func (entry *Entry) Fatalf(format string, args ...interface{}) {
- entry.Logf(FatalLevel, format, args...)
- entry.Logger.Exit(1)
-}
-
-func (entry *Entry) Panicf(format string, args ...interface{}) {
- entry.Logf(PanicLevel, format, args...)
-}
-
-// Entry Println family functions
-
-func (entry *Entry) Logln(level Level, args ...interface{}) {
- if entry.Logger.IsLevelEnabled(level) {
- entry.Log(level, entry.sprintlnn(args...))
- }
-}
-
-func (entry *Entry) Traceln(args ...interface{}) {
- entry.Logln(TraceLevel, args...)
-}
-
-func (entry *Entry) Debugln(args ...interface{}) {
- entry.Logln(DebugLevel, args...)
-}
-
-func (entry *Entry) Infoln(args ...interface{}) {
- entry.Logln(InfoLevel, args...)
-}
-
-func (entry *Entry) Println(args ...interface{}) {
- entry.Infoln(args...)
-}
-
-func (entry *Entry) Warnln(args ...interface{}) {
- entry.Logln(WarnLevel, args...)
-}
-
-func (entry *Entry) Warningln(args ...interface{}) {
- entry.Warnln(args...)
-}
-
-func (entry *Entry) Errorln(args ...interface{}) {
- entry.Logln(ErrorLevel, args...)
-}
-
-func (entry *Entry) Fatalln(args ...interface{}) {
- entry.Logln(FatalLevel, args...)
- entry.Logger.Exit(1)
-}
-
-func (entry *Entry) Panicln(args ...interface{}) {
- entry.Logln(PanicLevel, args...)
-}
-
-// Sprintlnn => Sprint no newline. This is to get the behavior of how
-// fmt.Sprintln where spaces are always added between operands, regardless of
-// their type. Instead of vendoring the Sprintln implementation to spare a
-// string allocation, we do the simplest thing.
-func (entry *Entry) sprintlnn(args ...interface{}) string {
- msg := fmt.Sprintln(args...)
- return msg[:len(msg)-1]
-}
diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go
deleted file mode 100644
index 017c30c..0000000
--- a/vendor/github.com/sirupsen/logrus/exported.go
+++ /dev/null
@@ -1,270 +0,0 @@
-package logrus
-
-import (
- "context"
- "io"
- "time"
-)
-
-var (
- // std is the name of the standard logger in stdlib `log`
- std = New()
-)
-
-func StandardLogger() *Logger {
- return std
-}
-
-// SetOutput sets the standard logger output.
-func SetOutput(out io.Writer) {
- std.SetOutput(out)
-}
-
-// SetFormatter sets the standard logger formatter.
-func SetFormatter(formatter Formatter) {
- std.SetFormatter(formatter)
-}
-
-// SetReportCaller sets whether the standard logger will include the calling
-// method as a field.
-func SetReportCaller(include bool) {
- std.SetReportCaller(include)
-}
-
-// SetLevel sets the standard logger level.
-func SetLevel(level Level) {
- std.SetLevel(level)
-}
-
-// GetLevel returns the standard logger level.
-func GetLevel() Level {
- return std.GetLevel()
-}
-
-// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
-func IsLevelEnabled(level Level) bool {
- return std.IsLevelEnabled(level)
-}
-
-// AddHook adds a hook to the standard logger hooks.
-func AddHook(hook Hook) {
- std.AddHook(hook)
-}
-
-// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
-func WithError(err error) *Entry {
- return std.WithField(ErrorKey, err)
-}
-
-// WithContext creates an entry from the standard logger and adds a context to it.
-func WithContext(ctx context.Context) *Entry {
- return std.WithContext(ctx)
-}
-
-// WithField creates an entry from the standard logger and adds a field to
-// it. If you want multiple fields, use `WithFields`.
-//
-// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
-// or Panic on the Entry it returns.
-func WithField(key string, value interface{}) *Entry {
- return std.WithField(key, value)
-}
-
-// WithFields creates an entry from the standard logger and adds multiple
-// fields to it. This is simply a helper for `WithField`, invoking it
-// once for each field.
-//
-// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
-// or Panic on the Entry it returns.
-func WithFields(fields Fields) *Entry {
- return std.WithFields(fields)
-}
-
-// WithTime creates an entry from the standard logger and overrides the time of
-// logs generated with it.
-//
-// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
-// or Panic on the Entry it returns.
-func WithTime(t time.Time) *Entry {
- return std.WithTime(t)
-}
-
-// Trace logs a message at level Trace on the standard logger.
-func Trace(args ...interface{}) {
- std.Trace(args...)
-}
-
-// Debug logs a message at level Debug on the standard logger.
-func Debug(args ...interface{}) {
- std.Debug(args...)
-}
-
-// Print logs a message at level Info on the standard logger.
-func Print(args ...interface{}) {
- std.Print(args...)
-}
-
-// Info logs a message at level Info on the standard logger.
-func Info(args ...interface{}) {
- std.Info(args...)
-}
-
-// Warn logs a message at level Warn on the standard logger.
-func Warn(args ...interface{}) {
- std.Warn(args...)
-}
-
-// Warning logs a message at level Warn on the standard logger.
-func Warning(args ...interface{}) {
- std.Warning(args...)
-}
-
-// Error logs a message at level Error on the standard logger.
-func Error(args ...interface{}) {
- std.Error(args...)
-}
-
-// Panic logs a message at level Panic on the standard logger.
-func Panic(args ...interface{}) {
- std.Panic(args...)
-}
-
-// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
-func Fatal(args ...interface{}) {
- std.Fatal(args...)
-}
-
-// TraceFn logs a message from a func at level Trace on the standard logger.
-func TraceFn(fn LogFunction) {
- std.TraceFn(fn)
-}
-
-// DebugFn logs a message from a func at level Debug on the standard logger.
-func DebugFn(fn LogFunction) {
- std.DebugFn(fn)
-}
-
-// PrintFn logs a message from a func at level Info on the standard logger.
-func PrintFn(fn LogFunction) {
- std.PrintFn(fn)
-}
-
-// InfoFn logs a message from a func at level Info on the standard logger.
-func InfoFn(fn LogFunction) {
- std.InfoFn(fn)
-}
-
-// WarnFn logs a message from a func at level Warn on the standard logger.
-func WarnFn(fn LogFunction) {
- std.WarnFn(fn)
-}
-
-// WarningFn logs a message from a func at level Warn on the standard logger.
-func WarningFn(fn LogFunction) {
- std.WarningFn(fn)
-}
-
-// ErrorFn logs a message from a func at level Error on the standard logger.
-func ErrorFn(fn LogFunction) {
- std.ErrorFn(fn)
-}
-
-// PanicFn logs a message from a func at level Panic on the standard logger.
-func PanicFn(fn LogFunction) {
- std.PanicFn(fn)
-}
-
-// FatalFn logs a message from a func at level Fatal on the standard logger then the process will exit with status set to 1.
-func FatalFn(fn LogFunction) {
- std.FatalFn(fn)
-}
-
-// Tracef logs a message at level Trace on the standard logger.
-func Tracef(format string, args ...interface{}) {
- std.Tracef(format, args...)
-}
-
-// Debugf logs a message at level Debug on the standard logger.
-func Debugf(format string, args ...interface{}) {
- std.Debugf(format, args...)
-}
-
-// Printf logs a message at level Info on the standard logger.
-func Printf(format string, args ...interface{}) {
- std.Printf(format, args...)
-}
-
-// Infof logs a message at level Info on the standard logger.
-func Infof(format string, args ...interface{}) {
- std.Infof(format, args...)
-}
-
-// Warnf logs a message at level Warn on the standard logger.
-func Warnf(format string, args ...interface{}) {
- std.Warnf(format, args...)
-}
-
-// Warningf logs a message at level Warn on the standard logger.
-func Warningf(format string, args ...interface{}) {
- std.Warningf(format, args...)
-}
-
-// Errorf logs a message at level Error on the standard logger.
-func Errorf(format string, args ...interface{}) {
- std.Errorf(format, args...)
-}
-
-// Panicf logs a message at level Panic on the standard logger.
-func Panicf(format string, args ...interface{}) {
- std.Panicf(format, args...)
-}
-
-// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
-func Fatalf(format string, args ...interface{}) {
- std.Fatalf(format, args...)
-}
-
-// Traceln logs a message at level Trace on the standard logger.
-func Traceln(args ...interface{}) {
- std.Traceln(args...)
-}
-
-// Debugln logs a message at level Debug on the standard logger.
-func Debugln(args ...interface{}) {
- std.Debugln(args...)
-}
-
-// Println logs a message at level Info on the standard logger.
-func Println(args ...interface{}) {
- std.Println(args...)
-}
-
-// Infoln logs a message at level Info on the standard logger.
-func Infoln(args ...interface{}) {
- std.Infoln(args...)
-}
-
-// Warnln logs a message at level Warn on the standard logger.
-func Warnln(args ...interface{}) {
- std.Warnln(args...)
-}
-
-// Warningln logs a message at level Warn on the standard logger.
-func Warningln(args ...interface{}) {
- std.Warningln(args...)
-}
-
-// Errorln logs a message at level Error on the standard logger.
-func Errorln(args ...interface{}) {
- std.Errorln(args...)
-}
-
-// Panicln logs a message at level Panic on the standard logger.
-func Panicln(args ...interface{}) {
- std.Panicln(args...)
-}
-
-// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
-func Fatalln(args ...interface{}) {
- std.Fatalln(args...)
-}
diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go
deleted file mode 100644
index 4088837..0000000
--- a/vendor/github.com/sirupsen/logrus/formatter.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package logrus
-
-import "time"
-
-// Default key names for the default fields
-const (
- defaultTimestampFormat = time.RFC3339
- FieldKeyMsg = "msg"
- FieldKeyLevel = "level"
- FieldKeyTime = "time"
- FieldKeyLogrusError = "logrus_error"
- FieldKeyFunc = "func"
- FieldKeyFile = "file"
-)
-
-// The Formatter interface is used to implement a custom Formatter. It takes an
-// `Entry`. It exposes all the fields, including the default ones:
-//
-// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
-// * `entry.Data["time"]`. The timestamp.
-// * `entry.Data["level"]. The level the entry was logged at.
-//
-// Any additional fields added with `WithField` or `WithFields` are also in
-// `entry.Data`. Format is expected to return an array of bytes which are then
-// logged to `logger.Out`.
-type Formatter interface {
- Format(*Entry) ([]byte, error)
-}
-
-// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
-// dumping it. If this code wasn't there doing:
-//
-// logrus.WithField("level", 1).Info("hello")
-//
-// Would just silently drop the user provided level. Instead with this code
-// it'll logged as:
-//
-// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
-//
-// It's not exported because it's still using Data in an opinionated way. It's to
-// avoid code duplication between the two default formatters.
-func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
- timeKey := fieldMap.resolve(FieldKeyTime)
- if t, ok := data[timeKey]; ok {
- data["fields."+timeKey] = t
- delete(data, timeKey)
- }
-
- msgKey := fieldMap.resolve(FieldKeyMsg)
- if m, ok := data[msgKey]; ok {
- data["fields."+msgKey] = m
- delete(data, msgKey)
- }
-
- levelKey := fieldMap.resolve(FieldKeyLevel)
- if l, ok := data[levelKey]; ok {
- data["fields."+levelKey] = l
- delete(data, levelKey)
- }
-
- logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
- if l, ok := data[logrusErrKey]; ok {
- data["fields."+logrusErrKey] = l
- delete(data, logrusErrKey)
- }
-
- // If reportCaller is not set, 'func' will not conflict.
- if reportCaller {
- funcKey := fieldMap.resolve(FieldKeyFunc)
- if l, ok := data[funcKey]; ok {
- data["fields."+funcKey] = l
- }
- fileKey := fieldMap.resolve(FieldKeyFile)
- if l, ok := data[fileKey]; ok {
- data["fields."+fileKey] = l
- }
- }
-}
diff --git a/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go
deleted file mode 100644
index 3f151cd..0000000
--- a/vendor/github.com/sirupsen/logrus/hooks.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package logrus
-
-// A hook to be fired when logging on the logging levels returned from
-// `Levels()` on your implementation of the interface. Note that this is not
-// fired in a goroutine or a channel with workers, you should handle such
-// functionality yourself if your call is non-blocking and you don't wish for
-// the logging calls for levels returned from `Levels()` to block.
-type Hook interface {
- Levels() []Level
- Fire(*Entry) error
-}
-
-// Internal type for storing the hooks on a logger instance.
-type LevelHooks map[Level][]Hook
-
-// Add a hook to an instance of logger. This is called with
-// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
-func (hooks LevelHooks) Add(hook Hook) {
- for _, level := range hook.Levels() {
- hooks[level] = append(hooks[level], hook)
- }
-}
-
-// Fire all the hooks for the passed level. Used by `entry.log` to fire
-// appropriate hooks for a log entry.
-func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
- for _, hook := range hooks[level] {
- if err := hook.Fire(entry); err != nil {
- return err
- }
- }
-
- return nil
-}
diff --git a/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/sirupsen/logrus/json_formatter.go
deleted file mode 100644
index c96dc56..0000000
--- a/vendor/github.com/sirupsen/logrus/json_formatter.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package logrus
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "runtime"
-)
-
-type fieldKey string
-
-// FieldMap allows customization of the key names for default fields.
-type FieldMap map[fieldKey]string
-
-func (f FieldMap) resolve(key fieldKey) string {
- if k, ok := f[key]; ok {
- return k
- }
-
- return string(key)
-}
-
-// JSONFormatter formats logs into parsable json
-type JSONFormatter struct {
- // TimestampFormat sets the format used for marshaling timestamps.
- // The format to use is the same than for time.Format or time.Parse from the standard
- // library.
- // The standard Library already provides a set of predefined format.
- TimestampFormat string
-
- // DisableTimestamp allows disabling automatic timestamps in output
- DisableTimestamp bool
-
- // DisableHTMLEscape allows disabling html escaping in output
- DisableHTMLEscape bool
-
- // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
- DataKey string
-
- // FieldMap allows users to customize the names of keys for default fields.
- // As an example:
- // formatter := &JSONFormatter{
- // FieldMap: FieldMap{
- // FieldKeyTime: "@timestamp",
- // FieldKeyLevel: "@level",
- // FieldKeyMsg: "@message",
- // FieldKeyFunc: "@caller",
- // },
- // }
- FieldMap FieldMap
-
- // CallerPrettyfier can be set by the user to modify the content
- // of the function and file keys in the json data when ReportCaller is
- // activated. If any of the returned value is the empty string the
- // corresponding key will be removed from json fields.
- CallerPrettyfier func(*runtime.Frame) (function string, file string)
-
- // PrettyPrint will indent all json logs
- PrettyPrint bool
-}
-
-// Format renders a single log entry
-func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
- data := make(Fields, len(entry.Data)+4)
- for k, v := range entry.Data {
- switch v := v.(type) {
- case error:
- // Otherwise errors are ignored by `encoding/json`
- // https://github.com/sirupsen/logrus/issues/137
- data[k] = v.Error()
- default:
- data[k] = v
- }
- }
-
- if f.DataKey != "" {
- newData := make(Fields, 4)
- newData[f.DataKey] = data
- data = newData
- }
-
- prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
-
- timestampFormat := f.TimestampFormat
- if timestampFormat == "" {
- timestampFormat = defaultTimestampFormat
- }
-
- if entry.err != "" {
- data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
- }
- if !f.DisableTimestamp {
- data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
- }
- data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
- data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
- if entry.HasCaller() {
- funcVal := entry.Caller.Function
- fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
- if f.CallerPrettyfier != nil {
- funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
- }
- if funcVal != "" {
- data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
- }
- if fileVal != "" {
- data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
- }
- }
-
- var b *bytes.Buffer
- if entry.Buffer != nil {
- b = entry.Buffer
- } else {
- b = &bytes.Buffer{}
- }
-
- encoder := json.NewEncoder(b)
- encoder.SetEscapeHTML(!f.DisableHTMLEscape)
- if f.PrettyPrint {
- encoder.SetIndent("", " ")
- }
- if err := encoder.Encode(data); err != nil {
- return nil, fmt.Errorf("failed to marshal fields to JSON, %w", err)
- }
-
- return b.Bytes(), nil
-}
diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go
deleted file mode 100644
index 5ff0aef..0000000
--- a/vendor/github.com/sirupsen/logrus/logger.go
+++ /dev/null
@@ -1,417 +0,0 @@
-package logrus
-
-import (
- "context"
- "io"
- "os"
- "sync"
- "sync/atomic"
- "time"
-)
-
-// LogFunction For big messages, it can be more efficient to pass a function
-// and only call it if the log level is actually enables rather than
-// generating the log message and then checking if the level is enabled
-type LogFunction func() []interface{}
-
-type Logger struct {
- // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
- // file, or leave it default which is `os.Stderr`. You can also set this to
- // something more adventurous, such as logging to Kafka.
- Out io.Writer
- // Hooks for the logger instance. These allow firing events based on logging
- // levels and log entries. For example, to send errors to an error tracking
- // service, log to StatsD or dump the core on fatal errors.
- Hooks LevelHooks
- // All log entries pass through the formatter before logged to Out. The
- // included formatters are `TextFormatter` and `JSONFormatter` for which
- // TextFormatter is the default. In development (when a TTY is attached) it
- // logs with colors, but to a file it wouldn't. You can easily implement your
- // own that implements the `Formatter` interface, see the `README` or included
- // formatters for examples.
- Formatter Formatter
-
- // Flag for whether to log caller info (off by default)
- ReportCaller bool
-
- // The logging level the logger should log at. This is typically (and defaults
- // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
- // logged.
- Level Level
- // Used to sync writing to the log. Locking is enabled by Default
- mu MutexWrap
- // Reusable empty entry
- entryPool sync.Pool
- // Function to exit the application, defaults to `os.Exit()`
- ExitFunc exitFunc
- // The buffer pool used to format the log. If it is nil, the default global
- // buffer pool will be used.
- BufferPool BufferPool
-}
-
-type exitFunc func(int)
-
-type MutexWrap struct {
- lock sync.Mutex
- disabled bool
-}
-
-func (mw *MutexWrap) Lock() {
- if !mw.disabled {
- mw.lock.Lock()
- }
-}
-
-func (mw *MutexWrap) Unlock() {
- if !mw.disabled {
- mw.lock.Unlock()
- }
-}
-
-func (mw *MutexWrap) Disable() {
- mw.disabled = true
-}
-
-// Creates a new logger. Configuration should be set by changing `Formatter`,
-// `Out` and `Hooks` directly on the default logger instance. You can also just
-// instantiate your own:
-//
-// var log = &logrus.Logger{
-// Out: os.Stderr,
-// Formatter: new(logrus.TextFormatter),
-// Hooks: make(logrus.LevelHooks),
-// Level: logrus.DebugLevel,
-// }
-//
-// It's recommended to make this a global instance called `log`.
-func New() *Logger {
- return &Logger{
- Out: os.Stderr,
- Formatter: new(TextFormatter),
- Hooks: make(LevelHooks),
- Level: InfoLevel,
- ExitFunc: os.Exit,
- ReportCaller: false,
- }
-}
-
-func (logger *Logger) newEntry() *Entry {
- entry, ok := logger.entryPool.Get().(*Entry)
- if ok {
- return entry
- }
- return NewEntry(logger)
-}
-
-func (logger *Logger) releaseEntry(entry *Entry) {
- entry.Data = map[string]interface{}{}
- logger.entryPool.Put(entry)
-}
-
-// WithField allocates a new entry and adds a field to it.
-// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
-// this new returned entry.
-// If you want multiple fields, use `WithFields`.
-func (logger *Logger) WithField(key string, value interface{}) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithField(key, value)
-}
-
-// Adds a struct of fields to the log entry. All it does is call `WithField` for
-// each `Field`.
-func (logger *Logger) WithFields(fields Fields) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithFields(fields)
-}
-
-// Add an error as single field to the log entry. All it does is call
-// `WithError` for the given `error`.
-func (logger *Logger) WithError(err error) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithError(err)
-}
-
-// Add a context to the log entry.
-func (logger *Logger) WithContext(ctx context.Context) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithContext(ctx)
-}
-
-// Overrides the time of the log entry.
-func (logger *Logger) WithTime(t time.Time) *Entry {
- entry := logger.newEntry()
- defer logger.releaseEntry(entry)
- return entry.WithTime(t)
-}
-
-func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Logf(level, format, args...)
- logger.releaseEntry(entry)
- }
-}
-
-func (logger *Logger) Tracef(format string, args ...interface{}) {
- logger.Logf(TraceLevel, format, args...)
-}
-
-func (logger *Logger) Debugf(format string, args ...interface{}) {
- logger.Logf(DebugLevel, format, args...)
-}
-
-func (logger *Logger) Infof(format string, args ...interface{}) {
- logger.Logf(InfoLevel, format, args...)
-}
-
-func (logger *Logger) Printf(format string, args ...interface{}) {
- entry := logger.newEntry()
- entry.Printf(format, args...)
- logger.releaseEntry(entry)
-}
-
-func (logger *Logger) Warnf(format string, args ...interface{}) {
- logger.Logf(WarnLevel, format, args...)
-}
-
-func (logger *Logger) Warningf(format string, args ...interface{}) {
- logger.Warnf(format, args...)
-}
-
-func (logger *Logger) Errorf(format string, args ...interface{}) {
- logger.Logf(ErrorLevel, format, args...)
-}
-
-func (logger *Logger) Fatalf(format string, args ...interface{}) {
- logger.Logf(FatalLevel, format, args...)
- logger.Exit(1)
-}
-
-func (logger *Logger) Panicf(format string, args ...interface{}) {
- logger.Logf(PanicLevel, format, args...)
-}
-
-// Log will log a message at the level given as parameter.
-// Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit.
-// For this behaviour Logger.Panic or Logger.Fatal should be used instead.
-func (logger *Logger) Log(level Level, args ...interface{}) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Log(level, args...)
- logger.releaseEntry(entry)
- }
-}
-
-func (logger *Logger) LogFn(level Level, fn LogFunction) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Log(level, fn()...)
- logger.releaseEntry(entry)
- }
-}
-
-func (logger *Logger) Trace(args ...interface{}) {
- logger.Log(TraceLevel, args...)
-}
-
-func (logger *Logger) Debug(args ...interface{}) {
- logger.Log(DebugLevel, args...)
-}
-
-func (logger *Logger) Info(args ...interface{}) {
- logger.Log(InfoLevel, args...)
-}
-
-func (logger *Logger) Print(args ...interface{}) {
- entry := logger.newEntry()
- entry.Print(args...)
- logger.releaseEntry(entry)
-}
-
-func (logger *Logger) Warn(args ...interface{}) {
- logger.Log(WarnLevel, args...)
-}
-
-func (logger *Logger) Warning(args ...interface{}) {
- logger.Warn(args...)
-}
-
-func (logger *Logger) Error(args ...interface{}) {
- logger.Log(ErrorLevel, args...)
-}
-
-func (logger *Logger) Fatal(args ...interface{}) {
- logger.Log(FatalLevel, args...)
- logger.Exit(1)
-}
-
-func (logger *Logger) Panic(args ...interface{}) {
- logger.Log(PanicLevel, args...)
-}
-
-func (logger *Logger) TraceFn(fn LogFunction) {
- logger.LogFn(TraceLevel, fn)
-}
-
-func (logger *Logger) DebugFn(fn LogFunction) {
- logger.LogFn(DebugLevel, fn)
-}
-
-func (logger *Logger) InfoFn(fn LogFunction) {
- logger.LogFn(InfoLevel, fn)
-}
-
-func (logger *Logger) PrintFn(fn LogFunction) {
- entry := logger.newEntry()
- entry.Print(fn()...)
- logger.releaseEntry(entry)
-}
-
-func (logger *Logger) WarnFn(fn LogFunction) {
- logger.LogFn(WarnLevel, fn)
-}
-
-func (logger *Logger) WarningFn(fn LogFunction) {
- logger.WarnFn(fn)
-}
-
-func (logger *Logger) ErrorFn(fn LogFunction) {
- logger.LogFn(ErrorLevel, fn)
-}
-
-func (logger *Logger) FatalFn(fn LogFunction) {
- logger.LogFn(FatalLevel, fn)
- logger.Exit(1)
-}
-
-func (logger *Logger) PanicFn(fn LogFunction) {
- logger.LogFn(PanicLevel, fn)
-}
-
-func (logger *Logger) Logln(level Level, args ...interface{}) {
- if logger.IsLevelEnabled(level) {
- entry := logger.newEntry()
- entry.Logln(level, args...)
- logger.releaseEntry(entry)
- }
-}
-
-func (logger *Logger) Traceln(args ...interface{}) {
- logger.Logln(TraceLevel, args...)
-}
-
-func (logger *Logger) Debugln(args ...interface{}) {
- logger.Logln(DebugLevel, args...)
-}
-
-func (logger *Logger) Infoln(args ...interface{}) {
- logger.Logln(InfoLevel, args...)
-}
-
-func (logger *Logger) Println(args ...interface{}) {
- entry := logger.newEntry()
- entry.Println(args...)
- logger.releaseEntry(entry)
-}
-
-func (logger *Logger) Warnln(args ...interface{}) {
- logger.Logln(WarnLevel, args...)
-}
-
-func (logger *Logger) Warningln(args ...interface{}) {
- logger.Warnln(args...)
-}
-
-func (logger *Logger) Errorln(args ...interface{}) {
- logger.Logln(ErrorLevel, args...)
-}
-
-func (logger *Logger) Fatalln(args ...interface{}) {
- logger.Logln(FatalLevel, args...)
- logger.Exit(1)
-}
-
-func (logger *Logger) Panicln(args ...interface{}) {
- logger.Logln(PanicLevel, args...)
-}
-
-func (logger *Logger) Exit(code int) {
- runHandlers()
- if logger.ExitFunc == nil {
- logger.ExitFunc = os.Exit
- }
- logger.ExitFunc(code)
-}
-
-//When file is opened with appending mode, it's safe to
-//write concurrently to a file (within 4k message on Linux).
-//In these cases user can choose to disable the lock.
-func (logger *Logger) SetNoLock() {
- logger.mu.Disable()
-}
-
-func (logger *Logger) level() Level {
- return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
-}
-
-// SetLevel sets the logger level.
-func (logger *Logger) SetLevel(level Level) {
- atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
-}
-
-// GetLevel returns the logger level.
-func (logger *Logger) GetLevel() Level {
- return logger.level()
-}
-
-// AddHook adds a hook to the logger hooks.
-func (logger *Logger) AddHook(hook Hook) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.Hooks.Add(hook)
-}
-
-// IsLevelEnabled checks if the log level of the logger is greater than the level param
-func (logger *Logger) IsLevelEnabled(level Level) bool {
- return logger.level() >= level
-}
-
-// SetFormatter sets the logger formatter.
-func (logger *Logger) SetFormatter(formatter Formatter) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.Formatter = formatter
-}
-
-// SetOutput sets the logger output.
-func (logger *Logger) SetOutput(output io.Writer) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.Out = output
-}
-
-func (logger *Logger) SetReportCaller(reportCaller bool) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.ReportCaller = reportCaller
-}
-
-// ReplaceHooks replaces the logger hooks and returns the old ones
-func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
- logger.mu.Lock()
- oldHooks := logger.Hooks
- logger.Hooks = hooks
- logger.mu.Unlock()
- return oldHooks
-}
-
-// SetBufferPool sets the logger buffer pool.
-func (logger *Logger) SetBufferPool(pool BufferPool) {
- logger.mu.Lock()
- defer logger.mu.Unlock()
- logger.BufferPool = pool
-}
diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go
deleted file mode 100644
index 2f16224..0000000
--- a/vendor/github.com/sirupsen/logrus/logrus.go
+++ /dev/null
@@ -1,186 +0,0 @@
-package logrus
-
-import (
- "fmt"
- "log"
- "strings"
-)
-
-// Fields type, used to pass to `WithFields`.
-type Fields map[string]interface{}
-
-// Level type
-type Level uint32
-
-// Convert the Level to a string. E.g. PanicLevel becomes "panic".
-func (level Level) String() string {
- if b, err := level.MarshalText(); err == nil {
- return string(b)
- } else {
- return "unknown"
- }
-}
-
-// ParseLevel takes a string level and returns the Logrus log level constant.
-func ParseLevel(lvl string) (Level, error) {
- switch strings.ToLower(lvl) {
- case "panic":
- return PanicLevel, nil
- case "fatal":
- return FatalLevel, nil
- case "error":
- return ErrorLevel, nil
- case "warn", "warning":
- return WarnLevel, nil
- case "info":
- return InfoLevel, nil
- case "debug":
- return DebugLevel, nil
- case "trace":
- return TraceLevel, nil
- }
-
- var l Level
- return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
-}
-
-// UnmarshalText implements encoding.TextUnmarshaler.
-func (level *Level) UnmarshalText(text []byte) error {
- l, err := ParseLevel(string(text))
- if err != nil {
- return err
- }
-
- *level = l
-
- return nil
-}
-
-func (level Level) MarshalText() ([]byte, error) {
- switch level {
- case TraceLevel:
- return []byte("trace"), nil
- case DebugLevel:
- return []byte("debug"), nil
- case InfoLevel:
- return []byte("info"), nil
- case WarnLevel:
- return []byte("warning"), nil
- case ErrorLevel:
- return []byte("error"), nil
- case FatalLevel:
- return []byte("fatal"), nil
- case PanicLevel:
- return []byte("panic"), nil
- }
-
- return nil, fmt.Errorf("not a valid logrus level %d", level)
-}
-
-// A constant exposing all logging levels
-var AllLevels = []Level{
- PanicLevel,
- FatalLevel,
- ErrorLevel,
- WarnLevel,
- InfoLevel,
- DebugLevel,
- TraceLevel,
-}
-
-// These are the different logging levels. You can set the logging level to log
-// on your instance of logger, obtained with `logrus.New()`.
-const (
- // PanicLevel level, highest level of severity. Logs and then calls panic with the
- // message passed to Debug, Info, ...
- PanicLevel Level = iota
- // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
- // logging level is set to Panic.
- FatalLevel
- // ErrorLevel level. Logs. Used for errors that should definitely be noted.
- // Commonly used for hooks to send errors to an error tracking service.
- ErrorLevel
- // WarnLevel level. Non-critical entries that deserve eyes.
- WarnLevel
- // InfoLevel level. General operational entries about what's going on inside the
- // application.
- InfoLevel
- // DebugLevel level. Usually only enabled when debugging. Very verbose logging.
- DebugLevel
- // TraceLevel level. Designates finer-grained informational events than the Debug.
- TraceLevel
-)
-
-// Won't compile if StdLogger can't be realized by a log.Logger
-var (
- _ StdLogger = &log.Logger{}
- _ StdLogger = &Entry{}
- _ StdLogger = &Logger{}
-)
-
-// StdLogger is what your logrus-enabled library should take, that way
-// it'll accept a stdlib logger and a logrus logger. There's no standard
-// interface, this is the closest we get, unfortunately.
-type StdLogger interface {
- Print(...interface{})
- Printf(string, ...interface{})
- Println(...interface{})
-
- Fatal(...interface{})
- Fatalf(string, ...interface{})
- Fatalln(...interface{})
-
- Panic(...interface{})
- Panicf(string, ...interface{})
- Panicln(...interface{})
-}
-
-// The FieldLogger interface generalizes the Entry and Logger types
-type FieldLogger interface {
- WithField(key string, value interface{}) *Entry
- WithFields(fields Fields) *Entry
- WithError(err error) *Entry
-
- Debugf(format string, args ...interface{})
- Infof(format string, args ...interface{})
- Printf(format string, args ...interface{})
- Warnf(format string, args ...interface{})
- Warningf(format string, args ...interface{})
- Errorf(format string, args ...interface{})
- Fatalf(format string, args ...interface{})
- Panicf(format string, args ...interface{})
-
- Debug(args ...interface{})
- Info(args ...interface{})
- Print(args ...interface{})
- Warn(args ...interface{})
- Warning(args ...interface{})
- Error(args ...interface{})
- Fatal(args ...interface{})
- Panic(args ...interface{})
-
- Debugln(args ...interface{})
- Infoln(args ...interface{})
- Println(args ...interface{})
- Warnln(args ...interface{})
- Warningln(args ...interface{})
- Errorln(args ...interface{})
- Fatalln(args ...interface{})
- Panicln(args ...interface{})
-
- // IsDebugEnabled() bool
- // IsInfoEnabled() bool
- // IsWarnEnabled() bool
- // IsErrorEnabled() bool
- // IsFatalEnabled() bool
- // IsPanicEnabled() bool
-}
-
-// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
-// here for consistancy. Do not use. Use Logger or Entry instead.
-type Ext1FieldLogger interface {
- FieldLogger
- Tracef(format string, args ...interface{})
- Trace(args ...interface{})
- Traceln(args ...interface{})
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
deleted file mode 100644
index 2403de9..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build appengine
-
-package logrus
-
-import (
- "io"
-)
-
-func checkIfTerminal(w io.Writer) bool {
- return true
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
deleted file mode 100644
index 4997899..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// +build darwin dragonfly freebsd netbsd openbsd
-// +build !js
-
-package logrus
-
-import "golang.org/x/sys/unix"
-
-const ioctlReadTermios = unix.TIOCGETA
-
-func isTerminal(fd int) bool {
- _, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
- return err == nil
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/sirupsen/logrus/terminal_check_js.go
deleted file mode 100644
index ebdae3e..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_js.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// +build js
-
-package logrus
-
-func isTerminal(fd int) bool {
- return false
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
deleted file mode 100644
index 97af92c..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build js nacl plan9
-
-package logrus
-
-import (
- "io"
-)
-
-func checkIfTerminal(w io.Writer) bool {
- return false
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
deleted file mode 100644
index 3293fb3..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// +build !appengine,!js,!windows,!nacl,!plan9
-
-package logrus
-
-import (
- "io"
- "os"
-)
-
-func checkIfTerminal(w io.Writer) bool {
- switch v := w.(type) {
- case *os.File:
- return isTerminal(int(v.Fd()))
- default:
- return false
- }
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go b/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
deleted file mode 100644
index f6710b3..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package logrus
-
-import (
- "golang.org/x/sys/unix"
-)
-
-// IsTerminal returns true if the given file descriptor is a terminal.
-func isTerminal(fd int) bool {
- _, err := unix.IoctlGetTermio(fd, unix.TCGETA)
- return err == nil
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
deleted file mode 100644
index 04748b8..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// +build linux aix zos
-// +build !js
-
-package logrus
-
-import "golang.org/x/sys/unix"
-
-const ioctlReadTermios = unix.TCGETS
-
-func isTerminal(fd int) bool {
- _, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
- return err == nil
-}
diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go
deleted file mode 100644
index 2879eb5..0000000
--- a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// +build !appengine,!js,windows
-
-package logrus
-
-import (
- "io"
- "os"
-
- "golang.org/x/sys/windows"
-)
-
-func checkIfTerminal(w io.Writer) bool {
- switch v := w.(type) {
- case *os.File:
- handle := windows.Handle(v.Fd())
- var mode uint32
- if err := windows.GetConsoleMode(handle, &mode); err != nil {
- return false
- }
- mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
- if err := windows.SetConsoleMode(handle, mode); err != nil {
- return false
- }
- return true
- }
- return false
-}
diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go
deleted file mode 100644
index be2c6ef..0000000
--- a/vendor/github.com/sirupsen/logrus/text_formatter.go
+++ /dev/null
@@ -1,339 +0,0 @@
-package logrus
-
-import (
- "bytes"
- "fmt"
- "os"
- "runtime"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
- "unicode/utf8"
-)
-
-const (
- red = 31
- yellow = 33
- blue = 36
- gray = 37
-)
-
-var baseTimestamp time.Time
-
-func init() {
- baseTimestamp = time.Now()
-}
-
-// TextFormatter formats logs into text
-type TextFormatter struct {
- // Set to true to bypass checking for a TTY before outputting colors.
- ForceColors bool
-
- // Force disabling colors.
- DisableColors bool
-
- // Force quoting of all values
- ForceQuote bool
-
- // DisableQuote disables quoting for all values.
- // DisableQuote will have a lower priority than ForceQuote.
- // If both of them are set to true, quote will be forced on all values.
- DisableQuote bool
-
- // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
- EnvironmentOverrideColors bool
-
- // Disable timestamp logging. useful when output is redirected to logging
- // system that already adds timestamps.
- DisableTimestamp bool
-
- // Enable logging the full timestamp when a TTY is attached instead of just
- // the time passed since beginning of execution.
- FullTimestamp bool
-
- // TimestampFormat to use for display when a full timestamp is printed.
- // The format to use is the same than for time.Format or time.Parse from the standard
- // library.
- // The standard Library already provides a set of predefined format.
- TimestampFormat string
-
- // The fields are sorted by default for a consistent output. For applications
- // that log extremely frequently and don't use the JSON formatter this may not
- // be desired.
- DisableSorting bool
-
- // The keys sorting function, when uninitialized it uses sort.Strings.
- SortingFunc func([]string)
-
- // Disables the truncation of the level text to 4 characters.
- DisableLevelTruncation bool
-
- // PadLevelText Adds padding the level text so that all the levels output at the same length
- // PadLevelText is a superset of the DisableLevelTruncation option
- PadLevelText bool
-
- // QuoteEmptyFields will wrap empty fields in quotes if true
- QuoteEmptyFields bool
-
- // Whether the logger's out is to a terminal
- isTerminal bool
-
- // FieldMap allows users to customize the names of keys for default fields.
- // As an example:
- // formatter := &TextFormatter{
- // FieldMap: FieldMap{
- // FieldKeyTime: "@timestamp",
- // FieldKeyLevel: "@level",
- // FieldKeyMsg: "@message"}}
- FieldMap FieldMap
-
- // CallerPrettyfier can be set by the user to modify the content
- // of the function and file keys in the data when ReportCaller is
- // activated. If any of the returned value is the empty string the
- // corresponding key will be removed from fields.
- CallerPrettyfier func(*runtime.Frame) (function string, file string)
-
- terminalInitOnce sync.Once
-
- // The max length of the level text, generated dynamically on init
- levelTextMaxLength int
-}
-
-func (f *TextFormatter) init(entry *Entry) {
- if entry.Logger != nil {
- f.isTerminal = checkIfTerminal(entry.Logger.Out)
- }
- // Get the max length of the level text
- for _, level := range AllLevels {
- levelTextLength := utf8.RuneCount([]byte(level.String()))
- if levelTextLength > f.levelTextMaxLength {
- f.levelTextMaxLength = levelTextLength
- }
- }
-}
-
-func (f *TextFormatter) isColored() bool {
- isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows"))
-
- if f.EnvironmentOverrideColors {
- switch force, ok := os.LookupEnv("CLICOLOR_FORCE"); {
- case ok && force != "0":
- isColored = true
- case ok && force == "0", os.Getenv("CLICOLOR") == "0":
- isColored = false
- }
- }
-
- return isColored && !f.DisableColors
-}
-
-// Format renders a single log entry
-func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
- data := make(Fields)
- for k, v := range entry.Data {
- data[k] = v
- }
- prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
- keys := make([]string, 0, len(data))
- for k := range data {
- keys = append(keys, k)
- }
-
- var funcVal, fileVal string
-
- fixedKeys := make([]string, 0, 4+len(data))
- if !f.DisableTimestamp {
- fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
- }
- fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel))
- if entry.Message != "" {
- fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
- }
- if entry.err != "" {
- fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
- }
- if entry.HasCaller() {
- if f.CallerPrettyfier != nil {
- funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
- } else {
- funcVal = entry.Caller.Function
- fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
- }
-
- if funcVal != "" {
- fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc))
- }
- if fileVal != "" {
- fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile))
- }
- }
-
- if !f.DisableSorting {
- if f.SortingFunc == nil {
- sort.Strings(keys)
- fixedKeys = append(fixedKeys, keys...)
- } else {
- if !f.isColored() {
- fixedKeys = append(fixedKeys, keys...)
- f.SortingFunc(fixedKeys)
- } else {
- f.SortingFunc(keys)
- }
- }
- } else {
- fixedKeys = append(fixedKeys, keys...)
- }
-
- var b *bytes.Buffer
- if entry.Buffer != nil {
- b = entry.Buffer
- } else {
- b = &bytes.Buffer{}
- }
-
- f.terminalInitOnce.Do(func() { f.init(entry) })
-
- timestampFormat := f.TimestampFormat
- if timestampFormat == "" {
- timestampFormat = defaultTimestampFormat
- }
- if f.isColored() {
- f.printColored(b, entry, keys, data, timestampFormat)
- } else {
-
- for _, key := range fixedKeys {
- var value interface{}
- switch {
- case key == f.FieldMap.resolve(FieldKeyTime):
- value = entry.Time.Format(timestampFormat)
- case key == f.FieldMap.resolve(FieldKeyLevel):
- value = entry.Level.String()
- case key == f.FieldMap.resolve(FieldKeyMsg):
- value = entry.Message
- case key == f.FieldMap.resolve(FieldKeyLogrusError):
- value = entry.err
- case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
- value = funcVal
- case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
- value = fileVal
- default:
- value = data[key]
- }
- f.appendKeyValue(b, key, value)
- }
- }
-
- b.WriteByte('\n')
- return b.Bytes(), nil
-}
-
-func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) {
- var levelColor int
- switch entry.Level {
- case DebugLevel, TraceLevel:
- levelColor = gray
- case WarnLevel:
- levelColor = yellow
- case ErrorLevel, FatalLevel, PanicLevel:
- levelColor = red
- case InfoLevel:
- levelColor = blue
- default:
- levelColor = blue
- }
-
- levelText := strings.ToUpper(entry.Level.String())
- if !f.DisableLevelTruncation && !f.PadLevelText {
- levelText = levelText[0:4]
- }
- if f.PadLevelText {
- // Generates the format string used in the next line, for example "%-6s" or "%-7s".
- // Based on the max level text length.
- formatString := "%-" + strconv.Itoa(f.levelTextMaxLength) + "s"
- // Formats the level text by appending spaces up to the max length, for example:
- // - "INFO "
- // - "WARNING"
- levelText = fmt.Sprintf(formatString, levelText)
- }
-
- // Remove a single newline if it already exists in the message to keep
- // the behavior of logrus text_formatter the same as the stdlib log package
- entry.Message = strings.TrimSuffix(entry.Message, "\n")
-
- caller := ""
- if entry.HasCaller() {
- funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
- fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
-
- if f.CallerPrettyfier != nil {
- funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
- }
-
- if fileVal == "" {
- caller = funcVal
- } else if funcVal == "" {
- caller = fileVal
- } else {
- caller = fileVal + " " + funcVal
- }
- }
-
- switch {
- case f.DisableTimestamp:
- fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
- case !f.FullTimestamp:
- fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message)
- default:
- fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message)
- }
- for _, k := range keys {
- v := data[k]
- fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
- f.appendValue(b, v)
- }
-}
-
-func (f *TextFormatter) needsQuoting(text string) bool {
- if f.ForceQuote {
- return true
- }
- if f.QuoteEmptyFields && len(text) == 0 {
- return true
- }
- if f.DisableQuote {
- return false
- }
- for _, ch := range text {
- if !((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- (ch >= '0' && ch <= '9') ||
- ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
- return true
- }
- }
- return false
-}
-
-func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
- if b.Len() > 0 {
- b.WriteByte(' ')
- }
- b.WriteString(key)
- b.WriteByte('=')
- f.appendValue(b, value)
-}
-
-func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
- stringVal, ok := value.(string)
- if !ok {
- stringVal = fmt.Sprint(value)
- }
-
- if !f.needsQuoting(stringVal) {
- b.WriteString(stringVal)
- } else {
- b.WriteString(fmt.Sprintf("%q", stringVal))
- }
-}
diff --git a/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/sirupsen/logrus/writer.go
deleted file mode 100644
index 074fd4b..0000000
--- a/vendor/github.com/sirupsen/logrus/writer.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package logrus
-
-import (
- "bufio"
- "io"
- "runtime"
- "strings"
-)
-
-// Writer at INFO level. See WriterLevel for details.
-func (logger *Logger) Writer() *io.PipeWriter {
- return logger.WriterLevel(InfoLevel)
-}
-
-// WriterLevel returns an io.Writer that can be used to write arbitrary text to
-// the logger at the given log level. Each line written to the writer will be
-// printed in the usual way using formatters and hooks. The writer is part of an
-// io.Pipe and it is the callers responsibility to close the writer when done.
-// This can be used to override the standard library logger easily.
-func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
- return NewEntry(logger).WriterLevel(level)
-}
-
-// Writer returns an io.Writer that writes to the logger at the info log level
-func (entry *Entry) Writer() *io.PipeWriter {
- return entry.WriterLevel(InfoLevel)
-}
-
-// WriterLevel returns an io.Writer that writes to the logger at the given log level
-func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
- reader, writer := io.Pipe()
-
- var printFunc func(args ...interface{})
-
- // Determine which log function to use based on the specified log level
- switch level {
- case TraceLevel:
- printFunc = entry.Trace
- case DebugLevel:
- printFunc = entry.Debug
- case InfoLevel:
- printFunc = entry.Info
- case WarnLevel:
- printFunc = entry.Warn
- case ErrorLevel:
- printFunc = entry.Error
- case FatalLevel:
- printFunc = entry.Fatal
- case PanicLevel:
- printFunc = entry.Panic
- default:
- printFunc = entry.Print
- }
-
- // Start a new goroutine to scan the input and write it to the logger using the specified print function.
- // It splits the input into chunks of up to 64KB to avoid buffer overflows.
- go entry.writerScanner(reader, printFunc)
-
- // Set a finalizer function to close the writer when it is garbage collected
- runtime.SetFinalizer(writer, writerFinalizer)
-
- return writer
-}
-
-// writerScanner scans the input from the reader and writes it to the logger
-func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
- scanner := bufio.NewScanner(reader)
-
- // Set the buffer size to the maximum token size to avoid buffer overflows
- scanner.Buffer(make([]byte, bufio.MaxScanTokenSize), bufio.MaxScanTokenSize)
-
- // Define a split function to split the input into chunks of up to 64KB
- chunkSize := bufio.MaxScanTokenSize // 64KB
- splitFunc := func(data []byte, atEOF bool) (int, []byte, error) {
- if len(data) >= chunkSize {
- return chunkSize, data[:chunkSize], nil
- }
-
- return bufio.ScanLines(data, atEOF)
- }
-
- // Use the custom split function to split the input
- scanner.Split(splitFunc)
-
- // Scan the input and write it to the logger using the specified print function
- for scanner.Scan() {
- printFunc(strings.TrimRight(scanner.Text(), "\r\n"))
- }
-
- // If there was an error while scanning the input, log an error
- if err := scanner.Err(); err != nil {
- entry.Errorf("Error while reading from Writer: %s", err)
- }
-
- // Close the reader when we are done
- reader.Close()
-}
-
-// WriterFinalizer is a finalizer function that closes then given writer when it is garbage collected
-func writerFinalizer(writer *io.PipeWriter) {
- writer.Close()
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 8e9a9da..417dbdf 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -163,9 +163,6 @@ github.com/prometheus/procfs/internal/util
# github.com/rogpeppe/go-internal v1.12.0
## explicit; go 1.20
github.com/rogpeppe/go-internal/fmtsort
-# github.com/sirupsen/logrus v1.9.3
-## explicit; go 1.13
-github.com/sirupsen/logrus
# golang.org/x/crypto v0.25.0
## explicit; go 1.20
golang.org/x/crypto/pbkdf2