mirror of
https://github.com/traefik/traefik.git
synced 2025-10-28 15:01:15 +01:00
fix: enable stdio logging when otlp is enabled
This commit is contained in:
parent
862116c050
commit
6e0012cb0a
@ -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
integration/dual_logging_test.go
Normal file
134
integration/dual_logging_test.go
Normal 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)
|
||||
}
|
||||
24
integration/fixtures/dual_logging/otlp_and_stdout.toml
Normal file
24
integration/fixtures/dual_logging/otlp_and_stdout.toml
Normal 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
|
||||
@ -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))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user