|
| 1 | +// Copyright 2025 The Cockroach Authors. |
| 2 | +// |
| 3 | +// Use of this software is governed by the CockroachDB Software License |
| 4 | +// included in the /LICENSE file. |
| 5 | + |
| 6 | +package log |
| 7 | + |
| 8 | +import ( |
| 9 | + "context" |
| 10 | + |
| 11 | + "github.com/cockroachdb/cockroach/pkg/settings" |
| 12 | + "github.com/cockroachdb/cockroach/pkg/util/log/logpb" |
| 13 | + "github.com/cockroachdb/cockroach/pkg/util/log/severity" |
| 14 | + "github.com/cockroachdb/cockroach/pkg/util/metamorphic" |
| 15 | +) |
| 16 | + |
| 17 | +// ChannelCompatibilityModeEnabled controls whether certain logs are routed |
| 18 | +// to newly defined logging channels or continue to use their original ones. |
| 19 | +var ChannelCompatibilityModeEnabled = settings.RegisterBoolSetting( |
| 20 | + settings.ApplicationLevel, |
| 21 | + "log.channel_compatibility_mode.enabled", |
| 22 | + "when true, logs will continue to log to the expected logging channels; "+ |
| 23 | + "when false, logs will be moved to new logging channels as part of a "+ |
| 24 | + "logging channel consolidation effort", |
| 25 | + metamorphic.ConstantWithTestBool("log.channel_compatibility_mode.enabled", true), |
| 26 | + settings.WithPublic, |
| 27 | +) |
| 28 | + |
| 29 | +func ShouldMigrateEvent(sv *settings.Values) bool { |
| 30 | + return !ChannelCompatibilityModeEnabled.Get(sv) |
| 31 | +} |
| 32 | + |
| 33 | +// StructuredEventMigrator handles conditional routing of structured events |
| 34 | +// between old and new logging channels based on a shouldMigrate function. |
| 35 | +type StructuredEventMigrator struct { |
| 36 | + shouldMigrate func() bool |
| 37 | + newChannel Channel |
| 38 | +} |
| 39 | + |
| 40 | +// NewStructuredEventMigrator creates a new StructuredEventMigrator that routes |
| 41 | +// structured events to either the specified new channel (when shouldMigrate returns |
| 42 | +// true) or to the event's original channel (when shouldMigrate returns false). |
| 43 | +func NewStructuredEventMigrator( |
| 44 | + shouldMigrate func() bool, newChannel Channel, |
| 45 | +) StructuredEventMigrator { |
| 46 | + return StructuredEventMigrator{ |
| 47 | + shouldMigrate: shouldMigrate, |
| 48 | + newChannel: newChannel, |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +// StructuredEvent logs a structured event using the migrator's routing logic. |
| 53 | +func (sem StructuredEventMigrator) StructuredEvent( |
| 54 | + ctx context.Context, sev logpb.Severity, event logpb.EventPayload, |
| 55 | +) { |
| 56 | + sem.structuredEventDepth(ctx, sev, 1, event) |
| 57 | +} |
| 58 | + |
| 59 | +// StructuredEventDepth logs a structured event with a custom stack depth |
| 60 | +// for accurate caller identification in logs. |
| 61 | +func (sem StructuredEventMigrator) StructuredEventDepth( |
| 62 | + ctx context.Context, sev logpb.Severity, depth int, event logpb.EventPayload, |
| 63 | +) { |
| 64 | + sem.structuredEventDepth(ctx, sev, depth+1, event) |
| 65 | +} |
| 66 | + |
| 67 | +// structuredEventDepth is the internal implementation that performs the actual |
| 68 | +// channel routing based on the shouldMigrate function value. |
| 69 | +func (sem StructuredEventMigrator) structuredEventDepth( |
| 70 | + ctx context.Context, sev logpb.Severity, depth int, event logpb.EventPayload, |
| 71 | +) { |
| 72 | + if sem.shouldMigrate() { |
| 73 | + structuredEventDepth(ctx, sev, depth+1, sem.newChannel, event) |
| 74 | + } else { |
| 75 | + structuredEventDepth(ctx, sev, depth+1, event.LoggingChannel(), event) |
| 76 | + |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +// Migrator handles conditional routing of formatted log messages between |
| 81 | +// deprecated and new logging channels based on a migration setting. |
| 82 | +type Migrator struct { |
| 83 | + shouldMigrate func() bool |
| 84 | + oldChannel Channel |
| 85 | + newChannel Channel |
| 86 | +} |
| 87 | + |
| 88 | +// NewMigrator creates a new Migrator that routes log messages between old and new |
| 89 | +// channels based on the shouldMigrate function. |
| 90 | +func NewMigrator(shouldMigrate func() bool, oldChannel Channel, newChannel Channel) Migrator { |
| 91 | + return Migrator{shouldMigrate: shouldMigrate, oldChannel: oldChannel, newChannel: newChannel} |
| 92 | +} |
| 93 | + |
| 94 | +// logfDepth is the internal helper that routes log messages to either the |
| 95 | +// new channel (when shouldMigrate returns true) or old channel (when shouldMigrate returns false). |
| 96 | +func (m Migrator) logfDepth( |
| 97 | + ctx context.Context, sev Severity, depth int, format string, args ...interface{}, |
| 98 | +) { |
| 99 | + if m.shouldMigrate() { |
| 100 | + logfDepth(ctx, depth+1, sev, m.newChannel, format, args...) |
| 101 | + } else { |
| 102 | + logfDepth(ctx, depth+1, sev, m.oldChannel, format, args...) |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | +// Infof logs an info-level message using the migrator's routing logic. |
| 107 | +func (m Migrator) Infof(ctx context.Context, format string, args ...interface{}) { |
| 108 | + m.logfDepth(ctx, severity.INFO, 1, format, args...) |
| 109 | +} |
| 110 | + |
| 111 | +// Warningf logs a warning-level message using the migrator's routing logic. |
| 112 | +func (m Migrator) Warningf(ctx context.Context, format string, args ...interface{}) { |
| 113 | + m.logfDepth(ctx, severity.WARNING, 1, format, args...) |
| 114 | +} |
| 115 | + |
| 116 | +// Errorf logs an error-level message using the migrator's routing logic. |
| 117 | +func (m Migrator) Errorf(ctx context.Context, format string, args ...interface{}) { |
| 118 | + m.logfDepth(ctx, severity.ERROR, 1, format, args...) |
| 119 | +} |
| 120 | + |
| 121 | +// Fatalf logs a fatal-level message using the migrator's routing logic. |
| 122 | +func (m Migrator) Fatalf(ctx context.Context, format string, args ...interface{}) { |
| 123 | + m.logfDepth(ctx, severity.FATAL, 1, format, args...) |
| 124 | +} |
| 125 | + |
| 126 | +func (m Migrator) VEventf(ctx context.Context, level Level, format string, args ...interface{}) { |
| 127 | + selectedChannel := m.oldChannel |
| 128 | + if m.shouldMigrate() { |
| 129 | + selectedChannel = m.newChannel |
| 130 | + } |
| 131 | + vEventf(ctx, false /* isErr */, 1, level, selectedChannel, format, args...) |
| 132 | +} |
0 commit comments