dolthub--dolt
206 行
6.6 KiB
Go
206 行
6.6 KiB
Go
// Copyright 2019 Dolthub, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package commands
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc"
|
|
|
|
"github.com/dolthub/dolt/go/cmd/dolt/cli"
|
|
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
|
|
"github.com/dolthub/dolt/go/libraries/doltcore/dbfactory"
|
|
"github.com/dolthub/dolt/go/libraries/doltcore/env"
|
|
"github.com/dolthub/dolt/go/libraries/doltcore/grpcendpoint"
|
|
"github.com/dolthub/dolt/go/libraries/events"
|
|
"github.com/dolthub/dolt/go/libraries/utils/argparser"
|
|
"github.com/dolthub/dolt/go/libraries/utils/config"
|
|
)
|
|
|
|
// SendMetricsCommand is the command used for sending metrics
|
|
const (
|
|
SendMetricsCommand = "send-metrics"
|
|
EventsOutputFormat = "output-format"
|
|
sendMetricsShortDesc = "Send usage metrics to the events server (default), or log them in another way"
|
|
)
|
|
|
|
type SendMetricsCmd struct{}
|
|
|
|
// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
|
func (cmd SendMetricsCmd) Name() string {
|
|
return SendMetricsCommand
|
|
}
|
|
|
|
// Description returns a description of the command
|
|
func (cmd SendMetricsCmd) Description() string {
|
|
return "Send events logs to server."
|
|
}
|
|
|
|
// Hidden should return true if this command should be hidden from the help text
|
|
func (cmd SendMetricsCmd) Hidden() bool {
|
|
return true
|
|
}
|
|
|
|
func (cmd SendMetricsCmd) Docs() *cli.CommandDocumentation {
|
|
return nil
|
|
}
|
|
|
|
func (cmd SendMetricsCmd) ArgParser() *argparser.ArgParser {
|
|
ap := argparser.NewArgParserWithMaxArgs(cmd.Name(), 0)
|
|
ap.SupportsString(
|
|
EventsOutputFormat,
|
|
"r",
|
|
"output-format",
|
|
"Format of the events output. Valid values are null, stdout, grpc, file, logger. Defaults to grpc.",
|
|
)
|
|
return ap
|
|
}
|
|
|
|
// Exec is the implementation of the command that flushes the events to the grpc service
|
|
func (cmd SendMetricsCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv, cliCtx cli.CliContext) int {
|
|
if dEnv.DoltDB(ctx) != nil { // see go/cmd/dolt/dolt.go:interceptSendMetrics()
|
|
cli.PrintErrln("expected DoltEnv without doltDB")
|
|
return 1
|
|
}
|
|
|
|
ap := cmd.ArgParser()
|
|
|
|
help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, cli.CommandDocumentationContent{ShortDesc: sendMetricsShortDesc}, ap))
|
|
apr := cli.ParseArgsOrDie(ap, args, help)
|
|
|
|
metricsDisabled := dEnv.Config.GetStringOrDefault(config.MetricsDisabled, "false")
|
|
|
|
disabled, err := strconv.ParseBool(metricsDisabled)
|
|
if err != nil {
|
|
return 1
|
|
}
|
|
|
|
if disabled {
|
|
cli.Println(color.CyanString("Sending metrics is currently disabled\n"))
|
|
return 0
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
|
defer cancel()
|
|
|
|
userHomeDir, err := dEnv.GetUserHomeDir()
|
|
if err != nil {
|
|
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
|
}
|
|
|
|
output := apr.GetValueOrDefault(EventsOutputFormat, events.EmitterTypeGrpc)
|
|
err = FlushLoggedEvents(ctx, dEnv, userHomeDir, output)
|
|
|
|
if err != nil {
|
|
cli.PrintErrf("Error flushing events: %s\n", err.Error())
|
|
|
|
if err == events.ErrFileLocked {
|
|
return 2
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// FlushLoggedEvents flushes any logged events in the directory given to an appropriate event emitter
|
|
func FlushLoggedEvents(ctx context.Context, dEnv *env.DoltEnv, userHomeDir string, outputType string) error {
|
|
emitter, closer, err := NewEmitter(outputType, dEnv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closer()
|
|
flusher := events.NewFileFlusher(dEnv.FS, userHomeDir, dbfactory.DoltDir, emitter)
|
|
return flusher.Flush(ctx)
|
|
}
|
|
|
|
// NewEmitter returns an emitter for the given configuration provider, of the type named. If an empty name is provided,
|
|
// defaults to a file-based emitter.
|
|
func NewEmitter(emitterType string, pro EmitterConfigProvider) (events.Emitter, func() error, error) {
|
|
switch emitterType {
|
|
case events.EmitterTypeNull:
|
|
return events.NullEmitter{}, func() error { return nil }, nil
|
|
case events.EmitterTypeStdout:
|
|
return events.WriterEmitter{Wr: os.Stdout}, func() error { return nil }, nil
|
|
case events.EmitterTypeGrpc:
|
|
return GRPCEmitterForConfig(pro)
|
|
case events.EmitterTypeFile:
|
|
homeDir, err := pro.GetUserHomeDir()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return events.NewFileEmitter(homeDir, dbfactory.DoltDir), func() error { return nil }, nil
|
|
case events.EmitterTypeLogger:
|
|
return events.NewLoggerEmitter(logrus.DebugLevel), func() error { return nil }, nil
|
|
default:
|
|
return nil, nil, fmt.Errorf("unknown emitter type: %s", emitterType)
|
|
}
|
|
}
|
|
|
|
// GRPCEmitterForConfig returns an event emitter for the given environment, or nil if the environment cannot
|
|
// provide one
|
|
func GRPCEmitterForConfig(pro EmitterConfigProvider, opts ...events.GrpcEmitterOption) (*events.GrpcEmitter, func() error, error) {
|
|
cfg, err := GRPCEventRemoteConfig(pro)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
conn, err := grpc.NewClient("dns:///"+cfg.Endpoint, cfg.DialOptions...)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return events.NewGrpcEmitter(conn, opts...), conn.Close, nil
|
|
}
|
|
|
|
// GRPCEventRemoteConfig returns a GRPCRemoteConfig for the given configuration provider
|
|
func GRPCEventRemoteConfig(pro EmitterConfigProvider) (dbfactory.GRPCRemoteConfig, error) {
|
|
host := pro.GetConfig().GetStringOrDefault(config.MetricsHost, events.DefaultMetricsHost)
|
|
portStr := pro.GetConfig().GetStringOrDefault(config.MetricsPort, events.DefaultMetricsPort)
|
|
insecureStr := pro.GetConfig().GetStringOrDefault(config.MetricsInsecure, "false")
|
|
|
|
port, err := strconv.ParseUint(portStr, 10, 16)
|
|
if err != nil {
|
|
return dbfactory.GRPCRemoteConfig{}, nil
|
|
}
|
|
|
|
insecure, _ := strconv.ParseBool(insecureStr)
|
|
|
|
hostAndPort := fmt.Sprintf("%s:%d", host, port)
|
|
cfg, err := pro.GetGRPCDialParams(grpcendpoint.Config{
|
|
Endpoint: hostAndPort,
|
|
Insecure: insecure,
|
|
})
|
|
if err != nil {
|
|
return dbfactory.GRPCRemoteConfig{}, nil
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
// EmitterConfigProvider is an interface used to get the configuration to create an emitter
|
|
type EmitterConfigProvider interface {
|
|
GetGRPCDialParams(config grpcendpoint.Config) (dbfactory.GRPCRemoteConfig, error)
|
|
GetConfig() config.ReadableConfig
|
|
GetUserHomeDir() (string, error)
|
|
}
|