mirror of
https://github.com/kopia/kopia.git
synced 2026-01-31 09:43:19 -05:00
The kopia server was not uploading any logs to the repository, because "repodiag" blob uploads would always fail. The cause was the following: when the (log) repodiag blob PUT operation was initiated, the `Context` used for this operation was already canceled. The context used for blob uploads is passed to `repodiag.NewLogManager` when opening the repository. In the case of the kopia server, the repository is asynchronously opened in `server.Server.InitReposotoryAsync`. The context passed to `repo.Open` is canceled after the "open repository" server task completes. This issue was introduced in #1691 Change: Use `context.WithoutCancel()` instead of the context passed when the repo diagnoser is created. New tests are included to reproduce this failure and verify the fix. - test: ensure server logs are uploaded to the repo - test: honor cancellation in map storage - test: repodiag context cancellation Ref: - #1691
87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
// Package repodiag manages logs and metrics in the repository.
|
|
package repodiag
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"fmt"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
|
|
"github.com/kopia/kopia/internal/clock"
|
|
"github.com/kopia/kopia/internal/gather"
|
|
"github.com/kopia/kopia/internal/zaplogutil"
|
|
"github.com/kopia/kopia/repo/blob"
|
|
)
|
|
|
|
const blobLoggerFlushThreshold = 4 << 20
|
|
|
|
// LogBlobPrefix is a prefix given to text logs stored in repository.
|
|
const LogBlobPrefix = "_log_"
|
|
|
|
// LogManager manages writing encrypted log blobs to the repository.
|
|
type LogManager struct {
|
|
// Set by Enable(). Log blobs are not written to the repository until
|
|
// Enable() is called.
|
|
enabled atomic.Bool
|
|
|
|
// InternalLogManager implements io.Writer and we must be able to write to the
|
|
// repository asynchronously when the context is not provided.
|
|
ctx context.Context //nolint:containedctx
|
|
|
|
writer *BlobWriter
|
|
|
|
timeFunc func() time.Time
|
|
flushThreshold int
|
|
}
|
|
|
|
func (m *LogManager) encryptAndWriteLogBlob(prefix blob.ID, data gather.Bytes, closeFunc func()) {
|
|
m.writer.EncryptAndWriteBlobAsync(m.ctx, prefix, data, closeFunc)
|
|
}
|
|
|
|
// NewLogger creates new logger.
|
|
func (m *LogManager) NewLogger() *zap.SugaredLogger {
|
|
if m == nil {
|
|
return zap.NewNop().Sugar()
|
|
}
|
|
|
|
var rnd [2]byte
|
|
|
|
rand.Read(rnd[:]) //nolint:errcheck
|
|
|
|
w := &logWriteSyncer{
|
|
m: m,
|
|
prefix: blob.ID(fmt.Sprintf("%v%v_%x", LogBlobPrefix, clock.Now().Local().Format("20060102150405"), rnd)),
|
|
}
|
|
|
|
return zap.New(zapcore.NewCore(
|
|
zaplogutil.NewStdConsoleEncoder(zaplogutil.StdConsoleEncoderConfig{
|
|
TimeLayout: zaplogutil.PreciseLayout,
|
|
LocalTime: false,
|
|
}),
|
|
w, zap.DebugLevel), zap.WithClock(zaplogutil.Clock())).Sugar()
|
|
}
|
|
|
|
// Enable enables writing log blobs to repository.
|
|
// Logs are not written to the repository until Enable is called.
|
|
func (m *LogManager) Enable() {
|
|
if m == nil {
|
|
return
|
|
}
|
|
|
|
m.enabled.Store(true)
|
|
}
|
|
|
|
// NewLogManager creates a new LogManager that will emit logs as repository blobs.
|
|
func NewLogManager(ctx context.Context, w *BlobWriter) *LogManager {
|
|
return &LogManager{
|
|
ctx: context.WithoutCancel(ctx),
|
|
writer: w,
|
|
flushThreshold: blobLoggerFlushThreshold,
|
|
timeFunc: clock.Now,
|
|
}
|
|
}
|