add analytics cli commands

This commit is contained in:
Aleksandr Trushkin
2024-02-07 12:24:02 +03:00
parent 52f1280c3c
commit 2f4a973b45
3 changed files with 159 additions and 2 deletions

View File

@ -62,8 +62,14 @@ func SetupDI(ctx context.Context, cfgpath string, verbose bool, logAsJSON bool)
writer = os.Stdout
}
log := zerolog.New(writer).With().Timestamp().Str("app", "converter").Logger()
log := zerolog.
New(writer).
With().
Timestamp().
Str("app", "converter").
Logger()
if verbose {
return log.Level(zerolog.DebugLevel), nil
}

View File

@ -54,6 +54,14 @@ func runcli(ctx context.Context) (err error) {
func setupDI() cli.BeforeFunc {
return func(ctx context.Context, cmd *cli.Command) error {
if out := cmd.String("output"); out != "" {
var err error
cmd.Writer, err = os.Create(out)
if err != nil {
return fmt.Errorf("setting writer: %w", err)
}
}
cfgpath := cmd.String("config")
debugLevel := cmd.Bool("verbose")
jsonFormat := cmd.Bool("json")
@ -69,6 +77,13 @@ func setupDI() cli.BeforeFunc {
func releaseDI() cli.AfterFunc {
return func(ctx context.Context, c *cli.Command) error {
if f, ok := c.Writer.(*os.File); ok {
err := f.Close()
if err != nil {
println("unable to close output file:", err.Error())
}
}
return components.Shutdown()
}
}
@ -95,6 +110,12 @@ func setupCLI() *cli.Command {
Usage: "enables json log format",
Persistent: true,
},
&cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "Defines output for commands",
TakesFile: true,
},
},
Before: setupDI(),
@ -348,10 +369,30 @@ func newViewItemsCmd() *cli.Command {
Commands: []*cli.Command{
newViewItemsGetCmd(),
newViewItemsCountCmd(),
newViewItemsUniqueParams(),
newViewItemsParamsKnownValues(),
},
}
}
func newViewItemsUniqueParams() *cli.Command {
return &cli.Command{
Name: "unique-params",
Usage: "Show all stored unique param values",
Description: "This command iterates over each item and collect keys of params in a dict and then" +
" print it to the output. It's useful to find all unique parameters",
Action: decorateAction(viewItemsUniqueParamsAction),
}
}
func newViewItemsParamsKnownValues() *cli.Command {
return &cli.Command{
Name: "params-values",
Usage: "Show all values of requested parameters",
Action: decorateAction(viewItemsParamsKnownValuesAction),
}
}
func newViewItemsCountCmd() *cli.Command {
return &cli.Command{
Name: "count",
@ -437,6 +478,115 @@ func viewItemsGetAction(ctx context.Context, c *cli.Command) error {
return nil
}
func viewItemsUniqueParamsAction(ctx context.Context, c *cli.Command) error {
repository, err := components.GetRepository()
if err != nil {
return fmt.Errorf("getting repository: %w", err)
}
knownParams := map[string]struct{}{}
iter, err := repository.GoodsItem().ListIter(ctx, 1)
if err != nil {
return fmt.Errorf("getting list iter: %w", err)
}
for item := range iter {
for k := range item.Parameters {
knownParams[k] = struct{}{}
}
}
bw := bufio.NewWriter(c.Writer)
for paramName := range knownParams {
_, err = bw.WriteString(paramName + "\n")
if err != nil {
return fmt.Errorf("unable to write: %w", err)
}
}
return bw.Flush()
}
type chanIter[T any] struct {
in <-chan T
err error
next T
}
func (i *chanIter[T]) Next() (ok bool) {
if i.err != nil {
return false
}
i.next, ok = <-i.in
if !ok {
i.err = errors.New("channel closed")
}
return ok
}
func (i *chanIter[T]) Get() T {
return i.next
}
func (i *chanIter[T]) Err() error {
return i.err
}
func (i *chanIter[T]) Close() {
for range i.in {
}
}
func getItemsIter(ctx context.Context, r entity.GoodsItemRepository) *chanIter[entity.GoodsItem] {
in, err := r.ListIter(ctx, 3)
return &chanIter[entity.GoodsItem]{
in: in,
err: err,
}
}
func viewItemsParamsKnownValuesAction(ctx context.Context, c *cli.Command) error {
repository, err := components.GetRepository()
if err != nil {
return fmt.Errorf("getting repository: %w", err)
}
log, err := components.GetLogger()
if err != nil {
return fmt.Errorf("getting logger: %w", err)
}
params := c.Args().Slice()
requestedValues := make(map[string]map[string]struct{}, len(params))
for _, param := range params {
log.Debug().Str("param", param).Msg("registering param")
requestedValues[param] = make(map[string]struct{}, 16)
}
iter := getItemsIter(ctx, repository.GoodsItem())
for iter.Next() {
item := iter.Get()
for k, v := range item.Parameters {
if _, ok := requestedValues[k]; ok {
requestedValues[k][v] = struct{}{}
}
}
}
tbl := table.New("key", "values").WithWriter(c.Writer)
for k, v := range requestedValues {
values := make([]string, 0, len(v))
for value := range v {
values = append(values, strconv.Quote(value))
}
tbl.AddRow(k, values)
}
tbl.Print()
return nil
}
func viewItemsCountAction(ctx context.Context, c *cli.Command) error {
r, err := components.GetRepository()
if err != nil {

View File

@ -35,10 +35,11 @@ func Open(ctx context.Context, path string, debug bool, log zerolog.Logger) (*ba
log: log.With().Str("db", "badger").Logger(),
}
level := badger.INFO
level := badger.WARNING
if debug {
level = badger.DEBUG
}
opts := badger.DefaultOptions(path).
WithLogger(bl).
WithLoggingLevel(level).