Add detailed peer closure logging in reader loop.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package honeybee
|
package honeybee
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
stderrors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -175,7 +176,23 @@ func (c *Connection) startReader() {
|
|||||||
messageType, data, err := c.socket.ReadMessage()
|
messageType, data, err := c.socket.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if c.logger != nil {
|
if c.logger != nil {
|
||||||
c.logger.Error("read error", "error", err)
|
var closeErr *websocket.CloseError
|
||||||
|
if stderrors.As(err, &closeErr) {
|
||||||
|
switch closeErr.Code {
|
||||||
|
case websocket.CloseNormalClosure, websocket.CloseGoingAway:
|
||||||
|
c.logger.Info("connection closed by peer",
|
||||||
|
"code", closeErr.Code,
|
||||||
|
"text", closeErr.Text,
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
c.logger.Error("unexpected close",
|
||||||
|
"code", closeErr.Code,
|
||||||
|
"text", closeErr.Text,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.logger.Error("read error", "error", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case c.errors <- err:
|
case c.errors <- err:
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package honeybee
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -315,31 +317,79 @@ func TestCloseLogging(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReaderLogging(t *testing.T) {
|
func TestReaderLogging(t *testing.T) {
|
||||||
t.Run("read message error", func(t *testing.T) {
|
t.Run("clean close by peer", func(t *testing.T) {
|
||||||
mockHandler := newMockSlogHandler()
|
mockHandler := newMockSlogHandler()
|
||||||
logger := slog.New(mockHandler)
|
logger := slog.New(mockHandler)
|
||||||
|
|
||||||
readErr := fmt.Errorf("read error")
|
|
||||||
mockSocket := NewMockSocket()
|
mockSocket := NewMockSocket()
|
||||||
mockSocket.ReadMessageFunc = func() (int, []byte, error) {
|
mockSocket.ReadMessageFunc = func() (int, []byte, error) {
|
||||||
return 0, nil, readErr
|
return 0, nil, &websocket.CloseError{
|
||||||
|
Code: websocket.CloseNormalClosure,
|
||||||
|
Text: "goodbye",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := NewConnectionFromSocket(mockSocket, nil, logger)
|
conn, err := NewConnectionFromSocket(mockSocket, nil, logger)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
assert.Eventually(t, func() bool {
|
||||||
|
return findLogRecord(
|
||||||
|
mockHandler.GetRecords(), slog.LevelInfo, "connection closed by peer") != nil
|
||||||
|
}, testTimeout, testTick)
|
||||||
|
|
||||||
|
record := findLogRecord(mockHandler.GetRecords(), slog.LevelInfo, "connection closed by peer")
|
||||||
|
assert.NotNil(t, record)
|
||||||
|
assertAttributePresent(t, *record, "code", websocket.CloseNormalClosure)
|
||||||
|
assertAttributePresent(t, *record, "text", "goodbye")
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("unexpected close", func(t *testing.T) {
|
||||||
|
mockHandler := newMockSlogHandler()
|
||||||
|
logger := slog.New(mockHandler)
|
||||||
|
|
||||||
|
mockSocket := NewMockSocket()
|
||||||
|
mockSocket.ReadMessageFunc = func() (int, []byte, error) {
|
||||||
|
return 0, nil, &websocket.CloseError{
|
||||||
|
Code: websocket.CloseProtocolError,
|
||||||
|
Text: "bad protocol",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := NewConnectionFromSocket(mockSocket, nil, logger)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
assert.Eventually(t, func() bool {
|
||||||
|
return findLogRecord(
|
||||||
|
mockHandler.GetRecords(), slog.LevelError, "unexpected close") != nil
|
||||||
|
}, testTimeout, testTick)
|
||||||
|
|
||||||
|
record := findLogRecord(mockHandler.GetRecords(), slog.LevelError, "unexpected close")
|
||||||
|
assert.NotNil(t, record)
|
||||||
|
assertAttributePresent(t, *record, "code", websocket.CloseProtocolError)
|
||||||
|
assertAttributePresent(t, *record, "text", "bad protocol")
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("read error", func(t *testing.T) {
|
||||||
|
mockHandler := newMockSlogHandler()
|
||||||
|
logger := slog.New(mockHandler)
|
||||||
|
|
||||||
|
mockSocket := NewMockSocket()
|
||||||
|
mockSocket.ReadMessageFunc = func() (int, []byte, error) {
|
||||||
|
return 0, nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := NewConnectionFromSocket(mockSocket, nil, logger)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
assert.Eventually(t, func() bool {
|
assert.Eventually(t, func() bool {
|
||||||
return findLogRecord(
|
return findLogRecord(
|
||||||
mockHandler.GetRecords(), slog.LevelError, "read error") != nil
|
mockHandler.GetRecords(), slog.LevelError, "read error") != nil
|
||||||
}, testTimeout, testTick)
|
}, testTimeout, testTick)
|
||||||
|
|
||||||
records := mockHandler.GetRecords()
|
|
||||||
|
|
||||||
record := findLogRecord(records, slog.LevelError, "read error")
|
|
||||||
assert.NotNil(t, record)
|
|
||||||
assertAttributePresent(t, *record, "error", readErr)
|
|
||||||
|
|
||||||
conn.Close()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user