stdlog_bridge_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package logger
  2. import (
  3. "io"
  4. "log"
  5. "os"
  6. "strings"
  7. "testing"
  8. )
  9. func TestInferStdLogLevel(t *testing.T) {
  10. cases := []struct {
  11. msg string
  12. want Level
  13. }{
  14. {msg: "Warning: queue full", want: LevelWarn},
  15. {msg: "Forward request failed: timeout", want: LevelError},
  16. {msg: "[ERROR] upstream unavailable", want: LevelError},
  17. {msg: "[OpenAI WS Mode] reconnect_retry account_id=22 retry=1 max_retries=5", want: LevelInfo},
  18. {msg: "service started", want: LevelInfo},
  19. {msg: "debug: cache miss", want: LevelDebug},
  20. }
  21. for _, tc := range cases {
  22. got := inferStdLogLevel(tc.msg)
  23. if got != tc.want {
  24. t.Fatalf("inferStdLogLevel(%q)=%v want=%v", tc.msg, got, tc.want)
  25. }
  26. }
  27. }
  28. func TestNormalizeStdLogMessage(t *testing.T) {
  29. raw := " [TokenRefresh] cycle complete \n total=1 failed=0 \n"
  30. got := normalizeStdLogMessage(raw)
  31. want := "[TokenRefresh] cycle complete total=1 failed=0"
  32. if got != want {
  33. t.Fatalf("normalizeStdLogMessage()=%q want=%q", got, want)
  34. }
  35. }
  36. func TestStdLogBridgeRoutesLevels(t *testing.T) {
  37. origStdout := os.Stdout
  38. origStderr := os.Stderr
  39. stdoutR, stdoutW, err := os.Pipe()
  40. if err != nil {
  41. t.Fatalf("create stdout pipe: %v", err)
  42. }
  43. stderrR, stderrW, err := os.Pipe()
  44. if err != nil {
  45. t.Fatalf("create stderr pipe: %v", err)
  46. }
  47. os.Stdout = stdoutW
  48. os.Stderr = stderrW
  49. t.Cleanup(func() {
  50. os.Stdout = origStdout
  51. os.Stderr = origStderr
  52. _ = stdoutR.Close()
  53. _ = stdoutW.Close()
  54. _ = stderrR.Close()
  55. _ = stderrW.Close()
  56. })
  57. if err := Init(InitOptions{
  58. Level: "debug",
  59. Format: "json",
  60. ServiceName: "sub2api",
  61. Environment: "test",
  62. Output: OutputOptions{
  63. ToStdout: true,
  64. ToFile: false,
  65. },
  66. Sampling: SamplingOptions{Enabled: false},
  67. }); err != nil {
  68. t.Fatalf("Init() error: %v", err)
  69. }
  70. log.Printf("service started")
  71. log.Printf("Warning: queue full")
  72. log.Printf("Forward request failed: timeout")
  73. // Skip Sync() — on Windows, fsync on pipes deadlocks (FlushFileBuffers).
  74. _ = stdoutW.Close()
  75. _ = stderrW.Close()
  76. stdoutBytes, _ := io.ReadAll(stdoutR)
  77. stderrBytes, _ := io.ReadAll(stderrR)
  78. stdoutText := string(stdoutBytes)
  79. stderrText := string(stderrBytes)
  80. if !strings.Contains(stdoutText, "service started") {
  81. t.Fatalf("stdout missing info log: %s", stdoutText)
  82. }
  83. if !strings.Contains(stderrText, "Warning: queue full") {
  84. t.Fatalf("stderr missing warn log: %s", stderrText)
  85. }
  86. if !strings.Contains(stderrText, "Forward request failed: timeout") {
  87. t.Fatalf("stderr missing error log: %s", stderrText)
  88. }
  89. if !strings.Contains(stderrText, "\"legacy_stdlog\":true") {
  90. t.Fatalf("stderr missing legacy_stdlog marker: %s", stderrText)
  91. }
  92. }
  93. func TestLegacyPrintfRoutesLevels(t *testing.T) {
  94. origStdout := os.Stdout
  95. origStderr := os.Stderr
  96. stdoutR, stdoutW, err := os.Pipe()
  97. if err != nil {
  98. t.Fatalf("create stdout pipe: %v", err)
  99. }
  100. stderrR, stderrW, err := os.Pipe()
  101. if err != nil {
  102. t.Fatalf("create stderr pipe: %v", err)
  103. }
  104. os.Stdout = stdoutW
  105. os.Stderr = stderrW
  106. t.Cleanup(func() {
  107. os.Stdout = origStdout
  108. os.Stderr = origStderr
  109. _ = stdoutR.Close()
  110. _ = stdoutW.Close()
  111. _ = stderrR.Close()
  112. _ = stderrW.Close()
  113. })
  114. if err := Init(InitOptions{
  115. Level: "debug",
  116. Format: "json",
  117. ServiceName: "sub2api",
  118. Environment: "test",
  119. Output: OutputOptions{
  120. ToStdout: true,
  121. ToFile: false,
  122. },
  123. Sampling: SamplingOptions{Enabled: false},
  124. }); err != nil {
  125. t.Fatalf("Init() error: %v", err)
  126. }
  127. LegacyPrintf("service.test", "request started")
  128. LegacyPrintf("service.test", "Warning: queue full")
  129. LegacyPrintf("service.test", "forward failed: timeout")
  130. // Skip Sync() — on Windows, fsync on pipes deadlocks (FlushFileBuffers).
  131. _ = stdoutW.Close()
  132. _ = stderrW.Close()
  133. stdoutBytes, _ := io.ReadAll(stdoutR)
  134. stderrBytes, _ := io.ReadAll(stderrR)
  135. stdoutText := string(stdoutBytes)
  136. stderrText := string(stderrBytes)
  137. if !strings.Contains(stdoutText, "request started") {
  138. t.Fatalf("stdout missing info log: %s", stdoutText)
  139. }
  140. if !strings.Contains(stderrText, "Warning: queue full") {
  141. t.Fatalf("stderr missing warn log: %s", stderrText)
  142. }
  143. if !strings.Contains(stderrText, "forward failed: timeout") {
  144. t.Fatalf("stderr missing error log: %s", stderrText)
  145. }
  146. if !strings.Contains(stderrText, "\"legacy_printf\":true") {
  147. t.Fatalf("stderr missing legacy_printf marker: %s", stderrText)
  148. }
  149. if !strings.Contains(stderrText, "\"component\":\"service.test\"") {
  150. t.Fatalf("stderr missing component field: %s", stderrText)
  151. }
  152. }