Skip to content

Commit 5161f4b

Browse files
committed

File tree

3 files changed

+82
-16
lines changed

3 files changed

+82
-16
lines changed

polycode/errors.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package polycode
22

33
import (
4+
"bytes"
5+
"compress/gzip"
46
"fmt"
7+
"io"
8+
"strings"
59
)
610

711
var ErrBadRequest = DefineError("polycode.client", 2, "bad request")
@@ -24,6 +28,56 @@ type Error struct {
2428
CanRetry bool
2529
}
2630

31+
type Stacktrace struct {
32+
Stacktrace string `json:"stacktrace"`
33+
IsAvailable bool `json:"isAvailable"`
34+
IsCompressed bool `json:"isCompressed"`
35+
}
36+
37+
// Compress compresses the stacktrace string using gzip.
38+
func (s *Stacktrace) Compress() error {
39+
if s.IsCompressed || !s.IsAvailable || s.Stacktrace == "" {
40+
return nil
41+
}
42+
43+
var buf bytes.Buffer
44+
gz := gzip.NewWriter(&buf)
45+
_, err := gz.Write([]byte(s.Stacktrace))
46+
if err != nil {
47+
return err
48+
}
49+
if err := gz.Close(); err != nil {
50+
return err
51+
}
52+
53+
s.Stacktrace = buf.String() // convert []byte to string for JSON compatibility
54+
s.IsCompressed = true
55+
return nil
56+
}
57+
58+
// Extract decompresses the stacktrace if it is compressed.
59+
func (s *Stacktrace) Extract() error {
60+
if !s.IsCompressed || s.Stacktrace == "" {
61+
return nil
62+
}
63+
64+
buf := strings.NewReader(s.Stacktrace)
65+
gz, err := gzip.NewReader(buf)
66+
if err != nil {
67+
return err
68+
}
69+
defer gz.Close()
70+
71+
decoded, err := io.ReadAll(gz)
72+
if err != nil {
73+
return err
74+
}
75+
76+
s.Stacktrace = string(decoded)
77+
s.IsCompressed = false
78+
return nil
79+
}
80+
2781
func (t Error) Wrap(err error) Error {
2882
return Error{
2983
Module: t.Module,

polycode/model.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,12 @@ type ServiceMeta struct {
4242
}
4343

4444
type ServiceCompleteEvent struct {
45-
IsError bool `json:"isError"`
46-
Output any `json:"output"`
47-
Error Error `json:"error"`
48-
Logs []LogMsg `json:"logs"`
49-
Meta ServiceMeta `json:"meta"`
45+
IsError bool `json:"isError"`
46+
Output any `json:"output"`
47+
Error Error `json:"error"`
48+
Stacktrace Stacktrace `json:"stacktrace"`
49+
Logs []LogMsg `json:"logs"`
50+
Meta ServiceMeta `json:"meta"`
5051
}
5152

5253
type ApiStartEvent struct {

polycode/runtime.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func runService(ctx context.Context, taskLogger Logger, event ServiceStartEvent)
156156

157157
taskLogger.Error().Msg(recovered.Error())
158158
err2 := ErrInternal.Wrap(recovered)
159-
evt = ErrorToServiceComplete(err2)
159+
evt = ErrorToServiceComplete(err2, stackTrace)
160160
}
161161
} else {
162162
stackTrace := string(debug.Stack())
@@ -165,7 +165,7 @@ func runService(ctx context.Context, taskLogger Logger, event ServiceStartEvent)
165165
errorStr := fmt.Sprintf("recoverted %v", r)
166166
taskLogger.Error().Msg(errorStr)
167167
err2 := ErrInternal.Wrap(fmt.Errorf(errorStr))
168-
evt = ErrorToServiceComplete(err2)
168+
evt = ErrorToServiceComplete(err2, stackTrace)
169169
}
170170
}
171171
}()
@@ -174,7 +174,7 @@ func runService(ctx context.Context, taskLogger Logger, event ServiceStartEvent)
174174
if err != nil {
175175
err2 := ErrServiceExecError.Wrap(err)
176176
taskLogger.Error().Msg(err2.Error())
177-
return ErrorToServiceComplete(err2)
177+
return ErrorToServiceComplete(err2, "")
178178
}
179179

180180
meta := ServiceMeta{
@@ -185,21 +185,21 @@ func runService(ctx context.Context, taskLogger Logger, event ServiceStartEvent)
185185
if err != nil {
186186
err2 := ErrServiceExecError.Wrap(err)
187187
taskLogger.Error().Msg(err2.Error())
188-
return ErrorToServiceComplete(err2)
188+
return ErrorToServiceComplete(err2, "")
189189
}
190190

191191
err = ConvertType(event.Input, inputObj)
192192
if err != nil {
193193
err2 := ErrBadRequest.Wrap(err)
194194
taskLogger.Error().Msg(err2.Error())
195-
return ErrorToServiceComplete(err2)
195+
return ErrorToServiceComplete(err2, "")
196196
}
197197

198198
err = currentValidator.Validate(inputObj)
199199
if err != nil {
200200
err2 := ErrBadRequest.Wrap(err)
201201
taskLogger.Error().Msg(err2.Error())
202-
return ErrorToServiceComplete(err2)
202+
return ErrorToServiceComplete(err2, "")
203203
}
204204

205205
ctxImpl := &ContextImpl{
@@ -227,7 +227,7 @@ func runService(ctx context.Context, taskLogger Logger, event ServiceStartEvent)
227227
if err != nil {
228228
err2 := ErrServiceExecError.Wrap(err)
229229
taskLogger.Error().Msg(err2.Error())
230-
return ErrorToServiceComplete(err2)
230+
return ErrorToServiceComplete(err2, "")
231231
}
232232

233233
taskLogger.Info().Msg("service completed")
@@ -330,11 +330,22 @@ func ValueToServiceComplete(output any) ServiceCompleteEvent {
330330
}
331331
}
332332

333-
func ErrorToServiceComplete(err Error) ServiceCompleteEvent {
333+
func ErrorToServiceComplete(err Error, stacktraceStr string) ServiceCompleteEvent {
334+
var stacktrace Stacktrace
335+
if stacktraceStr != "" {
336+
stacktrace = Stacktrace{
337+
Stacktrace: stacktraceStr,
338+
IsAvailable: true,
339+
IsCompressed: false,
340+
}
341+
_ = stacktrace.Compress()
342+
}
343+
334344
return ServiceCompleteEvent{
335-
Output: nil,
336-
IsError: true,
337-
Error: err,
345+
Output: nil,
346+
IsError: true,
347+
Error: err,
348+
Stacktrace: stacktrace,
338349
}
339350
}
340351

0 commit comments

Comments
 (0)