1.修改代码适配阿里云的服务器
This commit is contained in:
313
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/component.go
generated
vendored
Normal file
313
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/component.go
generated
vendored
Normal file
@@ -0,0 +1,313 @@
|
||||
// Copyright (C) MongoDB, Inc. 2023-present.
|
||||
//
|
||||
// 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
|
||||
|
||||
package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
const (
|
||||
CommandFailed = "Command failed"
|
||||
CommandStarted = "Command started"
|
||||
CommandSucceeded = "Command succeeded"
|
||||
ConnectionPoolCreated = "Connection pool created"
|
||||
ConnectionPoolReady = "Connection pool ready"
|
||||
ConnectionPoolCleared = "Connection pool cleared"
|
||||
ConnectionPoolClosed = "Connection pool closed"
|
||||
ConnectionCreated = "Connection created"
|
||||
ConnectionReady = "Connection ready"
|
||||
ConnectionClosed = "Connection closed"
|
||||
ConnectionCheckoutStarted = "Connection checkout started"
|
||||
ConnectionCheckoutFailed = "Connection checkout failed"
|
||||
ConnectionCheckedOut = "Connection checked out"
|
||||
ConnectionCheckedIn = "Connection checked in"
|
||||
ServerSelectionFailed = "Server selection failed"
|
||||
ServerSelectionStarted = "Server selection started"
|
||||
ServerSelectionSucceeded = "Server selection succeeded"
|
||||
ServerSelectionWaiting = "Waiting for suitable server to become available"
|
||||
TopologyClosed = "Stopped topology monitoring"
|
||||
TopologyDescriptionChanged = "Topology description changed"
|
||||
TopologyOpening = "Starting topology monitoring"
|
||||
TopologyServerClosed = "Stopped server monitoring"
|
||||
TopologyServerHeartbeatFailed = "Server heartbeat failed"
|
||||
TopologyServerHeartbeatStarted = "Server heartbeat started"
|
||||
TopologyServerHeartbeatSucceeded = "Server heartbeat succeeded"
|
||||
TopologyServerOpening = "Starting server monitoring"
|
||||
)
|
||||
|
||||
const (
|
||||
KeyAwaited = "awaited"
|
||||
KeyCommand = "command"
|
||||
KeyCommandName = "commandName"
|
||||
KeyDatabaseName = "databaseName"
|
||||
KeyDriverConnectionID = "driverConnectionId"
|
||||
KeyDurationMS = "durationMS"
|
||||
KeyError = "error"
|
||||
KeyFailure = "failure"
|
||||
KeyMaxConnecting = "maxConnecting"
|
||||
KeyMaxIdleTimeMS = "maxIdleTimeMS"
|
||||
KeyMaxPoolSize = "maxPoolSize"
|
||||
KeyMessage = "message"
|
||||
KeyMinPoolSize = "minPoolSize"
|
||||
KeyNewDescription = "newDescription"
|
||||
KeyOperation = "operation"
|
||||
KeyOperationID = "operationId"
|
||||
KeyPreviousDescription = "previousDescription"
|
||||
KeyRemainingTimeMS = "remainingTimeMS"
|
||||
KeyReason = "reason"
|
||||
KeyReply = "reply"
|
||||
KeyRequestID = "requestId"
|
||||
KeySelector = "selector"
|
||||
KeyServerConnectionID = "serverConnectionId"
|
||||
KeyServerHost = "serverHost"
|
||||
KeyServerPort = "serverPort"
|
||||
KeyServiceID = "serviceId"
|
||||
KeyTimestamp = "timestamp"
|
||||
KeyTopologyDescription = "topologyDescription"
|
||||
KeyTopologyID = "topologyId"
|
||||
)
|
||||
|
||||
// KeyValues is a list of key-value pairs.
|
||||
type KeyValues []any
|
||||
|
||||
// Add adds a key-value pair to an instance of a KeyValues list.
|
||||
func (kvs *KeyValues) Add(key string, value any) {
|
||||
*kvs = append(*kvs, key, value)
|
||||
}
|
||||
|
||||
const (
|
||||
ReasonConnClosedStale = "Connection became stale because the pool was cleared"
|
||||
ReasonConnClosedIdle = "Connection has been available but unused for longer than the configured max idle time"
|
||||
ReasonConnClosedError = "An error occurred while using the connection"
|
||||
ReasonConnClosedPoolClosed = "Connection pool was closed"
|
||||
ReasonConnCheckoutFailedTimout = "Wait queue timeout elapsed without a connection becoming available"
|
||||
ReasonConnCheckoutFailedError = "An error occurred while trying to establish a new connection"
|
||||
ReasonConnCheckoutFailedPoolClosed = "Connection pool was closed"
|
||||
)
|
||||
|
||||
// Component is an enumeration representing the "components" which can be
|
||||
// logged against. A LogLevel can be configured on a per-component basis.
|
||||
type Component int
|
||||
|
||||
const (
|
||||
// ComponentAll enables logging for all components.
|
||||
ComponentAll Component = iota
|
||||
|
||||
// ComponentCommand enables command monitor logging.
|
||||
ComponentCommand
|
||||
|
||||
// ComponentTopology enables topology logging.
|
||||
ComponentTopology
|
||||
|
||||
// ComponentServerSelection enables server selection logging.
|
||||
ComponentServerSelection
|
||||
|
||||
// ComponentConnection enables connection services logging.
|
||||
ComponentConnection
|
||||
)
|
||||
|
||||
const (
|
||||
mongoDBLogAllEnvVar = "MONGODB_LOG_ALL"
|
||||
mongoDBLogCommandEnvVar = "MONGODB_LOG_COMMAND"
|
||||
mongoDBLogTopologyEnvVar = "MONGODB_LOG_TOPOLOGY"
|
||||
mongoDBLogServerSelectionEnvVar = "MONGODB_LOG_SERVER_SELECTION"
|
||||
mongoDBLogConnectionEnvVar = "MONGODB_LOG_CONNECTION"
|
||||
)
|
||||
|
||||
var componentEnvVarMap = map[string]Component{
|
||||
mongoDBLogAllEnvVar: ComponentAll,
|
||||
mongoDBLogCommandEnvVar: ComponentCommand,
|
||||
mongoDBLogTopologyEnvVar: ComponentTopology,
|
||||
mongoDBLogServerSelectionEnvVar: ComponentServerSelection,
|
||||
mongoDBLogConnectionEnvVar: ComponentConnection,
|
||||
}
|
||||
|
||||
// EnvHasComponentVariables returns true if the environment contains any of the
|
||||
// component environment variables.
|
||||
func EnvHasComponentVariables() bool {
|
||||
for envVar := range componentEnvVarMap {
|
||||
if os.Getenv(envVar) != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Command is a struct defining common fields that must be included in all
|
||||
// commands.
|
||||
type Command struct {
|
||||
DriverConnectionID int64 // Driver's ID for the connection
|
||||
Name string // Command name
|
||||
DatabaseName string // Database name
|
||||
Message string // Message associated with the command
|
||||
OperationID int32 // Driver-generated operation ID
|
||||
RequestID int64 // Driver-generated request ID
|
||||
ServerConnectionID *int64 // Server's ID for the connection used for the command
|
||||
ServerHost string // Hostname or IP address for the server
|
||||
ServerPort string // Port for the server
|
||||
ServiceID *bson.ObjectID // ID for the command in load balancer mode
|
||||
}
|
||||
|
||||
// SerializeCommand takes a command and a variable number of key-value pairs and
|
||||
// returns a slice of any that can be passed to the logger for
|
||||
// structured logging.
|
||||
func SerializeCommand(cmd Command, extraKeysAndValues ...any) KeyValues {
|
||||
// Initialize the boilerplate keys and values.
|
||||
keysAndValues := KeyValues{
|
||||
KeyCommandName, cmd.Name,
|
||||
KeyDatabaseName, cmd.DatabaseName,
|
||||
KeyDriverConnectionID, cmd.DriverConnectionID,
|
||||
KeyMessage, cmd.Message,
|
||||
KeyOperationID, cmd.OperationID,
|
||||
KeyRequestID, cmd.RequestID,
|
||||
KeyServerHost, cmd.ServerHost,
|
||||
}
|
||||
|
||||
// Add the extra keys and values.
|
||||
for i := 0; i < len(extraKeysAndValues); i += 2 {
|
||||
keysAndValues.Add(extraKeysAndValues[i].(string), extraKeysAndValues[i+1])
|
||||
}
|
||||
|
||||
port, err := strconv.ParseInt(cmd.ServerPort, 10, 32)
|
||||
if err == nil {
|
||||
keysAndValues.Add(KeyServerPort, port)
|
||||
}
|
||||
|
||||
// Add the "serverConnectionId" if it is not nil.
|
||||
if cmd.ServerConnectionID != nil {
|
||||
keysAndValues.Add(KeyServerConnectionID, *cmd.ServerConnectionID)
|
||||
}
|
||||
|
||||
// Add the "serviceId" if it is not nil.
|
||||
if cmd.ServiceID != nil {
|
||||
keysAndValues.Add(KeyServiceID, cmd.ServiceID.Hex())
|
||||
}
|
||||
|
||||
return keysAndValues
|
||||
}
|
||||
|
||||
// Connection contains data that all connection log messages MUST contain.
|
||||
type Connection struct {
|
||||
Message string // Message associated with the connection
|
||||
ServerHost string // Hostname or IP address for the server
|
||||
ServerPort string // Port for the server
|
||||
}
|
||||
|
||||
// SerializeConnection serializes a Connection message into a slice of keys and
|
||||
// values that can be passed to a logger.
|
||||
func SerializeConnection(conn Connection, extraKeysAndValues ...any) KeyValues {
|
||||
// Initialize the boilerplate keys and values.
|
||||
keysAndValues := KeyValues{
|
||||
KeyMessage, conn.Message,
|
||||
KeyServerHost, conn.ServerHost,
|
||||
}
|
||||
|
||||
// Add the optional keys and values.
|
||||
for i := 0; i < len(extraKeysAndValues); i += 2 {
|
||||
keysAndValues.Add(extraKeysAndValues[i].(string), extraKeysAndValues[i+1])
|
||||
}
|
||||
|
||||
port, err := strconv.ParseInt(conn.ServerPort, 10, 32)
|
||||
if err == nil {
|
||||
keysAndValues.Add(KeyServerPort, port)
|
||||
}
|
||||
|
||||
return keysAndValues
|
||||
}
|
||||
|
||||
// Server contains data that all server messages MAY contain.
|
||||
type Server struct {
|
||||
DriverConnectionID int64 // Driver's ID for the connection
|
||||
TopologyID bson.ObjectID // Driver's unique ID for this topology
|
||||
Message string // Message associated with the topology
|
||||
ServerConnectionID *int64 // Server's ID for the connection
|
||||
ServerHost string // Hostname or IP address for the server
|
||||
ServerPort string // Port for the server
|
||||
}
|
||||
|
||||
// SerializeServer serializes a Server message into a slice of keys and
|
||||
// values that can be passed to a logger.
|
||||
func SerializeServer(srv Server, extraKV ...any) KeyValues {
|
||||
// Initialize the boilerplate keys and values.
|
||||
keysAndValues := KeyValues{
|
||||
KeyDriverConnectionID, srv.DriverConnectionID,
|
||||
KeyMessage, srv.Message,
|
||||
KeyServerHost, srv.ServerHost,
|
||||
KeyTopologyID, srv.TopologyID.Hex(),
|
||||
}
|
||||
|
||||
if connID := srv.ServerConnectionID; connID != nil {
|
||||
keysAndValues.Add(KeyServerConnectionID, *connID)
|
||||
}
|
||||
|
||||
port, err := strconv.ParseInt(srv.ServerPort, 10, 32)
|
||||
if err == nil {
|
||||
keysAndValues.Add(KeyServerPort, port)
|
||||
}
|
||||
|
||||
// Add the optional keys and values.
|
||||
for i := 0; i < len(extraKV); i += 2 {
|
||||
keysAndValues.Add(extraKV[i].(string), extraKV[i+1])
|
||||
}
|
||||
|
||||
return keysAndValues
|
||||
}
|
||||
|
||||
// ServerSelection contains data that all server selection messages MUST
|
||||
// contain.
|
||||
type ServerSelection struct {
|
||||
Selector string
|
||||
OperationID *int32
|
||||
Operation string
|
||||
TopologyDescription string
|
||||
}
|
||||
|
||||
// SerializeServerSelection serializes a Topology message into a slice of keys
|
||||
// and values that can be passed to a logger.
|
||||
func SerializeServerSelection(srvSelection ServerSelection, extraKV ...any) KeyValues {
|
||||
keysAndValues := KeyValues{
|
||||
KeySelector, srvSelection.Selector,
|
||||
KeyOperation, srvSelection.Operation,
|
||||
KeyTopologyDescription, srvSelection.TopologyDescription,
|
||||
}
|
||||
|
||||
if srvSelection.OperationID != nil {
|
||||
keysAndValues.Add(KeyOperationID, *srvSelection.OperationID)
|
||||
}
|
||||
|
||||
// Add the optional keys and values.
|
||||
for i := 0; i < len(extraKV); i += 2 {
|
||||
keysAndValues.Add(extraKV[i].(string), extraKV[i+1])
|
||||
}
|
||||
|
||||
return keysAndValues
|
||||
}
|
||||
|
||||
// Topology contains data that all topology messages MAY contain.
|
||||
type Topology struct {
|
||||
ID bson.ObjectID // Driver's unique ID for this topology
|
||||
Message string // Message associated with the topology
|
||||
}
|
||||
|
||||
// SerializeTopology serializes a Topology message into a slice of keys and
|
||||
// values that can be passed to a logger.
|
||||
func SerializeTopology(topo Topology, extraKV ...any) KeyValues {
|
||||
keysAndValues := KeyValues{
|
||||
KeyTopologyID, topo.ID.Hex(),
|
||||
}
|
||||
|
||||
// Add the optional keys and values.
|
||||
for i := 0; i < len(extraKV); i += 2 {
|
||||
keysAndValues.Add(extraKV[i].(string), extraKV[i+1])
|
||||
}
|
||||
|
||||
return keysAndValues
|
||||
}
|
||||
48
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/context.go
generated
vendored
Normal file
48
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/context.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) MongoDB, Inc. 2023-present.
|
||||
//
|
||||
// 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
|
||||
|
||||
package logger
|
||||
|
||||
import "context"
|
||||
|
||||
// contextKey is a custom type used to prevent key collisions when using the
|
||||
// context package.
|
||||
type contextKey string
|
||||
|
||||
const (
|
||||
contextKeyOperation contextKey = "operation"
|
||||
contextKeyOperationID contextKey = "operationID"
|
||||
)
|
||||
|
||||
// WithOperationName adds the operation name to the context.
|
||||
func WithOperationName(ctx context.Context, operation string) context.Context {
|
||||
return context.WithValue(ctx, contextKeyOperation, operation)
|
||||
}
|
||||
|
||||
// WithOperationID adds the operation ID to the context.
|
||||
func WithOperationID(ctx context.Context, operationID int32) context.Context {
|
||||
return context.WithValue(ctx, contextKeyOperationID, operationID)
|
||||
}
|
||||
|
||||
// OperationName returns the operation name from the context.
|
||||
func OperationName(ctx context.Context) (string, bool) {
|
||||
operationName := ctx.Value(contextKeyOperation)
|
||||
if operationName == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return operationName.(string), true
|
||||
}
|
||||
|
||||
// OperationID returns the operation ID from the context.
|
||||
func OperationID(ctx context.Context) (int32, bool) {
|
||||
operationID := ctx.Value(contextKeyOperationID)
|
||||
if operationID == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return operationID.(int32), true
|
||||
}
|
||||
63
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/io_sink.go
generated
vendored
Normal file
63
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/io_sink.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (C) MongoDB, Inc. 2023-present.
|
||||
//
|
||||
// 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
|
||||
|
||||
package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IOSink writes a JSON-encoded message to the io.Writer.
|
||||
type IOSink struct {
|
||||
enc *json.Encoder
|
||||
|
||||
// encMu protects the encoder from concurrent writes. While the logger
|
||||
// itself does not concurrently write to the sink, the sink may be used
|
||||
// concurrently within the driver.
|
||||
encMu sync.Mutex
|
||||
}
|
||||
|
||||
// Compile-time check to ensure IOSink implements the LogSink interface.
|
||||
var _ LogSink = &IOSink{}
|
||||
|
||||
// NewIOSink will create an IOSink object that writes JSON messages to the
|
||||
// provided io.Writer.
|
||||
func NewIOSink(out io.Writer) *IOSink {
|
||||
return &IOSink{
|
||||
enc: json.NewEncoder(out),
|
||||
}
|
||||
}
|
||||
|
||||
// Info will write a JSON-encoded message to the io.Writer.
|
||||
func (sink *IOSink) Info(_ int, msg string, keysAndValues ...any) {
|
||||
mapSize := len(keysAndValues) / 2
|
||||
if math.MaxInt-mapSize >= 2 {
|
||||
mapSize += 2
|
||||
}
|
||||
kvMap := make(map[string]any, mapSize)
|
||||
|
||||
kvMap[KeyTimestamp] = time.Now().UnixNano()
|
||||
kvMap[KeyMessage] = msg
|
||||
|
||||
for i := 0; i < len(keysAndValues); i += 2 {
|
||||
kvMap[keysAndValues[i].(string)] = keysAndValues[i+1]
|
||||
}
|
||||
|
||||
sink.encMu.Lock()
|
||||
defer sink.encMu.Unlock()
|
||||
|
||||
_ = sink.enc.Encode(kvMap)
|
||||
}
|
||||
|
||||
// Error will write a JSON-encoded error message to the io.Writer.
|
||||
func (sink *IOSink) Error(err error, msg string, kv ...any) {
|
||||
kv = append(kv, KeyError, err.Error())
|
||||
sink.Info(0, msg, kv...)
|
||||
}
|
||||
74
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/level.go
generated
vendored
Normal file
74
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/level.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (C) MongoDB, Inc. 2023-present.
|
||||
//
|
||||
// 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
|
||||
|
||||
package logger
|
||||
|
||||
import "strings"
|
||||
|
||||
// DiffToInfo is the number of levels in the Go Driver that come before the
|
||||
// "Info" level. This should ensure that "Info" is the 0th level passed to the
|
||||
// sink.
|
||||
const DiffToInfo = 1
|
||||
|
||||
// Level is an enumeration representing the log severity levels supported by
|
||||
// the driver. The order of the logging levels is important. The driver expects
|
||||
// that a user will likely use the "logr" package to create a LogSink, which
|
||||
// defaults InfoLevel as 0. Any additions to the Level enumeration before the
|
||||
// InfoLevel will need to also update the "diffToInfo" constant.
|
||||
type Level int
|
||||
|
||||
const (
|
||||
// LevelOff suppresses logging.
|
||||
LevelOff Level = iota
|
||||
|
||||
// LevelInfo enables logging of informational messages. These logs are
|
||||
// high-level information about normal driver behavior.
|
||||
LevelInfo
|
||||
|
||||
// LevelDebug enables logging of debug messages. These logs can be
|
||||
// voluminous and are intended for detailed information that may be
|
||||
// helpful when debugging an application.
|
||||
LevelDebug
|
||||
)
|
||||
|
||||
const (
|
||||
levelLiteralOff = "off"
|
||||
levelLiteralEmergency = "emergency"
|
||||
levelLiteralAlert = "alert"
|
||||
levelLiteralCritical = "critical"
|
||||
levelLiteralError = "error"
|
||||
levelLiteralWarning = "warning"
|
||||
levelLiteralNotice = "notice"
|
||||
levelLiteralInfo = "info"
|
||||
levelLiteralDebug = "debug"
|
||||
levelLiteralTrace = "trace"
|
||||
)
|
||||
|
||||
var LevelLiteralMap = map[string]Level{
|
||||
levelLiteralOff: LevelOff,
|
||||
levelLiteralEmergency: LevelInfo,
|
||||
levelLiteralAlert: LevelInfo,
|
||||
levelLiteralCritical: LevelInfo,
|
||||
levelLiteralError: LevelInfo,
|
||||
levelLiteralWarning: LevelInfo,
|
||||
levelLiteralNotice: LevelInfo,
|
||||
levelLiteralInfo: LevelInfo,
|
||||
levelLiteralDebug: LevelDebug,
|
||||
levelLiteralTrace: LevelDebug,
|
||||
}
|
||||
|
||||
// ParseLevel will check if the given string is a valid environment variable
|
||||
// for a logging severity level. If it is, then it will return the associated
|
||||
// driver's Level. The default Level is “LevelOff”.
|
||||
func ParseLevel(str string) Level {
|
||||
for literal, level := range LevelLiteralMap {
|
||||
if strings.EqualFold(literal, str) {
|
||||
return level
|
||||
}
|
||||
}
|
||||
|
||||
return LevelOff
|
||||
}
|
||||
266
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/logger.go
generated
vendored
Normal file
266
server/vendor/go.mongodb.org/mongo-driver/v2/internal/logger/logger.go
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
// Copyright (C) MongoDB, Inc. 2023-present.
|
||||
//
|
||||
// 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
|
||||
|
||||
// Package logger provides the internal logging solution for the MongoDB Go
|
||||
// Driver.
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/internal/bsoncoreutil"
|
||||
"go.mongodb.org/mongo-driver/v2/x/bsonx/bsoncore"
|
||||
)
|
||||
|
||||
// DefaultMaxDocumentLength is the default maximum number of bytes that can be
|
||||
// logged for a stringified BSON document.
|
||||
const DefaultMaxDocumentLength = 1000
|
||||
|
||||
// TruncationSuffix are trailing ellipsis "..." appended to a message to
|
||||
// indicate to the user that truncation occurred. This constant does not count
|
||||
// toward the max document length.
|
||||
const TruncationSuffix = "..."
|
||||
|
||||
const (
|
||||
logSinkPathEnvVar = "MONGODB_LOG_PATH"
|
||||
maxDocumentLengthEnvVar = "MONGODB_LOG_MAX_DOCUMENT_LENGTH"
|
||||
)
|
||||
|
||||
// LogSink represents a logging implementation, this interface should be 1-1
|
||||
// with the exported "LogSink" interface in the mongo/options package.
|
||||
type LogSink interface {
|
||||
// Info logs a non-error message with the given key/value pairs. The
|
||||
// level argument is provided for optional logging.
|
||||
Info(level int, msg string, keysAndValues ...any)
|
||||
|
||||
// Error logs an error, with the given message and key/value pairs.
|
||||
Error(err error, msg string, keysAndValues ...any)
|
||||
}
|
||||
|
||||
// Logger represents the configuration for the internal logger.
|
||||
type Logger struct {
|
||||
ComponentLevels map[Component]Level // Log levels for each component.
|
||||
Sink LogSink // LogSink for log printing.
|
||||
MaxDocumentLength uint // Command truncation width.
|
||||
logFile *os.File // File to write logs to.
|
||||
}
|
||||
|
||||
// New will construct a new logger. If any of the given options are the
|
||||
// zero-value of the argument type, then the constructor will attempt to
|
||||
// source the data from the environment. If the environment has not been set,
|
||||
// then the constructor will the respective default values.
|
||||
func New(sink LogSink, maxDocLen uint, compLevels map[Component]Level) (*Logger, error) {
|
||||
logger := &Logger{
|
||||
ComponentLevels: selectComponentLevels(compLevels),
|
||||
MaxDocumentLength: selectMaxDocumentLength(maxDocLen),
|
||||
}
|
||||
|
||||
sink, logFile, err := selectLogSink(sink)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Sink = sink
|
||||
logger.logFile = logFile
|
||||
|
||||
return logger, nil
|
||||
}
|
||||
|
||||
// Close will close the logger's log file, if it exists.
|
||||
func (logger *Logger) Close() error {
|
||||
if logger.logFile != nil {
|
||||
return logger.logFile.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LevelComponentEnabled will return true if the given LogLevel is enabled for
|
||||
// the given LogComponent. If the ComponentLevels on the logger are enabled for
|
||||
// "ComponentAll", then this function will return true for any level bound by
|
||||
// the level assigned to "ComponentAll".
|
||||
//
|
||||
// If the level is not enabled (i.e. LevelOff), then false is returned. This is
|
||||
// to avoid false positives, such as returning "true" for a component that is
|
||||
// not enabled. For example, without this condition, an empty LevelComponent
|
||||
// would be considered "enabled" for "LevelOff".
|
||||
func (logger *Logger) LevelComponentEnabled(level Level, component Component) bool {
|
||||
if level == LevelOff {
|
||||
return false
|
||||
}
|
||||
|
||||
if logger.ComponentLevels == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return logger.ComponentLevels[component] >= level ||
|
||||
logger.ComponentLevels[ComponentAll] >= level
|
||||
}
|
||||
|
||||
// Print will synchronously print the given message to the configured LogSink.
|
||||
// If the LogSink is nil, then this method will do nothing. Future work could be done to make
|
||||
// this method asynchronous, see buffer management in libraries such as log4j.
|
||||
//
|
||||
// It's worth noting that many structured logs defined by DBX-wide
|
||||
// specifications include a "message" field, which is often shared with the
|
||||
// message arguments passed to this print function. The "Info" method used by
|
||||
// this function is implemented based on the go-logr/logr LogSink interface,
|
||||
// which is why "Print" has a message parameter. Any duplication in code is
|
||||
// intentional to adhere to the logr pattern.
|
||||
func (logger *Logger) Print(level Level, component Component, msg string, keysAndValues ...any) {
|
||||
// If the level is not enabled for the component, then
|
||||
// skip the message.
|
||||
if !logger.LevelComponentEnabled(level, component) {
|
||||
return
|
||||
}
|
||||
|
||||
// If the sink is nil, then skip the message.
|
||||
if logger.Sink == nil {
|
||||
return
|
||||
}
|
||||
|
||||
logger.Sink.Info(int(level)-DiffToInfo, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// Error logs an error, with the given message and key/value pairs.
|
||||
// It functions similarly to Print, but may have unique behavior, and should be
|
||||
// preferred for logging errors.
|
||||
func (logger *Logger) Error(err error, msg string, keysAndValues ...any) {
|
||||
if logger.Sink == nil {
|
||||
return
|
||||
}
|
||||
|
||||
logger.Sink.Error(err, msg, keysAndValues...)
|
||||
}
|
||||
|
||||
// selectMaxDocumentLength will return the integer value of the first non-zero
|
||||
// function, with the user-defined function taking priority over the environment
|
||||
// variables. For the environment, the function will attempt to get the value of
|
||||
// "MONGODB_LOG_MAX_DOCUMENT_LENGTH" and parse it as an unsigned integer. If the
|
||||
// environment variable is not set or is not an unsigned integer, then this
|
||||
// function will return the default max document length.
|
||||
func selectMaxDocumentLength(maxDocLen uint) uint {
|
||||
if maxDocLen != 0 {
|
||||
return maxDocLen
|
||||
}
|
||||
|
||||
maxDocLenEnv := os.Getenv(maxDocumentLengthEnvVar)
|
||||
if maxDocLenEnv != "" {
|
||||
maxDocLenEnvInt, err := strconv.ParseUint(maxDocLenEnv, 10, 32)
|
||||
if err == nil {
|
||||
return uint(maxDocLenEnvInt)
|
||||
}
|
||||
}
|
||||
|
||||
return DefaultMaxDocumentLength
|
||||
}
|
||||
|
||||
const (
|
||||
logSinkPathStdout = "stdout"
|
||||
logSinkPathStderr = "stderr"
|
||||
)
|
||||
|
||||
// selectLogSink will return the first non-nil LogSink, with the user-defined
|
||||
// LogSink taking precedence over the environment-defined LogSink. If no LogSink
|
||||
// is defined, then this function will return a LogSink that writes to stderr.
|
||||
func selectLogSink(sink LogSink) (LogSink, *os.File, error) {
|
||||
if sink != nil {
|
||||
return sink, nil, nil
|
||||
}
|
||||
|
||||
path := os.Getenv(logSinkPathEnvVar)
|
||||
lowerPath := strings.ToLower(path)
|
||||
|
||||
if lowerPath == string(logSinkPathStderr) {
|
||||
return NewIOSink(os.Stderr), nil, nil
|
||||
}
|
||||
|
||||
if lowerPath == string(logSinkPathStdout) {
|
||||
return NewIOSink(os.Stdout), nil, nil
|
||||
}
|
||||
|
||||
if path != "" {
|
||||
logFile, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to open log file: %w", err)
|
||||
}
|
||||
|
||||
return NewIOSink(logFile), logFile, nil
|
||||
}
|
||||
|
||||
return NewIOSink(os.Stderr), nil, nil
|
||||
}
|
||||
|
||||
// selectComponentLevels returns a new map of LogComponents to LogLevels that is
|
||||
// the result of merging the user-defined data with the environment, with the
|
||||
// user-defined data taking priority.
|
||||
func selectComponentLevels(componentLevels map[Component]Level) map[Component]Level {
|
||||
selected := make(map[Component]Level)
|
||||
|
||||
// Determine if the "MONGODB_LOG_ALL" environment variable is set.
|
||||
var globalEnvLevel *Level
|
||||
if all := os.Getenv(mongoDBLogAllEnvVar); all != "" {
|
||||
level := ParseLevel(all)
|
||||
globalEnvLevel = &level
|
||||
}
|
||||
|
||||
for envVar, component := range componentEnvVarMap {
|
||||
// If the component already has a level, then skip it.
|
||||
if _, ok := componentLevels[component]; ok {
|
||||
selected[component] = componentLevels[component]
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// If the "MONGODB_LOG_ALL" environment variable is set, then
|
||||
// set the level for the component to the value of the
|
||||
// environment variable.
|
||||
if globalEnvLevel != nil {
|
||||
selected[component] = *globalEnvLevel
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, set the level for the component to the value of
|
||||
// the environment variable.
|
||||
selected[component] = ParseLevel(os.Getenv(envVar))
|
||||
}
|
||||
|
||||
return selected
|
||||
}
|
||||
|
||||
// FormatDocument formats a BSON document or RawValue for logging. The document is truncated
|
||||
// to the given width.
|
||||
func FormatDocument(msg bson.Raw, width uint) string {
|
||||
if len(msg) == 0 {
|
||||
return "{}"
|
||||
}
|
||||
|
||||
str, truncated := bsoncore.Document(msg).StringN(int(width))
|
||||
|
||||
if truncated {
|
||||
str += TruncationSuffix
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// FormatString formats a String for logging. The string is truncated
|
||||
// to the given width.
|
||||
func FormatString(str string, width uint) string {
|
||||
strTrunc := bsoncoreutil.Truncate(str, int(width))
|
||||
|
||||
// Checks if the string was truncating by comparing the lengths of the two strings.
|
||||
if len(strTrunc) < len(str) {
|
||||
strTrunc += TruncationSuffix
|
||||
}
|
||||
|
||||
return strTrunc
|
||||
}
|
||||
Reference in New Issue
Block a user