github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/server/ingest/server.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package ingestserver 18 19 import ( 20 "net" 21 "time" 22 23 "github.com/siglens/siglens/pkg/hooks" 24 "github.com/siglens/siglens/pkg/segment/query" 25 log "github.com/sirupsen/logrus" 26 27 "github.com/fasthttp/router" 28 "github.com/oklog/run" 29 "github.com/siglens/siglens/pkg/config" 30 "github.com/siglens/siglens/pkg/ingest" 31 "github.com/siglens/siglens/pkg/segment/writer" 32 server_utils "github.com/siglens/siglens/pkg/server/utils" 33 "github.com/valyala/fasthttp" 34 "github.com/valyala/fasthttp/pprofhandler" 35 ) 36 37 type ingestionServerCfg struct { 38 Config config.WebConfig 39 Addr string 40 // Log *zap.Logger //ToDo implement debug logger 41 ln net.Listener 42 router *router.Router 43 debug bool 44 } 45 46 var ( 47 corsAllowHeaders = "Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Max-Age, Access-Control-Allow-Credentials, Content-Type, Authorization, Origin, X-Requested-With , Accept" 48 corsAllowMethods = "HEAD, GET, POST, PUT, DELETE, OPTIONS" 49 corsAllowOrigin = "*" 50 ) 51 52 // ConstructHttpServer new fasthttp server 53 func ConstructIngestServer(cfg config.WebConfig, ServerAddr string) *ingestionServerCfg { 54 55 s := &ingestionServerCfg{ 56 Config: cfg, 57 Addr: ServerAddr, 58 router: router.New(), 59 debug: true, 60 } 61 return s 62 } 63 64 func (hs *ingestionServerCfg) Close() { 65 _ = hs.ln.Close() 66 } 67 68 func getMyIds() []uint64 { 69 myids := make([]uint64, 1) 70 71 alreadyHandled := false 72 if hook := hooks.GlobalHooks.GetIdsConditionHook; hook != nil { 73 alreadyHandled = hook(myids) 74 } 75 76 if !alreadyHandled { 77 myids[0] = 0 78 } 79 80 return myids 81 } 82 83 func (hs *ingestionServerCfg) Run() (err error) { 84 85 //Register all the method handlers here 86 ingest.InitIngestionMetrics() 87 writer.InitWriterNode() 88 89 if !config.IsQueryNode() && config.IsIngestNode() { 90 go query.InitQueryInfoRefresh(getMyIds) 91 } 92 93 hs.router.GET(server_utils.API_PREFIX+"/health", hs.Recovery(getHealthHandler())) 94 hs.router.POST(server_utils.API_PREFIX+"/sampledataset_bulk", hs.Recovery(sampleDatasetBulkHandler())) 95 96 hs.router.POST("/setconfig/transient", hs.Recovery(postSetconfigHandler(false))) 97 hs.router.POST("/setconfig/persistent", hs.Recovery(postSetconfigHandler(true))) 98 hs.router.GET("/config", hs.Recovery(getConfigHandler())) 99 hs.router.POST("/config/reload", hs.Recovery(getConfigReloadHandler())) 100 101 //elasticsearch endpoints 102 hs.router.HEAD(server_utils.ELASTIC_PREFIX+"/", hs.Recovery(esGreetHandler())) 103 hs.router.GET(server_utils.ELASTIC_PREFIX+"/", hs.Recovery(esGreetHandler())) 104 hs.router.GET(server_utils.ELASTIC_PREFIX+"/_xpack", hs.Recovery(esGreetHandler())) 105 hs.router.POST(server_utils.ELASTIC_PREFIX+"/_bulk", hs.Recovery(esPostBulkHandler())) 106 hs.router.PUT(server_utils.ELASTIC_PREFIX+"/{indexName}", hs.Recovery(EsPutIndexHandler())) 107 108 // Loki endpoints 109 hs.router.POST(server_utils.LOKI_PREFIX+"/api/v1/push", hs.Recovery(lokiPostBulkHandler())) 110 111 // Splunk Handlers 112 hs.router.POST("/services/collector/event", hs.Recovery(splunkHecIngestHandler())) 113 hs.router.GET("/services/collector/health", hs.Recovery(getHealthHandler())) 114 hs.router.GET("/services/collector/health/1.0", hs.Recovery(getHealthHandler())) 115 116 // OpenTSDB Handlers 117 hs.router.PUT(server_utils.OTSDB_PREFIX+"/api/put", hs.Recovery(otsdbPutMetricsHandler())) 118 hs.router.POST(server_utils.OTSDB_PREFIX+"/api/put", hs.Recovery(otsdbPutMetricsHandler())) 119 120 // Influx Handlers 121 hs.router.POST(server_utils.INFLUX_PREFIX+"/api/v2/write", hs.Recovery(influxPutMetricsHandler())) 122 123 // Prometheus Handlers 124 hs.router.POST(server_utils.PROMQL_PREFIX+"/api/v1/write", hs.Recovery(prometheusPutMetricsHandler())) 125 126 // OTLP Handlers 127 hs.router.POST(server_utils.OTLP_PREFIX+"/v1/traces", hs.Recovery(otlpIngestTracesHandler())) 128 129 if config.IsDebugMode() { 130 hs.router.GET("/debug/pprof/{profile:*}", pprofhandler.PprofHandler) 131 } 132 133 if hook := hooks.GlobalHooks.ExtraIngestEndpointsHook; hook != nil { 134 hook(hs.router, hs.Recovery) 135 } 136 137 hs.ln, err = net.Listen("tcp4", hs.Addr) 138 if err != nil { 139 return err 140 } 141 142 s := &fasthttp.Server{ 143 Handler: cors(hs.router.Handler), 144 Name: hs.Config.Name, 145 ReadBufferSize: hs.Config.ReadBufferSize, 146 MaxConnsPerIP: hs.Config.MaxConnsPerIP, 147 MaxRequestsPerConn: hs.Config.MaxRequestsPerConn, 148 MaxRequestBodySize: hs.Config.MaxRequestBodySize, // 100 << 20, // 100MB // 1024 * 4, // MaxRequestBodySize: 149 Concurrency: hs.Config.Concurrency, 150 } 151 152 // run fasthttp server 153 var g run.Group 154 155 if config.IsTlsEnabled() { 156 g.Add(func() error { 157 return s.ServeTLS(hs.ln, config.GetTLSCertificatePath(), config.GetTLSPrivateKeyPath()) 158 }, func(e error) { 159 _ = hs.ln.Close() 160 }) 161 } else { 162 g.Add(func() error { 163 return s.Serve(hs.ln) 164 }, func(e error) { 165 _ = hs.ln.Close() 166 }) 167 } 168 return g.Run() 169 } 170 171 func (hs *ingestionServerCfg) RunSafeServer() (err error) { 172 hs.router.GET("/health", hs.Recovery(getSafeHealthHandler())) 173 hs.ln, err = net.Listen("tcp4", hs.Addr) 174 if err != nil { 175 return err 176 } 177 178 s := &fasthttp.Server{ 179 Handler: cors(hs.router.Handler), 180 Name: hs.Config.Name, 181 ReadBufferSize: hs.Config.ReadBufferSize, 182 MaxConnsPerIP: hs.Config.MaxConnsPerIP, 183 MaxRequestsPerConn: hs.Config.MaxRequestsPerConn, 184 MaxRequestBodySize: hs.Config.MaxRequestBodySize, // 100 << 20, // 100MB // 1024 * 4, // MaxRequestBodySize: 185 Concurrency: hs.Config.Concurrency, 186 } 187 188 log.Infof("Starting Ingestion Server on safe mode...") 189 ticker := time.NewTicker(1 * time.Minute) 190 go func() { 191 for range ticker.C { 192 log.Infof("Siglens Ingestion Server has started in safe mode...") 193 } 194 }() 195 196 // run fasthttp server 197 var g run.Group 198 g.Add(func() error { 199 return s.Serve(hs.ln) 200 }, func(e error) { 201 _ = hs.ln.Close() 202 }) 203 return g.Run() 204 } 205 206 func cors(next fasthttp.RequestHandler) fasthttp.RequestHandler { 207 return func(ctx *fasthttp.RequestCtx) { 208 ctx.Response.Header.Set("Access-Control-Allow-Headers", corsAllowHeaders) 209 ctx.Response.Header.Set("Access-Control-Allow-Methods", corsAllowMethods) 210 ctx.Response.Header.Set("Access-Control-Allow-Origin", corsAllowOrigin) 211 ctx.Response.Header.Set("Access-Control-Allow-Credentials", "true") 212 next(ctx) 213 } 214 }