Initialize module and dependencies
This commit is contained in:
226
vendor/golang.org/x/telemetry/internal/upload/run.go
generated
vendored
Normal file
226
vendor/golang.org/x/telemetry/internal/upload/run.go
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package upload
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/telemetry/internal/configstore"
|
||||
"golang.org/x/telemetry/internal/telemetry"
|
||||
)
|
||||
|
||||
// RunConfig configures non-default behavior of a call to Run.
|
||||
//
|
||||
// All fields are optional, for testing or observability.
|
||||
type RunConfig struct {
|
||||
TelemetryDir string // if set, overrides the telemetry data directory
|
||||
UploadURL string // if set, overrides the telemetry upload endpoint
|
||||
LogWriter io.Writer // if set, used for detailed logging of the upload process
|
||||
Env []string // if set, appended to the config download environment
|
||||
StartTime time.Time // if set, overrides the upload start time
|
||||
}
|
||||
|
||||
// Run generates and uploads reports, as allowed by the mode file.
|
||||
func Run(config RunConfig) error {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Printf("upload recover: %v", err)
|
||||
}
|
||||
}()
|
||||
uploader, err := newUploader(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer uploader.Close()
|
||||
return uploader.Run()
|
||||
}
|
||||
|
||||
// uploader encapsulates a single upload operation, carrying parameters and
|
||||
// shared state.
|
||||
type uploader struct {
|
||||
// config is used to select counters to upload.
|
||||
config *telemetry.UploadConfig //
|
||||
configVersion string // version of the config
|
||||
dir telemetry.Dir // the telemetry dir to process
|
||||
|
||||
uploadServerURL string
|
||||
startTime time.Time
|
||||
|
||||
cache parsedCache
|
||||
|
||||
logFile *os.File
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// newUploader creates a new uploader to use for running the upload for the
|
||||
// given config.
|
||||
//
|
||||
// Uploaders should only be used for one call to [uploader.Run].
|
||||
func newUploader(rcfg RunConfig) (*uploader, error) {
|
||||
// Determine the upload directory.
|
||||
var dir telemetry.Dir
|
||||
if rcfg.TelemetryDir != "" {
|
||||
dir = telemetry.NewDir(rcfg.TelemetryDir)
|
||||
} else {
|
||||
dir = telemetry.Default
|
||||
}
|
||||
|
||||
// Determine the upload URL.
|
||||
uploadURL := rcfg.UploadURL
|
||||
if uploadURL == "" {
|
||||
uploadURL = "https://telemetry.go.dev/upload"
|
||||
}
|
||||
|
||||
// Determine the upload logger.
|
||||
//
|
||||
// This depends on the provided rcfg.LogWriter and the presence of
|
||||
// dir.DebugDir, as follows:
|
||||
// 1. If LogWriter is present, log to it.
|
||||
// 2. If DebugDir is present, log to a file within it.
|
||||
// 3. If both LogWriter and DebugDir are present, log to a multi writer.
|
||||
// 4. If neither LogWriter nor DebugDir are present, log to a noop logger.
|
||||
var logWriters []io.Writer
|
||||
logFile, err := debugLogFile(dir.DebugDir())
|
||||
if err != nil {
|
||||
logFile = nil
|
||||
}
|
||||
if logFile != nil {
|
||||
logWriters = append(logWriters, logFile)
|
||||
}
|
||||
if rcfg.LogWriter != nil {
|
||||
logWriters = append(logWriters, rcfg.LogWriter)
|
||||
}
|
||||
var logWriter io.Writer
|
||||
switch len(logWriters) {
|
||||
case 0:
|
||||
logWriter = io.Discard
|
||||
case 1:
|
||||
logWriter = logWriters[0]
|
||||
default:
|
||||
logWriter = io.MultiWriter(logWriters...)
|
||||
}
|
||||
logger := log.New(logWriter, "", log.Ltime|log.Lmicroseconds|log.Lshortfile)
|
||||
|
||||
// Fetch the upload config, if it is not provided.
|
||||
var (
|
||||
config *telemetry.UploadConfig
|
||||
configVersion string
|
||||
)
|
||||
|
||||
if mode, _ := dir.Mode(); mode == "on" {
|
||||
// golang/go#68946: only download the upload config if it will be used.
|
||||
//
|
||||
// TODO(rfindley): This is a narrow change aimed at minimally fixing the
|
||||
// associated bug. In the future, we should read the mode only once during
|
||||
// the upload process.
|
||||
config, configVersion, err = configstore.Download("latest", rcfg.Env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
config = &telemetry.UploadConfig{}
|
||||
configVersion = "v0.0.0-0"
|
||||
}
|
||||
|
||||
// Set the start time, if it is not provided.
|
||||
startTime := time.Now().UTC()
|
||||
if !rcfg.StartTime.IsZero() {
|
||||
startTime = rcfg.StartTime
|
||||
}
|
||||
|
||||
return &uploader{
|
||||
config: config,
|
||||
configVersion: configVersion,
|
||||
dir: dir,
|
||||
uploadServerURL: uploadURL,
|
||||
startTime: startTime,
|
||||
|
||||
logFile: logFile,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close cleans up any resources associated with the uploader.
|
||||
func (u *uploader) Close() error {
|
||||
if u.logFile == nil {
|
||||
return nil
|
||||
}
|
||||
return u.logFile.Close()
|
||||
}
|
||||
|
||||
// Run generates and uploads reports
|
||||
func (u *uploader) Run() error {
|
||||
if telemetry.DisabledOnPlatform {
|
||||
return nil
|
||||
}
|
||||
todo := u.findWork()
|
||||
ready, err := u.reports(&todo)
|
||||
if err != nil {
|
||||
u.logger.Printf("Error building reports: %v", err)
|
||||
return fmt.Errorf("reports failed: %v", err)
|
||||
}
|
||||
u.logger.Printf("Uploading %d reports", len(ready))
|
||||
for _, f := range ready {
|
||||
u.uploadReport(f)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// debugLogFile arranges to write a log file in the given debug directory, if
|
||||
// it exists.
|
||||
func debugLogFile(debugDir string) (*os.File, error) {
|
||||
fd, err := os.Stat(debugDir)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !fd.IsDir() {
|
||||
return nil, fmt.Errorf("debug path %q is not a directory", debugDir)
|
||||
}
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no build info")
|
||||
}
|
||||
year, month, day := time.Now().UTC().Date()
|
||||
goVers := info.GoVersion
|
||||
// E.g., goVers:"go1.22-20240109-RC01 cl/597041403 +dcbe772469 X:loopvar"
|
||||
words := strings.Fields(goVers)
|
||||
goVers = words[0]
|
||||
progPkgPath := info.Path
|
||||
if progPkgPath == "" {
|
||||
progPkgPath = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
|
||||
}
|
||||
prog := path.Base(progPkgPath)
|
||||
progVers := info.Main.Version
|
||||
if progVers == "(devel)" { // avoid special characters in created file names
|
||||
progVers = "devel"
|
||||
}
|
||||
logBase := strings.ReplaceAll(
|
||||
fmt.Sprintf("%s-%s-%s-%4d%02d%02d-%d.log", prog, progVers, goVers, year, month, day, os.Getpid()),
|
||||
" ", "")
|
||||
fname := filepath.Join(debugDir, logBase)
|
||||
if _, err := os.Stat(fname); err == nil {
|
||||
// This process previously called upload.Run
|
||||
return nil, nil
|
||||
}
|
||||
f, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
return nil, nil // this process previously called upload.Run
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
Reference in New Issue
Block a user