Skip to content

Commit e41bbb2

Browse files
authored
Improve logging and debugging (#38)
* refactored logging class and added error logging and json debugging helpers Signed-off-by: Marc Jeffrey <[email protected]> * redactor the way the handler middleware is mounted Signed-off-by: Marc Jeffrey <[email protected]> * user the Cable::INTERNAL messages Signed-off-by: Marc Jeffrey <[email protected]> * updated readme Signed-off-by: Marc Jeffrey <[email protected]> * remove version changes Signed-off-by: Marc Jeffrey <[email protected]> * moved debug stuff out of main server class Signed-off-by: Marc Jeffrey <[email protected]> * fix issues after rebase Signed-off-by: Marc Jeffrey <[email protected]>
1 parent d320ac8 commit e41bbb2

File tree

12 files changed

+172
-170
lines changed

12 files changed

+172
-170
lines changed

README.md

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ On your `src/app_server.cr` add the `Cable::Handler` before `Lucky::RouteHandler
3030
class AppServer < Lucky::BaseAppServer
3131
def middleware
3232
[
33-
Cable::Handler.new(ApplicationCable::Connection),
33+
Cable::Handler(ApplicationCable::Connection).new, # place before the middleware below
34+
Honeybadger::Handler.new,
35+
Lucky::ErrorHandler.new(action: Errors::Show),
3436
Lucky::RouteHandler.new,
3537
]
3638
end
@@ -46,6 +48,21 @@ Cable.configure do |settings|
4648
end
4749
```
4850

51+
You may want to tune how to report logging
52+
53+
```crystal
54+
# config/log.cr
55+
56+
log_levels = {
57+
"debug" => Log::Severity::Debug,
58+
"info" => Log::Severity::Info,
59+
"error" => Log::Severity::Error,
60+
}
61+
62+
# use the `CABLE_DEBUG_LEVEL` env var to choose any of the 3 log levels above
63+
Cable::Logger.level = log_levels[ENV.fetch("CABLE_DEBUG_LEVEL", "info")]
64+
```
65+
4966
Then you need to implement a few classes
5067

5168
The connection class is how you are gonna handle connections, it's referenced on the `src/app_server.cr` when creating the handler.
@@ -196,7 +213,32 @@ Cable.configure do |settings|
196213
settings.disable_sec_websocket_protocol_header = true
197214
end
198215
```
199-
4
216+
217+
## Debugging
218+
219+
You can create a json endpoint to ping your server and check how things are going.
220+
221+
```crystal
222+
223+
# src/actions/debug/index.cr
224+
225+
class Debug::Index < ApiAction
226+
include RequireAuthToken
227+
228+
get "/debug" do
229+
json(Cable.server.debug_json) # Cable.server.debug_json is provided by this shard
230+
end
231+
end
232+
```
233+
234+
Alternatively, you can ping redis directly using the redis-cli as follows;
235+
236+
```bash
237+
PUBLISH _internal debug
238+
```
239+
240+
This will dump a debug status into your logs
241+
200242
## TODO
201243

202244
After reading the docs, I realized I'm using some weird naming for variables / methods, so

spec/cable/connection_spec.cr

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ describe Cable::Connection do
1616

1717
connection.close
1818
socket.close
19-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
20-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
21-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
2219
end
2320
end
2421

@@ -43,9 +40,6 @@ describe Cable::Connection do
4340

4441
connection.close
4542
socket.close
46-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
47-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
48-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\",\"person\":{\"name\":\"Foo\",\"age\":32,\"boom\":\"boom\"}}")
4943
end
5044
end
5145

@@ -58,9 +52,6 @@ describe Cable::Connection do
5852

5953
connection.close
6054
socket.close
61-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
62-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
63-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\",\"person\":{\"name\":\"Celso\",\"age\":32,\"boom\":\"boom\"}}")
6455
end
6556
end
6657

@@ -94,10 +85,6 @@ describe Cable::Connection do
9485

9586
connection.close
9687
socket.close
97-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
98-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
99-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
100-
Cable::Logger.messages.should contain("ChatChannel is transmitting the unsubscribe confirmation")
10188
end
10289
end
10390
end
@@ -132,7 +119,6 @@ describe Cable::Connection do
132119
socket.messages.size.should eq(0)
133120

134121
# we check only the first that is the one we care about, the others make no sense to our test
135-
Cable::Logger.messages.should contain("An unauthorized connection attempt was rejected")
136122
socket.closed?.should be_truthy
137123

138124
Cable.server.connections.should eq({} of String => Cable::Connection)
@@ -151,9 +137,6 @@ describe Cable::Connection do
151137

152138
connection.close
153139
socket.close
154-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
155-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
156-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
157140
end
158141
end
159142

@@ -169,12 +152,6 @@ describe Cable::Connection do
169152

170153
connection.close
171154
socket.close
172-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
173-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
174-
Cable::Logger.messages.should contain("ChatChannel#receive({\"message\" => \"Hello\"})")
175-
Cable::Logger.messages.should contain("[ActionCable] Broadcasting to chat_1: {\"message\" => \"Hello\", \"current_user\" => \"98\"}")
176-
Cable::Logger.messages.should contain("ChatChannel transmitting {\"message\" => \"Hello\", \"current_user\" => \"98\"} (via streamed from chat_1)")
177-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
178155
end
179156
end
180157

@@ -190,12 +167,6 @@ describe Cable::Connection do
190167

191168
connection.close
192169
socket.close
193-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
194-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
195-
Cable::Logger.messages.should contain("ChatChannel#perform(\"invite\", {\"invite_id\" => \"4\"})")
196-
Cable::Logger.messages.should contain("[ActionCable] Broadcasting to chat_1: {\"performed\" => \"invite\", \"params\" => \"4\"}")
197-
Cable::Logger.messages.should contain("ChatChannel transmitting {\"performed\" => \"invite\", \"params\" => \"4\"} (via streamed from chat_1)")
198-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
199170
end
200171
end
201172
end
@@ -211,9 +182,6 @@ describe Cable::Connection do
211182

212183
connection.close
213184
socket.close
214-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
215-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
216-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
217185
end
218186
end
219187
end
@@ -231,10 +199,6 @@ describe Cable::Connection do
231199

232200
connection.close
233201
socket.close
234-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
235-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
236-
Cable::Logger.messages.should contain("ChatChannel transmitting {\"hello\" => \"Broadcast!\"} (via streamed from chat_1)")
237-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
238202
end
239203
end
240204
end
@@ -253,11 +217,6 @@ describe Cable::Connection do
253217

254218
connection.close
255219
socket.close
256-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
257-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
258-
Cable::Logger.messages.should contain("[ActionCable] Broadcasting to chat_1: <turbo-stream></turbo-stream>")
259-
Cable::Logger.messages.should contain("ChatChannel transmitting <turbo-stream></turbo-stream> (via streamed from chat_1)")
260-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
261220
end
262221
end
263222

@@ -291,11 +250,6 @@ describe Cable::Connection do
291250

292251
connection.close
293252
socket.close
294-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
295-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
296-
Cable::Logger.messages.should contain("[ActionCable] Broadcasting to chat_1: {\"foo\" => \"bar\"}")
297-
Cable::Logger.messages.should contain("ChatChannel transmitting {\"foo\" => \"bar\"} (via streamed from chat_1)")
298-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
299253
end
300254
end
301255
end
@@ -314,11 +268,6 @@ describe Cable::Connection do
314268

315269
connection.close
316270
socket.close
317-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
318-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
319-
Cable::Logger.messages.should contain("[ActionCable] Broadcasting to chat_1: {\"foo\" => \"bar\"}")
320-
Cable::Logger.messages.should contain("ChatChannel transmitting {\"foo\" => \"bar\"} (via streamed from chat_1)")
321-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
322271
end
323272
end
324273
end
@@ -398,14 +347,7 @@ describe Cable::Connection do
398347

399348
connection.close
400349
socket.close
401-
Cable::Logger.messages.should contain("ChatChannel is streaming from chat_1")
402-
Cable::Logger.messages.should contain("ChatChannel is transmitting the subscription confirmation")
403-
Cable::Logger.messages.should contain("RejectionChannel is transmitting the subscription rejection")
404-
Cable::Logger.messages.should contain("[ActionCable] Broadcasting to chat_1: {\"foo\" => \"bar\"}")
405350
# and here we can confirm the message was broadcasted
406-
Cable::Logger.messages.should contain("ChatChannel transmitting {\"foo\" => \"bar\"} (via streamed from chat_1)")
407-
Cable::Logger.messages.should contain("[ActionCable] Broadcasting to rejection: {\"foo\" => \"bar\"}")
408-
Cable::Logger.messages.should contain("ChatChannel stopped streaming from {\"channel\":\"ChatChannel\",\"room\":\"1\"}")
409351
end
410352
end
411353
end

spec/cable/handler_spec.cr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ require "../spec_helper"
33
describe Cable::Handler do
44
describe "basic handling" do
55
it "matches the right route" do
6-
handler = Cable::Handler.new(ApplicationCable::Connection)
6+
handler = Cable::Handler(ApplicationCable::Connection).new
77
request = HTTP::Request.new("GET", "#{Cable.settings.route}?test_token=1", headers)
88

99
io_with_context = create_ws_request_and_return_io_and_context(handler, request)[0]
@@ -12,7 +12,7 @@ describe Cable::Handler do
1212

1313
it "allows you to remove undesired actioncable headers" do
1414
Cable.settings.disable_sec_websocket_protocol_header = true
15-
handler = Cable::Handler.new(ApplicationCable::Connection)
15+
handler = Cable::Handler(ApplicationCable::Connection).new
1616
request = HTTP::Request.new("GET", "#{Cable.settings.route}?test_token=1", headers_without_sec_websocket_protocol)
1717

1818
io_with_context = create_ws_request_and_return_io_and_context(handler, request)[0]
@@ -168,15 +168,15 @@ describe Cable::Handler do
168168

169169
describe "the error handling" do
170170
it "doesn't match the wrong route" do
171-
handler = Cable::Handler.new(ApplicationCable::Connection)
171+
handler = Cable::Handler(ApplicationCable::Connection).new
172172
request = HTTP::Request.new("GET", "/unknown_route?test_token=1", headers)
173173

174174
io_with_context = create_ws_request_and_return_io_and_context(handler, request)[0]
175175
io_with_context.to_s.should contain("404 Not Found")
176176
end
177177

178178
it "doesn't upgrade with wrong headers (without Upgrade header)" do
179-
handler = Cable::Handler.new(ApplicationCable::Connection)
179+
handler = Cable::Handler(ApplicationCable::Connection).new
180180
headers_without_upgrade = headers
181181
headers_without_upgrade.delete("Upgrade")
182182
request = HTTP::Request.new("GET", "/unknown_route?test_token=1", headers_without_upgrade)
@@ -186,7 +186,7 @@ describe Cable::Handler do
186186
end
187187

188188
it "doesn't upgrade with wrong headers (without Connection header)" do
189-
handler = Cable::Handler.new(ApplicationCable::Connection)
189+
handler = Cable::Handler(ApplicationCable::Connection).new
190190
headers_without_connection = headers
191191
headers_without_connection.delete("Connection")
192192
request = HTTP::Request.new("GET", "/unknown_route?test_token=1", headers_without_connection)
@@ -217,7 +217,7 @@ private def start_server
217217
spawn do
218218
# Make pinger real fast so we don't need to wait
219219
http_ref = nil
220-
http_server = http_ref = HTTP::Server.new([Cable::Handler.new(ApplicationCable::Connection)])
220+
http_server = http_ref = HTTP::Server.new([Cable::Handler(ApplicationCable::Connection).new])
221221
address = http_server.bind_unused_port
222222
address_chan.send(address)
223223
http_server.listen

spec/spec_helper.cr

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@ require "./support/application_cable/connection"
44
require "./support/application_cable/channel"
55
require "./support/channels/*"
66

7-
Cable::Logger.suppress_output
8-
97
Cable.configure do |settings|
108
settings.route = "/updates"
119
settings.token = "test_token"
1210
end
1311

1412
Spec.before_each do
1513
Cable.restart
16-
Cable::Logger.reset_messages
1714
end

src/cable.cr

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,27 @@ module Cable
1414
ping: "ping",
1515
confirmation: "confirm_subscription",
1616
rejection: "reject_subscription",
17+
unsubscribe: "confirm_unsubscription",
1718
},
1819
disconnect_reasons: {
1920
unauthorized: "unauthorized",
2021
invalid_request: "invalid_request",
2122
server_restart: "server_restart",
2223
},
2324
default_mount_path: "/cable",
24-
protocols: ["actioncable-v1-json", "actioncable-unsupported"].freeze,
25+
protocols: ["actioncable-v1-json", "actioncable-unsupported"],
2526
}
2627

2728
Habitat.create do
28-
setting route : String = "/cable", example: "/cable"
29+
setting route : String = Cable.message(:default_mount_path), example: "/cable"
2930
setting token : String = "token", example: "token"
3031
setting url : String = ENV.fetch("REDIS_URL", "redis://localhost:6379"), example: "redis://localhost:6379"
3132
setting disable_sec_websocket_protocol_header : Bool = false
3233
end
34+
35+
def self.message(event : Symbol)
36+
INTERNAL[:message_types][event]
37+
end
38+
3339
# TODO: Put your code here
3440
end

0 commit comments

Comments
 (0)