Skip to content

Commit 59b0f27

Browse files
committed
Stop writing channel logs to database and add is_error data field
1 parent 6f91e0b commit 59b0f27

File tree

5 files changed

+25
-77
lines changed

5 files changed

+25
-77
lines changed

core/models/call.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,6 @@ func (c *Call) AttachLog(ctx context.Context, db DBorTx, clog *ChannelLog) error
364364
if err != nil {
365365
return fmt.Errorf("error attaching log to call: %w", err)
366366
}
367-
368-
clog.attached = true
369367
return nil
370368
}
371369

core/models/channel_log.go

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

33
import (
44
"context"
5-
"encoding/json"
65
"fmt"
76
"log/slog"
87
"slices"
@@ -13,14 +12,10 @@ import (
1312
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
1413
"github.com/nyaruka/gocommon/aws/dynamo"
1514
"github.com/nyaruka/gocommon/httpx"
16-
"github.com/nyaruka/gocommon/jsonx"
1715
"github.com/nyaruka/mailroom/runtime"
1816
"github.com/nyaruka/mailroom/utils/clogs"
1917
)
2018

21-
// ChannelLogID is our type for a channel log id
22-
type ChannelLogID int64
23-
2419
const (
2520
ChannelLogTypeIVRStart clogs.Type = "ivr_start"
2621
ChannelLogTypeIVRIncoming clogs.Type = "ivr_incoming"
@@ -35,8 +30,7 @@ const (
3530
type ChannelLog struct {
3631
*clogs.Log
3732

38-
channel *Channel
39-
attached bool
33+
channel *Channel
4034
}
4135

4236
// NewChannelLog creates a new channel log with the given type and channel
@@ -56,21 +50,6 @@ func newChannelLog(t clogs.Type, ch *Channel, r *httpx.Recorder, redactVals []st
5650
}
5751
}
5852

59-
// if we have an error or a non 2XX/3XX http response then log is considered an error
60-
func (l *ChannelLog) isError() bool {
61-
if len(l.Errors) > 0 {
62-
return true
63-
}
64-
65-
for _, l := range l.HttpLogs {
66-
if l.StatusCode < 200 || l.StatusCode >= 400 {
67-
return true
68-
}
69-
}
70-
71-
return false
72-
}
73-
7453
func (l *ChannelLog) DynamoKey() runtime.DynamoKey {
7554
pk := fmt.Sprintf("cha#%s#%s", l.channel.UUID(), l.UUID[35:36]) // 16 buckets for each channel
7655
sk := fmt.Sprintf("log#%s", l.UUID)
@@ -96,29 +75,12 @@ func (l *ChannelLog) DynamoItem() (*runtime.DynamoItem, error) {
9675
"type": l.Type,
9776
"elapsed_ms": int(l.Elapsed / time.Millisecond),
9877
"created_on": l.CreatedOn,
78+
"is_error": l.IsError(),
9979
},
10080
DataGZ: dataGZ,
10181
}, nil
10282
}
10383

104-
const sqlInsertChannelLog = `
105-
INSERT INTO channels_channellog( uuid, channel_id, log_type, http_logs, errors, is_error, elapsed_ms, created_on)
106-
VALUES(:uuid, :channel_id, :log_type, :http_logs, :errors, :is_error, :elapsed_ms, :created_on)
107-
RETURNING id`
108-
109-
// channel log to be inserted into the database
110-
type dbChannelLog struct {
111-
ID ChannelLogID `db:"id"`
112-
UUID clogs.UUID `db:"uuid"`
113-
ChannelID ChannelID `db:"channel_id"`
114-
Type clogs.Type `db:"log_type"`
115-
HTTPLogs json.RawMessage `db:"http_logs"`
116-
Errors json.RawMessage `db:"errors"`
117-
IsError bool `db:"is_error"`
118-
ElapsedMS int `db:"elapsed_ms"`
119-
CreatedOn time.Time `db:"created_on"`
120-
}
121-
12284
// InsertChannelLogs writes the given channel logs to the db
12385
func InsertChannelLogs(ctx context.Context, rt *runtime.Runtime, logs []*ChannelLog) error {
12486
// write all logs to DynamoDB
@@ -150,30 +112,5 @@ func InsertChannelLogs(ctx context.Context, rt *runtime.Runtime, logs []*Channel
150112
}
151113
}
152114

153-
unattached := make([]*dbChannelLog, 0, len(logs))
154-
155-
for _, l := range logs {
156-
if !l.attached {
157-
// if log isn't attached to a message or call we need to write it to the db so that it's retrievable
158-
unattached = append(unattached, &dbChannelLog{
159-
UUID: l.UUID,
160-
ChannelID: l.channel.ID(),
161-
Type: l.Type,
162-
HTTPLogs: jsonx.MustMarshal(l.HttpLogs),
163-
Errors: jsonx.MustMarshal(l.Errors),
164-
IsError: l.isError(),
165-
CreatedOn: l.CreatedOn,
166-
ElapsedMS: int(l.Elapsed / time.Millisecond),
167-
})
168-
}
169-
}
170-
171-
if len(unattached) > 0 {
172-
err := BulkQuery(ctx, "insert channel log", rt.DB, sqlInsertChannelLog, unattached)
173-
if err != nil {
174-
return fmt.Errorf("error inserting unattached channel logs: %w", err)
175-
}
176-
}
177-
178115
return nil
179116
}

