wangkang 9 months ago
commit
467be79402
19 changed files with 891 additions and 0 deletions
  1. 10 0
      Dockerfile
  2. 119 0
      README.md
  3. 10 0
      client/client.go
  4. 28 0
      conf/config.yaml
  5. 46 0
      config/config.go
  6. 5 0
      db/db.go
  7. 52 0
      db/mongo.go
  8. 10 0
      go.mod
  9. 163 0
      go.sum
  10. 18 0
      handler/article.go
  11. 201 0
      logger/log.go
  12. 26 0
      logger/logger.go
  13. 23 0
      main.go
  14. 8 0
      model/article.go
  15. 27 0
      router/middleware/bodycheck.go
  16. 48 0
      router/middleware/header.go
  17. 47 0
      router/middleware/monitor.go
  18. 19 0
      router/middleware/tracer.go
  19. 31 0
      router/router.go

+ 10 - 0
Dockerfile

@@ -0,0 +1,10 @@
+FROM docker.finogeeks.club/base/alpine
+
+RUN ls
+
+RUN set -ex \
+  && apk add --no-cache ca-certificates
+
+COPY web_test_cgi /opt/web_test_cgi
+
+ENTRYPOINT /opt/web_test_cgi

+ 119 - 0
README.md

@@ -0,0 +1,119 @@
+go 微服务开发脚手架
+
+## git 提交规则
+
+参考 https://loveky.github.io/2018/06/04/write-good-commit-message/
+
+使用 作为前缀
+
+* build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交
+* ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
+* docs:文档更新
+* feat:新增功能
+* fix:bug 修复
+* perf:性能优化
+* refactor:重构代码(既没有新增功能,也没有修复 bug)
+* style:不影响程序逻辑的代码修改(修改空白字符,补全缺失的分号等)
+* test:新增测试用例或是更新现有测试
+* revert:回滚某个更早之前的提交
+* chore:不属于以上类型的其他类型
+
+
+## 目录结构
+
+```
+client -- 和其他微服务交互的client
+conf -- 存放配置文件 config.yaml 等
+config -- 加载配置文件
+docs -- 生成文档
+handler -- 路由Handler
+model -- model 的 curd
+router -- 存放路由和中间件
+        |
+        --- middleware 中间件
+service -- service 相关        
+util -- util包
+db -- 数据库包
+logger -- 打印日志
+
+DOCKERFILE 生成Docker镜像
+.drone.yml 基于docker持续交付
+
+```
+
+## START
+
+1. 使用 GIN 作为开发框架,使用 go mod 管理依赖
+
+2. 网络请求使用 振锋封装的 go-fetch `github.com/zzfup/go-fetch`
+
+### api doc
+
+对于接口需要编写 api doc,然后需要把项目打上tag,放到对应文档库,可以生成api文档,在 https://api.finogeeks.club 供其他人查看
+
+
+### 数据库
+
+脚手架数据库采用 mongodb,
+
+### 日志
+
+日志还没改,还是俊涛那个
+
+### 错误码
+
+http status code
+
+200 OK
+
+201 一般用于 post,新建一条记录
+
+202 用于异步请求,给客户端即时响应
+
+204 一般用于 delete,不需要返回给客户端内容
+
+400 参数错误
+
+{
+  "errcode": "", // 全大写,蛇形命名  FC_TOPIC_FORMAT_ERROR  前缀(FC: finochat   SW: 金服宝   )
+  "error": "", // 具体的报错信息
+  "service": "swan-manager" // 容器名称(直接取hostname)
+}
+
+res.status(400).send({})
+401 jwt 无权限,或用户名密码验证失败
+
+403 一般是权限控制时,低权限的无法查看高权限的
+
+404 找不到
+
+409 数据冲突,或者用于新增时出现重复
+
+429 用于限制请求频率
+
+500 服务异常
+
+下游服务相关
+
+https://wiki.finogeeks.club/pages/viewpage.action?pageId=15565151
+
+尽量透传上游错误码
+如果没有,参照上述的规则
+
+### 编写DOCKERFILE
+
+DOCKERFILE 是将当前代码编写成镜像,在docker环境中只需要下镜像就能启动
+
+
+### 持续集成
+
+编写 .drone.yml 文件
+
+### 性能测试
+
+
+
+### 联调
+
+
+

+ 10 - 0
client/client.go

@@ -0,0 +1,10 @@
+package client
+
+import "web_test_cgi/config"
+
+var headers = map[string]string{
+	"Accept":       "application/json, text/plain, */*",
+	"Content-Type": "application/json",
+}
+
+var cfg = config.GetConfig()

+ 28 - 0
conf/config.yaml

@@ -0,0 +1,28 @@
+# 端口
+port: 40040
+
+# debug release test
+mode: "debug"
+
+debuglog: true
+tracelog: true
+logfile: ""
+
+mongo:
+  # 数据库url
+  url: mongodb://127.0.0.1:27017
+  # db名称
+  db: swan-observe-go
+
+homeServer:
+  staff:
+    server: http://staff-server.finochat:8008
+    domain: finolabs.club
+
+senstive:
+  url: https://api.finolabs.club  #http://sensitive-words:3000
+
+compliance:
+  url: https://api.finolabs.club #http://compliance-bot:3000
+
+

+ 46 - 0
config/config.go

@@ -0,0 +1,46 @@
+package config
+
+import (
+	"github.com/spf13/viper"
+	"log"
+	"strings"
+)
+
+// Init read the base file
+func init() {
+	viper.AddConfigPath("./conf")
+	viper.AddConfigPath("../conf")
+	viper.SetConfigName("config")
+	viper.SetConfigType("yaml")
+	viper.AutomaticEnv()
+	replacer := strings.NewReplacer(".", "_")
+	viper.SetEnvKeyReplacer(replacer)
+	if err := viper.ReadInConfig(); err != nil {
+		log.Println("init config error ", err)
+		panic(err)
+	}
+}
+
+// Config 导出的配置类
+type Config struct {
+	Port     string
+	Mode     string
+	MongoURL string
+	DBName   string
+	DebugLog bool
+	TraceLog bool
+	LogFile  string
+}
+
+// GetConfig get config
+func GetConfig() *Config {
+	return &Config{
+		Port:     viper.GetString("port"),
+		Mode:     viper.GetString("mode"),
+		MongoURL: viper.GetString("mongo.url"),
+		DBName:   viper.GetString("mongo.db"),
+		DebugLog: viper.GetBool("debuglog"),
+		TraceLog: viper.GetBool("tracelog"),
+		LogFile:  viper.GetString("logfile"),
+	}
+}

+ 5 - 0
db/db.go

@@ -0,0 +1,5 @@
+package db
+
+import "web_test_cgi/config"
+
+var cfg = config.GetConfig()

+ 52 - 0
db/mongo.go

@@ -0,0 +1,52 @@
+package db
+
+import (
+	"gopkg.in/mgo.v2"
+)
+
+type DBConnection struct {
+	session *mgo.Session
+}
+
+func NewConnection(host string) (conn *DBConnection) {
+	session, err := mgo.Dial(host)
+	if err != nil {
+		panic(err)
+	}
+	session.SetMode(mgo.Monotonic, true)
+	conn = &DBConnection{session}
+
+	return conn
+}
+
+func (conn *DBConnection) EnsureIndex(dbName string, tableName string, index mgo.Index) {
+
+	copySession := conn.session.Copy()
+
+	defer func() {
+		copySession.Close()
+	}()
+
+	copySession.DB(dbName).C(tableName).EnsureIndex(index)
+}
+
+func (conn *DBConnection) EnsureIndexKey(dbName string, tableName string, key ...string) {
+
+	copySession := conn.session.Copy()
+
+	defer func() {
+		copySession.Close()
+	}()
+
+	copySession.DB(dbName).C(tableName).EnsureIndexKey(key...)
+}
+
+//外面调用需要close()
+func (conn *DBConnection) Use(dbName, tableName string) (collection *mgo.Collection) {
+	return conn.session.DB(dbName).C(tableName)
+}
+
+func (conn *DBConnection) Close() {
+	conn.session.Close()
+	return
+}

+ 10 - 0
go.mod

@@ -0,0 +1,10 @@
+module web_test_cgi
+
+go 1.12
+
+require (
+	git.finogeeks.club/monitor/go-client v0.0.0-20171124095506-52407144eb4a
+	github.com/gin-gonic/gin v1.4.0
+	github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d
+	github.com/spf13/viper v1.5.0
+)

+ 163 - 0
go.sum

@@ -0,0 +1,163 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+git.finogeeks.club/monitor/go-client v0.0.0-20171124095506-52407144eb4a h1:WO7BekTJJKoviQ/5UkFUXsb8sVpq8RGxADMykqvjePA=
+git.finogeeks.club/monitor/go-client v0.0.0-20171124095506-52407144eb4a/go.mod h1:oaRPMqnXlBtiBMS+XooygnRAS5Dmk4i2neyhgLobHiE=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
+github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
+github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
+github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4=
+github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 18 - 0
handler/article.go

