diff --git a/app/app.go b/app/app.go index 84682f2c..80d5b1fe 100644 --- a/app/app.go +++ b/app/app.go @@ -8,6 +8,7 @@ import ( "go.uber.org/zap" "os" "runtime" + "runtime/debug" "strings" "sync" "time" @@ -15,8 +16,8 @@ import ( var ( // values of this vars will be defined while compilation - GitCommit, GitBranch, GitState, GitSummary, BuildDate string - name string + AppName, GitCommit, GitBranch, GitState, GitSummary, BuildDate string + name string ) var ( @@ -54,11 +55,12 @@ type ComponentStatable interface { // App is the central part of the application // It contains and manages all components type App struct { - components []Component - mu sync.RWMutex - startStat Stat - stopStat Stat - deviceState int + components []Component + mu sync.RWMutex + startStat Stat + stopStat Stat + deviceState int + anySyncVersion string } // Name returns app name @@ -66,6 +68,10 @@ func (app *App) Name() string { return name } +func (app *App) AppName() string { + return AppName +} + // Version return app version func (app *App) Version() string { return GitSummary @@ -257,7 +263,7 @@ func (app *App) Close(ctx context.Context) error { case <-time.After(StopWarningAfter): statLogger(app.stopStat, log). With(zap.String("in_progress", currentComponentStopping)). - Warn("components close in progress") + Warn("components close in progress") } }() go func() { @@ -311,3 +317,20 @@ func (app *App) SetDeviceState(state int) { } } } + +var onceVersion sync.Once + +func (app *App) AnySyncVersion() string { + onceVersion.Do(func() { + info, ok := debug.ReadBuildInfo() + if ok { + for _, mod := range info.Deps { + if mod.Path == "github.com/anytypeio/any-sync" { + app.anySyncVersion = mod.Version + break + } + } + } + }) + return app.anySyncVersion +} diff --git a/metric/log.go b/metric/log.go index 7cc34e66..edb63249 100644 --- a/metric/log.go +++ b/metric/log.go @@ -35,6 +35,10 @@ func Identity(val string) zap.Field { return zap.String("identity", val) } +func App(app string) zap.Field { + return zap.String("app", app) +} + func FileId(fileId string) zap.Field { return zap.String("fileId", fileId) } @@ -57,5 +61,5 @@ func (m *metric) RequestLog(ctx context.Context, rpc string, fields ...zap.Field if ak != nil { acc = ak.Account() } - m.rpcLog.Info("", append(fields, PeerId(peerId), Identity(acc), Method(rpc))...) + m.rpcLog.Info("", append(fields, m.appField, PeerId(peerId), Identity(acc), Method(rpc))...) } diff --git a/metric/log_test.go b/metric/log_test.go index 50835795..e22a7112 100644 --- a/metric/log_test.go +++ b/metric/log_test.go @@ -3,10 +3,11 @@ package metric import ( "context" "github.com/anytypeio/any-sync/app/logger" + "go.uber.org/zap" "testing" ) func TestLog(t *testing.T) { - m := &metric{rpcLog: logger.NewNamed("rpcLog")} + m := &metric{rpcLog: logger.NewNamed("rpcLog"), appField: zap.String("appName", "test")} m.RequestLog(context.Background(), "rpc") } diff --git a/metric/metric.go b/metric/metric.go index d5319982..aeac0550 100644 --- a/metric/metric.go +++ b/metric/metric.go @@ -32,12 +32,16 @@ type metric struct { registry *prometheus.Registry rpcLog logger.CtxLogger config Config + a *app.App + appField zap.Field } func (m *metric) Init(a *app.App) (err error) { + m.a = a m.registry = prometheus.NewRegistry() m.config = a.MustComponent("config").(configSource).GetMetric() m.rpcLog = logger.NewNamed("rpcLog") + m.appField = App(a.Version()) return nil } @@ -52,6 +56,9 @@ func (m *metric) Run(ctx context.Context) (err error) { if err = m.registry.Register(collectors.NewGoCollector()); err != nil { return err } + if err = m.registry.Register(newVersionsCollector(m.a)); err != nil { + return + } if m.config.Addr != "" { var errCh = make(chan error) http.Handle("/metrics", promhttp.HandlerFor(m.registry, promhttp.HandlerOpts{})) diff --git a/metric/version.go b/metric/version.go new file mode 100644 index 00000000..19a93a12 --- /dev/null +++ b/metric/version.go @@ -0,0 +1,30 @@ +package metric + +import ( + "github.com/anytypeio/any-sync/app" + "github.com/prometheus/client_golang/prometheus" +) + +func newVersionsCollector(a *app.App) prometheus.Collector { + return &versionCollector{prometheus.MustNewConstMetric(prometheus.NewDesc( + "anysync_versions", + "Build information about the main Go module.", + nil, prometheus.Labels{ + "anysync_version": a.AnySyncVersion(), + "app_name": a.AppName(), + "app_version": a.Version(), + }, + ), prometheus.GaugeValue, 1)} +} + +type versionCollector struct { + ver prometheus.Metric +} + +func (v *versionCollector) Describe(descs chan<- *prometheus.Desc) { + descs <- v.ver.Desc() +} + +func (v *versionCollector) Collect(metrics chan<- prometheus.Metric) { + metrics <- v.ver +}