core/models/channel_log_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"net/http"
55
"testing"
66

7-
"github.com/nyaruka/gocommon/dbutil/assertdb"
7+
"github.com/nyaruka/gocommon/aws/dynamo"
88
"github.com/nyaruka/gocommon/httpx"
99
"github.com/nyaruka/mailroom/core/models"
1010
"github.com/nyaruka/mailroom/testsuite"
@@ -52,13 +52,15 @@ func TestChannelLogsOutgoing(t *testing.T) {
5252
err = models.InsertChannelLogs(ctx, rt, []*models.ChannelLog{clog1, clog2})
5353
require.NoError(t, err)
5454

55-
assertdb.Query(t, rt.DB, `SELECT count(*) FROM channels_channellog`).Returns(2)
56-
assertdb.Query(t, rt.DB, `SELECT count(*) FROM channels_channellog WHERE log_type = 'ivr_start' AND http_logs -> 0 ->> 'url' = 'http://ivr.com/start' AND is_error = FALSE AND channel_id = $1`, channel.ID()).Returns(1)
57-
assertdb.Query(t, rt.DB, `SELECT count(*) FROM channels_channellog WHERE log_type = 'ivr_hangup' AND http_logs -> 0 ->> 'url' = 'http://ivr.com/hangup' AND is_error = TRUE AND channel_id = $1`, channel.ID()).Returns(1)
58-
assertdb.Query(t, rt.DB, `SELECT count(*) FROM channels_channellog WHERE http_logs::text LIKE '%sesame%'`).Returns(0)
59-
6055
// read log back from DynamoDB
6156
item, err := rt.Dynamo.Main.GetItem(ctx, clog1.DynamoKey())
6257
require.NoError(t, err)
6358
assert.Equal(t, string(models.ChannelLogTypeIVRStart), item.Data["type"])
59+
60+
var dataGZ map[string]any
61+
err = dynamo.UnmarshalJSONGZ(item.DataGZ, &dataGZ)
62+
require.NoError(t, err)
63+
assert.Len(t, dataGZ["http_logs"], 1)
64+
65+
assert.NotContains(t, string(item.DataGZ), "sesame", "redacted value should not be present in DynamoDB log")
6466
}

utils/clogs/clog.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ func (l *Log) End() {
7676
l.Elapsed = time.Since(l.CreatedOn)
7777
}
7878

79+
// if we have an error or a non 2XX/3XX http response then log is considered an error
80+
func (l *Log) IsError() bool {
81+
if len(l.Errors) > 0 {
82+
return true
83+
}
84+
85+
for _, l := range l.HttpLogs {
86+
if l.StatusCode < 200 || l.StatusCode >= 400 {
87+
return true
88+
}
89+
}
90+
91+
return false
92+
}
93+
7994
func (l *Log) traceToLog(t *httpx.Trace) *httpx.Log {
8095
return httpx.NewLog(t, 2048, 50000, l.redactor)
8196
}

web/ivr/ivr_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -638,10 +638,6 @@ func TestVonageIVR(t *testing.T) {
638638
for _, log := range logs {
639639
assert.NotContains(t, string(jsonx.MustMarshal(log)), "BEGIN PRIVATE KEY") // private key redacted
640640
}
641-
642-
// and 2 unattached logs in the database
643-
assertdb.Query(t, rt.DB, `SELECT count(*) FROM channels_channellog WHERE channel_id = $1`, testdb.VonageChannel.ID).Returns(2)
644-
assertdb.Query(t, rt.DB, `SELECT array_agg(log_type ORDER BY id) FROM channels_channellog WHERE channel_id = $1`, testdb.VonageChannel.ID).Returns([]byte(`{ivr_status,ivr_status}`))
645641
}
646642

647643
func getCallLogs(t *testing.T, ctx context.Context, rt *runtime.Runtime, ch *testdb.Channel) []*httpx.Log {

0 commit comments

Comments
 (0)