项目文件夹

文件
wehub-resource-sync 5357c39144
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:40 +08:00

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)
}