fix: enable stdio logging when otlp is enabled

This commit is contained in:
Landry Benguigui
2025-10-17 16:06:06 +02:00
committed by GitHub
parent 862116c050
commit 6e0012cb0a
5 changed files with 161 additions and 7 deletions
-4
View File
@@ -68,10 +68,6 @@ func setupLogger(ctx context.Context, staticConfiguration *static.Configuration)
}
func getLogWriter(staticConfiguration *static.Configuration) io.Writer {
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil {
return io.Discard
}
var w io.Writer = os.Stdout
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
_, _ = os.OpenFile(staticConfiguration.Log.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666)
@@ -65,6 +65,9 @@ experimental:
!!! warning
This is an experimental feature.
!!! note "Stdio logs remain available"
When OTLP logging is enabled, standard output (stdio) logs are still available and will continue to be written alongside OTLP exports.
#### Configuration Example
```yaml tab="File (YAML)"
+134
View File
@@ -0,0 +1,134 @@
package integration
import (
"compress/gzip"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"go.opentelemetry.io/collector/pdata/plog/plogotlp"
)
const traefikTestOTLPLogFile = "traefik_otlp.log"
// DualLoggingSuite tests that both OTLP and stdout logging can work together.
type DualLoggingSuite struct {
BaseSuite
otlpLogs []string
collector *httptest.Server
}
func TestDualLoggingSuite(t *testing.T) {
suite.Run(t, new(DualLoggingSuite))
}
func (s *DualLoggingSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
// Clean up any existing log files
os.Remove(traefikTestLogFile)
os.Remove(traefikTestOTLPLogFile)
}
func (s *DualLoggingSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
// Clean up log files
generatedFiles := []string{
traefikTestLogFile,
traefikTestOTLPLogFile,
}
for _, filename := range generatedFiles {
if err := os.Remove(filename); err != nil {
s.T().Logf("Failed to remove %s: %v", filename, err)
}
}
}
func (s *DualLoggingSuite) SetupTest() {
s.otlpLogs = []string{}
// Create mock OTLP collector
s.collector = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
gzr, err := gzip.NewReader(r.Body)
if err != nil {
s.T().Logf("Error creating gzip reader: %v", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer gzr.Close()
body, err := io.ReadAll(gzr)
if err != nil {
s.T().Logf("Error reading gzipped body: %v", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
req := plogotlp.NewExportRequest()
err = req.UnmarshalProto(body)
if err != nil {
s.T().Logf("Error unmarshaling protobuf: %v", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
marshalledReq, err := json.Marshal(req)
if err != nil {
s.T().Logf("Error marshaling to JSON: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
s.otlpLogs = append(s.otlpLogs, string(marshalledReq))
w.WriteHeader(http.StatusOK)
}))
}
func (s *DualLoggingSuite) TearDownTest() {
if s.collector != nil {
s.collector.Close()
s.collector = nil
}
}
func (s *DualLoggingSuite) TestOTLPAndStdoutLogging() {
tempObjects := struct {
CollectorURL string
}{
CollectorURL: s.collector.URL + "/v1/logs",
}
file := s.adaptFile("fixtures/dual_logging/otlp_and_stdout.toml", tempObjects)
cmd, display := s.cmdTraefik(withConfigFile(file))
defer s.displayTraefikLogFile(traefikTestLogFile)
s.waitForTraefik("dashboard")
time.Sleep(3 * time.Second)
s.killCmd(cmd)
time.Sleep(1 * time.Second)
assert.NotEmpty(s.T(), s.otlpLogs)
output := display.String()
otlpOutput := strings.Join(s.otlpLogs, "\n")
foundStdoutLog := strings.Contains(output, "Starting provider")
assert.True(s.T(), foundStdoutLog)
foundOTLPLog := strings.Contains(otlpOutput, "Starting provider")
assert.True(s.T(), foundOTLPLog)
}
@@ -0,0 +1,24 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "INFO"
[experimental]
otlpLogs = true
[log.otlp]
serviceName = "traefik-test"
[log.otlp.http]
endpoint = "{{ .CollectorURL }}"
[api]
insecure = true
[entryPoints]
[entryPoints.web]
address = ":8000"
[providers.docker]
exposedByDefault = false
-3
View File
@@ -41,9 +41,6 @@ func (h *otelLoggerHook) Run(e *zerolog.Event, level zerolog.Level, message stri
return
}
// Discard the event to avoid double logging.
e.Discard()
var record otellog.Record
record.SetTimestamp(time.Now().UTC())
record.SetSeverity(otelLogSeverity(level))