优化结构
This commit is contained in:
parent
e22301f8f6
commit
ba1c73fa66
|
|
@ -128,7 +128,10 @@ admin:
|
||||||
access_resp_data: true
|
access_resp_data: true
|
||||||
access_req_headers: true
|
access_req_headers: true
|
||||||
access_log_max_bytes: 1024
|
access_log_max_bytes: 1024
|
||||||
file_only_modules: []
|
# High-volume request and SQL details remain available in logs/http and logs/sql.
|
||||||
|
file_only_modules:
|
||||||
|
- http
|
||||||
|
- sql
|
||||||
cors:
|
cors:
|
||||||
mode: whitelist
|
mode: whitelist
|
||||||
whitelist: []
|
whitelist: []
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -79,28 +78,9 @@ func NewGinEngineWithRuntime(runtime *conf.Runtime, access *service.AccessContro
|
||||||
}
|
}
|
||||||
httpx.Fail(c, "请求的接口不存在")
|
httpx.Fail(c, "请求的接口不存在")
|
||||||
})
|
})
|
||||||
logRegisteredRoutes(engine, logger)
|
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
func logRegisteredRoutes(engine *gin.Engine, logger *slog.Logger) {
|
|
||||||
if logger == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
routes := append([]gin.RouteInfo(nil), engine.Routes()...)
|
|
||||||
sort.Slice(routes, func(i, j int) bool {
|
|
||||||
if routes[i].Path == routes[j].Path {
|
|
||||||
return routes[i].Method < routes[j].Method
|
|
||||||
}
|
|
||||||
return routes[i].Path < routes[j].Path
|
|
||||||
})
|
|
||||||
systemLogger := logger.With("mod", "system")
|
|
||||||
for _, route := range routes {
|
|
||||||
systemLogger.Info("router registered", "method", route.Method, "path", route.Path)
|
|
||||||
}
|
|
||||||
systemLogger.Info("router register success", "route_count", len(routes))
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGinServer(c *conf.Server, engine *gin.Engine) *kratoshttp.Server {
|
func NewGinServer(c *conf.Server, engine *gin.Engine) *kratoshttp.Server {
|
||||||
network, address := "tcp", ":8000"
|
network, address := "tcp", ":8000"
|
||||||
if c != nil && c.Http != nil {
|
if c != nil && c.Http != nil {
|
||||||
|
|
|
||||||
|
|
@ -433,7 +433,18 @@ func newZapHandler(root, filename string, options Options, errorSink *errorSinkS
|
||||||
for _, module := range options.FileOnlyModules {
|
for _, module := range options.FileOnlyModules {
|
||||||
fileOnly[module] = struct{}{}
|
fileOnly[module] = struct{}{}
|
||||||
}
|
}
|
||||||
consoleCore := zapcore.NewCore(outputEncoder.Clone(), zapcore.AddSync(os.Stdout), levelEnabler)
|
// Files stay structured JSON for searching and the log viewer. The console
|
||||||
|
// gets a compact human-readable encoder so entries do not become one long
|
||||||
|
// JSON line that extends far beyond the terminal viewport.
|
||||||
|
consoleEncoderConfig := zap.NewProductionEncoderConfig()
|
||||||
|
consoleEncoderConfig.EncodeTime = func(value time.Time, output zapcore.PrimitiveArrayEncoder) {
|
||||||
|
output.AppendString(options.Prefix + value.Format("2006-01-02 15:04:05.000"))
|
||||||
|
}
|
||||||
|
consoleEncoderConfig.EncodeLevel = zapcore.LowercaseColorLevelEncoder
|
||||||
|
consoleEncoderConfig.EncodeCaller = zapcore.FullCallerEncoder
|
||||||
|
consoleEncoderConfig.ConsoleSeparator = " "
|
||||||
|
consoleEncoder := zapcore.NewConsoleEncoder(consoleEncoderConfig)
|
||||||
|
consoleCore := zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), levelEnabler)
|
||||||
core = zapcore.NewTee(fileCore, &moduleFilterCore{Core: consoleCore, fileOnly: fileOnly})
|
core = zapcore.NewTee(fileCore, &moduleFilterCore{Core: consoleCore, fileOnly: fileOnly})
|
||||||
}
|
}
|
||||||
routed := &routedFileCore{base: core, encoder: outputEncoder.Clone(), level: levelEnabler, root: root, retentionDay: options.RetentionDay, state: &routedFileState{writers: map[string]*DailyWriter{}}, errorSink: errorSink}
|
routed := &routedFileCore{base: core, encoder: outputEncoder.Clone(), level: levelEnabler, root: root, retentionDay: options.RetentionDay, state: &routedFileState{writers: map[string]*DailyWriter{}}, errorSink: errorSink}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
|
@ -61,6 +62,21 @@ func TestZapHandlerRoutesHTTPAndErrorLogs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConsoleEncoderDoesNotChangeJSONFileEncoder(t *testing.T) {
|
||||||
|
config := zap.NewProductionEncoderConfig()
|
||||||
|
config.EncodeTime = zapcore.RFC3339NanoTimeEncoder
|
||||||
|
fileEncoder := zapcore.NewJSONEncoder(config)
|
||||||
|
entry := zapcore.Entry{Level: zapcore.InfoLevel, Time: time.Date(2026, 8, 21, 16, 30, 0, 0, time.Local), Message: "started"}
|
||||||
|
buffer, err := fileEncoder.EncodeEntry(entry, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer buffer.Free()
|
||||||
|
if !strings.HasPrefix(buffer.String(), "{") || !strings.Contains(buffer.String(), `"msg":"started"`) {
|
||||||
|
t.Fatalf("file encoder is no longer JSON: %s", buffer.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestZapHandlerRecordsEveryErrorThroughSink(t *testing.T) {
|
func TestZapHandlerRecordsEveryErrorThroughSink(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
var entries []ErrorEntry
|
var entries []ErrorEntry
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@
|
||||||
jwt: { signingKey: '******', expiresTime: '168h', bufferTime: '24h', issuer: 'kra' },
|
jwt: { signingKey: '******', expiresTime: '168h', bufferTime: '24h', issuer: 'kra' },
|
||||||
captcha: { keyLong: 6, imgWidth: 240, imgHeight: 80, storeExpiration: '3m' },
|
captcha: { keyLong: 6, imgWidth: 240, imgHeight: 80, storeExpiration: '3m' },
|
||||||
local: { storePath: 'uploads/file', pathPrefix: 'uploads/file' }, media: { sessionTtl: 24, maxFileSize: 0, chunkDir: 'uploads/chunks' },
|
local: { storePath: 'uploads/file', pathPrefix: 'uploads/file' }, media: { sessionTtl: 24, maxFileSize: 0, chunkDir: 'uploads/chunks' },
|
||||||
zap: { level: 'info', prefix: '[kra] ', format: 'json', director: 'logs', encode_level: 'LowercaseLevelEncoder', stacktrace_key: 'stacktrace', show_line: true, log_in_console: true, retention_day: 7, access_req_body: true, access_resp_data: true, access_req_headers: true, access_log_max_bytes: 1024, file_only_modules: [] },
|
zap: { level: 'info', prefix: '[kra] ', format: 'json', director: 'logs', encode_level: 'LowercaseLevelEncoder', stacktrace_key: 'stacktrace', show_line: true, log_in_console: true, retention_day: 7, access_req_body: true, access_resp_data: true, access_req_headers: true, access_log_max_bytes: 1024, file_only_modules: ['http', 'sql'] },
|
||||||
cors: { mode: 'whitelist', whitelist: [] }, app: { node: '', app_id: 'kra', env: 'development' },
|
cors: { mode: 'whitelist', whitelist: [] }, app: { node: '', app_id: 'kra', env: 'development' },
|
||||||
system: { useRedis: false, useMultipoint: false, useStrictAuth: false, disableAutoMigrate: false, useMongo: false, addr: 8000, iplimitCount: 0, iplimitTime: 0 },
|
system: { useRedis: false, useMultipoint: false, useStrictAuth: false, disableAutoMigrate: false, useMongo: false, addr: 8000, iplimitCount: 0, iplimitTime: 0 },
|
||||||
storage: { type: 'local', qiniu: {}, aliyun_oss: {}, huawei_obs: {}, tencent_cos: {}, aws_s3: {}, cloudflare_r2: {}, minio: {} }
|
storage: { type: 'local', qiniu: {}, aliyun_oss: {}, huawei_obs: {}, tencent_cos: {}, aws_s3: {}, cloudflare_r2: {}, minio: {} }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue