feat: add logs client for go sdk, logs client go example (#2550)

* feat: add logs client for go sdk, logs client go example

* add: comment-based markup for go sdk log example

---------

Co-authored-by: matt <mrkaye97@gmail.com>
This commit is contained in:
Jishnu
2025-12-08 03:08:01 +05:30
committed by GitHub
parent 34090a71f2
commit 7ab13d3b46
3 changed files with 159 additions and 0 deletions

View File

@@ -30,6 +30,7 @@ type Client struct {
runs *features.RunsClient
workers *features.WorkersClient
workflows *features.WorkflowsClient
logs *features.LogsClient
}
// NewClient creates a new Hatchet client.
@@ -698,3 +699,13 @@ func (c *Client) Filters() *features.FiltersClient {
func (c *Client) Events() v0Client.EventClient {
return c.legacyClient.Event()
}
// Logs returns a client for managing task logs.
func (c *Client) Logs() *features.LogsClient {
if c.logs == nil {
tenantId := c.legacyClient.TenantId()
c.logs = features.NewLogsClient(c.legacyClient.API(), tenantId)
}
return c.logs
}

View File

@@ -0,0 +1,116 @@
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/hatchet-dev/hatchet/pkg/client/rest"
"github.com/hatchet-dev/hatchet/pkg/cmdutils"
hatchet "github.com/hatchet-dev/hatchet/sdks/go"
)
type LogsTestInput struct {
Message string `json:"message"`
}
type LogsTestOutput struct {
Result string `json:"result"`
}
func main() {
// > Create a new Hatchet client
client, err := hatchet.NewClient()
if err != nil {
log.Fatalf("failed to create hatchet client: %v", err)
}
// !!
var since_log_time time.Time
// > Create a new standalone task with logging during execution
task := client.NewStandaloneTask("logs-test", func(ctx hatchet.Context, input LogsTestInput) (LogsTestOutput, error) {
ctx.Log("Starting task execution")
time.Sleep(5 * time.Second)
since_log_time = time.Now()
ctx.Log("Logging input: " + input.Message)
ctx.Log("Task completed successfully")
return LogsTestOutput{
Result: "Task completed successfully",
}, nil
})
// !!
// > Create a new worker
worker, err := client.NewWorker("logs-test-worker",
hatchet.WithWorkflows(task),
)
if err != nil {
log.Fatalf("failed to create worker: %v", err)
}
// !!
runTaskAndFetchLogs := func() error {
// > Run the task
result, err := task.Run(context.Background(), LogsTestInput{Message: "Invalid input received!"})
if err != nil {
return err
}
// !!
time.Sleep(2 * time.Second)
// > Get the task run details
runDetails, err := client.Runs().Get(context.Background(), result.RunId)
if err != nil {
return err
}
// !!
if len(runDetails.Tasks) > 0 {
taskRunId := runDetails.Tasks[0].TaskExternalId
fmt.Printf("\nTask Run ID: %s\n", taskRunId)
// > Fetch logs for the task run, with a since filter
logs, err := client.Logs().List(context.Background(), taskRunId, &rest.V1LogLineListParams{
Since: &since_log_time,
})
if err != nil {
return err
}
// !!
if logs != nil && logs.Rows != nil {
fmt.Println("\nTask Logs:")
for _, logLine := range *logs.Rows {
fmt.Printf("[%s] %s\n", logLine.CreatedAt.Format(time.RFC3339), logLine.Message)
}
} else {
fmt.Println("No logs found")
}
}
return nil
}
// > Start the worker in a goroutine
interruptCtx, cancel := cmdutils.NewInterruptContext()
defer cancel()
go func() {
if err := worker.StartBlocking(interruptCtx); err != nil {
log.Printf("worker error: %v", err)
}
}()
// !!
if err := runTaskAndFetchLogs(); err != nil {
log.Printf("error: %v", err)
}
<-interruptCtx.Done()
}

32
sdks/go/features/logs.go Normal file
View File

@@ -0,0 +1,32 @@
package features
import (
"context"
"github.com/cockroachdb/errors"
"github.com/google/uuid"
"github.com/hatchet-dev/hatchet/pkg/client/rest"
)
type LogsClient struct {
api *rest.ClientWithResponses
tenantId uuid.UUID
}
func NewLogsClient(api *rest.ClientWithResponses, tenantId string) *LogsClient {
return &LogsClient{api: api, tenantId: uuid.MustParse(tenantId)}
}
func (l *LogsClient) List(ctx context.Context, taskRunId uuid.UUID, opts *rest.V1LogLineListParams) (*rest.V1LogLineList, error) {
resp, err := l.api.V1LogLineListWithResponse(ctx, taskRunId, opts)
if err != nil {
return nil, errors.Wrap(err, "failed to list logs")
}
if err := validateJSON200Response(resp.StatusCode(), resp.Body, resp.JSON200); err != nil {
return nil, err
}
return resp.JSON200, nil
}