github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/ginx/README.md (about) 1 # ginx 2 3 some extensions for gin. 4 5 ## ginpprof 6 7 [ginpprof](pkg/ginpprof/README.md) - A wrapper for [gin](https://github.com/gin-gonic/gin) to use `net/http/pprof` easily. 8 9 ```go 10 import ( 11 "github.com/gin-gonic/gin" 12 "github.com/bingoohuang/gg/pkg/ginx/ginpprof" 13 ) 14 15 func main() { 16 router := gin.Default() 17 18 router.GET("/ping", func(c *gin.Context) { 19 c.String(200, "pong") 20 }) 21 22 // automatically add routers for net/http/pprof 23 // e.g. /debug/pprof, /debug/pprof/heap, etc. 24 ginpprof.Wrap(router) 25 26 // ginpprof also plays well with *gin.RouterGroup 27 // group := router.Group("/debug/pprof") 28 // ginpprof.WrapGroup(group) 29 30 router.Run(":57047") 31 } 32 ``` 33 34 Now visit [http://127.0.0.1:57047/debug/pprof/](http://127.0.0.1:57047/debug/pprof/) and you'll see what you want. 35 36 More scripts: 37 38 1. `go tool pprof -http=:8080 http://127.0.0.1:57047/debug/pprof/profile` 39 1. `go tool pprof -http=:8080 http://127.0.0.1:57047/debug/pprof/heap` 40 41 ## func adapter 42 43 The func adapter can adapt any prototype of router function to gin.HandlerFunc by registering in advance. 44 45 ```go 46 import ( 47 "github.com/bingoohuang/gg/pkg/ginx/adapt" 48 "github.com/bingoohuang/gg/pkg/ginx/anyfn" 49 "github.com/gin-gonic/gin" 50 ) 51 52 func main() { 53 r := adapt.Adapt(gin.New()) 54 r.RegisterAdapter(func(f func(string) string) gin.HandlerFunc { 55 return func(c *gin.Context) { 56 c.String(http.StatusOK, f(StringArg(c))) 57 } 58 }) 59 60 // the binding func will be adapted to gin.HandlerFunc. 61 r.GET("/user/:name", func(name string) string { 62 return fmt.Sprintf("Hello %s", name) 63 }) 64 65 // or use direct gin.HandlerFunc. 66 r.GET("/direct/:name", func(c *gin.Context) { 67 c.String(http.StatusOK, "Hello Direct %s", c.Param("name")) 68 }) 69 70 r.Run(":8080") 71 } 72 73 ``` 74 75 ## anyfn adapter 76 77 ```go 78 import ( 79 "github.com/bingoohuang/gg/pkg/ginx/adapt" 80 "github.com/bingoohuang/gg/pkg/ginx/anyfn" 81 "github.com/bingoohuang/gg/pkg/ginx/gintest" 82 "github.com/gin-gonic/gin" 83 ) 84 85 func main() { 86 r := adapt.Adapt(gin.New()) 87 af := anyfn.NewAdapter() 88 r.RegisterAdapter(af) 89 90 // This handler will match /user/john but will not match /user/ or /user 91 r.GET("/user/:name", func(name string) string { 92 return fmt.Sprintf("Hello %s", name) 93 }) 94 95 type MyObject struct { 96 Name string 97 } 98 99 // af.F can adapt any function as you desired to gin.HandlerFunc. 100 r.POST("/MyObject1", af.F(func(m MyObject) string { 101 return "Object: " + m.Name 102 })) 103 104 r.Run(":8080") 105 } 106 ``` 107 108 ## hlog for logrus 109 110 ```go 111 import ( 112 "database/sql" 113 114 "github.com/bingoohuang/golog" 115 "github.com/bingoohuang/golog/pkg/ginlogrus" 116 117 "github.com/bingoohuang/gg/pkg/ginx/adapt" 118 "github.com/bingoohuang/gg/pkg/ginx/anyfn" 119 "github.com/bingoohuang/gg/pkg/ginx/hlog" 120 "github.com/gin-gonic/gin" 121 ) 122 123 func init() { 124 _, _ = golog.SetupLogrus(nil, "", "") 125 gin.SetMode(gin.ReleaseMode) 126 } 127 128 func main() { 129 af := anyfn.NewAdapter() 130 hf := hlog.NewAdapter(hlog.NewLogrusStore()) 131 r := adapt.Adapt(gin.New(), af, hf) 132 r.Use(ginlogrus.Logger(nil, true)) 133 134 r.POST("/hello", af.F(func() string { return "Hello hello!" }), hf.F(hf.Biz("你好啊"))) 135 r.POST("/world", af.F(func() string { return "Hello world!" })) 136 r.POST("/bye", af.F(func() string { return "Hello bye!" }), hf.F(hf.Ignore())) 137 138 r.Run(":8080") 139 } 140 ``` 141 142 ## hlog for mysql 143 144 ```go 145 import ( 146 "database/sql" 147 148 "github.com/bingoohuang/golog" 149 "github.com/bingoohuang/golog/pkg/ginlogrus" 150 151 "github.com/bingoohuang/gg/pkg/ginx/adapt" 152 "github.com/bingoohuang/gg/pkg/ginx/anyfn" 153 "github.com/bingoohuang/gg/pkg/ginx/hlog" 154 "github.com/gin-gonic/gin" 155 156 _ "github.com/go-sql-driver/mysql" 157 ) 158 159 func init() { 160 _, _ = golog.SetupLogrus(nil, "", "") 161 gin.SetMode(gin.ReleaseMode) 162 } 163 164 const DSN = `root:root@tcp(127.0.0.1:3306)/httplog?charset=utf8mb4&parseTime=true&loc=Local` 165 166 167 func main() { 168 db, err := sql.Open("mysql", DSN) 169 assert.Nil(t, err) 170 171 af := anyfn.NewAdapter() 172 hf := hlog.NewAdapter(hlog.NewSQLStore(db, "biz_log")) 173 r := adapt.Adapt(gin.New(), af, hf) 174 r.Use(ginlogrus.Logger(nil, true)) 175 176 r.POST("/hello", af.F(handleIndex), hf.F(hf.Biz("回显处理hlog"))) 177 r.POST("/world", af.F(func() string { return "Hello world!" }), hf.F(hf.Biz("世界你好"))) 178 r.POST("/bye", af.F(func() string { return "Hello bye!" }), hf.F(hf.Ignore())) 179 180 r.Run(":8080") 181 } 182 ``` 183 184 ### Prepare log tables 185 186 业务日志表定义,根据具体业务需要,必须字段为主键`id`(名字固定), 示例: [mysql](testdata/mysql.sql) 187 188 <details> 189 <summary> 190 <p>日志表建表规范</p> 191 </summary> 192 193 字段注释包含| 或者字段名 | 说明 194 ---|---|--- 195 内置类:|| 196 `httplog:"id"`|id| 日志记录ID 197 `httplog:"created"`|created| 创建时间 198 `httplog:"ip"` |ip|当前机器IP 199 `httplog:"addr"` |addr|http客户端地址 200 `httplog:"hostname"` |hostname|当前机器名称 201 `httplog:"pid"` |pid|应用程序PID 202 `httplog:"started"` |start|开始时间 203 `httplog:"end"` |end|结束时间 204 `httplog:"cost"` |cost|花费时间(ms) 205 `httplog:"biz"` |biz|业务名称,eg `httplog.Biz("项目列表")` 206 请求类:|| 207 `httplog:"req_head_xxx"` |req_head_xxx|请求中的xxx头 208 `httplog:"req_heads"` |req_heads|请求中的所有头 209 `httplog:"req_method"` |req_method|请求method 210 `httplog:"req_url"` |req_url|请求URL 211 `httplog:"req_path_xxx"` |req_path_xxx|请求URL中的xxx路径参数 212 `httplog:"req_paths"` |req_paths|请求URL中的所有路径参数 213 `httplog:"req_query_xxx"` |req_query_xxx|请求URl中的xxx查询参数 214 `httplog:"req_queries"` |req_queries|请求URl中的所有查询参数 215 `httplog:"req_param_xxx"` |req_param_xxx|请求中query/form的xxx参数 216 `httplog:"req_params"` |req_params|请求中query/form的所有参数 217 `httplog:"req_body"` |req_body|请求体 218 `httplog:"req_json"` |req_json|请求体(当Content-Type为JSON时) 219 `httplog:"req_json_xxx"` |req_json_xxx|请求体JSON中的xxx属性 220 响应类:|| 221 `httplog:"rsp_head_xxx"` |rsp_head_xxx|响应中的xxx头 222 `httplog:"rsp_heads"` |rsp_heads|响应中的所有头 223 `httplog:"rsp_body"` |rsp_body|响应体 224 `httplog:"rsp_json"` |rsp_json|响应体JSON(当Content-Type为JSON时) 225 `httplog:"rsp_json_xxx"`|rsp_json_xxx| 请求体JSON中的xxx属性 226 `httplog:"rsp_status"`|rsp_status| 响应编码 227 上下文:|| 228 `httplog:"ctx_xxx"` |ctx_xxx|上下文对象xxx的值, 通过api设置: `hlog.PutAttr(c, "xxx", "yyy")` 或者 `hlog.PutAttrMap(r, hlog.Attrs{"name": "alice", "female": true})`, See [example](pkg/hlog/hlog_test.go#L78) 229 </details>