mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-06-05 23:03:48 +00:00
Extract helper libraries from private repo of telegram-bot.app
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
package libpack_config
|
||||||
|
|
||||||
|
var (
|
||||||
|
PKG_NAME string = "not-specified"
|
||||||
|
PKG_VERSION string = "0.0.0-dev"
|
||||||
|
)
|
||||||
+1
-1
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/lukaszraczylo/ask"
|
"github.com/lukaszraczylo/ask"
|
||||||
libpack_monitoring "github.com/telegram-bot-app/libpack/monitoring"
|
libpack_monitoring "github.com/lukaszraczylo/graphql-monitoring-proxy/monitoring"
|
||||||
)
|
)
|
||||||
|
|
||||||
func extractClaimsFromJWTHeader(authorization string) (usr string, role string) {
|
func extractClaimsFromJWTHeader(authorization string) (usr string, role string) {
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ module github.com/lukaszraczylo/graphql-monitoring-proxy
|
|||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/VictoriaMetrics/metrics v1.24.0
|
||||||
github.com/akyoto/cache v1.0.6
|
github.com/akyoto/cache v1.0.6
|
||||||
|
github.com/buger/jsonparser v1.1.1
|
||||||
github.com/gofiber/fiber/v2 v2.49.2
|
github.com/gofiber/fiber/v2 v2.49.2
|
||||||
github.com/gookit/goutil v0.6.12
|
github.com/gookit/goutil v0.6.12
|
||||||
github.com/graphql-go/graphql v0.8.1
|
github.com/graphql-go/graphql v0.8.1
|
||||||
@@ -11,20 +13,20 @@ require (
|
|||||||
github.com/lukaszraczylo/ask v0.0.0-20230927103145-2ff1123b4415
|
github.com/lukaszraczylo/ask v0.0.0-20230927103145-2ff1123b4415
|
||||||
github.com/lukaszraczylo/go-ratecounter v0.1.8
|
github.com/lukaszraczylo/go-ratecounter v0.1.8
|
||||||
github.com/lukaszraczylo/go-simple-graphql v1.1.31
|
github.com/lukaszraczylo/go-simple-graphql v1.1.31
|
||||||
|
github.com/rs/zerolog v1.31.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/telegram-bot-app/libpack v0.0.0-20231008100411-9f7f8bf94315
|
github.com/telegram-bot-app/lib-logging v0.0.19
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
github.com/VictoriaMetrics/metrics v1.24.0 // indirect
|
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||||
github.com/avast/retry-go/v4 v4.5.0 // indirect
|
github.com/avast/retry-go/v4 v4.5.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/google/uuid v1.3.1 // indirect
|
github.com/google/uuid v1.3.1 // indirect
|
||||||
github.com/gookit/color v1.5.4 // indirect
|
github.com/gookit/color v1.5.4 // indirect
|
||||||
github.com/klauspost/compress v1.17.0 // indirect
|
github.com/klauspost/compress v1.17.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/lukaszraczylo/pandati v0.0.29 // indirect
|
github.com/lukaszraczylo/pandati v0.0.29 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
@@ -33,8 +35,7 @@ require (
|
|||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/rs/zerolog v1.31.0 // indirect
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
github.com/telegram-bot-app/lib-logging v0.0.19 // indirect
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.50.0 // indirect
|
github.com/valyala/fasthttp v1.50.0 // indirect
|
||||||
github.com/valyala/fastrand v1.1.0 // indirect
|
github.com/valyala/fastrand v1.1.0 // indirect
|
||||||
@@ -42,10 +43,12 @@ require (
|
|||||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||||
github.com/wI2L/jsondiff v0.4.0 // indirect
|
github.com/wI2L/jsondiff v0.4.0 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/net v0.17.0 // indirect
|
||||||
golang.org/x/sync v0.4.0 // indirect
|
golang.org/x/sync v0.4.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
golang.org/x/term v0.13.0 // indirect
|
golang.org/x/term v0.13.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/text v0.13.0 // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,8 +31,11 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
|||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lukaszraczylo/ask v0.0.0-20230927103145-2ff1123b4415 h1:lvI8Wlbg4PxkRcg2f10wgoaRpfN19v+YdRek3+dLtlM=
|
github.com/lukaszraczylo/ask v0.0.0-20230927103145-2ff1123b4415 h1:lvI8Wlbg4PxkRcg2f10wgoaRpfN19v+YdRek3+dLtlM=
|
||||||
@@ -55,12 +58,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
@@ -72,8 +77,6 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
|||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/telegram-bot-app/lib-logging v0.0.19 h1:zbyFr2ygeBY+yuaB9moXyOGk8dIBCn0jPJQjvx7YvLE=
|
github.com/telegram-bot-app/lib-logging v0.0.19 h1:zbyFr2ygeBY+yuaB9moXyOGk8dIBCn0jPJQjvx7YvLE=
|
||||||
github.com/telegram-bot-app/lib-logging v0.0.19/go.mod h1:n8d29fRUTdgJhC4RZ8s4lP2RHiGCCRYEj2ENEClUGc8=
|
github.com/telegram-bot-app/lib-logging v0.0.19/go.mod h1:n8d29fRUTdgJhC4RZ8s4lP2RHiGCCRYEj2ENEClUGc8=
|
||||||
github.com/telegram-bot-app/libpack v0.0.0-20231008100411-9f7f8bf94315 h1:gf+3gFgtdh48RQNmLNdK1IcGqpuTuj6RAdHxDMd/YPY=
|
|
||||||
github.com/telegram-bot-app/libpack v0.0.0-20231008100411-9f7f8bf94315/go.mod h1:W2kWHcfNNS0r++dJ1T2XX/C4cTSxI3MsoiMbOtyqu+I=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M=
|
github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M=
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
|||||||
fiber "github.com/gofiber/fiber/v2"
|
fiber "github.com/gofiber/fiber/v2"
|
||||||
"github.com/graphql-go/graphql/language/ast"
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
"github.com/graphql-go/graphql/language/parser"
|
"github.com/graphql-go/graphql/language/parser"
|
||||||
libpack_monitoring "github.com/telegram-bot-app/libpack/monitoring"
|
libpack_monitoring "github.com/lukaszraczylo/graphql-monitoring-proxy/monitoring"
|
||||||
)
|
)
|
||||||
|
|
||||||
var retrospection_queries = []string{
|
var retrospection_queries = []string{
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package libpack_logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gookit/goutil/envutil"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogConfig struct {
|
||||||
|
logger zerolog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var baseLogger zerolog.Logger
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
zerolog.TimeFieldFormat = time.RFC3339
|
||||||
|
zerolog.MessageFieldName = "short_message"
|
||||||
|
zerolog.TimestampFieldName = "timestamp"
|
||||||
|
zerolog.LevelFieldName = "level"
|
||||||
|
zerolog.LevelFatalValue = "critical"
|
||||||
|
baseLogger = zerolog.New(os.Stdout).With().Timestamp().Logger()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger() *LogConfig {
|
||||||
|
switch logLevel := envutil.Getenv("LOG_LEVEL", "info"); logLevel {
|
||||||
|
case "debug":
|
||||||
|
baseLogger = baseLogger.Level(zerolog.DebugLevel)
|
||||||
|
case "warn":
|
||||||
|
baseLogger = baseLogger.Level(zerolog.WarnLevel)
|
||||||
|
case "error":
|
||||||
|
baseLogger = baseLogger.Level(zerolog.ErrorLevel)
|
||||||
|
default:
|
||||||
|
baseLogger = baseLogger.Level(zerolog.InfoLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &LogConfig{logger: baseLogger}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LogConfig) log(w io.Writer, level zerolog.Level, message string, v map[string]interface{}) {
|
||||||
|
e := lw.logger.With().Logger()
|
||||||
|
e = e.Output(w)
|
||||||
|
event := e.WithLevel(level).CallerSkipFrame(3)
|
||||||
|
for k, val := range v {
|
||||||
|
switch v := val.(type) {
|
||||||
|
case string:
|
||||||
|
event.Str(k, v)
|
||||||
|
case int:
|
||||||
|
event.Int(k, v)
|
||||||
|
case float64:
|
||||||
|
event.Float64(k, v)
|
||||||
|
default:
|
||||||
|
event.Interface(k, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.Msg(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LogConfig) Debug(message string, v ...map[string]interface{}) {
|
||||||
|
lw.log(os.Stdout, zerolog.DebugLevel, message, mergeMaps(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LogConfig) Info(message string, v ...map[string]interface{}) {
|
||||||
|
lw.log(os.Stdout, zerolog.InfoLevel, message, mergeMaps(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LogConfig) Warning(message string, v ...map[string]interface{}) {
|
||||||
|
lw.log(os.Stdout, zerolog.WarnLevel, message, mergeMaps(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LogConfig) Error(message string, v ...map[string]interface{}) {
|
||||||
|
lw.log(os.Stderr, zerolog.ErrorLevel, message, mergeMaps(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lw *LogConfig) Critical(message string, v ...map[string]interface{}) {
|
||||||
|
lw.log(os.Stderr, zerolog.FatalLevel, message, mergeMaps(v))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeMaps(maps []map[string]interface{}) map[string]interface{} {
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
for _, m := range maps {
|
||||||
|
for k, v := range m {
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package libpack_logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkNewLogger(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
NewLogger()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkInfoLog(b *testing.B) {
|
||||||
|
oldEnv := os.Getenv("LOG_LEVEL")
|
||||||
|
os.Setenv("LOG_LEVEL", "info")
|
||||||
|
oldStdout := os.Stdout
|
||||||
|
oldStderr := os.Stderr
|
||||||
|
os.Stdout, _ = os.Open(os.DevNull)
|
||||||
|
os.Stderr, _ = os.Open(os.DevNull)
|
||||||
|
defer func() {
|
||||||
|
os.Stdout = oldStdout
|
||||||
|
os.Stderr = oldStderr
|
||||||
|
os.Setenv("LOG_LEVEL", oldEnv)
|
||||||
|
}()
|
||||||
|
|
||||||
|
testsLogger := NewLogger()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
testsLogger.Info("test", map[string]interface{}{"test": "test"})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
package libpack_logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/buger/jsonparser"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoggingTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testsLogger *LogConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
type stdoutCapture struct {
|
||||||
|
oldStdout *os.File
|
||||||
|
readPipe *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *stdoutCapture) StartCapture() {
|
||||||
|
sc.oldStdout = os.Stdout
|
||||||
|
sc.readPipe, os.Stdout, _ = os.Pipe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *stdoutCapture) StopCapture() (string, error) {
|
||||||
|
if sc.oldStdout == nil || sc.readPipe == nil {
|
||||||
|
return "", errors.New("StartCapture not called before StopCapture on Stdout")
|
||||||
|
}
|
||||||
|
os.Stdout.Close()
|
||||||
|
os.Stdout = sc.oldStdout
|
||||||
|
bytes, err := io.ReadAll(sc.readPipe)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type stderrCapture struct {
|
||||||
|
oldStderr *os.File
|
||||||
|
readPipe *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *stderrCapture) StartCapture() {
|
||||||
|
sc.oldStderr = os.Stderr
|
||||||
|
sc.readPipe, os.Stderr, _ = os.Pipe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *stderrCapture) StopCapture() (string, error) {
|
||||||
|
if sc.oldStderr == nil || sc.readPipe == nil {
|
||||||
|
return "", errors.New("StartCapture not called before StopCapture on Stderr")
|
||||||
|
}
|
||||||
|
os.Stderr.Close()
|
||||||
|
os.Stderr = sc.oldStderr
|
||||||
|
bytes, err := io.ReadAll(sc.readPipe)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LoggingTestSuite) SetupTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoggingTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(LoggingTestSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LoggingTestSuite) TestLogConfig_AllHandlers() {
|
||||||
|
type args struct {
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantLevel string
|
||||||
|
wantMessage string
|
||||||
|
envMinLogLevel string
|
||||||
|
loggerType string
|
||||||
|
stdOutExpect bool
|
||||||
|
stdErrExpect bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test log: Error",
|
||||||
|
loggerType: "Error",
|
||||||
|
args: args{
|
||||||
|
message: "This is a error message",
|
||||||
|
},
|
||||||
|
wantLevel: "error",
|
||||||
|
wantMessage: "This is a error message",
|
||||||
|
stdErrExpect: true,
|
||||||
|
stdOutExpect: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Warning",
|
||||||
|
loggerType: "Warning",
|
||||||
|
args: args{
|
||||||
|
message: "This is a warning message",
|
||||||
|
},
|
||||||
|
wantLevel: "warn",
|
||||||
|
wantMessage: "This is a warning message",
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: true,
|
||||||
|
envMinLogLevel: "info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Warning | Min level: Debug",
|
||||||
|
loggerType: "Warning",
|
||||||
|
args: args{
|
||||||
|
message: "This is a warning message",
|
||||||
|
},
|
||||||
|
wantLevel: "warn",
|
||||||
|
wantMessage: "This is a warning message",
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: true,
|
||||||
|
envMinLogLevel: "debug",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Info",
|
||||||
|
loggerType: "Info",
|
||||||
|
args: args{
|
||||||
|
message: "This is a info message",
|
||||||
|
},
|
||||||
|
wantLevel: "info",
|
||||||
|
wantMessage: "This is a info message",
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Info | Min level: Warn",
|
||||||
|
loggerType: "Info",
|
||||||
|
args: args{
|
||||||
|
message: "This is a info message",
|
||||||
|
},
|
||||||
|
wantLevel: "",
|
||||||
|
wantMessage: "",
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: false,
|
||||||
|
envMinLogLevel: "warn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Warning | Min level: Warn",
|
||||||
|
loggerType: "Warning",
|
||||||
|
args: args{
|
||||||
|
message: "This is a warning message",
|
||||||
|
},
|
||||||
|
wantLevel: "warn",
|
||||||
|
wantMessage: "This is a warning message",
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: true,
|
||||||
|
envMinLogLevel: "warn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Warning | Min level: Error",
|
||||||
|
loggerType: "Warning",
|
||||||
|
args: args{
|
||||||
|
message: "This is an error message",
|
||||||
|
},
|
||||||
|
wantLevel: "",
|
||||||
|
wantMessage: "",
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: false,
|
||||||
|
envMinLogLevel: "error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Debug | Min level: Debug",
|
||||||
|
loggerType: "Debug",
|
||||||
|
args: args{
|
||||||
|
message: "This is a debug message",
|
||||||
|
},
|
||||||
|
wantLevel: "debug",
|
||||||
|
wantMessage: "This is a debug message",
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: true,
|
||||||
|
envMinLogLevel: "debug",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
suite.T().Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.envMinLogLevel != "" {
|
||||||
|
os.Setenv("LOG_LEVEL", tt.envMinLogLevel)
|
||||||
|
defer os.Unsetenv("LOG_LEVEL")
|
||||||
|
}
|
||||||
|
testsLogger = NewLogger()
|
||||||
|
|
||||||
|
captureStdout := stdoutCapture{}
|
||||||
|
captureStdout.StartCapture()
|
||||||
|
captureStderr := stderrCapture{}
|
||||||
|
captureStderr.StartCapture()
|
||||||
|
|
||||||
|
reflect.ValueOf(testsLogger).MethodByName(tt.loggerType).Call([]reflect.Value{reflect.ValueOf(tt.args.message)})
|
||||||
|
|
||||||
|
stdoutOut, err := captureStdout.StopCapture()
|
||||||
|
if err != nil {
|
||||||
|
suite.T().Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stderrOut, err := captureStderr.StopCapture()
|
||||||
|
if err != nil {
|
||||||
|
suite.T().Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.stdErrExpect && !tt.stdOutExpect {
|
||||||
|
gotLvl, gotMsg, err := getResponseValues(stderrOut, "short_message")
|
||||||
|
suite.NoError(err, "Failed in [STDERR]: "+tt.name)
|
||||||
|
suite.Equal(tt.wantLevel, gotLvl, "Failed in [STDERR]: "+tt.name)
|
||||||
|
suite.Equal(tt.wantMessage, gotMsg, "Failed in [STDERR]: "+tt.name)
|
||||||
|
suite.Equal("", stdoutOut, "Failed in [STDERR]: "+tt.name)
|
||||||
|
}
|
||||||
|
if tt.stdOutExpect && !tt.stdErrExpect {
|
||||||
|
gotLvl, gotMsg, err := getResponseValues(stdoutOut, "short_message")
|
||||||
|
suite.NoError(err, "Failed in [STDOUT]: "+tt.name)
|
||||||
|
suite.Equal(tt.wantLevel, gotLvl, "Failed in [STDOUT]: "+tt.name)
|
||||||
|
suite.Equal(tt.wantMessage, gotMsg, "Failed in [STDOUT]: "+tt.name)
|
||||||
|
suite.Equal("", stderrOut, "Failed in [STDOUT]: "+tt.name)
|
||||||
|
}
|
||||||
|
if !tt.stdErrExpect && !tt.stdOutExpect {
|
||||||
|
suite.Equal("", stderrOut, "Failed in [NEITHER]: "+tt.name)
|
||||||
|
suite.Equal("", stdoutOut, "Failed in [NEITHER]: "+tt.name)
|
||||||
|
}
|
||||||
|
os.Unsetenv("LOG_LEVEL")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LoggingTestSuite) TestFullMessage() {
|
||||||
|
type args struct {
|
||||||
|
extraFields map[string]interface{}
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
extraFields := make(map[string]interface{})
|
||||||
|
extraFields["_full_message"] = "full message"
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
args args
|
||||||
|
name string
|
||||||
|
wantLevel string
|
||||||
|
wantMessage string
|
||||||
|
envMinLogLevel string
|
||||||
|
loggerType string
|
||||||
|
stdOutExpect bool
|
||||||
|
stdErrExpect bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test log: Error",
|
||||||
|
loggerType: "Error",
|
||||||
|
args: args{
|
||||||
|
message: "This is a error message",
|
||||||
|
extraFields: extraFields,
|
||||||
|
},
|
||||||
|
wantLevel: "error",
|
||||||
|
wantMessage: extraFields["_full_message"].(string),
|
||||||
|
stdErrExpect: true,
|
||||||
|
stdOutExpect: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test log: Info",
|
||||||
|
loggerType: "Info",
|
||||||
|
args: args{
|
||||||
|
message: "This is a info message",
|
||||||
|
extraFields: extraFields,
|
||||||
|
},
|
||||||
|
wantMessage: extraFields["_full_message"].(string),
|
||||||
|
stdErrExpect: false,
|
||||||
|
stdOutExpect: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
suite.T().Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.envMinLogLevel != "" {
|
||||||
|
os.Setenv("LOG_LEVEL", tt.envMinLogLevel)
|
||||||
|
defer os.Unsetenv("LOG_LEVEL")
|
||||||
|
}
|
||||||
|
testsLogger = NewLogger()
|
||||||
|
|
||||||
|
captureStdout := stdoutCapture{}
|
||||||
|
captureStdout.StartCapture()
|
||||||
|
captureStderr := stderrCapture{}
|
||||||
|
captureStderr.StartCapture()
|
||||||
|
|
||||||
|
reflect.ValueOf(testsLogger).MethodByName(tt.loggerType).Call([]reflect.Value{
|
||||||
|
reflect.ValueOf(tt.args.message),
|
||||||
|
reflect.ValueOf(tt.args.extraFields),
|
||||||
|
})
|
||||||
|
|
||||||
|
stdoutOut, err := captureStdout.StopCapture()
|
||||||
|
if err != nil {
|
||||||
|
suite.T().Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
stderrOut, err := captureStderr.StopCapture()
|
||||||
|
if err != nil {
|
||||||
|
suite.T().Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.stdErrExpect && !tt.stdOutExpect {
|
||||||
|
_, gotMsg, err := getResponseValues(stderrOut, "_full_message")
|
||||||
|
suite.NoError(err, "Failed in [STDERR]: "+tt.name)
|
||||||
|
suite.Equal(tt.wantMessage, gotMsg, "Failed in [STDERR]: "+tt.name)
|
||||||
|
}
|
||||||
|
if tt.stdOutExpect && !tt.stdErrExpect {
|
||||||
|
_, gotMsg, err := getResponseValues(stdoutOut, "_full_message")
|
||||||
|
suite.NoError(err, "Failed in [STDOUT]: "+tt.name)
|
||||||
|
suite.Equal(tt.wantMessage, gotMsg, "Failed in [STDOUT]: "+tt.name)
|
||||||
|
}
|
||||||
|
os.Unsetenv("LOG_LEVEL")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_getResponseValues(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
sourceJson string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantGotLvl string
|
||||||
|
wantGotMsg string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test with json",
|
||||||
|
args: args{
|
||||||
|
sourceJson: `{"level": "debug", "short_message": "hello world"`,
|
||||||
|
},
|
||||||
|
wantGotLvl: "debug",
|
||||||
|
wantGotMsg: "hello world",
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test with json, wrong message field",
|
||||||
|
args: args{
|
||||||
|
sourceJson: `{"level": "debug", "message": "hello world"`,
|
||||||
|
},
|
||||||
|
wantGotLvl: "debug",
|
||||||
|
wantGotMsg: "",
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotGotLvl, gotGotMsg, err := getResponseValues(tt.args.sourceJson, "short_message")
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("getResponseValues() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if gotGotLvl != tt.wantGotLvl {
|
||||||
|
t.Errorf("getResponseValues() gotGotLvl = %v, want %v", gotGotLvl, tt.wantGotLvl)
|
||||||
|
}
|
||||||
|
if gotGotMsg != tt.wantGotMsg {
|
||||||
|
t.Errorf("getResponseValues() gotGotMsg = %v, want %v", gotGotMsg, tt.wantGotMsg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getResponseValues(sourceJson string, key string) (gotLvl, gotMsg string, err error) {
|
||||||
|
gotLvl, err = jsonparser.GetString([]byte(sourceJson), "level")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gotMsg, err = jsonparser.GetString([]byte(sourceJson), key)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -3,8 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/gookit/goutil/envutil"
|
"github.com/gookit/goutil/envutil"
|
||||||
graphql "github.com/lukaszraczylo/go-simple-graphql"
|
graphql "github.com/lukaszraczylo/go-simple-graphql"
|
||||||
libpack_config "github.com/telegram-bot-app/libpack/config"
|
libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config"
|
||||||
libpack_logging "github.com/telegram-bot-app/libpack/logging"
|
libpack_logging "github.com/lukaszraczylo/graphql-monitoring-proxy/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cfg *config
|
var cfg *config
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
libpack_monitoring "github.com/telegram-bot-app/libpack/monitoring"
|
libpack_monitoring "github.com/lukaszraczylo/graphql-monitoring-proxy/monitoring"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StartMonitoringServer() {
|
func StartMonitoringServer() {
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package libpack_monitoring
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RegisterDefaultMetrics() {
|
||||||
|
ms.RegisterMetricsCounter(MetricsSucceeded, nil)
|
||||||
|
ms.RegisterMetricsCounter(MetricsFailed, nil)
|
||||||
|
ms.RegisterMetricsCounter(MetricsSkipped, nil)
|
||||||
|
ms.RegisterMetricsHistogram(MetricsDuration, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RegisterGoMetrics() {
|
||||||
|
// TODO: metrics.WriteProcessMetrics(ms.metrics_set)
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package libpack_monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) get_metrics_name(name string, labels map[string]string) (complete_name string) {
|
||||||
|
if labels == nil {
|
||||||
|
labels = make(map[string]string)
|
||||||
|
}
|
||||||
|
labels["microservice"] = libpack_config.PKG_NAME
|
||||||
|
|
||||||
|
if ms.metrics_prefix != "" {
|
||||||
|
complete_name = ms.metrics_prefix + "_" + name
|
||||||
|
} else {
|
||||||
|
complete_name = name
|
||||||
|
}
|
||||||
|
if labels != nil {
|
||||||
|
complete_name += "{"
|
||||||
|
for k, v := range labels {
|
||||||
|
complete_name += k + "=\"" + v + "\","
|
||||||
|
}
|
||||||
|
complete_name = strings.TrimSuffix(complete_name, ",")
|
||||||
|
complete_name += "}"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate_metrics_name validates the name of the metric to adhere to the Prometheus naming conventions
|
||||||
|
// https://prometheus.io/docs/practices/naming/
|
||||||
|
func validate_metrics_name(name string) error {
|
||||||
|
// replace all spaces with underscores and remove all other non-alphanumeric characters
|
||||||
|
name_new := strings.ReplaceAll(name, " ", "_")
|
||||||
|
name_new = strings.Map(func(r rune) rune {
|
||||||
|
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}, name_new)
|
||||||
|
name_new = strings.ReplaceAll(name_new, "__", "_")
|
||||||
|
name_new = strings.Trim(name_new, "_")
|
||||||
|
if name_new != name {
|
||||||
|
return fmt.Errorf("Invalid metric name: %s, expected %s", name, name_new)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func compile_metrics_with_labels(name string, labels map[string]string) string {
|
||||||
|
metric_name := name
|
||||||
|
for k, v := range labels {
|
||||||
|
metric_name += "_" + k + "_" + v
|
||||||
|
}
|
||||||
|
return metric_name
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package libpack_monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *MonitoringTestSuite) Test_validate_metrics_name() {
|
||||||
|
type args struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Test_validate_metrics_name - valid",
|
||||||
|
args: args{
|
||||||
|
name: "test_metrics_name",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test_validate_metrics_name - invalid",
|
||||||
|
args: args{
|
||||||
|
name: "test metrics name",
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test_validate_metrics_name - invalid - special chars",
|
||||||
|
args: args{
|
||||||
|
name: "test_metrics_name!",
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
suite.T().Run(tt.name, func(t *testing.T) {
|
||||||
|
err := validate_metrics_name(tt.args.name)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MonitoringTestSuite) TestValidateMetricsName() {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expected error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid_name",
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name with spaces",
|
||||||
|
expected: fmt.Errorf("Invalid metric name: %s, expected %s", "name with spaces", "name_with_spaces"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name with non-alphanumeric characters",
|
||||||
|
expected: fmt.Errorf("Invalid metric name: %s, expected %s", "name with non-alphanumeric characters", "name_with_nonalphanumeric_characters"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "name__with__consecutive__underscores",
|
||||||
|
expected: fmt.Errorf("Invalid metric name: %s, expected %s", "name__with__consecutive__underscores", "name_with_consecutive_underscores"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "_name_with_leading_or_trailing_underscores_",
|
||||||
|
expected: fmt.Errorf("Invalid metric name: %s, expected %s", "_name_with_leading_or_trailing_underscores_", "name_with_leading_or_trailing_underscores"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
suite.T().Run(tt.name, func(t *testing.T) {
|
||||||
|
err := validate_metrics_name(tt.name)
|
||||||
|
assert.Equal(t, tt.expected, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
// Package `libpack_monitoring` provides and easy way to add prometheus metrics to your application.
|
||||||
|
// It also provides a way to add custom metrics to the already started prometheus registry.
|
||||||
|
|
||||||
|
package libpack_monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/VictoriaMetrics/metrics"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gookit/goutil/envutil"
|
||||||
|
logging "github.com/telegram-bot-app/lib-logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MetricsSetup struct {
|
||||||
|
metrics_prefix string
|
||||||
|
metrics_set *metrics.Set
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
log *logging.LogConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewMonitoring() *MetricsSetup {
|
||||||
|
log = logging.NewLogger()
|
||||||
|
ms := &MetricsSetup{}
|
||||||
|
ms.metrics_set = metrics.NewSet()
|
||||||
|
go ms.startPrometheusEndpoint()
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) startPrometheusEndpoint() {
|
||||||
|
app := fiber.New()
|
||||||
|
app.Get("/metrics", ms.metricsEndpoint)
|
||||||
|
err := app.Listen(fmt.Sprintf(":%d", envutil.GetInt("MONITORING_PORT", 9393)))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Can't start the service: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) metricsEndpoint(c *fiber.Ctx) error {
|
||||||
|
ms.metrics_set.WritePrometheus(c.Response().BodyWriter())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) AddMetricsPrefix(prefix string) {
|
||||||
|
ms.metrics_prefix = prefix
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) ListActiveMetrics() []string {
|
||||||
|
return ms.metrics_set.ListMetricNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RegisterMetricsGauge(metric_name string, labels map[string]string, val float64) *metrics.Gauge {
|
||||||
|
if validate_metrics_name(metric_name) != nil {
|
||||||
|
log.Critical("RegisterMetricsGauge() error", map[string]interface{}{"_error": "Invalid metric name", "_metric_name": metric_name})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ms.metrics_set.GetOrCreateGauge(ms.get_metrics_name(metric_name, labels), func() float64 {
|
||||||
|
// get current value of the gauge and add val to it
|
||||||
|
return val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RegisterMetricsCounter(metric_name string, labels map[string]string) *metrics.Counter {
|
||||||
|
if validate_metrics_name(metric_name) != nil {
|
||||||
|
log.Critical("RegisterMetricsCounter() error", map[string]interface{}{"_error": "Invalid metric name", "_metric_name": metric_name})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ms.metrics_set.GetOrCreateCounter(ms.get_metrics_name(metric_name, labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RegisterFloatCounter(metric_name string, labels map[string]string) *metrics.FloatCounter {
|
||||||
|
if validate_metrics_name(metric_name) != nil {
|
||||||
|
log.Critical("RegisterFloatCounter() error", map[string]interface{}{"_error": "Invalid metric name", "_metric_name": metric_name})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ms.metrics_set.GetOrCreateFloatCounter(ms.get_metrics_name(metric_name, labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RegisterMetricsSummary(metric_name string, labels map[string]string) *metrics.Summary {
|
||||||
|
if validate_metrics_name(metric_name) != nil {
|
||||||
|
log.Critical("RegisterMetricsSummary() error", map[string]interface{}{"_error": "Invalid metric name", "_metric_name": metric_name})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ms.metrics_set.GetOrCreateSummary(ms.get_metrics_name(metric_name, labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RegisterMetricsHistogram(metric_name string, labels map[string]string) *metrics.Histogram {
|
||||||
|
if validate_metrics_name(metric_name) != nil {
|
||||||
|
log.Critical("RegisterMetricsHistogram() error", map[string]interface{}{"_error": "Invalid metric name", "_metric_name": metric_name})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ms.metrics_set.GetOrCreateHistogram(ms.get_metrics_name(metric_name, labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) Increment(metric_name string, labels map[string]string) {
|
||||||
|
ms.RegisterMetricsCounter(metric_name, labels).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) IncrementFloat(metric_name string, labels map[string]string, value float64) {
|
||||||
|
ms.RegisterFloatCounter(metric_name, labels).Add(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) Set(metric_name string, labels map[string]string, value uint64) {
|
||||||
|
ms.RegisterMetricsCounter(metric_name, labels).Set(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) Update(metric_name string, labels map[string]string, value float64) {
|
||||||
|
ms.RegisterMetricsHistogram(metric_name, labels).Update(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) UpdateDuration(metric_name string, labels map[string]string, value time.Time) {
|
||||||
|
ms.RegisterMetricsHistogram(metric_name, labels).UpdateDuration(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) UpdateSummary(metric_name string, labels map[string]string, value float64) {
|
||||||
|
ms.RegisterMetricsSummary(metric_name, labels).Update(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) RemoveMetrics(metric_name string, labels map[string]string) {
|
||||||
|
ms.metrics_set.UnregisterMetric(ms.get_metrics_name(metric_name, labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MetricsSetup) PurgeMetrics() {
|
||||||
|
ms.metrics_set.UnregisterAllMetrics()
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package libpack_monitoring
|
||||||
|
|
||||||
|
const (
|
||||||
|
MetricsSucceeded = "requests_succesful"
|
||||||
|
MetricsFailed = "requests_failed"
|
||||||
|
MetricsDuration = "requests_duration"
|
||||||
|
MetricsSkipped = "requests_skipped"
|
||||||
|
)
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package libpack_monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// import (
|
||||||
|
// "fmt"
|
||||||
|
// "io"
|
||||||
|
// "net/http"
|
||||||
|
// "testing"
|
||||||
|
// "time"
|
||||||
|
|
||||||
|
// "github.com/stretchr/testify/assert"
|
||||||
|
// "github.com/stretchr/testify/suite"
|
||||||
|
// libpack_config "github.com/lukaszraczylo/graphql-monitoring-proxy/config"
|
||||||
|
// )
|
||||||
|
|
||||||
|
type MonitoringTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
metrics_endpoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MonitoringTestSuite) SetupTest() {
|
||||||
|
suite.metrics_endpoint = "http://localhost:9393/metrics"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MonitoringTestSuite) TearDownTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonitoringSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(MonitoringTestSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MonitoringTestSuite) testing_call_metrics_endpoint() *http.Response {
|
||||||
|
resp, err := http.Get(suite.metrics_endpoint)
|
||||||
|
if err != nil {
|
||||||
|
suite.T().Error("Can't call metrics endpoint", err)
|
||||||
|
suite.T().FailNow()
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MonitoringTestSuite) testing_get_body_as_text(resp *http.Response) string {
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
suite.T().Error("Can't read response body", err)
|
||||||
|
suite.T().FailNow()
|
||||||
|
}
|
||||||
|
return string(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MonitoringTestSuite) TestNewMonitoring() {
|
||||||
|
metrics_prefix := "within_test"
|
||||||
|
|
||||||
|
suite.T().Run("TestWholeEndpoint", func(t *testing.T) {
|
||||||
|
mon := NewMonitoring()
|
||||||
|
mon.AddMetricsPrefix(metrics_prefix)
|
||||||
|
mon.RegisterDefaultMetrics()
|
||||||
|
|
||||||
|
resp := suite.testing_call_metrics_endpoint()
|
||||||
|
assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
assert.Contains(t, suite.testing_get_body_as_text(resp), "within_test_requests_succesful", "Metrics endpoint should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
mon.RegisterMetricsGauge("test_gauge_metrics", nil, 14)
|
||||||
|
resp = suite.testing_call_metrics_endpoint()
|
||||||
|
assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
assert.Contains(t, suite.testing_get_body_as_text(resp), "within_test_test_gauge_metrics", "Metrics endpoint should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
// Triggering it again will increase the gauge by 1
|
||||||
|
mon.RegisterMetricsGauge("test_gauge_metrics", nil, 7)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
resp = suite.testing_call_metrics_endpoint()
|
||||||
|
assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
assert.Contains(t, suite.testing_get_body_as_text(resp), "within_test_test_gauge_metrics 7", "Metrics endpoint should contain incremented () gauge metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
mon.RegisterMetricsCounter("test_counter_metrics", nil)
|
||||||
|
mon.Increment("test_counter_metrics", nil)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
resp = suite.testing_call_metrics_endpoint()
|
||||||
|
assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
assert.Contains(t, suite.testing_get_body_as_text(resp), "within_test_test_counter_metrics", "Metrics endpoint should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
mon.Increment("test_counter_metrics", nil)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
resp = suite.testing_call_metrics_endpoint()
|
||||||
|
assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
assert.Contains(t, suite.testing_get_body_as_text(resp), "within_test_test_counter_metrics 2", "Metrics endpoint should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
// mon.AddCustomMetrics(&CustomMetrics{
|
||||||
|
// Name: "test_custom_metrics",
|
||||||
|
// Help: "test custom metrics",
|
||||||
|
// Type: TypeHistogram,
|
||||||
|
// }, libpack_config.PKG_NAME)
|
||||||
|
// resp = suite.testing_call_metrics_endpoint()
|
||||||
|
// assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
// assert.Contains(t, suite.testing_get_body_as_text(resp), "within_test_test_custom_metrics", "Metrics endpoint should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
// fmt.Println(suite.testing_get_body_as_text(resp))
|
||||||
|
|
||||||
|
// assert.Containsf(t, mon.ListActiveMetrics(), "test_custom_metrics", "ListActiveMetrics() should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
// mon.AddCustomMetrics(&CustomMetrics{
|
||||||
|
// Name: "test_gauge_metrics",
|
||||||
|
// Help: "test gauge metrics",
|
||||||
|
// Type: TypeGauge,
|
||||||
|
// }, libpack_config.PKG_NAME)
|
||||||
|
// mon.Increment("test_gauge_metrics")
|
||||||
|
// time.Sleep(2 * time.Second)
|
||||||
|
// resp = suite.testing_call_metrics_endpoint()
|
||||||
|
// assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
// assert.Contains(t, suite.testing_get_body_as_text(resp), "test_gauge_metrics{microservice=\""+libpack_config.PKG_NAME+"\"} 1", "Metrics endpoint should contain incremented (1) gauge metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
// mon.Increment("test_gauge_metrics")
|
||||||
|
// time.Sleep(2 * time.Second)
|
||||||
|
// resp = suite.testing_call_metrics_endpoint()
|
||||||
|
// assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
// assert.Contains(t, suite.testing_get_body_as_text(resp), "test_gauge_metrics{microservice=\""+libpack_config.PKG_NAME+"\"} 2", "Metrics endpoint should contain incremented (2) gauge metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
// mon.AddCustomMetrics(&CustomMetrics{
|
||||||
|
// Name: "test_counter_metrics",
|
||||||
|
// Help: "test counter metrics",
|
||||||
|
// Type: TypeCounter,
|
||||||
|
// }, libpack_config.PKG_NAME)
|
||||||
|
// mon.Set("test_counter_metrics", 7)
|
||||||
|
// time.Sleep(2 * time.Second)
|
||||||
|
// resp = suite.testing_call_metrics_endpoint()
|
||||||
|
// assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
// assert.Contains(t, suite.testing_get_body_as_text(resp), "test_counter_metrics{microservice=\""+libpack_config.PKG_NAME+"\"} 7", "Metrics endpoint should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
resp = suite.testing_call_metrics_endpoint()
|
||||||
|
assert.Equal(t, 200, resp.StatusCode)
|
||||||
|
assert.Contains(t, suite.testing_get_body_as_text(resp), "go_goroutines", "Metrics endpoint should contain metrics with prefix %s", metrics_prefix)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
|
|
||||||
fiber "github.com/gofiber/fiber/v2"
|
fiber "github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/fiber/v2/middleware/proxy"
|
"github.com/gofiber/fiber/v2/middleware/proxy"
|
||||||
libpack_monitoring "github.com/telegram-bot-app/libpack/monitoring"
|
libpack_monitoring "github.com/lukaszraczylo/graphql-monitoring-proxy/monitoring"
|
||||||
)
|
)
|
||||||
|
|
||||||
func proxyTheRequest(c *fiber.Ctx) error {
|
func proxyTheRequest(c *fiber.Ctx) error {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
libpack_monitoring "github.com/telegram-bot-app/libpack/monitoring"
|
libpack_monitoring "github.com/lukaszraczylo/graphql-monitoring-proxy/monitoring"
|
||||||
)
|
)
|
||||||
|
|
||||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/akyoto/cache"
|
"github.com/akyoto/cache"
|
||||||
graphql "github.com/lukaszraczylo/go-simple-graphql"
|
graphql "github.com/lukaszraczylo/go-simple-graphql"
|
||||||
libpack_logging "github.com/telegram-bot-app/libpack/logging"
|
libpack_logging "github.com/lukaszraczylo/graphql-monitoring-proxy/logging"
|
||||||
libpack_monitoring "github.com/telegram-bot-app/libpack/monitoring"
|
libpack_monitoring "github.com/lukaszraczylo/graphql-monitoring-proxy/monitoring"
|
||||||
)
|
)
|
||||||
|
|
||||||
// config is a struct that holds the configuration of the application.
|
// config is a struct that holds the configuration of the application.
|
||||||
|
|||||||
Reference in New Issue
Block a user