-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathserver.go
151 lines (123 loc) · 3.92 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package ginhelper
import (
"bytes"
"context"
"github.com/samborkent/uuid"
"github.com/synapsecns/sanguine/core/metrics/logger"
// embed is used for importing the robots.txt file.
_ "embed"
"net/http"
"time"
helmet "github.com/danielkov/gin-helmet"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/requestid"
ginzap "github.com/gin-contrib/zap"
"github.com/gin-gonic/gin"
"github.com/go-http-utils/headers"
"github.com/ipfs/go-log"
"go.uber.org/zap/zapcore"
)
//go:embed robots.txt
var robots []byte
// New creates a new gin server with some sensible defaults.
// these include:
// - helmet-default handlers
// - request-ids (used for stack tracing)
// - cors (used for requests from the frontend)
// - health-checks
// - restrictive robots.txt.
func New(logger *log.ZapEventLogger) *gin.Engine {
server := newBase()
server.Use(ginzap.RecoveryWithZap(logger.Desugar(), true))
// add the request id to the logger
server.Use(ginzap.GinzapWithConfig(logger.Desugar(), &ginzap.Config{
TimeFormat: time.RFC3339,
UTC: true,
Context: func(c *gin.Context) (fields []zapcore.Field) {
requestID := c.GetHeader(RequestIDHeader)
fields = append(fields, zapcore.Field{
Key: "request-id",
Type: zapcore.StringType,
String: requestID,
})
return fields
},
}))
return server
}
// NewWithExperimentalLogger creates a new gin server with some sensible defaults.
// See New for more information.
func NewWithExperimentalLogger(ctx context.Context, logger logger.ExperimentalLogger) *gin.Engine {
server := newBase()
wrapped := wrappedExperimentalLogger{
ctx: ctx,
logger: logger,
}
server.Use(ginzap.RecoveryWithZap(wrapped, true))
server.Use(ginzap.GinzapWithConfig(wrapped, &ginzap.Config{
TimeFormat: time.RFC3339,
UTC: true,
Context: func(c *gin.Context) (fields []zapcore.Field) {
requestID := c.GetHeader(RequestIDHeader)
fields = append(fields, zapcore.Field{
Key: "request-id",
Type: zapcore.StringType,
String: requestID,
})
return fields
},
}))
return server
}
// CorsEnabled is used to enable cors on the server. It can be set to false to disable cors.
// TODO: this is an anti-pattern and needs to be replaced by an option asap.
var CorsEnabled = true
func newBase() *gin.Engine {
server := gin.New()
// required for opentracing.
server.ContextWithFallback = true
server.Use(gin.Recovery())
if CorsEnabled {
server.Use(helmet.Default())
server.Use(cors.New(cors.Config{
AllowAllOrigins: true,
AllowHeaders: []string{"*"},
AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodPatch, http.MethodDelete, http.MethodOptions},
MaxAge: 12 * time.Hour,
}))
}
// configure the request id
server.Use(requestid.New(
requestid.WithCustomHeaderStrKey(RequestIDHeader),
requestid.WithGenerator(func() string {
return uuid.NewV8().String()
})))
// set the request id header if the client didn't
server.Use(func(c *gin.Context) {
if c.Request.Header.Get(RequestIDHeader) == "" {
c.Request.Header.Set(RequestIDHeader, c.Writer.Header().Get(RequestIDHeader))
}
})
server.GET(HealthCheck, func(c *gin.Context) {
c.JSON(200, gin.H{
"status": "UP",
})
})
server.GET(RobotsTxt, func(context *gin.Context) {
reader := bytes.NewReader(robots)
context.Header(headers.ContentType, gin.MIMEPlain)
http.ServeContent(context.Writer, context.Request, "robots.txt", bootTime, reader)
})
return server
}
// HealthCheck is the health check endpoint.
const HealthCheck string = "/health-check"
// RobotsTxt is used for apis to disallow crawls.
const RobotsTxt string = "/robots.txt"
// RequestIDHeader is used for tracking request ids.
const RequestIDHeader = "X-Request-ID"
// bootTime is used for the mod-time of the robots.txt.
var bootTime = time.Now()
// MetricsEndpoint is used for prometheus metrics.
// Deprecated: use METRICS_PATH instead.
const MetricsEndpoint string = "/metrics"