88 "fmt"
99 "io"
1010 "net/http"
11+ "strconv"
1112 "time"
1213
1314 "github.com/ozontech/file.d/cfg"
@@ -37,7 +38,7 @@ type Plugin struct {
3738 controller pipeline.OutputPluginController
3839
3940 // plugin metrics
40- sendErrorMetric prometheus.Counter
41+ sendErrorMetric * prometheus.CounterVec
4142}
4243
4344// ! config-params
@@ -172,7 +173,11 @@ func (p *Plugin) Start(config pipeline.AnyConfig, params *pipeline.OutputPluginP
172173}
173174
174175func (p * Plugin ) registerMetrics (ctl * metric.Ctl ) {
175- p .sendErrorMetric = ctl .RegisterCounter ("output_splunk_send_error" , "Total splunk send errors" )
176+ p .sendErrorMetric = ctl .RegisterCounterVec (
177+ "output_splunk_send_error" ,
178+ "Total splunk send errors" ,
179+ "status_code" ,
180+ )
176181}
177182
178183func (p * Plugin ) Stop () {
@@ -209,10 +214,15 @@ func (p *Plugin) out(workerData *pipeline.WorkerData, batch *pipeline.Batch) err
209214
210215 p .logger .Debugf ("trying to send: %s" , outBuf )
211216
212- err := p .send (outBuf )
217+ code , err := p .send (outBuf )
213218 if err != nil {
214- p .sendErrorMetric .Inc ()
219+ p .sendErrorMetric .WithLabelValues ( strconv . Itoa ( code )). Inc ()
215220 p .logger .Errorf ("can't send data to splunk address=%s: %s" , p .config .Endpoint , err .Error ())
221+
222+ // skip retries for bad request
223+ if code == http .StatusBadRequest {
224+ return nil
225+ }
216226 } else {
217227 p .logger .Debugf ("successfully sent: %s" , outBuf )
218228 }
@@ -234,46 +244,46 @@ func (p *Plugin) newClient(timeout time.Duration) http.Client {
234244 }
235245}
236246
237- func (p * Plugin ) send (data []byte ) error {
247+ func (p * Plugin ) send (data []byte ) ( int , error ) {
238248 r := bytes .NewReader (data )
239249 // todo pass context from parent.
240250 req , err := http .NewRequestWithContext (context .Background (), http .MethodPost , p .config .Endpoint , r )
241251 if err != nil {
242- return fmt .Errorf ("can't create request: %w" , err )
252+ return 0 , fmt .Errorf ("can't create request: %w" , err )
243253 }
244254
245255 req .Header .Set ("Authorization" , "Splunk " + p .config .Token )
246256 resp , err := p .client .Do (req )
247257 if err != nil {
248- return fmt .Errorf ("can't send request: %w" , err )
258+ return 0 , fmt .Errorf ("can't send request: %w" , err )
249259 }
250260 defer func (Body io.ReadCloser ) {
251261 _ = Body .Close ()
252262 }(resp .Body )
253263
254- if resp .StatusCode != http .StatusOK {
255- return fmt .Errorf ("can't send request: %s" , resp .Status )
256- }
257-
258264 b , err := io .ReadAll (resp .Body )
259265 if err != nil {
260- return fmt .Errorf ("can't read response: %w" , err )
266+ return resp .StatusCode , fmt .Errorf ("can't read response: %w" , err )
267+ }
268+
269+ if resp .StatusCode != http .StatusOK {
270+ return resp .StatusCode , fmt .Errorf ("bad response: code=%s, body=%s" , resp .Status , b )
261271 }
262272
263273 root , err := insaneJSON .DecodeBytes (b )
264274 defer insaneJSON .Release (root )
265275 if err != nil {
266- return fmt .Errorf ("can't decode response: %w" , err )
276+ return resp . StatusCode , fmt .Errorf ("can't decode response: %w" , err )
267277 }
268278
269279 code := root .Dig ("code" )
270280 if code == nil {
271- return fmt .Errorf ("invalid response format, expecting json with 'code' field, got: %s" , string (b ))
281+ return resp . StatusCode , fmt .Errorf ("invalid response format, expecting json with 'code' field, got: %s" , string (b ))
272282 }
273283
274284 if code .AsInt () > 0 {
275- return fmt .Errorf ("error while sending to splunk: %s" , string (b ))
285+ return resp . StatusCode , fmt .Errorf ("error while sending to splunk: %s" , string (b ))
276286 }
277287
278- return nil
288+ return resp . StatusCode , nil
279289}
0 commit comments