@@ -52,7 +52,9 @@ func NewSink(conf SinkConfig) (*Sink, error) {
5252 if conf .QueueSize == 0 {
5353 conf .QueueSize = DefaultQueueSize
5454 }
55-
55+ if conf .Username != "" && (conf .AuthType != AuthTypeBasic && conf .AuthType != AuthTypeDigest ) {
56+ conf .AuthType = AuthTypeBasic
57+ }
5658 url , err := url .Parse (conf .Address )
5759 if err != nil {
5860 return nil , fmt .Errorf ("invalid sink address: %w" , err )
@@ -109,7 +111,8 @@ outer:
109111 default :
110112 // drop front of queue
111113 <- sink .queue
112- log .Info ().Str ("sink" , sink .url .Host ).Msg ("queue overflow" )
114+ sink .metrics .totalNumDropped .Inc ()
115+ log .Warn ().Str ("sink" , sink .url .Host ).Msg ("queue full, dropping request" )
113116 continue
114117 }
115118 }
@@ -126,71 +129,113 @@ func (sink *Sink) work(ctx context.Context, client *http.Client) {
126129 case <- ctx .Done ():
127130 return
128131 case entry := <- sink .queue :
129- retry:
130- for {
131- select {
132- case <- entry .Request .Context ().Done ():
133- log .Warn ().Str ("sink" , sink .url .Host ).Msg ("discarding timed out request" )
134- break retry
135- default :
136- }
137- res , err := client .Do (entry .Request )
138- if err != nil {
139- log .Error ().Str ("sink" , sink .url .Host ).Err (err ).Msg ("sink error" )
140- break retry
141- }
142- res .Body .Close ()
143- if res .StatusCode < 200 || res .StatusCode > 299 {
144- log .Warn ().
145- Str ("sink" , sink .url .Host ).
146- Str ("method" , entry .Request .Method ).
147- Str ("path" , entry .Request .URL .Path ).
148- Str ("status" , res .Status ).
149- Msg ("upload failed" )
150-
151- // get new body
152- entry .Request .Body , _ = entry .Request .GetBody ()
153-
154- // retry if we have space in queue
155- time .Sleep (time .Second )
156- continue
157- }
158- // success
159- sink .metrics .totalNumUploaded .Inc ()
160- sink .metrics .totalUploadDelay .Add (time .Since (entry .QueuedAt ).Seconds ())
161- break
132+ sink .upload (ctx , entry , client )
133+ }
134+ }
135+ }
136+
137+ func (sink * Sink ) upload (ctx context.Context , entry SinkEntry , client * http.Client ) {
138+ for {
139+ if entry .Deadline .Before (time .Now ()) {
140+ log .Warn ().Str ("sink" , sink .url .Host ).Msg ("discarding timed out request" )
141+ sink .metrics .totalNumDropped .Inc ()
142+ return
143+ }
144+ queuedFor := time .Since (entry .QueuedAt )
145+ uploadStart := time .Now ()
146+ res , err := client .Do (entry .Request )
147+ if err != nil {
148+ log .Error ().Str ("sink" , sink .url .Host ).Err (err ).Msg ("sink error" )
149+ sink .metrics .totalNumDropped .Inc ()
150+ return
151+ }
152+ _ = res .Body .Close ()
153+ if res .StatusCode < 200 || res .StatusCode > 299 {
154+ log .Warn ().
155+ Str ("sink" , sink .url .Host ).
156+ Str ("method" , entry .Request .Method ).
157+ Str ("path" , entry .Request .URL .Path ).
158+ Str ("status" , res .Status ).
159+ Msg ("upload failed" )
160+ sink .metrics .totalTransientErrors .Inc ()
161+
162+ // get new body
163+ entry .Request .Body , _ = entry .Request .GetBody ()
164+
165+ // drop if queue is almost full
166+ if len (sink .queue ) > cap (sink .queue )- 2 {
167+ log .Error ().Str ("sink" , sink .url .Host ).Err (err ).Msg ("queue full, dropping request" )
168+ sink .metrics .totalNumDropped .Inc ()
169+ return
170+ }
171+ // retry after short delay
172+ select {
173+ case <- ctx .Done ():
174+ return
175+ case <- time .After (time .Second ):
162176 }
177+ continue
163178 }
179+ // success
180+ sink .metrics .totalNumUploaded .Inc ()
181+ sink .metrics .totalQueueDelay .Add (queuedFor .Seconds ())
182+ sink .metrics .totalUploadDuration .Add (time .Since (uploadStart ).Seconds ())
183+ sink .metrics .totalBytesUploaded .Add (float64 (entry .Request .ContentLength ))
184+ return
164185 }
165186}
166187
167188type SinkMetrics struct {
168- reg prometheus.Registerer
169- totalNumUploaded prometheus.Counter
170- totalUploadDelay prometheus.Counter
171- queueLength prometheus.Gauge
189+ reg prometheus.Registerer
190+ totalNumUploaded prometheus.Counter
191+ totalNumDropped prometheus.Counter
192+ totalQueueDelay prometheus.Counter
193+ totalUploadDuration prometheus.Counter
194+ totalBytesUploaded prometheus.Counter
195+ totalTransientErrors prometheus.Counter
172196}
173197
174198func NewSinkMetrics (reg prometheus.Registerer , cfg SinkConfig ) * SinkMetrics {
175199 return & SinkMetrics {
176200 reg : reg ,
177201 totalNumUploaded : promauto .With (reg ).NewCounter (prometheus.CounterOpts {
178202 Name : "upload_proxy_sink_uploaded_total" ,
179- Help : "Total number of uploaded requests" ,
203+ Help : "Number of uploaded requests" ,
204+ ConstLabels : prometheus.Labels {
205+ "sink" : cfg .Address ,
206+ },
207+ }),
208+ totalNumDropped : promauto .With (reg ).NewCounter (prometheus.CounterOpts {
209+ Name : "upload_proxy_sink_dropped_total" ,
210+ Help : "Number of dropped requests due to error, timeout or full queue" ,
211+ ConstLabels : prometheus.Labels {
212+ "sink" : cfg .Address ,
213+ },
214+ }),
215+ totalQueueDelay : promauto .With (reg ).NewCounter (prometheus.CounterOpts {
216+ Name : "upload_proxy_sink_queue_delay_total" ,
217+ Help : "Queue delay in seconds" ,
218+ ConstLabels : prometheus.Labels {
219+ "sink" : cfg .Address ,
220+ },
221+ }),
222+ totalUploadDuration : promauto .With (reg ).NewCounter (prometheus.CounterOpts {
223+ Name : "upload_proxy_sink_upload_duration_total" ,
224+ Help : "Upload duration in seconds" ,
180225 ConstLabels : prometheus.Labels {
181226 "sink" : cfg .Address ,
182227 },
183228 }),
184- totalUploadDelay : promauto .With (reg ).NewCounter (prometheus.CounterOpts {
185- Name : "upload_proxy_sink_upload_delay_total " ,
186- Help : "Total upload delay in seconds " ,
229+ totalBytesUploaded : promauto .With (reg ).NewCounter (prometheus.CounterOpts {
230+ Name : "upload_proxy_sink_bytes_uploaded_total " ,
231+ Help : "Number of bytes uploaded " ,
187232 ConstLabels : prometheus.Labels {
188233 "sink" : cfg .Address ,
189234 },
190235 }),
191- queueLength : promauto .With (reg ).NewGauge (prometheus.GaugeOpts {
192- Name : "upload_proxy_sink_queue_length " ,
193- Help : "Number of entries in the sink queue " ,
236+ totalTransientErrors : promauto .With (reg ).NewCounter (prometheus.CounterOpts {
237+ Name : "upload_proxy_sink_transient_errors_total " ,
238+ Help : "Number of transient errors " ,
194239 ConstLabels : prometheus.Labels {
195240 "sink" : cfg .Address ,
196241 },
@@ -200,6 +245,9 @@ func NewSinkMetrics(reg prometheus.Registerer, cfg SinkConfig) *SinkMetrics {
200245
201246func (m * SinkMetrics ) deregister () {
202247 m .reg .Unregister (m .totalNumUploaded )
203- m .reg .Unregister (m .totalUploadDelay )
204- m .reg .Unregister (m .queueLength )
248+ m .reg .Unregister (m .totalNumDropped )
249+ m .reg .Unregister (m .totalQueueDelay )
250+ m .reg .Unregister (m .totalUploadDuration )
251+ m .reg .Unregister (m .totalBytesUploaded )
252+ m .reg .Unregister (m .totalTransientErrors )
205253}
0 commit comments