<commit_before>import { randomBytes } from 'crypto'
import fetch from 'node-fetch'
import * as Log from '../../../build/output/log'

let traceId = process.env.TRACE_ID

const localEndpoint = {
  serviceName: 'nextjs',
  ipv4: '127.0.0.1',
  port: 9411,
}
const zipkinUrl = `http://${localEndpoint.ipv4}:${localEndpoint.port}`
const zipkinAPI = `${zipkinUrl}/api/v2/spans`

const reportToLocalHost = (
  name: string,
  duration: number,
  timestamp: number,
  id: string,
  parentId?: string,
  attrs?: Object
) => {
  if (!traceId) {
    traceId = process.env.TRACE_ID = randomBytes(8).toString('hex')
    Log.info(
      `Zipkin trace will be available on ${zipkinUrl}/zipkin/traces/${traceId}`
    )
  }
  const body = [
    {
      traceId,
      parentId,
      name,
      id,
      timestamp,
      duration,
      localEndpoint,
      tags: attrs,
    },
  ]

  // We intentionally do not block on I/O here.
  fetch(zipkinAPI, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  }).catch(console.log)
}

export default reportToLocalHost<commit_msg>Add batching to zipkin reporter (#27082)<commit_after>import retry from 'next/dist/compiled/async-retry'
import { randomBytes } from 'crypto'
import fetch from 'node-fetch'
import * as Log from '../../../build/output/log'

let traceId = process.env.TRACE_ID
let batch: ReturnType<typeof batcher> | undefined

const localEndpoint = {
  serviceName: 'nextjs',
  ipv4: '127.0.0.1',
  port: 9411,
}
const zipkinUrl = `http://${localEndpoint.ipv4}:${localEndpoint.port}`
const zipkinAPI = `${zipkinUrl}/api/v2/spans`

type Event = {
  traceId: string
  parentId?: string
  name: string
  id: string
  timestamp: number
  duration: number
  localEndpoint: typeof localEndpoint
  tags?: Object
}

// Batch events as zipkin allows for multiple events to be sent in one go
function batcher(reportEvents: (evts: Event[]) => void) {
  const events: Event[] = []
  let timeout: ReturnType<typeof setTimeout> | undefined
  return (event: Event) => {
    events.push(event)
    // setTimeout is used instead of setInterval to ensure events sending does not block exiting the program
    if (!timeout) {
      timeout = setTimeout(() => {
        reportEvents(events.slice())
        events.length = 0
        timeout = undefined
      }, 1500)
    }
  }
}

const reportToLocalHost = (
  name: string,
  duration: number,
  timestamp: number,
  id: string,
  parentId?: string,
  attrs?: Object
) => {
  if (!traceId) {
    traceId = process.env.TRACE_ID = randomBytes(8).toString('hex')
    Log.info(
      `Zipkin trace will be available on ${zipkinUrl}/zipkin/traces/${traceId}`
    )
  }

  if (!batch) {
    batch = batcher((events) => {
      // Ensure ECONNRESET error is retried 3 times before erroring out
      retry(
        () =>
          // Send events to zipkin
          fetch(zipkinAPI, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(events),
          }),
        { minTimeout: 500, retries: 3, factor: 1 }
      ).catch(console.log)
    })
  }

  batch({
    traceId,
    parentId,
    name,
    id,
    timestamp,
    duration,
    localEndpoint,
    tags: attrs,
  })
}

export default reportToLocalHost
{'fraction_non_alphanumeric': 0.13367687177932708, 'fraction_numerical': 0.01333737496210973, 'mean_word_length': 2.8551401869158877, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5101057', 'n_tokens_mistral': 1079, 'n_tokens_neox': 1065, 'n_words': 281}