mirror of
https://github.com/hanzoai/o11y.git
synced 2026-11-03 02:04:48 +00:00
* debrand: signoz/SigNoz/SIGNOZ -> o11y/O11y/O11Y across the tree Rename all SigNoz *branding* to O11y in file contents, file/dir names, package names, env vars, config keys, comments, docs, SDK code, and the ClickHouse schema identifiers the querier reads. Collector dependency: - Repoint github.com/hanzoai/signoz-otel-collector -> github.com/hanzoai/otel-collector and bump v0.144.6 -> v0.144.7 (go.mod + go.sum reconciled via go mod tidy). Internal package paths also debranded upstream: signozschemamigrator -> o11yschemamigrator, signozlogspipelineprocessor -> o11ylogspipelineprocessor. - Fix: v0.144.7 dropped otelconst.DistributedFieldKeysTable from the collector's public constants; pin FieldKeysTable = "distributed_field_keys" locally in pkg/telemetrymetadata/tables.go. Package/dir renames (package decl + all importers): pkg/apiserver/signozapiserver -> o11yapiserver, plus signozalertmanager, signozauthzapi, signozglobal, signozquerier, signozruler, and pkg/signoz -> pkg/o11y. Schema (read plane): signoz_traces/metrics/logs/metadata/analytics/meter and signoz_index_v3/index_v2/error_index_v2/spans (+ distributed_*) -> o11y_*. Data-preserving cutover migration added: deploy/clickhouse/migrations/0001_rename_signoz_to_o11y.sql (metadata-only RENAME DATABASE/TABLE, no drop/recreate). Preserved (attribution / external / wire contracts): - LICENSE + NOTICE verbatim (incl. "software from SigNoz", "Copyright ... SigNoz Inc."). - Upstream github.com/SigNoz/* repo URLs + @SigNoz/* CODEOWNERS teams. - Billing resource-attribute regex "signoz.workspace.*" (external wire contract). go build ./pkg/... ./cmd/... = 0; gofmt clean; renamed+schema pkg tests pass. * o11y: bump collector to v0.144.8 (o11y_* physical schema writer) + lockstep deploy plan Collector v0.144.8's schema-migrator + exporters now CREATE/WRITE the same o11y_* physical databases/tables the querier reads and the RENAME migration (0001_rename_signoz_to_o11y.sql) targets. Cross-checked byte-identical: writer DB set == migration target DB set (6); writer prefixed-table set == migration target table set (8); o11y querier reads and cloud reads are subsets of that set. Zero table-name mismatches between writer, readers, and migration. Collector go.mod unchanged between v0.144.7 and v0.144.8 (identical go.mod hash) — pure source rename, no module-graph change. Adds deploy/clickhouse/DEPLOY_signoz_to_o11y_cutover.md: the lockstep order (collector v0.144.8 -> RENAME migration -> o11y+cloud readers) with a fresh/scratch-ClickHouse pre-flight (create via migrator, emit trace+metric, query back) and rollback. Ships together or telemetry blackholes. go build ./pkg/... ./cmd/community = 0.
224 lines
6.8 KiB
Go
224 lines
6.8 KiB
Go
package logparsingpipeline
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hanzoai/o11y/pkg/errors"
|
|
"github.com/hanzoai/o11y/pkg/query-service/model"
|
|
"github.com/hanzoai/o11y/pkg/types/pipelinetypes"
|
|
"github.com/hanzoai/otel-collector/pkg/collectorsimulator"
|
|
_ "github.com/hanzoai/otel-collector/pkg/parser/grok"
|
|
"github.com/hanzoai/otel-collector/processor/o11ylogspipelineprocessor"
|
|
"go.opentelemetry.io/collector/otelcol"
|
|
"go.opentelemetry.io/collector/pdata/pcommon"
|
|
"go.opentelemetry.io/collector/pdata/plog"
|
|
)
|
|
|
|
func SimulatePipelinesProcessing(ctx context.Context, pipelines []pipelinetypes.GettablePipeline, logs []model.O11yLog) (
|
|
[]model.O11yLog, []string, error) {
|
|
if len(pipelines) < 1 {
|
|
return logs, nil, nil
|
|
}
|
|
|
|
// Collector simulation does not guarantee that logs will come
|
|
// out in the same order as in the input.
|
|
//
|
|
// Add a temp attribute for sorting logs in simulation output
|
|
inputOrderAttribute := "__o11y_input_idx__"
|
|
for i := 0; i < len(logs); i++ {
|
|
if logs[i].Attributes_int64 == nil {
|
|
logs[i].Attributes_int64 = map[string]int64{}
|
|
}
|
|
logs[i].Attributes_int64[inputOrderAttribute] = int64(i)
|
|
}
|
|
simulatorInputPLogs := O11yLogsToPLogs(logs)
|
|
|
|
processorFactories, err := otelcol.MakeFactoryMap(o11ylogspipelineprocessor.NewFactory())
|
|
if err != nil {
|
|
return nil, nil, errors.WrapInternalf(err, CodeProcessorFactoryMapFailed, "could not construct processor factory map")
|
|
}
|
|
|
|
// Pipelines translate to logtransformprocessors in otel collector config.
|
|
// Each logtransformprocessor (stanza) does its own batching with a flush
|
|
// interval of 100ms. So e2e processing time for logs grows linearly with
|
|
// the number of logtransformprocessors involved.
|
|
// See defaultFlushInterval at https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/stanza/adapter/emitter.go
|
|
// TODO(Raj): Remove this after flushInterval is exposed in logtransformprocessor config
|
|
timeout := time.Millisecond * time.Duration(len(pipelines)*100+100)
|
|
|
|
configGenerator := func(baseConf []byte) ([]byte, error) {
|
|
updatedConf, err := GenerateCollectorConfigWithPipelines(baseConf, pipelines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return updatedConf, nil
|
|
}
|
|
|
|
outputPLogs, collectorErrs, simulationErr := collectorsimulator.SimulateLogsProcessing(
|
|
ctx,
|
|
processorFactories,
|
|
configGenerator,
|
|
simulatorInputPLogs,
|
|
timeout,
|
|
)
|
|
if simulationErr != nil {
|
|
if errors.Is(simulationErr, collectorsimulator.ErrInvalidConfig) {
|
|
return nil, nil, errors.WrapInvalidInputf(simulationErr, errors.CodeInvalidInput, "invalid config")
|
|
}
|
|
return nil, nil, errors.WrapInternalf(simulationErr, errors.CodeInternal, "could not simulate log pipelines processing")
|
|
}
|
|
|
|
outputO11yLogs := PLogsToO11yLogs(outputPLogs)
|
|
|
|
// Sort output logs by their order in the input and remove the temp ordering attribute
|
|
sort.Slice(outputO11yLogs, func(i, j int) bool {
|
|
iIdx := outputO11yLogs[i].Attributes_int64[inputOrderAttribute]
|
|
jIdx := outputO11yLogs[j].Attributes_int64[inputOrderAttribute]
|
|
return iIdx < jIdx
|
|
})
|
|
for _, sigLog := range outputO11yLogs {
|
|
delete(sigLog.Attributes_int64, inputOrderAttribute)
|
|
}
|
|
|
|
collectorWarnAndErrorLogs := []string{}
|
|
for _, log := range collectorErrs {
|
|
// if log is empty or log comes from featuregate.go, then remove it
|
|
if log == "" || strings.Contains(log, "featuregate.go") {
|
|
continue
|
|
}
|
|
collectorWarnAndErrorLogs = append(collectorWarnAndErrorLogs, log)
|
|
}
|
|
|
|
return outputO11yLogs, collectorWarnAndErrorLogs, nil
|
|
}
|
|
|
|
// plog doesn't contain an ID field.
|
|
// O11yLog.ID is stored as a log attribute in plogs for processing
|
|
// and gets hydrated back later.
|
|
const O11yLogIdAttr = "__o11y_log_id__"
|
|
|
|
func O11yLogsToPLogs(logs []model.O11yLog) []plog.Logs {
|
|
result := []plog.Logs{}
|
|
|
|
for _, log := range logs {
|
|
pl := plog.NewLogs()
|
|
rl := pl.ResourceLogs().AppendEmpty()
|
|
|
|
resourceAttribs := rl.Resource().Attributes()
|
|
for k, v := range log.Resources_string {
|
|
resourceAttribs.PutStr(k, v)
|
|
}
|
|
|
|
scopeLog := rl.ScopeLogs().AppendEmpty()
|
|
slRecord := scopeLog.LogRecords().AppendEmpty()
|
|
|
|
slRecord.SetTimestamp(pcommon.NewTimestampFromTime(
|
|
time.Unix(0, int64(log.Timestamp)),
|
|
))
|
|
|
|
var traceIdBuf [16]byte
|
|
copy(traceIdBuf[:], []byte(log.TraceID))
|
|
slRecord.SetTraceID(traceIdBuf)
|
|
|
|
var spanIdBuf [8]byte
|
|
copy(spanIdBuf[:], []byte(log.SpanID))
|
|
slRecord.SetSpanID(spanIdBuf)
|
|
|
|
slRecord.SetFlags(plog.LogRecordFlags(log.TraceFlags))
|
|
|
|
slRecord.SetSeverityText(log.SeverityText)
|
|
slRecord.SetSeverityNumber(plog.SeverityNumber(log.SeverityNumber))
|
|
|
|
slRecord.Body().FromRaw(log.Body)
|
|
|
|
slAttribs := slRecord.Attributes()
|
|
for k, v := range log.Attributes_int64 {
|
|
slAttribs.PutInt(k, v)
|
|
}
|
|
for k, v := range log.Attributes_float64 {
|
|
slAttribs.PutDouble(k, v)
|
|
}
|
|
for k, v := range log.Attributes_string {
|
|
slAttribs.PutStr(k, v)
|
|
}
|
|
slAttribs.PutStr(O11yLogIdAttr, log.ID)
|
|
|
|
result = append(result, pl)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func PLogsToO11yLogs(plogs []plog.Logs) []model.O11yLog {
|
|
result := []model.O11yLog{}
|
|
|
|
for _, pl := range plogs {
|
|
|
|
resourceLogsSlice := pl.ResourceLogs()
|
|
for i := 0; i < resourceLogsSlice.Len(); i++ {
|
|
rl := resourceLogsSlice.At(i)
|
|
|
|
scopeLogsSlice := rl.ScopeLogs()
|
|
for j := 0; j < scopeLogsSlice.Len(); j++ {
|
|
sl := scopeLogsSlice.At(j)
|
|
|
|
lrSlice := sl.LogRecords()
|
|
for k := 0; k < lrSlice.Len(); k++ {
|
|
lr := lrSlice.At(k)
|
|
|
|
// Recover ID for the log and remove temp attrib used for storing it
|
|
o11yLogId := ""
|
|
logIdVal, exists := lr.Attributes().Get(O11yLogIdAttr)
|
|
if exists {
|
|
o11yLogId = logIdVal.Str()
|
|
}
|
|
lr.Attributes().Remove(O11yLogIdAttr)
|
|
|
|
o11yLog := model.O11yLog{
|
|
Timestamp: uint64(lr.Timestamp()),
|
|
ID: o11yLogId,
|
|
TraceID: lr.TraceID().String(),
|
|
SpanID: lr.SpanID().String(),
|
|
TraceFlags: uint32(lr.Flags()),
|
|
SeverityText: lr.SeverityText(),
|
|
SeverityNumber: uint8(lr.SeverityNumber()),
|
|
Body: lr.Body().AsString(),
|
|
Resources_string: pMapToStrMap(rl.Resource().Attributes()),
|
|
Attributes_string: map[string]string{},
|
|
Attributes_int64: map[string]int64{},
|
|
Attributes_float64: map[string]float64{},
|
|
}
|
|
|
|
// Populate o11yLog.Attributes_...
|
|
lr.Attributes().Range(func(k string, v pcommon.Value) bool {
|
|
if v.Type() == pcommon.ValueTypeDouble {
|
|
o11yLog.Attributes_float64[k] = v.Double()
|
|
} else if v.Type() == pcommon.ValueTypeInt {
|
|
o11yLog.Attributes_int64[k] = v.Int()
|
|
} else {
|
|
o11yLog.Attributes_string[k] = v.AsString()
|
|
}
|
|
return true
|
|
})
|
|
|
|
result = append(result, o11yLog)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func pMapToStrMap(pMap pcommon.Map) map[string]string {
|
|
result := map[string]string{}
|
|
pMap.Range(func(k string, v pcommon.Value) bool {
|
|
result[k] = v.AsString()
|
|
return true
|
|
})
|
|
return result
|
|
}
|