mirror of
https://github.com/traefik/traefik.git
synced 2025-10-29 07:21:13 +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 {
|
func getLogWriter(staticConfiguration *static.Configuration) io.Writer {
|
||||||
if staticConfiguration.Log != nil && staticConfiguration.Log.OTLP != nil {
|
|
||||||
return io.Discard
|
|
||||||
}
|
|
||||||
|
|
||||||
var w io.Writer = os.Stdout
|
var w io.Writer = os.Stdout
|
||||||
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
|
if staticConfiguration.Log != nil && len(staticConfiguration.Log.FilePath) > 0 {
|
||||||
_, _ = os.OpenFile(staticConfiguration.Log.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666)
|
_, _ = os.OpenFile(staticConfiguration.Log.FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666)
|
||||||
|
|||||||
@ -65,6 +65,9 @@ experimental:
|
|||||||
!!! warning
|
!!! warning
|
||||||
This is an experimental feature.
|
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
|
#### Configuration Example
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
```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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discard the event to avoid double logging.
|
|
||||||
e.Discard()
|
|
||||||
|
|
||||||
var record otellog.Record
|
var record otellog.Record
|
||||||
record.SetTimestamp(time.Now().UTC())
|
record.SetTimestamp(time.Now().UTC())
|
||||||
record.SetSeverity(otelLogSeverity(level))
|
record.SetSeverity(otelLogSeverity(level))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user