Skip to main content

Overview

The Analytics Service provides metrics and analytics for users and workflows. Service Details:
  • Package: analytics
  • Port: 50055
  • Proto: proto/analytics/analytics.proto

Service Definition

service AnalyticsService {
    rpc GetUserAnalytics(GetUserAnalyticsRequest) returns (GetUserAnalyticsResponse) {}
    rpc GetWorkflowAnalytics(GetWorkflowAnalyticsRequest) returns (GetWorkflowAnalyticsResponse) {}
}

RPC Methods

GetUserAnalytics

Retrieve aggregated analytics for a user across all workflows. Request:
user_id
string
required
ID of the user whose analytics to retrieve
Response:
total_workflows
uint32
Total workflows ever created by the user (including active, terminated, and deleted)
total_jobs
uint64
Total jobs ever created by the user’s workflows (including all states)
total_joblogs
uint64
Total number of job logs generated across all jobs
total_job_execution_duration
uint64
Sum of job execution durations for all jobs (in seconds)
Example:
req := &analytics.GetUserAnalyticsRequest{
    UserId: "user-123",
}

resp, err := client.GetUserAnalytics(ctx, req)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("User Analytics:\n")
fmt.Printf("  Total Workflows: %d\n", resp.TotalWorkflows)
fmt.Printf("  Total Jobs: %d\n", resp.TotalJobs)
fmt.Printf("  Total Job Logs: %d\n", resp.TotalJoblogs)
fmt.Printf("  Total Execution Time: %d seconds\n", resp.TotalJobExecutionDuration)

// Calculate average execution time
if resp.TotalJobs > 0 {
    avgDuration := float64(resp.TotalJobExecutionDuration) / float64(resp.TotalJobs)
    fmt.Printf("  Average Job Duration: %.2f seconds\n", avgDuration)
}
# Using grpcurl
grpcurl -plaintext -d '{
  "user_id": "user-123"
}' localhost:50055 analytics.AnalyticsService/GetUserAnalytics

GetWorkflowAnalytics

Retrieve detailed analytics for a specific workflow. Request:
user_id
string
required
ID of the user who owns the workflow
workflow_id
string
required
ID of the workflow to analyze
Response:
workflow_id
string
Workflow identifier
total_job_execution_duration
uint64
Total execution time for all jobs in this workflow (in seconds)
total_jobs
uint32
Total jobs ever created by this workflow
total_joblogs
uint64
Total number of log entries generated by this workflow’s jobs
Example:
req := &analytics.GetWorkflowAnalyticsRequest{
    UserId:     "user-123",
    WorkflowId: "workflow-456",
}

resp, err := client.GetWorkflowAnalytics(ctx, req)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Workflow Analytics (ID: %s):\n", resp.WorkflowId)
fmt.Printf("  Total Jobs: %d\n", resp.TotalJobs)
fmt.Printf("  Total Job Logs: %d\n", resp.TotalJoblogs)
fmt.Printf("  Total Execution Time: %d seconds\n", resp.TotalJobExecutionDuration)

if resp.TotalJobs > 0 {
    avgDuration := float64(resp.TotalJobExecutionDuration) / float64(resp.TotalJobs)
    avgLogs := float64(resp.TotalJoblogs) / float64(resp.TotalJobs)
    fmt.Printf("  Average Job Duration: %.2f seconds\n", avgDuration)
    fmt.Printf("  Average Logs per Job: %.2f\n", avgLogs)
}
# Using grpcurl
grpcurl -plaintext -d '{
  "user_id": "user-123",
  "workflow_id": "workflow-456"
}' localhost:50055 analytics.AnalyticsService/GetWorkflowAnalytics

Use Cases

Dashboard Metrics

Display user-level statistics on a dashboard:
func getUserDashboard(client analytics.AnalyticsServiceClient, userID string) {
    ctx := context.Background()
    
    resp, err := client.GetUserAnalytics(ctx, &analytics.GetUserAnalyticsRequest{
        UserId: userID,
    })
    if err != nil {
        log.Fatal(err)
    }

    // Display metrics
    dashboard := map[string]interface{}{
        "workflows":      resp.TotalWorkflows,
        "jobs":           resp.TotalJobs,
        "logs":           resp.TotalJoblogs,
        "execution_time": resp.TotalJobExecutionDuration,
    }

    // Render dashboard...
}

Workflow Performance Comparison

Compare performance across multiple workflows:
func compareWorkflows(client analytics.AnalyticsServiceClient, userID string, workflowIDs []string) {
    ctx := context.Background()
    
    for _, wfID := range workflowIDs {
        resp, err := client.GetWorkflowAnalytics(ctx, &analytics.GetWorkflowAnalyticsRequest{
            UserId:     userID,
            WorkflowId: wfID,
        })
        if err != nil {
            log.Printf("Failed to get analytics for %s: %v", wfID, err)
            continue
        }

        efficiency := float64(0)
        if resp.TotalJobs > 0 {
            efficiency = float64(resp.TotalJobExecutionDuration) / float64(resp.TotalJobs)
        }

        fmt.Printf("%s: %d jobs, %.2fs avg duration\n", 
            resp.WorkflowId, resp.TotalJobs, efficiency)
    }
}

Cost Estimation

Estimate costs based on execution time:
func estimateCosts(client analytics.AnalyticsServiceClient, userID string) {
    ctx := context.Background()
    
    resp, err := client.GetUserAnalytics(ctx, &analytics.GetUserAnalyticsRequest{
        UserId: userID,
    })
    if err != nil {
        log.Fatal(err)
    }

    // Example: $0.0001 per second of execution
    costPerSecond := 0.0001
    totalCost := float64(resp.TotalJobExecutionDuration) * costPerSecond

    fmt.Printf("Total Execution Time: %d seconds\n", resp.TotalJobExecutionDuration)
    fmt.Printf("Estimated Cost: $%.4f\n", totalCost)
}

Resource Usage Monitoring

Monitor and alert on resource usage:
func monitorResourceUsage(client analytics.AnalyticsServiceClient, userID string) {
    ctx := context.Background()
    
    resp, err := client.GetUserAnalytics(ctx, &analytics.GetUserAnalyticsRequest{
        UserId: userID,
    })
    if err != nil {
        log.Fatal(err)
    }

    // Define thresholds
    const (
        maxJobs     = 10000
        maxLogs     = 1000000
        maxDuration = 86400 // 24 hours in seconds
    )

    // Check limits
    if resp.TotalJobs > maxJobs {
        fmt.Printf("WARNING: Job count exceeded: %d > %d\n", resp.TotalJobs, maxJobs)
    }
    if resp.TotalJoblogs > maxLogs {
        fmt.Printf("WARNING: Log count exceeded: %d > %d\n", resp.TotalJoblogs, maxLogs)
    }
    if resp.TotalJobExecutionDuration > maxDuration {
        fmt.Printf("WARNING: Execution time exceeded: %d > %d seconds\n", 
            resp.TotalJobExecutionDuration, maxDuration)
    }
}

Connection Example

package main

import (
    "context"
    "log"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    pb "github.com/hitesh22rana/chronoverse/pkg/proto/go/analytics"
)

func main() {
    conn, err := grpc.Dial(
        "localhost:50055",
        grpc.WithTransportCredentials(insecure.NewCredentials()),
    )
    if err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer conn.Close()

    client := pb.NewAnalyticsServiceClient(conn)
    ctx := context.Background()

    // Get user analytics
    userResp, err := client.GetUserAnalytics(ctx, &pb.GetUserAnalyticsRequest{
        UserId: "user-123",
    })
    if err != nil {
        log.Fatalf("GetUserAnalytics failed: %v", err)
    }

    log.Printf("User has %d workflows and %d jobs", 
        userResp.TotalWorkflows, userResp.TotalJobs)

    // Get workflow analytics
    wfResp, err := client.GetWorkflowAnalytics(ctx, &pb.GetWorkflowAnalyticsRequest{
        UserId:     "user-123",
        WorkflowId: "workflow-456",
    })
    if err != nil {
        log.Fatalf("GetWorkflowAnalytics failed: %v", err)
    }

    log.Printf("Workflow %s has %d jobs", wfResp.WorkflowId, wfResp.TotalJobs)
}

Metrics Reference

Duration Calculations

Job execution duration is calculated as:
duration = completed_at - started_at
  • Includes only completed jobs (success or failed)
  • Excludes pending, cancelled, or running jobs
  • Measured in seconds

Count Aggregations

All counts include:
  • Active: Currently running or scheduled
  • Terminated: Stopped due to failure threshold
  • Deleted: Removed from the system
Analytics provide historical data even for deleted resources to maintain accurate metrics.

Build docs developers (and LLMs) love