Skip to content

Commit 971360d

Browse files
committed
TUN-8238: Refactor proxy logging
Propagates the logger context into further locations to help provide more context for certain errors. For instance, upstream and downstream copying errors will properly have the assigned flow id attached and destination address.
1 parent 76badfa commit 971360d

File tree

2 files changed

+97
-123
lines changed

2 files changed

+97
-123
lines changed

proxy/logger.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package proxy
2+
3+
import (
4+
"net/http"
5+
"strconv"
6+
7+
"github.com/rs/zerolog"
8+
9+
"github.com/cloudflare/cloudflared/connection"
10+
"github.com/cloudflare/cloudflared/ingress"
11+
"github.com/cloudflare/cloudflared/management"
12+
)
13+
14+
const (
15+
logFieldCFRay = "cfRay"
16+
logFieldLBProbe = "lbProbe"
17+
logFieldRule = "ingressRule"
18+
logFieldOriginService = "originService"
19+
logFieldFlowID = "flowID"
20+
logFieldConnIndex = "connIndex"
21+
logFieldDestAddr = "destAddr"
22+
)
23+
24+
// newHTTPLogger creates a child zerolog.Logger from the provided with added context from the HTTP request, ingress
25+
// services, and connection index.
26+
func newHTTPLogger(logger *zerolog.Logger, connIndex uint8, req *http.Request, rule int, serviceName string) zerolog.Logger {
27+
ctx := logger.With().
28+
Int(management.EventTypeKey, int(management.HTTP)).
29+
Uint8(logFieldConnIndex, connIndex)
30+
cfRay := connection.FindCfRayHeader(req)
31+
lbProbe := connection.IsLBProbeRequest(req)
32+
if cfRay != "" {
33+
ctx.Str(logFieldCFRay, cfRay)
34+
}
35+
if lbProbe {
36+
ctx.Bool(logFieldLBProbe, lbProbe)
37+
}
38+
return ctx.
39+
Str(logFieldOriginService, serviceName).
40+
Interface(logFieldRule, rule).
41+
Logger()
42+
}
43+
44+
// newTCPLogger creates a child zerolog.Logger from the provided with added context from the TCPRequest.
45+
func newTCPLogger(logger *zerolog.Logger, req *connection.TCPRequest) zerolog.Logger {
46+
return logger.With().
47+
Int(management.EventTypeKey, int(management.TCP)).
48+
Uint8(logFieldConnIndex, req.ConnIndex).
49+
Str(logFieldOriginService, ingress.ServiceWarpRouting).
50+
Str(logFieldFlowID, req.FlowID).
51+
Str(logFieldDestAddr, req.Dest).
52+
Uint8(logFieldConnIndex, req.ConnIndex).
53+
Logger()
54+
}
55+
56+
// logHTTPRequest logs a Debug message with the corresponding HTTP request details from the eyeball.
57+
func logHTTPRequest(logger *zerolog.Logger, r *http.Request) {
58+
logger.Debug().
59+
Str("host", r.Host).
60+
Str("path", r.URL.Path).
61+
Interface("headers", r.Header).
62+
Int64("content-length", r.ContentLength).
63+
Msgf("%s %s %s", r.Method, r.URL, r.Proto)
64+
}
65+
66+
// logOriginHTTPResponse logs a Debug message of the origin response.
67+
func logOriginHTTPResponse(logger *zerolog.Logger, resp *http.Response) {
68+
responseByCode.WithLabelValues(strconv.Itoa(resp.StatusCode)).Inc()
69+
logger.Debug().
70+
Int64("content-length", resp.ContentLength).
71+
Msgf("%s", resp.Status)
72+
}
73+
74+
// logRequestError logs an error for the proxied request.
75+
func logRequestError(logger *zerolog.Logger, err error) {
76+
requestErrors.Inc()
77+
logger.Error().Err(err).Send()
78+
}

proxy/proxy.go

Lines changed: 19 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,15 @@ import (
1717
"github.com/cloudflare/cloudflared/cfio"
1818
"github.com/cloudflare/cloudflared/connection"
1919
"github.com/cloudflare/cloudflared/ingress"
20-
"github.com/cloudflare/cloudflared/management"
2120
"github.com/cloudflare/cloudflared/stream"
2221
"github.com/cloudflare/cloudflared/tracing"
2322
tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs"
2423
)
2524

2625
const (
2726
// TagHeaderNamePrefix indicates a Cloudflared Warp Tag prefix that gets appended for warp traffic stream headers.
28-
TagHeaderNamePrefix = "Cf-Warp-Tag-"
29-
LogFieldCFRay = "cfRay"
30-
LogFieldLBProbe = "lbProbe"
31-
LogFieldRule = "ingressRule"
32-
LogFieldOriginService = "originService"
33-
LogFieldFlowID = "flowID"
34-
LogFieldConnIndex = "connIndex"
35-
LogFieldDestAddr = "destAddr"
36-
37-
trailerHeaderName = "Trailer"
27+
TagHeaderNamePrefix = "Cf-Warp-Tag-"
28+
trailerHeaderName = "Trailer"
3829
)
3930