@@ -0,0 +1,18 @@
+package handler
+
+import (
+	"web_test_cgi/model"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+func AddArticle(c *gin.Context) {
+	article := model.Article{}
+	c.BindJSON(&article)
+	c.JSON(http.StatusOK, gin.H{"message": "msg created"})
+
+}
+
+func GetArticles(c *gin.Context) {
+	c.JSON(http.StatusOK, gin.H{"name": "wangkang"})
+}

+ 201 - 0
logger/log.go

@@ -0,0 +1,201 @@
+package logger
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"runtime"
+)
+
+
+
+// Logger is the server logger
+type Logger struct {
+	logger     *log.Logger
+	debug      bool
+	trace      bool
+	file       bool
+	infoLabel  string
+	errorLabel string
+	fatalLabel string
+	debugLabel string
+	traceLabel string
+}
+
+// NewStdLogger creates a logger with output directed to Stderr
+func NewStdLogger(time, file, debug, trace, colors, pid bool) *Logger {
+	flags := 0
+	if time {
+		flags = log.LstdFlags | log.Lmicroseconds
+	}
+
+	pre := ""
+	if pid {
+		pre = pidPrefix()
+	}
+
+	l := &Logger{
+		logger: log.New(os.Stdout, pre, flags),
+		debug:  debug,
+		trace:  trace,
+		file:   file,
+	}
+
+	if colors {
+		setColoredLabelFormats(l)
+	} else {
+		setPlainLabelFormats(l)
+	}
+
+	return l
+}
+
+// NewFileLogger creates a logger with output directed to a file
+func NewFileLogger(filename string, time, file, debug, trace, pid bool) *Logger {
+	fileflags := os.O_WRONLY | os.O_APPEND | os.O_CREATE
+	f, err := os.OpenFile(filename, fileflags, 0660)
+	if err != nil {
+		log.Fatalf("error opening file: %v", err)
+	}
+
+	flags := 0
+	if time {
+		flags = log.LstdFlags | log.Lmicroseconds
+	}
+
+	pre := ""
+	if pid {
+		pre = pidPrefix()
+	}
+
+	l := &Logger{
+		logger: log.New(f, pre, flags),
+		debug:  debug,
+		trace:  trace,
+		file:   file,
+	}
+
+	setPlainLabelFormats(l)
+	return l
+}
+
+// Generate the pid prefix string
+func pidPrefix() string {
+	return fmt.Sprintf("[%d] ", os.Getpid())
+}
+
+func setPlainLabelFormats(l *Logger) {
+	l.infoLabel = "[INF]"
+	l.debugLabel = "[DBG]"
+	l.errorLabel = "[ERR]"
+	l.fatalLabel = "[FTL]"
+	l.traceLabel = "[TRC]"
+}
+
+func setColoredLabelFormats(l *Logger) {
+	colorFormat := "[\x1b[%dm%s\x1b[0m]"
+	l.infoLabel = fmt.Sprintf(colorFormat, 32, "INF")
+	l.debugLabel = fmt.Sprintf(colorFormat, 36, "DBG")
+	l.errorLabel = fmt.Sprintf(colorFormat, 31, "ERR")
+	l.fatalLabel = fmt.Sprintf(colorFormat, 31, "FTL")
+	l.traceLabel = fmt.Sprintf(colorFormat, 33, "TRC")
+}
+
+// copy from go/src/log/log.go and modify by guojuntao, 2017/09/21
+// Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
+func itoa(i int, wid int) string {
+	// Assemble decimal in reverse order.
+	var b [20]byte
+	bp := len(b) - 1
+	for i >= 10 || wid > 1 {
+		wid--
+		q := i / 10
+		b[bp] = byte('0' + i - q*10)
+		bp--
+		i = q
+	}
+	// i < 10
+	b[bp] = byte('0' + i)
+	return string(b[bp:])
+}
+
+func (l *Logger) getFileLineFormat(calldepth int) string {
+	if l.file {
+		_, file, line, ok := runtime.Caller(calldepth)
+		if !ok {
+			file = "???"
+			line = 0
+		}
+		short := file
+		for i := len(file) - 1; i > 0; i-- {
+			if file[i] == '/' {
+				short = file[i+1:]
+				break
+			}
+		}
+		file = short
+		return " " + file + ":" + itoa(line, -1) + ":"
+	}
+	return ""
+}
+
+// Noticef logs a notice statement
+func (l *Logger) Noticef(format string, v ...interface{}) {
+	l.logger.Printf(l.infoLabel+l.getFileLineFormat(2)+" "+format, v...)
+}
+
+func (l *Logger) Noticeln(v ...interface{}) {
+	l.logger.Println(append([]interface{}{l.infoLabel + l.getFileLineFormat(2)}, v...)...)
+}
+
+// Errorf logs an error statement
+func (l *Logger) Errorf(format string, v ...interface{}) {
+	l.logger.Printf(l.errorLabel+l.getFileLineFormat(2)+" "+format, v...)
+}
+
+func (l *Logger) Errorln(v ...interface{}) {
+	l.logger.Println(append([]interface{}{l.errorLabel + l.getFileLineFormat(2)}, v...)...)
+}
+
+// Fatalf logs a fatal error
+func (l *Logger) Fatalf(format string, v ...interface{}) {
+	l.logger.Fatalf(l.fatalLabel+l.getFileLineFormat(2)+" "+format, v...)
+}
+
+func (l *Logger) Fatalln(v ...interface{}) {
+	l.logger.Fatalln(append([]interface{}{l.fatalLabel + l.getFileLineFormat(2)}, v...)...)
+}
+
+// Debugf logs a debug statement
+func (l *Logger) Debugf(format string, v ...interface{}) {
+	if l.debug {
+		l.logger.Printf(l.debugLabel+l.getFileLineFormat(2)+" "+format, v...)
+	}
+}
+
+func (l *Logger) Debugln(v ...interface{}) {
+	if l.debug {
+		l.logger.Println(append([]interface{}{l.debugLabel + l.getFileLineFormat(2)}, v...)...)
+	}
+}
+
+// Tracef logs a trace statement
+func (l *Logger) Tracef(format string, v ...interface{}) {
+	if l.trace {
+		l.logger.Printf(l.traceLabel+l.getFileLineFormat(2)+" "+format, v...)
+	}
+}
+
+func (l *Logger) Traceln(v ...interface{}) {
+	if l.trace {
+		l.logger.Println(append([]interface{}{l.traceLabel + l.getFileLineFormat(2)}, v...)...)
+	}
+}
+
+func (l *Logger) IsDebugEnabled() bool {
+	return l.debug
+}
+
+func (l *Logger) IsTraceEnabled() bool {
+	return l.trace
+}

