Merge branch v3.3 into v3.4
This commit is contained in:
commit
bf399f3075
4 changed files with 98 additions and 26 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
## [v3.3.7](https://github.com/traefik/traefik/tree/v3.3.7) (2025-05-05)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v3.3.6...v3.3.7)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[logs,middleware,accesslogs]** Add SpanID and TraceID accessLogs fields only when tracing is enabled ([#11715](https://github.com/traefik/traefik/pull/11715) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
|
||||||
## [v3.4.0-rc2](https://github.com/traefik/traefik/tree/v3.4.0-rc2) (2025-04-18)
|
## [v3.4.0-rc2](https://github.com/traefik/traefik/tree/v3.4.0-rc2) (2025-04-18)
|
||||||
[All Commits](https://github.com/traefik/traefik/compare/v3.4.0-rc1...v3.4.0-rc2)
|
[All Commits](https://github.com/traefik/traefik/compare/v3.4.0-rc1...v3.4.0-rc2)
|
||||||
|
|
||||||
|
|
|
@ -212,9 +212,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
|
||||||
|
|
||||||
if span := trace.SpanFromContext(req.Context()); span != nil {
|
if span := trace.SpanFromContext(req.Context()); span != nil {
|
||||||
spanContext := span.SpanContext()
|
spanContext := span.SpanContext()
|
||||||
|
if spanContext.HasTraceID() && spanContext.HasSpanID() {
|
||||||
logDataTable.Core[TraceID] = spanContext.TraceID().String()
|
logDataTable.Core[TraceID] = spanContext.TraceID().String()
|
||||||
logDataTable.Core[SpanID] = spanContext.SpanID().String()
|
logDataTable.Core[SpanID] = spanContext.SpanID().String()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reqWithDataTable := req.WithContext(context.WithValue(req.Context(), DataTableKey, logDataTable))
|
reqWithDataTable := req.WithContext(context.WithValue(req.Context(), DataTableKey, logDataTable))
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,10 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/middlewares/capture"
|
"github.com/traefik/traefik/v3/pkg/middlewares/capture"
|
||||||
"github.com/traefik/traefik/v3/pkg/types"
|
"github.com/traefik/traefik/v3/pkg/types"
|
||||||
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
|
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/codes"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
"go.opentelemetry.io/otel/trace/noop"
|
"go.opentelemetry.io/otel/trace/embedded"
|
||||||
)
|
)
|
||||||
|
|
||||||
const delta float64 = 1e-10
|
const delta float64 = 1e-10
|
||||||
|
@ -310,7 +312,7 @@ func TestLoggerHeaderFields(t *testing.T) {
|
||||||
func TestLoggerCLF(t *testing.T) {
|
func TestLoggerCLF(t *testing.T) {
|
||||||
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
||||||
config := &types.AccessLog{FilePath: logFilePath, Format: CommonFormat}
|
config := &types.AccessLog{FilePath: logFilePath, Format: CommonFormat}
|
||||||
doLogging(t, config)
|
doLogging(t, config, false)
|
||||||
|
|
||||||
logData, err := os.ReadFile(logFilePath)
|
logData, err := os.ReadFile(logFilePath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -322,7 +324,7 @@ func TestLoggerCLF(t *testing.T) {
|
||||||
func TestLoggerCLFWithBufferingSize(t *testing.T) {
|
func TestLoggerCLFWithBufferingSize(t *testing.T) {
|
||||||
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
|
||||||
config := &types.AccessLog{FilePath: logFilePath, Format: CommonFormat, BufferingSize: 1024}
|
config := &types.AccessLog{FilePath: logFilePath, Format: CommonFormat, BufferingSize: 1024}
|
||||||
doLogging(t, config)
|
doLogging(t, config, false)
|
||||||
|
|
||||||
// wait a bit for the buffer to be written in the file.
|
// wait a bit for the buffer to be written in the file.
|
||||||
time.Sleep(50 * time.Millisecond)
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
@ -371,10 +373,11 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
desc string
|
desc string
|
||||||
config *types.AccessLog
|
config *types.AccessLog
|
||||||
tls bool
|
tls bool
|
||||||
|
tracing bool
|
||||||
expected map[string]func(t *testing.T, value interface{})
|
expected map[string]func(t *testing.T, value interface{})
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "default config",
|
desc: "default config without tracing",
|
||||||
config: &types.AccessLog{
|
config: &types.AccessLog{
|
||||||
FilePath: "",
|
FilePath: "",
|
||||||
Format: JSONFormat,
|
Format: JSONFormat,
|
||||||
|
@ -410,8 +413,48 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
"time": assertNotEmpty(),
|
"time": assertNotEmpty(),
|
||||||
"StartLocal": assertNotEmpty(),
|
"StartLocal": assertNotEmpty(),
|
||||||
"StartUTC": assertNotEmpty(),
|
"StartUTC": assertNotEmpty(),
|
||||||
TraceID: assertNotEmpty(),
|
},
|
||||||
SpanID: assertNotEmpty(),
|
},
|
||||||
|
{
|
||||||
|
desc: "default config with tracing",
|
||||||
|
config: &types.AccessLog{
|
||||||
|
FilePath: "",
|
||||||
|
Format: JSONFormat,
|
||||||
|
},
|
||||||
|
tracing: true,
|
||||||
|
expected: map[string]func(t *testing.T, value interface{}){
|
||||||
|
RequestContentSize: assertFloat64(0),
|
||||||
|
RequestHost: assertString(testHostname),
|
||||||
|
RequestAddr: assertString(testHostname),
|
||||||
|
RequestMethod: assertString(testMethod),
|
||||||
|
RequestPath: assertString(testPath),
|
||||||
|
RequestProtocol: assertString(testProto),
|
||||||
|
RequestScheme: assertString(testScheme),
|
||||||
|
RequestPort: assertString("-"),
|
||||||
|
DownstreamStatus: assertFloat64(float64(testStatus)),
|
||||||
|
DownstreamContentSize: assertFloat64(float64(len(testContent))),
|
||||||
|
OriginContentSize: assertFloat64(float64(len(testContent))),
|
||||||
|
OriginStatus: assertFloat64(float64(testStatus)),
|
||||||
|
RequestRefererHeader: assertString(testReferer),
|
||||||
|
RequestUserAgentHeader: assertString(testUserAgent),
|
||||||
|
RouterName: assertString(testRouterName),
|
||||||
|
ServiceURL: assertString(testServiceName),
|
||||||
|
ClientUsername: assertString(testUsername),
|
||||||
|
ClientHost: assertString(testHostname),
|
||||||
|
ClientPort: assertString(strconv.Itoa(testPort)),
|
||||||
|
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
|
||||||
|
"level": assertString("info"),
|
||||||
|
"msg": assertString(""),
|
||||||
|
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
|
||||||
|
RequestCount: assertFloat64NotZero(),
|
||||||
|
Duration: assertFloat64NotZero(),
|
||||||
|
Overhead: assertFloat64NotZero(),
|
||||||
|
RetryAttempts: assertFloat64(float64(testRetryAttempts)),
|
||||||
|
"time": assertNotEmpty(),
|
||||||
|
"StartLocal": assertNotEmpty(),
|
||||||
|
"StartUTC": assertNotEmpty(),
|
||||||
|
TraceID: assertString("01000000000000000000000000000000"),
|
||||||
|
SpanID: assertString("0100000000000000"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -455,8 +498,6 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
"time": assertNotEmpty(),
|
"time": assertNotEmpty(),
|
||||||
StartLocal: assertNotEmpty(),
|
StartLocal: assertNotEmpty(),
|
||||||
StartUTC: assertNotEmpty(),
|
StartUTC: assertNotEmpty(),
|
||||||
TraceID: assertNotEmpty(),
|
|
||||||
SpanID: assertNotEmpty(),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -578,9 +619,9 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
|
|
||||||
test.config.FilePath = logFilePath
|
test.config.FilePath = logFilePath
|
||||||
if test.tls {
|
if test.tls {
|
||||||
doLoggingTLS(t, test.config)
|
doLoggingTLS(t, test.config, test.tracing)
|
||||||
} else {
|
} else {
|
||||||
doLogging(t, test.config)
|
doLogging(t, test.config, test.tracing)
|
||||||
}
|
}
|
||||||
|
|
||||||
logData, err := os.ReadFile(logFilePath)
|
logData, err := os.ReadFile(logFilePath)
|
||||||
|
@ -632,8 +673,6 @@ func TestLogger_AbortedRequest(t *testing.T) {
|
||||||
"downstream_Content-Type": assertString("text/plain"),
|
"downstream_Content-Type": assertString("text/plain"),
|
||||||
"downstream_Transfer-Encoding": assertString("chunked"),
|
"downstream_Transfer-Encoding": assertString("chunked"),
|
||||||
"downstream_Cache-Control": assertString("no-cache"),
|
"downstream_Cache-Control": assertString("no-cache"),
|
||||||
TraceID: assertNotEmpty(),
|
|
||||||
SpanID: assertNotEmpty(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &types.AccessLog{
|
config := &types.AccessLog{
|
||||||
|
@ -854,7 +893,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
|
||||||
file, restoreStdout := captureStdout(t)
|
file, restoreStdout := captureStdout(t)
|
||||||
defer restoreStdout()
|
defer restoreStdout()
|
||||||
|
|
||||||
doLogging(t, test.config)
|
doLogging(t, test.config, false)
|
||||||
|
|
||||||
written, err := os.ReadFile(file.Name())
|
written, err := os.ReadFile(file.Name())
|
||||||
require.NoError(t, err, "unable to read captured stdout from file")
|
require.NoError(t, err, "unable to read captured stdout from file")
|
||||||
|
@ -913,7 +952,7 @@ func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) {
|
||||||
return file, restoreStdout
|
return file, restoreStdout
|
||||||
}
|
}
|
||||||
|
|
||||||
func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) {
|
func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS, tracing bool) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
logger, err := NewHandler(config)
|
logger, err := NewHandler(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -952,9 +991,10 @@ func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer := noop.Tracer{}
|
if tracing {
|
||||||
spanCtx, _ := tracer.Start(req.Context(), "test")
|
contextWithSpan := trace.ContextWithSpan(req.Context(), &mockSpan{})
|
||||||
req = req.WithContext(spanCtx)
|
req = req.WithContext(contextWithSpan)
|
||||||
|
}
|
||||||
|
|
||||||
chain := alice.New()
|
chain := alice.New()
|
||||||
chain = chain.Append(capture.Wrap)
|
chain = chain.Append(capture.Wrap)
|
||||||
|
@ -965,16 +1005,16 @@ func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) {
|
||||||
handler.ServeHTTP(httptest.NewRecorder(), req)
|
handler.ServeHTTP(httptest.NewRecorder(), req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doLoggingTLS(t *testing.T, config *types.AccessLog) {
|
func doLoggingTLS(t *testing.T, config *types.AccessLog, tracing bool) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
doLoggingTLSOpt(t, config, true)
|
doLoggingTLSOpt(t, config, true, tracing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doLogging(t *testing.T, config *types.AccessLog) {
|
func doLogging(t *testing.T, config *types.AccessLog, tracing bool) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
doLoggingTLSOpt(t, config, false)
|
doLoggingTLSOpt(t, config, false, tracing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) {
|
func logWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -1091,3 +1131,27 @@ func streamBackend(rw http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mockSpan is an implementation of Span that preforms no operations.
|
||||||
|
type mockSpan struct {
|
||||||
|
embedded.Span
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ trace.Span = &mockSpan{}
|
||||||
|
|
||||||
|
func (*mockSpan) SpanContext() trace.SpanContext {
|
||||||
|
return trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID{1}, SpanID: trace.SpanID{1}})
|
||||||
|
}
|
||||||
|
func (*mockSpan) IsRecording() bool { return true }
|
||||||
|
func (s *mockSpan) SetStatus(_ codes.Code, _ string) {}
|
||||||
|
func (s *mockSpan) SetAttributes(...attribute.KeyValue) {}
|
||||||
|
func (s *mockSpan) End(...trace.SpanEndOption) {}
|
||||||
|
func (s *mockSpan) RecordError(_ error, _ ...trace.EventOption) {}
|
||||||
|
func (s *mockSpan) AddEvent(_ string, _ ...trace.EventOption) {}
|
||||||
|
func (s *mockSpan) AddLink(_ trace.Link) {}
|
||||||
|
|
||||||
|
func (s *mockSpan) SetName(_ string) {}
|
||||||
|
|
||||||
|
func (s *mockSpan) TracerProvider() trace.TracerProvider {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||||
OutputType = "file"
|
OutputType = "file"
|
||||||
FileName = "traefik_changelog.md"
|
FileName = "traefik_changelog.md"
|
||||||
|
|
||||||
# example new bugfix v3.3.6
|
# example new bugfix v3.3.7
|
||||||
CurrentRef = "v3.3"
|
CurrentRef = "v3.3"
|
||||||
PreviousRef = "v3.3.5"
|
PreviousRef = "v3.3.6"
|
||||||
BaseBranch = "v3.3"
|
BaseBranch = "v3.3"
|
||||||
FutureCurrentRefName = "v3.3.6"
|
FutureCurrentRefName = "v3.3.7"
|
||||||
|
|
||||||
ThresholdPreviousRef = 10
|
ThresholdPreviousRef = 10
|
||||||
ThresholdCurrentRef = 10
|
ThresholdCurrentRef = 10
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue