228 lines
4.7 KiB
Go
228 lines
4.7 KiB
Go
package irontelemetry
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// JourneyManager manages journey context
|
|
type JourneyManager struct {
|
|
mu sync.RWMutex
|
|
current *JourneyContext
|
|
client *Client
|
|
}
|
|
|
|
// NewJourneyManager creates a new JourneyManager
|
|
func NewJourneyManager(client *Client) *JourneyManager {
|
|
return &JourneyManager{
|
|
client: client,
|
|
}
|
|
}
|
|
|
|
// StartJourney starts a new journey
|
|
func (jm *JourneyManager) StartJourney(name string) *Journey {
|
|
jm.mu.Lock()
|
|
defer jm.mu.Unlock()
|
|
|
|
ctx := &JourneyContext{
|
|
JourneyID: uuid.New().String(),
|
|
Name: name,
|
|
StartedAt: time.Now(),
|
|
Metadata: make(map[string]any),
|
|
}
|
|
jm.current = ctx
|
|
|
|
// Add breadcrumb for journey start
|
|
if jm.client != nil {
|
|
jm.client.AddBreadcrumb("Started journey: "+name, CategoryBusiness)
|
|
}
|
|
|
|
return &Journey{
|
|
manager: jm,
|
|
context: ctx,
|
|
}
|
|
}
|
|
|
|
// GetCurrent returns the current journey context
|
|
func (jm *JourneyManager) GetCurrent() *JourneyContext {
|
|
jm.mu.RLock()
|
|
defer jm.mu.RUnlock()
|
|
|
|
return jm.current
|
|
}
|
|
|
|
// Clear clears the current journey
|
|
func (jm *JourneyManager) Clear() {
|
|
jm.mu.Lock()
|
|
defer jm.mu.Unlock()
|
|
|
|
jm.current = nil
|
|
}
|
|
|
|
// Journey represents an active journey
|
|
type Journey struct {
|
|
manager *JourneyManager
|
|
context *JourneyContext
|
|
}
|
|
|
|
// SetUser sets the user for the journey
|
|
func (j *Journey) SetUser(id, email, name string) *Journey {
|
|
j.manager.mu.Lock()
|
|
defer j.manager.mu.Unlock()
|
|
|
|
j.context.Metadata["userId"] = id
|
|
if email != "" {
|
|
j.context.Metadata["userEmail"] = email
|
|
}
|
|
if name != "" {
|
|
j.context.Metadata["userName"] = name
|
|
}
|
|
|
|
return j
|
|
}
|
|
|
|
// SetMetadata sets metadata for the journey
|
|
func (j *Journey) SetMetadata(key string, value any) *Journey {
|
|
j.manager.mu.Lock()
|
|
defer j.manager.mu.Unlock()
|
|
|
|
j.context.Metadata[key] = value
|
|
return j
|
|
}
|
|
|
|
// StartStep starts a new step in the journey
|
|
func (j *Journey) StartStep(name string, category BreadcrumbCategory) *Step {
|
|
j.manager.mu.Lock()
|
|
j.context.CurrentStep = name
|
|
j.manager.mu.Unlock()
|
|
|
|
// Add breadcrumb for step start
|
|
if j.manager.client != nil {
|
|
j.manager.client.AddBreadcrumbWithData(
|
|
"Started step: "+name,
|
|
category,
|
|
SeverityInfo,
|
|
map[string]any{
|
|
"journeyId": j.context.JourneyID,
|
|
"journeyName": j.context.Name,
|
|
},
|
|
)
|
|
}
|
|
|
|
return &Step{
|
|
journey: j,
|
|
name: name,
|
|
category: category,
|
|
startedAt: time.Now(),
|
|
data: make(map[string]any),
|
|
}
|
|
}
|
|
|
|
// Complete completes the journey successfully
|
|
func (j *Journey) Complete() {
|
|
if j.manager.client != nil {
|
|
j.manager.client.AddBreadcrumbWithData(
|
|
"Completed journey: "+j.context.Name,
|
|
CategoryBusiness,
|
|
SeverityInfo,
|
|
map[string]any{
|
|
"journeyId": j.context.JourneyID,
|
|
"duration": time.Since(j.context.StartedAt).Milliseconds(),
|
|
},
|
|
)
|
|
}
|
|
j.manager.Clear()
|
|
}
|
|
|
|
// Fail marks the journey as failed
|
|
func (j *Journey) Fail(err error) {
|
|
if j.manager.client != nil {
|
|
data := map[string]any{
|
|
"journeyId": j.context.JourneyID,
|
|
"duration": time.Since(j.context.StartedAt).Milliseconds(),
|
|
}
|
|
if err != nil {
|
|
data["error"] = err.Error()
|
|
}
|
|
j.manager.client.AddBreadcrumbWithData(
|
|
"Failed journey: "+j.context.Name,
|
|
CategoryBusiness,
|
|
SeverityError,
|
|
data,
|
|
)
|
|
}
|
|
j.manager.Clear()
|
|
}
|
|
|
|
// Step represents a step within a journey
|
|
type Step struct {
|
|
journey *Journey
|
|
name string
|
|
category BreadcrumbCategory
|
|
startedAt time.Time
|
|
data map[string]any
|
|
}
|
|
|
|
// SetData sets data for the step
|
|
func (s *Step) SetData(key string, value any) *Step {
|
|
s.data[key] = value
|
|
return s
|
|
}
|
|
|
|
// Complete completes the step successfully
|
|
func (s *Step) Complete() {
|
|
if s.journey.manager.client != nil {
|
|
data := map[string]any{
|
|
"journeyId": s.journey.context.JourneyID,
|
|
"journeyName": s.journey.context.Name,
|
|
"duration": time.Since(s.startedAt).Milliseconds(),
|
|
}
|
|
for k, v := range s.data {
|
|
data[k] = v
|
|
}
|
|
s.journey.manager.client.AddBreadcrumbWithData(
|
|
"Completed step: "+s.name,
|
|
s.category,
|
|
SeverityInfo,
|
|
data,
|
|
)
|
|
}
|
|
}
|
|
|
|
// Fail marks the step as failed
|
|
func (s *Step) Fail(err error) {
|
|
if s.journey.manager.client != nil {
|
|
data := map[string]any{
|
|
"journeyId": s.journey.context.JourneyID,
|
|
"journeyName": s.journey.context.Name,
|
|
"duration": time.Since(s.startedAt).Milliseconds(),
|
|
}
|
|
for k, v := range s.data {
|
|
data[k] = v
|
|
}
|
|
if err != nil {
|
|
data["error"] = err.Error()
|
|
}
|
|
s.journey.manager.client.AddBreadcrumbWithData(
|
|
"Failed step: "+s.name,
|
|
s.category,
|
|
SeverityError,
|
|
data,
|
|
)
|
|
}
|
|
}
|
|
|
|
// RunStep is a helper that runs a function as a step
|
|
func (j *Journey) RunStep(name string, category BreadcrumbCategory, fn func() error) error {
|
|
step := j.StartStep(name, category)
|
|
err := fn()
|
|
if err != nil {
|
|
step.Fail(err)
|
|
return err
|
|
}
|
|
step.Complete()
|
|
return nil
|
|
}
|