4031
// Proxy represents a means to Proxy between cloudflared and the origin services.
@@ -91,26 +82,18 @@ func (p *Proxy) ProxyHTTP(
9182
defer decrementConcurrentRequests()
9283

9384
req := tr.Request
94-
cfRay := connection.FindCfRayHeader(req)
95-
lbProbe := connection.IsLBProbeRequest(req)
9685
p.appendTagHeaders(req)
9786

9887
_, ruleSpan := tr.Tracer().Start(req.Context(), "ingress_match",
9988
trace.WithAttributes(attribute.String("req-host", req.Host)))
10089
rule, ruleNum := p.ingressRules.FindMatchingRule(req.Host, req.URL.Path)
101-
logFields := logFields{
102-
cfRay: cfRay,
103-
lbProbe: lbProbe,
104-
rule: ruleNum,
105-
connIndex: tr.ConnIndex,
106-
}
107-
p.logRequest(req, logFields)
10890
ruleSpan.SetAttributes(attribute.Int("rule-num", ruleNum))
10991
ruleSpan.End()
92+
logger := newHTTPLogger(p.log, tr.ConnIndex, req, ruleNum, rule.Service.String())
93+
logHTTPRequest(&logger, req)
11094
if err, applied := p.applyIngressMiddleware(rule, req, w); err != nil {
11195
if applied {
112-
rule, srv := ruleField(p.ingressRules, ruleNum)
113-
p.logRequestError(err, cfRay, "", rule, srv)
96+
logRequestError(&logger, err)
11497
return nil
11598
}
11699
return err
@@ -124,10 +107,9 @@ func (p *Proxy) ProxyHTTP(
124107
originProxy,
125108
isWebsocket,
126109
rule.Config.DisableChunkedEncoding,
127-
logFields,
110+
&logger,
128111
); err != nil {
129-
rule, srv := ruleField(p.ingressRules, ruleNum)
130-
p.logRequestError(err, cfRay, "", rule, srv)
112+
logRequestError(&logger, err)
131113
return err
132114
}
133115
return nil
@@ -141,14 +123,9 @@ func (p *Proxy) ProxyHTTP(
141123
return fmt.Errorf("response writer is not a flusher")
142124
}
143125
rws := connection.NewHTTPResponseReadWriterAcker(w, flusher, req)
144-
logger := p.log.With().
145-
Int(management.EventTypeKey, int(management.HTTP)).
146-
Str(LogFieldDestAddr, dest).
147-
Uint8(LogFieldConnIndex, tr.ConnIndex).
148-
Logger()
149-
if err := p.proxyStream(tr.ToTracedContext(), rws, dest, originProxy, logger); err != nil {
150-
rule, srv := ruleField(p.ingressRules, ruleNum)
151-
p.logRequestError(err, cfRay, "", rule, srv)
126+
logger := logger.With().Str(logFieldDestAddr, dest).Logger()
127+
if err := p.proxyStream(tr.ToTracedContext(), rws, dest, originProxy, &logger); err != nil {
128+
logRequestError(&logger, err)
152129
return err
153130
}
154131
return nil
@@ -178,19 +155,12 @@ func (p *Proxy) ProxyTCP(
178155
serveCtx, cancel := context.WithCancel(ctx)
179156
defer cancel()
180157

181-
tracedCtx := tracing.NewTracedContext(serveCtx, req.CfTraceID, p.log)
182-
183-
logger := p.log.With().
184-
Int(management.EventTypeKey, int(management.TCP)).
185-
Str(LogFieldFlowID, req.FlowID).
186-
Str(LogFieldDestAddr, req.Dest).
187-
Uint8(LogFieldConnIndex, req.ConnIndex).
188-
Logger()
189-
158+
logger := newTCPLogger(p.log, req)
159+
tracedCtx := tracing.NewTracedContext(serveCtx, req.CfTraceID, &logger)
190160
logger.Debug().Msg("tcp proxy stream started")
191161

192-
if err := p.proxyStream(tracedCtx, rwa, req.Dest, p.warpRouting.Proxy, logger); err != nil {
193-
p.logRequestError(err, req.CFRay, req.FlowID, "", ingress.ServiceWarpRouting)
162+
if err := p.proxyStream(tracedCtx, rwa, req.Dest, p.warpRouting.Proxy, &logger); err != nil {
163+
logRequestError(&logger, err)
194164
return err
195165
}
196166

@@ -199,22 +169,14 @@ func (p *Proxy) ProxyTCP(
199169
return nil
200170
}
201171

202-
func ruleField(ing ingress.Ingress, ruleNum int) (ruleID string, srv string) {
203-
srv = ing.Rules[ruleNum].Service.String()
204-
if ing.IsSingleRule() {
205-
return "", srv
206-
}
207-
return fmt.Sprintf("%d", ruleNum), srv
208-
}
209-
210172
// ProxyHTTPRequest proxies requests of underlying type http and websocket to the origin service.
211173
func (p *Proxy) proxyHTTPRequest(
212174
w connection.ResponseWriter,
213175
tr *tracing.TracedHTTPRequest,
214176
httpService ingress.HTTPOriginProxy,
215177
isWebsocket bool,
216178
disableChunkedEncoding bool,
217-
fields logFields,
179+
logger *zerolog.Logger,
218180
) error {
219181
roundTripReq := tr.Request
220182
if isWebsocket {
@@ -281,7 +243,7 @@ func (p *Proxy) proxyHTTPRequest(
281243
reader: tr.Request.Body,
282244
}
283245

284-
stream.Pipe(eyeballStream, rwc, p.log)
246+
stream.Pipe(eyeballStream, rwc, logger)
285247
return nil
286248
}
287249

@@ -292,7 +254,7 @@ func (p *Proxy) proxyHTTPRequest(
292254
// copy trailers
293255
copyTrailers(w, resp)
294256

295-
p.logOriginResponse(resp, fields)
257+
logOriginHTTPResponse(logger, resp)
296258
return nil
297259
}
298260

@@ -304,7 +266,7 @@ func (p *Proxy) proxyStream(
304266
rwa connection.ReadWriteAcker,
305267
dest string,
306268
connectionProxy ingress.StreamBasedOriginProxy,
307-
logger zerolog.Logger,
269+
logger *zerolog.Logger,
308270
) error {
309271
ctx := tr.Context
310272
_, connectSpan := tr.Tracer().Start(ctx, "stream-connect")
@@ -330,7 +292,7 @@ func (p *Proxy) proxyStream(
330292
connectLatency.Observe(float64(time.Since(start).Milliseconds()))
331293
logger.Debug().Msg("proxy stream acknowledged")
332294

333-
originConn.Stream(ctx, rwa, p.log)
295+
originConn.Stream(ctx, rwa, logger)
334296
return nil
335297
}
336298

@@ -364,14 +326,6 @@ func (p *Proxy) appendTagHeaders(r *http.Request) {
364326
}
365327
}
366328

367-
type logFields struct {
368-
cfRay string
369-
lbProbe bool
370-
rule int
371-
flowID string
372-
connIndex uint8
373-
}
374-
375329
func copyTrailers(w connection.ResponseWriter, response *http.Response) {
376330
for trailerHeader, trailerValues := range response.Trailer {
377331
for _, trailerValue := range trailerValues {
@@ -380,64 +334,6 @@ func copyTrailers(w connection.ResponseWriter, response *http.Response) {
380334
}
381335
}
382336

383-
func (p *Proxy) logRequest(r *http.Request, fields logFields) {
384-
log := p.log.With().Int(management.EventTypeKey, int(management.HTTP)).Logger()
385-
event := log.Debug()
386-
if fields.cfRay != "" {
387-
event = event.Str(LogFieldCFRay, fields.cfRay)
388-
}
389-
if fields.lbProbe {
390-
event = event.Bool(LogFieldLBProbe, fields.lbProbe)
391-
}
392-
if fields.cfRay == "" && !fields.lbProbe {
393-
log.Debug().Msgf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", r.Method, r.URL, r.Proto)
394-
}
395-
event.
396-
Uint8(LogFieldConnIndex, fields.connIndex).
397-
Str("host", r.Host).
398-
Str("path", r.URL.Path).
399-
Interface(LogFieldRule, fields.rule).
400-
Interface("headers", r.Header).
401-
Int64("content-length", r.ContentLength).
402-
Msgf("%s %s %s", r.Method, r.URL, r.Proto)
403-
}
404-
405-
func (p *Proxy) logOriginResponse(resp *http.Response, fields logFields) {
406-
responseByCode.WithLabelValues(strconv.Itoa(resp.StatusCode)).Inc()
407-
event := p.log.Debug()
408-
if fields.cfRay != "" {
409-
event = event.Str(LogFieldCFRay, fields.cfRay)
410-
}
411-
if fields.lbProbe {
412-
event = event.Bool(LogFieldLBProbe, fields.lbProbe)
413-
}
414-
event.
415-
Int(management.EventTypeKey, int(management.HTTP)).
416-
Uint8(LogFieldConnIndex, fields.connIndex).
417-
Int64("content-length", resp.ContentLength).
418-
Msgf("%s", resp.Status)
419-
}
420-
421-
func (p *Proxy) logRequestError(err error, cfRay string, flowID string, rule, service string) {
422-
requestErrors.Inc()
423-
log := p.log.Error().Err(err)
424-
if cfRay != "" {
425-
log = log.Str(LogFieldCFRay, cfRay)
426-
}
427-
if flowID != "" {
428-
log = log.Str(LogFieldFlowID, flowID).Int(management.EventTypeKey, int(management.TCP))
429-
} else {
430-
log = log.Int(management.EventTypeKey, int(management.HTTP))
431-
}
432-
if rule != "" {
433-
log = log.Str(LogFieldRule, rule)
434-
}
435-
if service != "" {
436-
log = log.Str(LogFieldOriginService, service)
437-
}
438-
log.Send()
439-
}
440-
441337
func getDestFromRule(rule *ingress.Rule, req *http.Request) (string, error) {
442338
switch rule.Service.String() {
443339
case ingress.ServiceBastion:

0 commit comments

Comments
 (0)