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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 161 additions and 7 deletions

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)

View File

@ -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)"

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)
}

View File

@ -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

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))