Compare commits

...

6 Commits

Author SHA1 Message Date
Abhishek Pandey
753acffec7 Utilize metrics summary instead of dumping metrics through syscalls 2023-04-11 20:35:37 -07:00
Abhishek Pandey
569dbf18ce Change os.signal from syscall.Signal(21) to syscall.SIGINT for Windows 2023-04-06 00:47:47 -07:00
Abhishek Pandey
5c774de630 Add unit test 2023-04-05 20:56:09 -07:00
Abhishek Pandey
5aca592f16 Minor cleanup 2023-04-04 21:05:15 -07:00
Abhishek Pandey
b92d5598e1 Add changes from testing on Windows platform 2023-04-04 20:55:12 -07:00
Abhishek Pandey
000086fcb6 Add windows signal support for dumping metrics 2023-04-04 20:25:41 -07:00
6 changed files with 94 additions and 14 deletions

View File

@ -6,7 +6,7 @@ replace github.com/kopia/kopia => github.com/alcionai/kopia v0.12.2-0.2023040317
require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0
github.com/alcionai/clues v0.0.0-20230330224331-77c1b3be97e0
github.com/alcionai/clues v0.0.0-20230331202049-339059c90c6e
github.com/armon/go-metrics v0.4.0
github.com/aws/aws-sdk-go v1.44.233
github.com/aws/aws-xray-sdk-go v1.8.1
@ -117,7 +117,7 @@ require (
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/sys v0.7.0
golang.org/x/text v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect
google.golang.org/grpc v1.54.0 // indirect

View File

@ -55,6 +55,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/alcionai/clues v0.0.0-20230330224331-77c1b3be97e0 h1:2Fv5zc02wURwUv3Gjo3oqGybSj5tNaXyNIijlrR8SI0=
github.com/alcionai/clues v0.0.0-20230330224331-77c1b3be97e0/go.mod h1:DeaMbAwDvYM6ZfPMR/GUl3hceqI5C8jIQ1lstjB2IW8=
github.com/alcionai/clues v0.0.0-20230331202049-339059c90c6e h1:3M/ND3HBj5U2N0q2l7sMbkKTagPMbCnp7Lk6i5bVX4Q=
github.com/alcionai/clues v0.0.0-20230331202049-339059c90c6e/go.mod h1:DeaMbAwDvYM6ZfPMR/GUl3hceqI5C8jIQ1lstjB2IW8=
github.com/alcionai/kopia v0.12.2-0.20230403174648-98bfae225045 h1:KalMY/JU+3t/3IosvP8yLdUWqcy+mAupTjFeV7I+wHg=
github.com/alcionai/kopia v0.12.2-0.20230403174648-98bfae225045/go.mod h1:WGFVh9/5R3bi6vgGw7pPR65I32cyKJjb854467Goz0w=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -600,6 +602,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View File

@ -1,8 +1,10 @@
package events
import (
"bytes"
"context"
"crypto/md5"
"encoding/json"
"fmt"
"io"
"os"
@ -173,8 +175,8 @@ const APICall m = "api_call"
// configurations
const (
reportInterval = 1 * time.Minute
retentionDuration = 2 * time.Minute
reportInterval = 100 * time.Millisecond
retentionDuration = 200 * time.Millisecond
)
// NewMetrics embeds a metrics bus into the provided context. The bus can be
@ -186,28 +188,28 @@ func NewMetrics(ctx context.Context, w io.Writer) (context.Context, func()) {
// logging rates; that's handled by dumpMetrics().
sink = metrics.NewInmemSink(reportInterval, retentionDuration)
cfg = metrics.DefaultConfig("corso")
sig = metrics.NewInmemSignal(sink, metrics.DefaultSignal, w)
//sig = metrics.NewInmemSignal(sink, sentSignal, w)
)
cfg.EnableHostname = false
cfg.EnableRuntimeMetrics = false
cfg.EnableRuntimeMetrics = true
gm, err := metrics.NewGlobal(cfg, sink)
if err != nil {
logger.CtxErr(ctx, err).Error("metrics bus constructor")
sig.Stop()
//sig.Stop()
return ctx, func() {}
}
stop := make(chan struct{})
go dumpMetrics(ctx, stop, sig)
go dumpMetrics(ctx, stop, sink)
flush := func() {
signalDump(ctx)
time.Sleep(500 * time.Millisecond)
close(stop)
sig.Stop()
//sig.Stop()
gm.Shutdown()
}
@ -220,19 +222,32 @@ func NewMetrics(ctx context.Context, w io.Writer) (context.Context, func()) {
// it to dump metrics to the provided writer (which should be the logger).
// Expectation is for users to call this in a goroutine. Any signal or close() on the stop chan
// will exit the loop.
func dumpMetrics(ctx context.Context, stop <-chan struct{}, sig *metrics.InmemSignal) {
func dumpMetrics(ctx context.Context, stop <-chan struct{}, sink *metrics.InmemSink) {
tock := time.NewTicker(reportInterval)
for {
select {
case <-tock.C:
signalDump(ctx)
//signalDump(ctx)
raw, _ := sink.DisplayMetrics(nil, nil)
result := raw.(metrics.MetricsSummary)
summary, _ := dumpMetricsSummary(result)
fmt.Fprintln(os.Stderr, string(summary))
case <-stop:
return
}
}
}
func dumpMetricsSummary(summary metrics.MetricsSummary) ([]byte, error) {
buf := bytes.NewBuffer(nil)
if err := json.NewEncoder(buf).Encode(summary); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Inc increments the given category by 1.
func Inc(cat m, keys ...string) {
cats := append([]string{string(cat)}, keys...)

View File

@ -0,0 +1,46 @@
package events
import (
"os"
"os/signal"
"testing"
"time"
"github.com/alcionai/corso/src/internal/tester"
"github.com/armon/go-metrics"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
type EventsSignalUnitSuite struct {
tester.Suite
}
func TestEventsSignalUnitSuite(t *testing.T) {
suite.Run(t, &EventsSignalUnitSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *EventsSignalUnitSuite) TestSignalDump() {
ctx, flush := tester.NewContext()
defer flush()
var (
t = suite.T()
)
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, metrics.DefaultSignal)
go func() {
signalDump(ctx)
}()
select {
case sig := <-sigCh:
assert.Equal(t, sentSignal, sig, "received wrong signal")
case <-time.After(1 * time.Second):
assert.Fail(t, "timeout waiting for signal")
}
signal.Stop(sigCh)
}

View File

@ -8,12 +8,17 @@ import (
"syscall"
"github.com/armon/go-metrics"
"golang.org/x/sys/unix"
"github.com/alcionai/corso/src/pkg/logger"
)
const (
sentSignal = metrics.DefaultSignal
)
func signalDump(ctx context.Context) {
if err := syscall.Kill(syscall.Getpid(), metrics.DefaultSignal); err != nil {
if err := unix.Kill(syscall.Getpid(), metrics.DefaultSignal); err != nil {
logger.CtxErr(ctx, err).Error("metrics interval signal")
}
}

View File

@ -2,10 +2,20 @@ package events
import (
"context"
"syscall"
"github.com/alcionai/corso/src/pkg/logger"
"golang.org/x/sys/windows"
)
const (
// On Windows, ctrl-break event appears as os.Interrupt(syscall.SIGINT)
//https://pkg.go.dev/os/signal#hdr-Windows
sentSignal = os.Interrupt
)
func signalDump(ctx context.Context) {
logger.Ctx(ctx).Warn("cannot send signal on Windows")
err := windows.GenerateConsoleCtrlEvent(syscall.CTRL_BREAK_EVENT, uint32(syscall.Getpid()))
if err != nil {
logger.CtxErr(ctx, err).Error("metrics interval signal")
}
}