Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8369d4680 | ||
|
|
8f85c503da | ||
|
|
c4b8c2d3eb |
883
.log.meta.json
883
.log.meta.json
@ -1,883 +0,0 @@
|
|||||||
{
|
|
||||||
"debug": [
|
|
||||||
{
|
|
||||||
"Index": 0,
|
|
||||||
"Name": "LogName",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 1,
|
|
||||||
"Name": "LogType",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 2,
|
|
||||||
"Name": "LogTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "time",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 3,
|
|
||||||
"Name": "TraceId",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 4,
|
|
||||||
"Name": "Image",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 5,
|
|
||||||
"Name": "Server",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 6,
|
|
||||||
"Name": "Debug",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 7,
|
|
||||||
"Name": "Extra",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"discover": [
|
|
||||||
{
|
|
||||||
"Index": 0,
|
|
||||||
"Name": "LogName",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 1,
|
|
||||||
"Name": "LogType",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 2,
|
|
||||||
"Name": "LogTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "time",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 3,
|
|
||||||
"Name": "TraceId",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 4,
|
|
||||||
"Name": "Image",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 5,
|
|
||||||
"Name": "Server",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 6,
|
|
||||||
"Name": "App",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 7,
|
|
||||||
"Name": "Method",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 8,
|
|
||||||
"Name": "Path",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "blue",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 9,
|
|
||||||
"Name": "Node",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "yellow",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 10,
|
|
||||||
"Name": "Attempts",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 11,
|
|
||||||
"Name": "UsedTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "%.2fms",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 12,
|
|
||||||
"Name": "Error",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "red",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 13,
|
|
||||||
"Name": "Extra",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"error": [
|
|
||||||
{
|
|
||||||
"Index": 0,
|
|
||||||
"Name": "LogName",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 1,
|
|
||||||
"Name": "LogType",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 2,
|
|
||||||
"Name": "LogTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "time",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 3,
|
|
||||||
"Name": "TraceId",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 4,
|
|
||||||
"Name": "Image",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 5,
|
|
||||||
"Name": "Server",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 6,
|
|
||||||
"Name": "Error",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "red",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 7,
|
|
||||||
"Name": "Extra",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 8,
|
|
||||||
"Name": "CallStacks",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info": [
|
|
||||||
{
|
|
||||||
"Index": 0,
|
|
||||||
"Name": "LogName",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 1,
|
|
||||||
"Name": "LogType",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 2,
|
|
||||||
"Name": "LogTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "time",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 3,
|
|
||||||
"Name": "TraceId",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 4,
|
|
||||||
"Name": "Image",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 5,
|
|
||||||
"Name": "Server",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 6,
|
|
||||||
"Name": "Info",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 7,
|
|
||||||
"Name": "Extra",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"request": [
|
|
||||||
{
|
|
||||||
"Index": 0,
|
|
||||||
"Name": "LogName",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 1,
|
|
||||||
"Name": "LogType",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 2,
|
|
||||||
"Name": "LogTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "time",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 3,
|
|
||||||
"Name": "TraceId",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 4,
|
|
||||||
"Name": "Image",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 5,
|
|
||||||
"Name": "Server",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 6,
|
|
||||||
"Name": "ServerId",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 7,
|
|
||||||
"Name": "App",
|
|
||||||
"KeyName": "App",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 8,
|
|
||||||
"Name": "Node",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": true,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 9,
|
|
||||||
"Name": "FromApp",
|
|
||||||
"KeyName": "From",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 10,
|
|
||||||
"Name": "FromNode",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": true,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 11,
|
|
||||||
"Name": "ClientIp",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 12,
|
|
||||||
"Name": "ClientAppName",
|
|
||||||
"KeyName": "Client",
|
|
||||||
"AttachBefore": true,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 13,
|
|
||||||
"Name": "ClientAppVersion",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": true,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 14,
|
|
||||||
"Name": "UserId",
|
|
||||||
"KeyName": "User",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 15,
|
|
||||||
"Name": "DeviceId",
|
|
||||||
"KeyName": "Device",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 16,
|
|
||||||
"Name": "SessionId",
|
|
||||||
"KeyName": "Session",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 17,
|
|
||||||
"Name": "Host",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 18,
|
|
||||||
"Name": "Method",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 19,
|
|
||||||
"Name": "Path",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 20,
|
|
||||||
"Name": "Scheme",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 21,
|
|
||||||
"Name": "Proto",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 22,
|
|
||||||
"Name": "AuthLevel",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "green",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 23,
|
|
||||||
"Name": "Priority",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 24,
|
|
||||||
"Name": "RequestData",
|
|
||||||
"KeyName": "Request",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 25,
|
|
||||||
"Name": "RequestHeaders",
|
|
||||||
"KeyName": "Headers",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 26,
|
|
||||||
"Name": "UsedTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "green",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 6,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 27,
|
|
||||||
"Name": "ResponseCode",
|
|
||||||
"KeyName": "Status",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 28,
|
|
||||||
"Name": "ResponseDataLength",
|
|
||||||
"KeyName": "ContentLength",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 29,
|
|
||||||
"Name": "ResponseData",
|
|
||||||
"KeyName": "Response",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 30,
|
|
||||||
"Name": "ResponseHeaders",
|
|
||||||
"KeyName": "Headers",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 31,
|
|
||||||
"Name": "Extra",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"warning": [
|
|
||||||
{
|
|
||||||
"Index": 0,
|
|
||||||
"Name": "LogName",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "cyan",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 1,
|
|
||||||
"Name": "LogType",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "magenta",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 2,
|
|
||||||
"Name": "LogTime",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "time",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 3,
|
|
||||||
"Name": "TraceId",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "gray",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 4,
|
|
||||||
"Name": "Image",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 5,
|
|
||||||
"Name": "Server",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 6,
|
|
||||||
"Name": "Warning",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "yellow",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": true,
|
|
||||||
"Hide": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Index": 7,
|
|
||||||
"Name": "Extra",
|
|
||||||
"KeyName": "",
|
|
||||||
"AttachBefore": false,
|
|
||||||
"Color": "",
|
|
||||||
"Format": "",
|
|
||||||
"Precision": 0,
|
|
||||||
"WithoutKey": false,
|
|
||||||
"Hide": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
29
CHANGELOG.md
29
CHANGELOG.md
@ -1,5 +1,34 @@
|
|||||||
# CHANGELOG - go/service
|
# CHANGELOG - go/service
|
||||||
|
|
||||||
|
## v1.5.20 (2026-06-22)
|
||||||
|
- **Client Key 应答头条件化**:
|
||||||
|
- `Device-Id` / `Session-Id` 仅当请求头未携带时才写入应答头,避免客户端已持有 ID 时重复返回。
|
||||||
|
- 静态文件和 WebSocket 升级应答中不再写入 `Device-Id` / `Session-Id` 头,仅通过 Cookie 维护身份(浏览器 WebSocket API 不支持自定义请求头)。
|
||||||
|
- **Client App 头命名规范化**:
|
||||||
|
- 客户端上报键名从 `AppName`/`AppVersion` 改为 `App-Name`/`App-Version`(与 `Device-Id`/`Session-Id` 一致使用破折号)。
|
||||||
|
- **Breaking**: 旧版客户端需同步修改请求头名称。
|
||||||
|
- **配置字段重命名**:
|
||||||
|
- `NoLogHeaders` → `NoLogRequestHeaders`(请求头排除列表)。
|
||||||
|
- `NoLogOutputFields` → `NoLogResponseFields`(响应体字段排除)。
|
||||||
|
- 新增 `NoLogResponseHeaders`(响应头排除列表,用户可追加自定义字段)。
|
||||||
|
- **Breaking**: 使用了旧字段名的配置需同步修改。
|
||||||
|
- **动态排除列表**:
|
||||||
|
- `NoLogRequestHeaders` 默认值动态构建(包含内部标准头 + 当前配置的 client key 名),用户只需追加自己关心的额外字段。
|
||||||
|
- 移除 `init()` 中的硬编码默认值。
|
||||||
|
- **Cookie 头智能过滤**:
|
||||||
|
- `sanitizeLogHeaders` 对 `Cookie` 头不再整体排除,而是解析 Cookie 内容,仅剔除 key 命中排除列表的键值对(如 `Device-Id`/`Session-Id`),保留业务 Cookie。
|
||||||
|
- 排除列表同时适用于 Header 名匹配和 Cookie key 匹配。
|
||||||
|
- **日志应答头排除**:
|
||||||
|
- 响应头日志捕获改为使用 `effectiveNoLogResponseHeaders()`,替代之前的硬编码空字符串。
|
||||||
|
|
||||||
|
## v1.5.19 (2026-06-22)
|
||||||
|
- **依赖更新**:
|
||||||
|
- 升级依赖 `id` 至 `v1.5.6`,`redis` 至 `v1.5.10`。
|
||||||
|
|
||||||
|
## v1.5.18 (2026-06-21)
|
||||||
|
- **依赖更新**:
|
||||||
|
- 升级依赖 `id` 至 `v1.5.5`,`redis` 至 `v1.5.9`(同步修复旧版本 ID 未打乱的 Bug)。
|
||||||
|
|
||||||
## v1.5.17 (2026-06-21)
|
## v1.5.17 (2026-06-21)
|
||||||
- **Session 增强**:
|
- **Session 增强**:
|
||||||
- `Save` 改为可变参数 `Save(args ...map[string]any) error`,支持传入 map 批量设置后保存。
|
- `Save` 改为可变参数 `Save(args ...map[string]any) error`,支持传入 map 批量设置后保存。
|
||||||
|
|||||||
10
TEST.md
10
TEST.md
@ -1,9 +1,9 @@
|
|||||||
# Service Module Test Report
|
# Service Module Test Report
|
||||||
|
|
||||||
## 性能测试 (Benchmark)
|
## 性能测试 (Benchmark)
|
||||||
- 测试日期: 2026-06-21
|
- 测试日期: 2026-06-22
|
||||||
- 版本: v1.0.4
|
- 版本: v1.5.20
|
||||||
- 指标: `BenchmarkRouting`: 2791 ns/op
|
- 指标: `BenchmarkRouting`: **5394 ns/op**
|
||||||
- 环境: Darwin / Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
|
- 环境: Darwin / Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
|
||||||
|
|
||||||
## 单元测试覆盖 (Unit Test)
|
## 单元测试覆盖 (Unit Test)
|
||||||
@ -27,7 +27,9 @@
|
|||||||
- [x] `TestSanitizeScalars` ~ `TestSanitizeMixedSlice`: 日志脱敏 10 个测试(标量/对象/数组/嵌套/预算/Unicode)
|
- [x] `TestSanitizeScalars` ~ `TestSanitizeMixedSlice`: 日志脱敏 10 个测试(标量/对象/数组/嵌套/预算/Unicode)
|
||||||
- [x] `TestSessionLogic`: Session Save/Load/Remove 及 AuthFuncs
|
- [x] `TestSessionLogic`: Session Save/Load/Remove 及 AuthFuncs
|
||||||
- [x] `TestSessionInjection`: Session HTTP 注入流程
|
- [x] `TestSessionInjection`: Session HTTP 注入流程
|
||||||
- [x] Logging Filters: NoLogInput/NoLogOutput/NoLogAllHeaders/NoLogGets/NoLogHeaders
|
- [x] Logging Filters: NoLogInput/NoLogOutput/NoLogAllHeaders/NoLogGets/NoLogRequestHeaders/NoLogResponseHeaders/NoLogResponseFields
|
||||||
|
- [x] Client Keys: Device-Id/Session-Id 应答头条件化(请求有则不应答)、静态文件/WebSocket 仅 Cookie
|
||||||
|
- [x] Cookie 头智能过滤: 排除列表中 key 从 Cookie 内容中剔除,保留业务 Cookie
|
||||||
- [x] Response Body: 200 响应和 dev 模式下 keepBody 捕获
|
- [x] Response Body: 200 响应和 dev 模式下 keepBody 捕获
|
||||||
|
|
||||||
## 基础设施对齐验证
|
## 基础设施对齐验证
|
||||||
|
|||||||
@ -26,11 +26,12 @@ type ServiceConfig struct {
|
|||||||
NoLogInput bool // 不记录请求输入
|
NoLogInput bool // 不记录请求输入
|
||||||
NoLogOutput bool // 不记录响应输出
|
NoLogOutput bool // 不记录响应输出
|
||||||
NoLogAllHeaders bool // 不记录所有请求/响应头
|
NoLogAllHeaders bool // 不记录所有请求/响应头
|
||||||
NoLogHeaders string // 不记录请求头中包含的这些字段,多个字段用逗号分隔
|
NoLogRequestHeaders string // 不记录请求头中包含的这些字段(追加到动态默认列表),多个字段用逗号分隔
|
||||||
|
NoLogResponseHeaders string // 不记录响应头中包含的这些字段(追加到动态默认列表),多个字段用逗号分隔
|
||||||
LogInputObjectNum int // 请求对象中最多记录的 key 数
|
LogInputObjectNum int // 请求对象中最多记录的 key 数
|
||||||
LogInputArrayNum int // 请求数组中最多记录的元素数
|
LogInputArrayNum int // 请求数组中最多记录的元素数
|
||||||
LogInputFieldSize int // 请求单个字段的字符串截断长度
|
LogInputFieldSize int // 请求单个字段的字符串截断长度
|
||||||
NoLogOutputFields string // 不记录响应字段中包含的这些字段
|
NoLogResponseFields string // 不记录响应字段中包含的这些字段
|
||||||
LogOutputObjectNum int // 响应对象中最多记录的 key 数
|
LogOutputObjectNum int // 响应对象中最多记录的 key 数
|
||||||
LogOutputArrayNum int // 响应数组中最多记录的元素数
|
LogOutputArrayNum int // 响应数组中最多记录的元素数
|
||||||
LogOutputFieldSize int // 响应单个字段的字符串截断长度
|
LogOutputFieldSize int // 响应单个字段的字符串截断长度
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -8,10 +8,10 @@ require (
|
|||||||
apigo.cc/go/discover v1.5.3
|
apigo.cc/go/discover v1.5.3
|
||||||
apigo.cc/go/file v1.5.5
|
apigo.cc/go/file v1.5.5
|
||||||
apigo.cc/go/http v1.5.3
|
apigo.cc/go/http v1.5.3
|
||||||
apigo.cc/go/id v1.5.5
|
apigo.cc/go/id v1.5.6
|
||||||
apigo.cc/go/jsmod v1.5.3
|
apigo.cc/go/jsmod v1.5.3
|
||||||
apigo.cc/go/log v1.5.8
|
apigo.cc/go/log v1.5.8
|
||||||
apigo.cc/go/redis v1.5.9
|
apigo.cc/go/redis v1.5.10
|
||||||
apigo.cc/go/safe v1.5.2
|
apigo.cc/go/safe v1.5.2
|
||||||
apigo.cc/go/starter v1.5.5
|
apigo.cc/go/starter v1.5.5
|
||||||
apigo.cc/go/timer v1.5.0
|
apigo.cc/go/timer v1.5.0
|
||||||
|
|||||||
47
handler.go
47
handler.go
@ -75,13 +75,13 @@ func (rh *RouteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// 请求头
|
// 请求头
|
||||||
var reqHeaders map[string]string
|
var reqHeaders map[string]string
|
||||||
if !ws.Config.NoLogAllHeaders {
|
if !ws.Config.NoLogAllHeaders {
|
||||||
reqHeaders = sanitizeLogHeaders(r.Header, ws.Config.NoLogHeaders)
|
reqHeaders = sanitizeLogHeaders(r.Header, ws.effectiveNoLogRequestHeaders())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应头
|
// 响应头
|
||||||
var respHeaders map[string]string
|
var respHeaders map[string]string
|
||||||
if !ws.Config.NoLogAllHeaders {
|
if !ws.Config.NoLogAllHeaders {
|
||||||
respHeaders = sanitizeLogHeaders(response.Header().H, "")
|
respHeaders = sanitizeLogHeaders(response.Header().H, ws.effectiveNoLogResponseHeaders())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求输入脱敏
|
// 请求输入脱敏
|
||||||
@ -434,8 +434,11 @@ func outputResult(response *Response, result any) {
|
|||||||
func (ws *WebServer) handleClientKeys(request *Request, response *Response) {
|
func (ws *WebServer) handleClientKeys(request *Request, response *Response) {
|
||||||
// SessionId
|
// SessionId
|
||||||
if ws.usedSessionIdKey != "" {
|
if ws.usedSessionIdKey != "" {
|
||||||
|
hasRequestSessionId := false
|
||||||
sessionId := request.Header().Get(ws.usedSessionIdKey)
|
sessionId := request.Header().Get(ws.usedSessionIdKey)
|
||||||
if sessionId == "" && !ws.Config.SessionWithoutCookie {
|
if sessionId != "" {
|
||||||
|
hasRequestSessionId = true
|
||||||
|
} else if !ws.Config.SessionWithoutCookie {
|
||||||
if ck := request.GetCookie(ws.usedSessionIdKey); ck != nil {
|
if ck := request.GetCookie(ws.usedSessionIdKey); ck != nil {
|
||||||
sessionId = ck.Value
|
sessionId = ck.Value
|
||||||
}
|
}
|
||||||
@ -456,13 +459,18 @@ func (ws *WebServer) handleClientKeys(request *Request, response *Response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
request.Request.Header.Set(discover.HeaderSessionID, sessionId)
|
request.Request.Header.Set(discover.HeaderSessionID, sessionId)
|
||||||
|
if !hasRequestSessionId {
|
||||||
response.Header().Set(ws.usedSessionIdKey, sessionId)
|
response.Header().Set(ws.usedSessionIdKey, sessionId)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DeviceId
|
// DeviceId
|
||||||
if ws.usedDeviceIdKey != "" {
|
if ws.usedDeviceIdKey != "" {
|
||||||
|
hasRequestDeviceId := false
|
||||||
deviceId := request.Header().Get(ws.usedDeviceIdKey)
|
deviceId := request.Header().Get(ws.usedDeviceIdKey)
|
||||||
if deviceId == "" && !ws.Config.DeviceWithoutCookie {
|
if deviceId != "" {
|
||||||
|
hasRequestDeviceId = true
|
||||||
|
} else if !ws.Config.DeviceWithoutCookie {
|
||||||
if ck := request.GetCookie(ws.usedDeviceIdKey); ck != nil {
|
if ck := request.GetCookie(ws.usedDeviceIdKey); ck != nil {
|
||||||
deviceId = ck.Value
|
deviceId = ck.Value
|
||||||
}
|
}
|
||||||
@ -480,16 +488,41 @@ func (ws *WebServer) handleClientKeys(request *Request, response *Response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
request.Request.Header.Set(discover.HeaderDeviceID, deviceId)
|
request.Request.Header.Set(discover.HeaderDeviceID, deviceId)
|
||||||
|
if !hasRequestDeviceId {
|
||||||
response.Header().Set(ws.usedDeviceIdKey, deviceId)
|
response.Header().Set(ws.usedDeviceIdKey, deviceId)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AppName / AppVersion(客户端上报,注入内部标准头供下游微服务使用)
|
// App-Name / App-Version(客户端上报,注入内部标准头供下游微服务使用)
|
||||||
if ws.usedClientAppKey != "" {
|
if ws.usedClientAppKey != "" {
|
||||||
if appName := request.Header().Get(ws.usedClientAppKey + "Name"); appName != "" {
|
if appName := request.Header().Get(ws.usedClientAppKey + "-Name"); appName != "" {
|
||||||
request.Request.Header.Set(discover.HeaderClientAppName, appName)
|
request.Request.Header.Set(discover.HeaderClientAppName, appName)
|
||||||
}
|
}
|
||||||
if appVersion := request.Header().Get(ws.usedClientAppKey + "Version"); appVersion != "" {
|
if appVersion := request.Header().Get(ws.usedClientAppKey + "-Version"); appVersion != "" {
|
||||||
request.Request.Header.Set(discover.HeaderClientAppVersion, appVersion)
|
request.Request.Header.Set(discover.HeaderClientAppVersion, appVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// effectiveNoLogRequestHeaders 返回请求头排除列表(动态默认值 + 用户配置追加)
|
||||||
|
func (ws *WebServer) effectiveNoLogRequestHeaders() string {
|
||||||
|
parts := []string{"X-Request-Id", "X-Device-Id", "X-Session-Id"}
|
||||||
|
if ws.usedDeviceIdKey != "" {
|
||||||
|
parts = append(parts, ws.usedDeviceIdKey)
|
||||||
|
}
|
||||||
|
if ws.usedSessionIdKey != "" {
|
||||||
|
parts = append(parts, ws.usedSessionIdKey)
|
||||||
|
}
|
||||||
|
if ws.usedClientAppKey != "" {
|
||||||
|
parts = append(parts, ws.usedClientAppKey+"-Name", ws.usedClientAppKey+"-Version")
|
||||||
|
}
|
||||||
|
if ws.Config.NoLogRequestHeaders != "" {
|
||||||
|
parts = append(parts, ws.Config.NoLogRequestHeaders)
|
||||||
|
}
|
||||||
|
return strings.Join(parts, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// effectiveNoLogResponseHeaders 返回响应头排除列表(用户配置追加)
|
||||||
|
func (ws *WebServer) effectiveNoLogResponseHeaders() string {
|
||||||
|
return ws.Config.NoLogResponseHeaders
|
||||||
|
}
|
||||||
|
|||||||
@ -137,14 +137,21 @@ func sanitizeSliceContent(s []any, opts sanitizeOpts, budget *int) []any {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// sanitizeLogHeaders 过滤请求/响应头,排除 NoLogHeaders 中指定的字段
|
// sanitizeLogHeaders 过滤请求/响应头,排除 noLogHeaders 中指定的字段。
|
||||||
|
// 对于 Cookie 头,不整体排除,而是从 Cookie 内容中剔除 key 命中排除列表的键值对。
|
||||||
func sanitizeLogHeaders(h http.Header, noLogHeaders string) map[string]string {
|
func sanitizeLogHeaders(h http.Header, noLogHeaders string) map[string]string {
|
||||||
result := make(map[string]string)
|
result := make(map[string]string)
|
||||||
excludes := strings.Split(noLogHeaders, ",")
|
excludes := splitAndTrim(noLogHeaders)
|
||||||
for k, v := range h {
|
for k, v := range h {
|
||||||
|
if k == "Cookie" && len(excludes) > 0 {
|
||||||
|
if filtered := sanitizeCookieValue(v, excludes); filtered != "" {
|
||||||
|
result[k] = filtered
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
skip := false
|
skip := false
|
||||||
for _, ex := range excludes {
|
for _, ex := range excludes {
|
||||||
if ex != "" && strings.EqualFold(k, strings.TrimSpace(ex)) {
|
if strings.EqualFold(k, ex) {
|
||||||
skip = true
|
skip = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -156,14 +163,52 @@ func sanitizeLogHeaders(h http.Header, noLogHeaders string) map[string]string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sanitizeCookieValue 从 Cookie 原始值中剔除 key 命中排除列表的键值对。
|
||||||
|
// 输入为原始 Cookie 头值(可能多个 key=value 以 "; " 或 ";" 分隔)。
|
||||||
|
func sanitizeCookieValue(values []string, excludes []string) string {
|
||||||
|
raw := strings.Join(values, "; ")
|
||||||
|
pairs := strings.Split(raw, ";")
|
||||||
|
var kept []string
|
||||||
|
for _, pair := range pairs {
|
||||||
|
pair = strings.TrimSpace(pair)
|
||||||
|
if pair == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key, _, _ := strings.Cut(pair, "=")
|
||||||
|
key = strings.TrimSpace(key)
|
||||||
|
excluded := false
|
||||||
|
for _, ex := range excludes {
|
||||||
|
if strings.EqualFold(key, ex) {
|
||||||
|
excluded = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !excluded {
|
||||||
|
kept = append(kept, pair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(kept, "; ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitAndTrim(s string) []string {
|
||||||
|
if s == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
parts := strings.Split(s, ",")
|
||||||
|
for i, p := range parts {
|
||||||
|
parts[i] = strings.TrimSpace(p)
|
||||||
|
}
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
// sanitizeRespBody 对响应体进行脱敏:尝试 JSON 解析后走对象脱敏,失败则按字符串截断
|
// sanitizeRespBody 对响应体进行脱敏:尝试 JSON 解析后走对象脱敏,失败则按字符串截断
|
||||||
func sanitizeRespBody(body []byte, cfg *ServiceConfig) any {
|
func sanitizeRespBody(body []byte, cfg *ServiceConfig) any {
|
||||||
// 尝试解析为 JSON 对象
|
// 尝试解析为 JSON 对象
|
||||||
var parsed any
|
var parsed any
|
||||||
if err := cast.UnmarshalJSON(body, &parsed); err == nil && parsed != nil {
|
if err := cast.UnmarshalJSON(body, &parsed); err == nil && parsed != nil {
|
||||||
// 排除敏感字段
|
// 排除敏感字段
|
||||||
if cfg.NoLogOutputFields != "" {
|
if cfg.NoLogResponseFields != "" {
|
||||||
parsed = stripFields(parsed, cfg.NoLogOutputFields)
|
parsed = stripFields(parsed, cfg.NoLogResponseFields)
|
||||||
}
|
}
|
||||||
return sanitizeLogData(parsed, sanitizeOpts{
|
return sanitizeLogData(parsed, sanitizeOpts{
|
||||||
maxSize: 200,
|
maxSize: 200,
|
||||||
|
|||||||
@ -111,7 +111,7 @@ var DefaultServer = NewWebServer()
|
|||||||
var Config = &DefaultServer.Config
|
var Config = &DefaultServer.Config
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Config.NoLogHeaders = "X-Request-Id,X-Device-Id,X-Session-Id,Cookie,Device-Id,Session-Id"
|
// NoLogRequestHeaders / NoLogResponseHeaders 的默认值在日志捕获时动态构建
|
||||||
Config.LogInputObjectNum = 10
|
Config.LogInputObjectNum = 10
|
||||||
Config.LogInputArrayNum = 5
|
Config.LogInputArrayNum = 5
|
||||||
Config.LogInputFieldSize = 20
|
Config.LogInputFieldSize = 20
|
||||||
|
|||||||
@ -131,6 +131,10 @@ func (ws *WebServer) processStatic(requestPath string, request *Request, respons
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 静态文件通过 Cookie 维护 ID,不应答 Device-Id / Session-Id 头
|
||||||
|
response.Header().Del(ws.usedDeviceIdKey)
|
||||||
|
response.Header().Del(ws.usedSessionIdKey)
|
||||||
|
|
||||||
// 检查 304
|
// 检查 304
|
||||||
if ifModifiedSince := request.Header().Get("If-Modified-Since"); ifModifiedSince != "" {
|
if ifModifiedSince := request.Header().Get("If-Modified-Since"); ifModifiedSince != "" {
|
||||||
if t, err := time.Parse(http.TimeFormat, ifModifiedSince); err == nil {
|
if t, err := time.Parse(http.TimeFormat, ifModifiedSince); err == nil {
|
||||||
|
|||||||
@ -78,6 +78,11 @@ func Upgrade(response *Response, request *Request) (*WebSocketConn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebServer) doWebsocketService(wsc *websocketServiceType, request *Request, response *Response, logger *log.Logger, object any) {
|
func (ws *WebServer) doWebsocketService(wsc *websocketServiceType, request *Request, response *Response, logger *log.Logger, object any) {
|
||||||
|
// WebSocket 浏览器 API 不支持自定义请求头,只能通过 Cookie 传递身份标识,
|
||||||
|
// 因此不应在升级应答中返回 Device-Id / Session-Id 头。
|
||||||
|
response.Header().Del(ws.usedDeviceIdKey)
|
||||||
|
response.Header().Del(ws.usedSessionIdKey)
|
||||||
|
|
||||||
wsConn, err := Upgrade(response, request)
|
wsConn, err := Upgrade(response, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("websocket upgrade failed", "error", err.Error())
|
logger.Error("websocket upgrade failed", "error", err.Error())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user