+ 26 - 0
logger/logger.go

@@ -0,0 +1,26 @@
+package logger
+
+import "web_test_cgi/config"
+
+var l *Logger
+
+func init() {
+	cfg := config.GetConfig()
+
+	time := true
+	file := true
+	debug := cfg.DebugLog
+	trace := cfg.TraceLog
+	colors := true
+	pid := false
+
+	if cfg.LogFile == "" {
+		l = NewStdLogger(time, file, debug, trace, colors, pid)
+	} else {
+		l = NewFileLogger(cfg.LogFile, time, file, debug, trace, pid)
+	}
+}
+
+func GetLogger() *Logger {
+	return l
+}

+ 23 - 0
main.go

@@ -0,0 +1,23 @@
+package main
+
+import (
+	"web_test_cgi/config"
+	"web_test_cgi/logger"
+	"web_test_cgi/router"
+	"github.com/gin-gonic/gin"
+	"github.com/spf13/viper"
+)
+
+func main() {
+
+	cfg := config.GetConfig()
+	gin.SetMode(cfg.Mode)
+	logger.GetLogger().Traceln(viper.AllSettings())
+
+	// 使用Default 里面已经包含了 log 和 recovery
+	// todo log 中间件可以考虑替换
+	g := gin.Default()
+	router.Load(g)
+
+	_ = g.Run(":" + cfg.Port)
+}

+ 8 - 0
model/article.go

@@ -0,0 +1,8 @@
+package model
+
+type Article struct {
+	Sender string `json:"sender"`
+	Url    string `json:"url"`
+	Time   int64  `json:"time"`
+}
+

+ 27 - 0
router/middleware/bodycheck.go

@@ -0,0 +1,27 @@
+package middleware
+
+import (
+	"git.finogeeks.club/swan/fino-gin-framework/pkg/common"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+// 例子
+// 应用这个中间件 可以实现在中间件校检参数 但是由于不能 Bind 2次
+// 使用这个中间件的时候需要 再从 context 中 get 出来
+
+func BodyCheck() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var reqInfo = struct {
+		}{}
+		err := c.BindJSON(&reqInfo)
+		if err != nil {
+			c.JSON(http.StatusBadRequest, common.ErrorResponse("", ""))
+			c.Abort()
+			return
+		}
+		c.Set("requet_params", reqInfo)
+		c.Next()
+
+	}
+}

