(ctx context.Context, r slog.Record)
| 156 | } |
| 157 | |
| 158 | func (h *LoggingHandler) handle(ctx context.Context, r slog.Record) error { |
| 159 | // Observe the rate limit. |
| 160 | // TODO(jba): use golang.org/x/time/rate. |
| 161 | h.mu.Lock() |
| 162 | skip := time.Since(h.lastMessageSent) < h.opts.MinInterval |
| 163 | h.mu.Unlock() |
| 164 | if skip { |
| 165 | return nil |
| 166 | } |
| 167 | |
| 168 | var err error |
| 169 | var data json.RawMessage |
| 170 | // Make the buffer reset atomic with the record write. |
| 171 | // We are careful here in the unlikely event that the handler panics. |
| 172 | // We don't want to hold the lock for the entire function, because Notify is |
| 173 | // an I/O operation. |
| 174 | // This can result in out-of-order delivery. |
| 175 | func() { |
| 176 | h.mu.Lock() |
| 177 | defer h.mu.Unlock() |
| 178 | h.buf.Reset() |
| 179 | err = h.handler.Handle(ctx, r) |
| 180 | // Clone the buffer as Bytes() references the internal buffer. |
| 181 | data = json.RawMessage(slices.Clone(h.buf.Bytes())) |
| 182 | }() |
| 183 | if err != nil { |
| 184 | return err |
| 185 | } |
| 186 | |
| 187 | h.mu.Lock() |
| 188 | h.lastMessageSent = time.Now() |
| 189 | h.mu.Unlock() |
| 190 | |
| 191 | params := &LoggingMessageParams{ |
| 192 | Logger: h.opts.LoggerName, |
| 193 | Level: slogLevelToMCP(r.Level), |
| 194 | Data: data, |
| 195 | } |
| 196 | // We pass the argument context to Notify, even though slog.Handler.Handle's |
| 197 | // documentation says not to. |
| 198 | // In this case logging is a service to clients, not a means for debugging the |
| 199 | // server, so we want to cancel the log message. |
| 200 | return h.ss.Log(ctx, params) |
| 201 | } |
no test coverage detected