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>