+ 48 - 0
router/middleware/header.go

@@ -0,0 +1,48 @@
+package middleware
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+)
+
+// NoCache is a middleware function that appends headers
+// to prevent the client from caching the HTTP response.
+func NoCache(c *gin.Context) {
+	c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
+	c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
+	c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
+	c.Next()
+}
+
+// Options is a middleware function that appends headers
+// for options requests and aborts then exits the middleware
+// chain and ends the request.
+func Options(c *gin.Context) {
+	if c.Request.Method != "OPTIONS" {
+		c.Next()
+	} else {
+		c.Header("Access-Control-Allow-Origin", "*")
+		c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
+		c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
+		c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
+		c.Header("Content-Type", "application/json")
+		c.AbortWithStatus(200)
+	}
+}
+
+// Secure is a middleware function that appends security
+// and resource access headers.
+func Secure(c *gin.Context) {
+	c.Header("Access-Control-Allow-Origin", "*")
+	c.Header("X-Frame-Options", "DENY")
+	c.Header("X-Content-Type-Options", "nosniff")
+	c.Header("X-XSS-Protection", "1; mode=block")
+	if c.Request.TLS != nil {
+		c.Header("Strict-Transport-Security", "max-age=31536000")
+	}
+
+	// Also consider adding Content-Security-Policy headers
+	// c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
+}

+ 47 - 0
router/middleware/monitor.go

@@ -0,0 +1,47 @@
+package middleware
+
+import (
+	mon "git.finogeeks.club/monitor/go-client/monitor"
+	"github.com/gin-gonic/gin"
+	"strconv"
+	"time"
+)
+
+// 应用这个中间件 可以 给项目配置监控
+
+var monitor mon.Monitor
+
+func init() {
+	monitor = mon.GetInstance()
+}
+
+func FinMonitor() gin.HandlerFunc {
+	var summary mon.LabeledSummary = monitor.NewLabeledSummary(
+		"http_request_duration_seconds",
+		[]string{"method", "path", "code"},
+		map[float64]float64{0.5: 0.01, 0.9: 0.01, 0.99: 0.001, 0.999: 0.0001},
+	)
+
+	var histogram mon.LabeledHistogram = monitor.NewLabeledHistogram(
+		"http_request_buckets_seconds",
+		[]string{"method", "path", "code"},
+		[]float64{0.05, 0.1, 0.5, 1, 2, 5},
+	)
+
+	return func(c *gin.Context) {
+		start := time.Now()
+
+		// Process request
+		c.Next()
+		//end := time.Now()
+		//latency := end.Sub(start)
+		duration := float64(time.Since(start)) / float64(time.Second)
+
+		method := c.Request.Method
+		path := c.Request.URL.Path
+		code := strconv.Itoa(c.Writer.Status())
+
+		summary.WithLabelValues(method, path, code).Observe(duration)
+		histogram.WithLabelValues(method, path, code).Observe(duration)
+	}
+}

+ 19 - 0
router/middleware/tracer.go

@@ -0,0 +1,19 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+	"github.com/nu7hatch/gouuid"
+)
+
+// 保留请求的链路id 如果没有生成一个id
+func Tracer() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		traceId := c.Request.Header.Get("x-trace-id")
+		if "" == traceId {
+			u, _ := uuid.NewV4()
+			traceId = u.String()
+		}
+		c.Header("x-trace-id", traceId)
+		c.Next()
+	}
+}

+ 31 - 0
router/router.go

@@ -0,0 +1,31 @@
+package router
+
+import (
+	"web_test_cgi/handler"
+	"web_test_cgi/router/middleware"
+	"github.com/gin-gonic/gin"
+	"net/http"
+)
+
+// router.go 所有的路由放到这里
+
+func Load(g *gin.Engine) *gin.Engine {
+	// Middlewares
+	g.Use(middleware.NoCache)
+	g.Use(middleware.Options)
+	g.Use(middleware.Secure)
+
+	// 404 Handler
+	g.NoRoute(func(c *gin.Context) {
+		c.String(http.StatusNotFound, "The incorrect API route.")
+	})
+
+	// 注意使用rest风格url
+	articleGroup := g.Group("/web_test_cgi")
+	{
+		articleGroup.GET("/user_info/:id", handler.GetArticles)
+		//articleGroup.POST("/article", handler.AddArticle)
+	}
+
+	return g
+}