From 83c63c5f931f8548cf0c640deb02f4a52d705628 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Tue, 28 Apr 2026 22:28:47 +0800 Subject: [PATCH] feat(notify): dummy notifier writing structured log lines --- internal/infra/notify/dummy.go | 32 +++++++++++++++++++++++++++++ internal/infra/notify/dummy_test.go | 26 +++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 internal/infra/notify/dummy.go create mode 100644 internal/infra/notify/dummy_test.go diff --git a/internal/infra/notify/dummy.go b/internal/infra/notify/dummy.go new file mode 100644 index 0000000..e2c7af1 --- /dev/null +++ b/internal/infra/notify/dummy.go @@ -0,0 +1,32 @@ +package notify + +import ( + "context" + "log/slog" +) + +// DummyNotifier 仅用于本地与测试环境,将通知以结构化日志形式打印,不做任何 +// 真实外发。生产环境如未配置真实 Notifier,可注册此实现作为兜底,避免投递 +// 流程因缺少 channel 而中断。 +type DummyNotifier struct { + log *slog.Logger +} + +// NewDummyNotifier 用调用方提供的 logger 构造 DummyNotifier。logger 为 nil 时 +// 调用 Send 会 panic,这是显式契约——上层负责传入有效 logger。 +func NewDummyNotifier(log *slog.Logger) *DummyNotifier { return &DummyNotifier{log: log} } + +// Name 返回 ChannelDummy,标识该 Notifier 的通道身份。 +func (d *DummyNotifier) Name() Channel { return ChannelDummy } + +// Send 将消息以 Info 级别结构化日志输出。ctx 在 dummy 实现中不消费, +// 真实通道(email/webhook/IM)应尊重 ctx 的取消与超时。 +func (d *DummyNotifier) Send(_ context.Context, msg Message) error { + d.log.Info("notify[dummy]", + "topic", msg.Topic, + "severity", string(msg.Severity), + "user_id", msg.UserID.String(), + "title", msg.Title, + ) + return nil +} diff --git a/internal/infra/notify/dummy_test.go b/internal/infra/notify/dummy_test.go new file mode 100644 index 0000000..e4383e0 --- /dev/null +++ b/internal/infra/notify/dummy_test.go @@ -0,0 +1,26 @@ +package notify + +import ( + "bytes" + "context" + "log/slog" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" +) + +func TestDummy_Send_LogsAndReturnsNil(t *testing.T) { + var buf bytes.Buffer + log := slog.New(slog.NewJSONHandler(&buf, nil)) + d := NewDummyNotifier(log) + + require.Equal(t, ChannelDummy, d.Name()) + err := d.Send(context.Background(), Message{ + ID: uuid.New(), UserID: uuid.New(), + Topic: "x", Severity: SeverityInfo, Title: "hi", Body: "world", + }) + require.NoError(t, err) + require.Contains(t, buf.String(), "notify[dummy]") + require.Contains(t, buf.String(), `"topic":"x"`) +}