Skip to content

Commit d4a3ad1

Browse files
committed
happy
1 parent 30e7917 commit d4a3ad1

File tree

3 files changed

+78
-104
lines changed

3 files changed

+78
-104
lines changed

pkg/tracer/base_tracer.go

Lines changed: 24 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/JudgmentLabs/judgeval-go/pkg/logger"
1414
"github.com/JudgmentLabs/judgeval-go/pkg/scorers"
1515
"github.com/JudgmentLabs/judgeval-go/pkg/tracer/exporters"
16-
"go.opentelemetry.io/otel"
1716
"go.opentelemetry.io/otel/attribute"
1817
sdktrace "go.opentelemetry.io/otel/sdk/trace"
1918
"go.opentelemetry.io/otel/trace"
@@ -61,91 +60,39 @@ func WithEnableEvaluation(enableEvaluation bool) TracerConfigurationOptions {
6160
}
6261
}
6362

64-
func NewTracerConfiguration(options ...TracerConfigurationOptions) TracerConfiguration {
65-
config := &TracerConfiguration{
66-
APIURL: env.JudgmentAPIURL,
67-
APIKey: env.JudgmentAPIKey,
68-
OrganizationID: env.JudgmentOrgID,
69-
EnableEvaluation: true,
70-
}
71-
72-
for _, option := range options {
73-
option(config)
74-
}
75-
76-
return *config
77-
}
78-
7963
type ISerializer interface {
8064
Serialize(obj interface{}) string
8165
}
8266

