func (ing *SpanIngestor) IngestSpan(span *common.Span) { ing.totalIngested++ // Make sure the span ID is valid. spanIdProblem := span.Id.FindProblem() if spanIdProblem != "" { // Can't print the invalid span ID because String() might fail. ing.lg.Warnf("Invalid span ID: %s\n", spanIdProblem) ing.serverDropped++ return } // Set the default tracer id, if needed. if span.TracerId == "" { span.TracerId = ing.defaultTrid } // Encode the span data. Doing the encoding here is better than doing it // in the shard goroutine, because we can achieve more parallelism. // There is one shard goroutine per shard, but potentially many more // ingestors per shard. err := ing.enc.Encode(span.SpanData) if err != nil { ing.lg.Warnf("Failed to encode span ID %s: %s\n", span.Id.String(), err.Error()) ing.serverDropped++ return } spanDataBytes := ing.spanDataBytes ing.spanDataBytes = make([]byte, 0, 1024) ing.enc.ResetBytes(&ing.spanDataBytes) // Determine which shard this span should go to. shardIdx := ing.store.getShardIndex(span.Id) batch := ing.batches[shardIdx] incomingLen := len(batch.incoming) if ing.lg.TraceEnabled() { ing.lg.Tracef("SpanIngestor#IngestSpan: spanId=%s, shardIdx=%d, "+ "incomingLen=%d, cap(batch.incoming)=%d\n", span.Id.String(), shardIdx, incomingLen, cap(batch.incoming)) } if incomingLen+1 == cap(batch.incoming) { if ing.lg.TraceEnabled() { ing.lg.Tracef("SpanIngestor#IngestSpan: flushing %d spans for "+ "shard %d\n", len(batch.incoming), shardIdx) } ing.store.WriteSpans(shardIdx, batch.incoming) batch.incoming = make([]*IncomingSpan, 1, WRITESPANS_BATCH_SIZE) incomingLen = 0 } else { batch.incoming = batch.incoming[0 : incomingLen+1] } batch.incoming[incomingLen] = &IncomingSpan{ Addr: ing.addr, Span: span, SpanDataBytes: spanDataBytes, } }
func (hand *writeSpansHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { setResponseHeaders(w.Header()) var dec *json.Decoder if hand.lg.TraceEnabled() { b, err := ioutil.ReadAll(req.Body) if err != nil { writeError(hand.lg, w, http.StatusBadRequest, fmt.Sprintf("Error reading span data: %s", err.Error())) return } hand.lg.Tracef("writeSpansHandler: read %s\n", string(b)) dec = json.NewDecoder(bytes.NewBuffer(b)) } else { dec = json.NewDecoder(req.Body) } spans := make([]*common.Span, 0, 32) defaultTrid := req.Header.Get("htrace-trid") for { var span common.Span err := dec.Decode(&span) if err != nil { if err != io.EOF { writeError(hand.lg, w, http.StatusBadRequest, fmt.Sprintf("Error parsing spans: %s", err.Error())) return } break } spanIdProblem := span.Id.FindProblem() if spanIdProblem != "" { writeError(hand.lg, w, http.StatusBadRequest, fmt.Sprintf("Invalid span ID: %s", spanIdProblem)) return } if span.TracerId == "" { span.TracerId = defaultTrid } spans = append(spans, &span) } hand.lg.Debugf("writeSpansHandler: received %d span(s). defaultTrid = %s\n", len(spans), defaultTrid) for spanIdx := range spans { if hand.lg.DebugEnabled() { hand.lg.Debugf("writing span %s\n", spans[spanIdx].ToJson()) } hand.store.WriteSpan(spans[spanIdx]) } }