github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/pkg/integrations/otsdb/writer/putmetrics.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 writer
    18  
    19  import (
    20  	"encoding/json"
    21  
    22  	jp "github.com/buger/jsonparser"
    23  	. "github.com/siglens/siglens/pkg/segment/utils"
    24  	"github.com/siglens/siglens/pkg/segment/writer"
    25  	"github.com/siglens/siglens/pkg/usageStats"
    26  	"github.com/siglens/siglens/pkg/utils"
    27  	log "github.com/sirupsen/logrus"
    28  	"github.com/valyala/fasthttp"
    29  )
    30  
    31  const METRICS_INDEXNAME = "metricsdb"
    32  
    33  type OtsdbPutResp struct {
    34  	Failed  uint64   `json:"failed"`
    35  	Success uint64   `json:"success"`
    36  	Errors  []string `json:"errors,omitempty"`
    37  }
    38  
    39  func PutMetrics(ctx *fasthttp.RequestCtx, myid uint64) {
    40  	var processedCount uint64
    41  	var failedCount uint64
    42  	var err error
    43  
    44  	cType := string(ctx.Request.Header.ContentType())
    45  	switch cType {
    46  	case "gzip":
    47  		var body []byte
    48  		body, err = ctx.Request.BodyGunzip()
    49  		if err != nil {
    50  			log.Errorf("PutMetrics: error unzipping body! %v", err)
    51  			break
    52  		}
    53  		processedCount, failedCount, err = HandlePutMetrics(body, myid)
    54  	case "application/json", "json":
    55  		body := ctx.PostBody()
    56  		processedCount, failedCount, err = HandlePutMetrics(body, myid)
    57  	default:
    58  		log.Errorf("PutMetrics: unknown content type [%s]! %v", cType, err)
    59  		writeOtsdbResponse(ctx, processedCount, failedCount, "unknown content type", fasthttp.StatusBadRequest)
    60  		return
    61  	}
    62  	if err != nil {
    63  		writeOtsdbResponse(ctx, processedCount, failedCount, err.Error(), fasthttp.StatusBadRequest)
    64  	}
    65  	writeOtsdbResponse(ctx, processedCount, failedCount, "", fasthttp.StatusOK)
    66  }
    67  
    68  func HandlePutMetrics(fullData []byte, myid uint64) (uint64, uint64, error) {
    69  
    70  	//to have a check if there are any errors in the request
    71  	//to check for status : 200 or 400
    72  	//to check if json is greater than MAX_RECORD_SIZE
    73  	var inCount uint64 = 0
    74  	var successCount uint64 = 0
    75  	var failedCount uint64 = 0
    76  
    77  	bytesReceived := uint64(len(fullData))
    78  	_, err := jp.ArrayEach(fullData, func(value []byte, valueType jp.ValueType, offset int, err error) {
    79  		inCount++
    80  		switch valueType {
    81  		case jp.Object:
    82  			mErr := writer.AddTimeSeriesEntryToInMemBuf(value, SIGNAL_METRICS_OTSDB, myid)
    83  			if mErr != nil {
    84  				log.Errorf("HandlePutMetrics: failed to add time series entry %+v", mErr)
    85  				failedCount++
    86  			} else {
    87  				successCount++
    88  			}
    89  		default:
    90  			log.Errorf("HandlePutMetrics: Unknown type %+v for a read put metrics reqeust", valueType)
    91  			failedCount++
    92  		}
    93  	})
    94  	if err != nil {
    95  		mErr := writer.AddTimeSeriesEntryToInMemBuf(fullData, SIGNAL_METRICS_OTSDB, myid)
    96  		if mErr != nil {
    97  			log.Errorf("HandlePutMetrics: failed to add time series entry %+v", mErr)
    98  			failedCount++
    99  		} else {
   100  			successCount++
   101  		}
   102  		return 0, 0, err
   103  	}
   104  	usageStats.UpdateMetricsStats(bytesReceived, successCount, myid)
   105  	return successCount, failedCount, nil
   106  
   107  }
   108  
   109  func writeOtsdbResponse(ctx *fasthttp.RequestCtx, processedCount uint64, failedCount uint64, err string, code int) {
   110  
   111  	resp := OtsdbPutResp{Success: processedCount, Failed: failedCount}
   112  	if err != "" {
   113  		resp.Errors = []string{err}
   114  	}
   115  
   116  	ctx.SetStatusCode(code)
   117  	ctx.SetContentType(utils.ContentJson)
   118  	jval, mErr := json.Marshal(resp)
   119  	if mErr != nil {
   120  		log.Errorf("writeInfluxResponse: failed to marshal resp %+v", mErr)
   121  	}
   122  	_, mErr = ctx.Write(jval)
   123  
   124  	if mErr != nil {
   125  		log.Errorf("writeInfluxResponse: failed to write jval to http request %+v", mErr)
   126  	}
   127  }