83-
type BaseTracer struct {
67+
type baseTracer struct {
8468
configuration TracerConfiguration
8569
apiClient *api.Client
8670
serializer ISerializer
8771
projectID string
8872
tracer trace.Tracer
8973
}
9074

91-
func NewBaseTracer(config TracerConfiguration, serializer ISerializer, initialize bool) *BaseTracer {
92-
if config.APIURL == "" {
93-
panic("Configuration APIURL cannot be empty")
94-
}
95-
if serializer == nil {
96-
panic("Serializer cannot be nil")
97-
}
98-
99-
apiClient := api.NewClient(config.APIURL, config.APIKey, config.OrganizationID)
100-
projectID := resolveProjectID(apiClient, config.ProjectName)
101-
102-
if projectID == "" {
103-
logger.Error("Failed to resolve project %s, please create it first at https://app.judgmentlabs.ai/org/%s/projects. Skipping Judgment export.",
104-
config.ProjectName, config.OrganizationID)
105-
}
106-
107-
tracer := otel.Tracer(TracerName)
108-
109-
bt := &BaseTracer{
110-
configuration: config,
111-
apiClient: apiClient,
112-
serializer: serializer,
113-
projectID: projectID,
114-
tracer: tracer,
115-
}
116-
117-
if initialize {
118-
bt.Initialize()
119-
}
120-
121-
return bt
122-
}
123-
124-
func (bt *BaseTracer) Initialize() {
125-
126-
}
127-
128-
func (bt *BaseTracer) GetSpanExporter() sdktrace.SpanExporter {
75+
func (bt *baseTracer) GetSpanExporter() sdktrace.SpanExporter {
12976
if bt.projectID == "" {
13077
logger.Error("Project not resolved; cannot create exporter, returning NoOpSpanExporter")
13178
return exporters.NewNoOpSpanExporter()
13279
}
13380
return bt.createJudgmentSpanExporter(bt.projectID)
13481
}
13582

136-
func (bt *BaseTracer) SetSpanKind(span trace.Span, kind string) {
83+
func (bt *baseTracer) SetSpanKind(span trace.Span, kind string) {
13784
if span.IsRecording() && kind != "" {
13885
span.SetAttributes(attribute.String(AttributeKeys.JudgmentSpanKind, kind))
13986
}
14087
}
14188

142-
func (bt *BaseTracer) SetAttribute(span trace.Span, key string, value interface{}) {
89+
func (bt *baseTracer) SetAttribute(span trace.Span, key string, value interface{}) {
14390
if span.IsRecording() {
14491
span.SetAttributes(attribute.String(key, bt.serializer.Serialize(value)))
14592
}
14693
}
14794

148-
func (bt *BaseTracer) AsyncEvaluate(ctx context.Context, scorer scorers.BaseScorer, example *data.Example, model string) {
95+
func (bt *baseTracer) AsyncEvaluate(ctx context.Context, scorer scorers.BaseScorer, example *data.Example, model string) {
14996
if !bt.configuration.EnableEvaluation {
15097
return
15198
}
@@ -169,7 +116,7 @@ func (bt *BaseTracer) AsyncEvaluate(ctx context.Context, scorer scorers.BaseScor
169116
bt.enqueueEvaluation(evaluationRun)
170117
}
171118

172-
func (bt *BaseTracer) AsyncTraceEvaluate(ctx context.Context, scorer scorers.BaseScorer, model string) {
119+
func (bt *baseTracer) AsyncTraceEvaluate(ctx context.Context, scorer scorers.BaseScorer, model string) {
173120
if !bt.configuration.EnableEvaluation {
174121
return
175122
}
@@ -192,7 +139,7 @@ func (bt *BaseTracer) AsyncTraceEvaluate(ctx context.Context, scorer scorers.Bas
192139
span.SetAttributes(attribute.String(AttributeKeys.PendingTraceEval, traceEvalJSON))
193140
}
194141

195-
func (bt *BaseTracer) SetAttributes(span trace.Span, attributes map[string]interface{}) {
142+
func (bt *baseTracer) SetAttributes(span trace.Span, attributes map[string]interface{}) {
196143
if attributes == nil {
197144
return
198145
}
@@ -206,70 +153,59 @@ func (bt *BaseTracer) SetAttributes(span trace.Span, attributes map[string]inter
206153
}
207154
}
208155

209-
func (bt *BaseTracer) SetLLMSpan(span trace.Span) {
156+
func (bt *baseTracer) SetLLMSpan(span trace.Span) {
210157
bt.SetSpanKind(span, "llm")
211158
}
212159

213-
func (bt *BaseTracer) SetToolSpan(span trace.Span) {
160+
func (bt *baseTracer) SetToolSpan(span trace.Span) {
214161
bt.SetSpanKind(span, "tool")
215162
}
216163

217-
func (bt *BaseTracer) SetGeneralSpan(span trace.Span) {
164+
func (bt *baseTracer) SetGeneralSpan(span trace.Span) {
218165
bt.SetSpanKind(span, "span")
219166
}
220167

221-
func (bt *BaseTracer) SetInput(span trace.Span, input interface{}) {
168+
func (bt *baseTracer) SetInput(span trace.Span, input interface{}) {
222169
bt.SetAttribute(span, AttributeKeys.JudgmentInput, input)
223170
}
224171

225-
func (bt *BaseTracer) SetOutput(span trace.Span, output interface{}) {
172+
func (bt *baseTracer) SetOutput(span trace.Span, output interface{}) {
226173
bt.SetAttribute(span, AttributeKeys.JudgmentOutput, output)
227174
}
228175

229-
func (bt *BaseTracer) GetTracer() trace.Tracer {
176+
func (bt *baseTracer) GetTracer() trace.Tracer {
230177
return bt.tracer
231178
}
232179

233-
func (bt *BaseTracer) Span(ctx context.Context, spanName string) (trace.Span, context.Context) {
180+
func (bt *baseTracer) Span(ctx context.Context, spanName string) (trace.Span, context.Context) {
234181
spanCtx, span := bt.tracer.Start(ctx, spanName)
235182

236183
spanCtx = trace.ContextWithSpan(spanCtx, span)
237184
return span, spanCtx
238185
}
239186

240-
func resolveProjectID(apiClient *api.Client, projectName string) string {
241-
request := &models.ResolveProjectNameRequest{
242-
ProjectName: projectName,
243-
}
244-
245-
response, err := apiClient.ProjectsResolve(request)
246-
if err != nil {
247-
return ""
248-
}
249-
250-
if response.ProjectId != "" {
251-
return response.ProjectId
252-
}
253-
return ""
254-
}
255-
256-
func (bt *BaseTracer) createJudgmentSpanExporter(projectID string) sdktrace.SpanExporter {
187+
func (bt *baseTracer) createJudgmentSpanExporter(projectID string) sdktrace.SpanExporter {
257188

258189
endpoint := bt.configuration.APIURL
259190
if endpoint[len(endpoint)-1] != '/' {
260191
endpoint += "/"
261192
}
262193
endpoint += "otel/v1/traces"
263194

264-
return exporters.NewJudgmentSpanExporterBuilder().
195+
exporter, err := exporters.NewJudgmentSpanExporterBuilder().
265196
Endpoint(endpoint).
266197
APIKey(bt.configuration.APIKey).
267198
OrganizationID(bt.configuration.OrganizationID).
268199
ProjectID(projectID).
269200
Build()
201+
if err != nil {
202+
logger.Error("Failed to create Judgment span exporter: %v", err)
203+
return exporters.NewNoOpSpanExporter()
204+
}
205+
return exporter
270206
}
271207

272-
func (bt *BaseTracer) createEvaluationRun(scorer scorers.BaseScorer, example *data.Example, model, traceID, spanID string) *data.ExampleEvaluationRun {
208+
func (bt *baseTracer) createEvaluationRun(scorer scorers.BaseScorer, example *data.Example, model, traceID, spanID string) *data.ExampleEvaluationRun {
273209
runID := fmt.Sprintf("async_evaluate_%s", spanID)
274210
if spanID == "" {
275211
runID = fmt.Sprintf("async_evaluate_%d", time.Now().UnixMilli())
@@ -292,7 +228,7 @@ func (bt *BaseTracer) createEvaluationRun(scorer scorers.BaseScorer, example *da
292228
)
293229
}
294230

295-
func (bt *BaseTracer) createTraceEvaluationRun(scorer scorers.BaseScorer, model, traceID, spanID string) *data.TraceEvaluationRun {
231+
func (bt *baseTracer) createTraceEvaluationRun(scorer scorers.BaseScorer, model, traceID, spanID string) *data.TraceEvaluationRun {
296232
evalName := fmt.Sprintf("async_trace_evaluate_%s", spanID)
297233
if spanID == "" {
298234
evalName = fmt.Sprintf("async_trace_evaluate_%d", time.Now().UnixMilli())
@@ -313,7 +249,7 @@ func (bt *BaseTracer) createTraceEvaluationRun(scorer scorers.BaseScorer, model,
313249
})
314250
}
315251

316-
func (bt *BaseTracer) enqueueEvaluation(evaluationRun *data.ExampleEvaluationRun) {
252+
func (bt *baseTracer) enqueueEvaluation(evaluationRun *data.ExampleEvaluationRun) {
317253
_, err := bt.apiClient.AddToRunEvalQueue(evaluationRun.ExampleEvaluationRun)
318254
if err != nil {
319255
logger.Error("Failed to enqueue evaluation run: %v", err)

pkg/tracer/exporters/judgment_span_exporter.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package exporters
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"time"
78

@@ -49,19 +50,18 @@ func (b *JudgmentSpanExporterBuilder) ProjectID(projectID string) *JudgmentSpanE
4950
return b
5051
}
5152

52-
func (b *JudgmentSpanExporterBuilder) Build() *JudgmentSpanExporter {
53-
53+
func (b *JudgmentSpanExporterBuilder) Build() (*JudgmentSpanExporter, error) {
5454
if b.endpoint == "" {
55-
panic("endpoint is required")
55+
return nil, fmt.Errorf("endpoint is required")
5656
}
5757
if b.apiKey == "" {
58-
panic("apiKey is required")
58+
return nil, fmt.Errorf("apiKey is required")
5959
}
6060
if b.orgID == "" {
61-
panic("organizationId is required")
61+
return nil, fmt.Errorf("organizationId is required")
6262
}
6363
if b.projectID == "" {
64-
panic("projectId is required")
64+
return nil, fmt.Errorf("projectId is required")
6565
}
6666

6767
client := &http.Client{
@@ -79,7 +79,7 @@ func (b *JudgmentSpanExporterBuilder) Build() *JudgmentSpanExporter {
7979
otlptracehttp.WithHTTPClient(client),
8080
)
8181
if err != nil {
82-
panic("Failed to create OTLP HTTP exporter: " + err.Error())
82+
return nil, fmt.Errorf("failed to create OTLP HTTP exporter: %w", err)
8383
}
8484

8585
return &JudgmentSpanExporter{
@@ -88,7 +88,7 @@ func (b *JudgmentSpanExporterBuilder) Build() *JudgmentSpanExporter {
8888
apiKey: b.apiKey,
8989
orgID: b.orgID,
9090
projectID: b.projectID,
91-
}
91+
}, nil
9292
}
9393

9494
func (j *JudgmentSpanExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {

pkg/tracer/tracer.go

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package tracer
22

33
import (
44
"context"
5+
"fmt"
56

7+
"github.com/JudgmentLabs/judgeval-go/pkg/internal/api"
8+
"github.com/JudgmentLabs/judgeval-go/pkg/internal/api/models"
69
"github.com/JudgmentLabs/judgeval-go/pkg/logger"
710
"github.com/JudgmentLabs/judgeval-go/pkg/version"
811
"go.opentelemetry.io/otel"
@@ -16,7 +19,7 @@ const (
1619
)
1720

1821
type Tracer struct {
19-
*BaseTracer
22+
*baseTracer
2023
tracerProvider *sdktrace.TracerProvider
2124
}
2225

@@ -46,7 +49,7 @@ func WithInitialize(initialize bool) TracerOptions {
4649
}
4750
}
4851

49-
func NewTracer(options ...TracerOptions) *Tracer {
52+
func NewTracer(options ...TracerOptions) (*Tracer, error) {
5053
config := &TracerConfig{
5154
Serializer: NewJSONSerializer(),
5255
Initialize: true,
@@ -57,20 +60,39 @@ func NewTracer(options ...TracerOptions) *Tracer {
5760
}
5861

5962
if config.Configuration.APIURL == "" {
60-
panic("Configuration is required")
63+
return nil, fmt.Errorf("configuration is required")
64+
}
65+
if config.Serializer == nil {
66+
return nil, fmt.Errorf("serializer cannot be nil")
67+
}
68+
69+
apiClient := api.NewClient(config.Configuration.APIURL, config.Configuration.APIKey, config.Configuration.OrganizationID)
70+
projectID := resolveProjectID(apiClient, config.Configuration.ProjectName)
71+
72+
if projectID == "" {
73+
logger.Error("Failed to resolve project %s, please create it first at https://app.judgmentlabs.ai/org/%s/projects. Skipping Judgment export.",
74+
config.Configuration.ProjectName, config.Configuration.OrganizationID)
6175
}
6276

63-
baseTracer := NewBaseTracer(config.Configuration, config.Serializer, false)
77+
tracer := otel.Tracer(TracerName)
6478

65-
tracer := &Tracer{
66-
BaseTracer: baseTracer,
79+
baseTracer := &baseTracer{
80+
configuration: config.Configuration,
81+
apiClient: apiClient,
82+
serializer: config.Serializer,
83+
projectID: projectID,
84+
tracer: tracer,
85+
}
86+
87+
tracerInstance := &Tracer{
88+
baseTracer: baseTracer,
6789
}
6890

6991
if config.Initialize {
70-
tracer.Initialize()
92+
tracerInstance.Initialize()
7193
}
7294

73-
return tracer
95+
return tracerInstance, nil
7496
}
7597

7698
func (t *Tracer) Initialize() {
@@ -114,3 +136,19 @@ func (t *Tracer) Flush(ctx context.Context) error {
114136
func (t *Tracer) GetTracerProvider() *sdktrace.TracerProvider {
115137
return t.tracerProvider
116138
}
139+
140+
func resolveProjectID(apiClient *api.Client, projectName string) string {
141+
request := &models.ResolveProjectNameRequest{
142+
ProjectName: projectName,
143+
}
144+
145+
response, err := apiClient.ProjectsResolve(request)
146+
if err != nil {
147+
return ""
148+
}
149+
150+
if response.ProjectId != "" {
151+
return response.ProjectId
152+
}
153+
return ""
154+
}

0 commit comments

Comments
 (0)