Skip to content

Commit 38b8993

Browse files
committed
The way that the request cycle was wrappen didn't work for keepalives. This new way does. It probably should have a span link from the request handling span to the connection span, but some providers (New Relic) don't handle span links yet.
1 parent 4b63f77 commit 38b8993

File tree

4 files changed

+67
-62
lines changed

4 files changed

+67
-62
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.1
1+
0.2.2

shard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: opentelemetry-instrumentation
2-
version: 0.2.1
2+
version: 0.2.2
33

44
authors:
55
- Kirk Haines <wyhaines@gmail.com>

spec/instrumentation/crystal_http_server_spec.cr

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,13 @@ describe HTTP::Server, tags: ["HTTP::Server"] do
5858
traces[0]["resource"]["service.name"].should eq "Crystal OTel Instrumentation - HTTP::Server"
5959
traces[0]["spans"][0]["kind"].should eq 2 # Unspecified = 0 | Internal = 1 | Server = 2 | Client = 3 | Producer = 4 | Consumer = 5
6060
traces[0]["resource"]["service.version"].should eq "1.0.0"
61-
traces[0]["spans"][0]["attributes"]["http.method"].should eq "GET"
62-
traces[0]["spans"][0]["attributes"]["http.scheme"].should eq "http"
61+
traces[0]["spans"][0]["attributes"]["net.peer.ip"].should eq "127.0.0.1"
6362

64-
traces[0]["spans"][1]["name"].should eq "Invoke handler Proc(HTTP::Server::Context, Nil)"
65-
traces[0]["spans"][1]["kind"].should eq 1
63+
traces[1]["spans"][0]["name"].should eq "HTTP Request Received"
64+
traces[1]["spans"][0]["attributes"]["http.method"].should eq "GET"
65+
traces[1]["spans"][0]["attributes"]["http.scheme"].should eq "http"
66+
67+
traces[1]["spans"][1]["name"].should eq "Invoke handler Proc(HTTP::Server::Context, Nil)"
68+
traces[1]["spans"][1]["kind"].should eq 1
6669
end
6770
end

src/opentelemetry/instrumentation/crystal/http_server.cr

Lines changed: 58 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ unless_enabled?("OTEL_CRYSTAL_DISABLE_INSTRUMENTATION_HTTP_SERVER") do
8686
span["net.peer.port"] = local_addr.port
8787
end
8888
span["http.host"] = local_addr.address
89-
previous_def
9089
end
90+
previous_def
9191
end
9292

9393
# If the RequestProcessor were refactored a little bit, this could be much cleaner.
@@ -104,81 +104,83 @@ unless_enabled?("OTEL_CRYSTAL_DISABLE_INSTRUMENTATION_HTTP_SERVER") do
104104
max_headers_size: max_headers_size,
105105
)
106106

107-
# EOF
108-
break unless request
107+
trace = OpenTelemetry.trace
108+
trace.in_span("HTTP Request Received") do |span|
109+
# EOF
110+
break unless request
109111

110-
response.reset
112+
response.reset
111113

112-
span = OpenTelemetry::Trace.current_span
113-
if request.is_a?(HTTP::Status)
114-
if span
115-
span["http.status_code"] = request.code
116-
span.add_event("Malformed Request or Error") do |event|
117-
event["http.status_code"] = request.code
114+
span = OpenTelemetry::Trace.current_span
115+
if request.is_a?(HTTP::Status)
116+
if span
117+
span["http.status_code"] = request.code
118+
span.add_event("Malformed Request or Error") do |event|
119+
event["http.status_code"] = request.code
120+
end
118121
end
122+
response.respond_with_status(request)
123+
return
119124
end
120-
response.respond_with_status(request)
121-
return
122-
end
123125

124-
response.version = request.version
125-
response.headers["Connection"] = "keep-alive" if request.keep_alive?
126-
context = Context.new(request, response)
127-
128-
if span
129-
span["http.host"] = request.hostname.to_s
130-
span["http.method"] = request.method
131-
span["http.flavor"] = request.version.split("/").last
132-
span["http.scheme"] = request.scheme
133-
if content_length = request.content_length
134-
span["http.response_content_length"] = content_length
135-
end
136-
span["http.url"] = request.full_url
137-
end
126+
response.version = request.version
127+
response.headers["Connection"] = "keep-alive" if request.keep_alive?
128+
context = Context.new(request, response)
138129

139-
OpenTelemetry::Trace.current_trace.not_nil!.in_span("Invoke handler #{@handler.class.name}") do |handler_span|
140-
Log.with_context do
141-
@handler.call(context)
142-
rescue ex : ClientError
143-
Log.debug(exception: ex.cause) { ex.message }
144-
handler_span.add_event("ClientError") do |event|
145-
event["message"] = ex.message.to_s
146-
end
147-
rescue ex
148-
Log.error(exception: ex) { "Unhandled exception on HTTP::Handler" }
149-
handler_span.add_event("Unhandled exception on HTTP::Handler") do |event|
150-
event["message"] = ex.message.to_s
130+
if span
131+
span["http.host"] = request.hostname.to_s
132+
span["http.method"] = request.method
133+
span["http.flavor"] = request.version.split("/").last
134+
span["http.scheme"] = request.scheme
135+
if content_length = request.content_length
136+
span["http.response_content_length"] = content_length
151137
end
152-
unless response.closed?
153-
unless response.wrote_headers?
154-
span["http.status_code"] = HTTP::Status::INTERNAL_SERVER_ERROR.value if span
155-
response.respond_with_status(:internal_server_error)
138+
span["http.url"] = request.full_url
139+
end
140+
141+
OpenTelemetry::Trace.current_trace.not_nil!.in_span("Invoke handler #{@handler.class.name}") do |handler_span|
142+
Log.with_context do
143+
@handler.call(context)
144+
rescue ex : ClientError
145+
Log.debug(exception: ex.cause) { ex.message }
146+
handler_span.add_event("ClientError") do |event|
147+
event["message"] = ex.message.to_s
148+
end
149+
rescue ex
150+
Log.error(exception: ex) { "Unhandled exception on HTTP::Handler" }
151+
handler_span.add_event("Unhandled exception on HTTP::Handler") do |event|
152+
event["message"] = ex.message.to_s
156153
end
154+
unless response.closed?
155+
unless response.wrote_headers?
156+
span["http.status_code"] = HTTP::Status::INTERNAL_SERVER_ERROR.value if span
157+
response.respond_with_status(:internal_server_error)
158+
end
159+
end
160+
return
161+
ensure
162+
response.output.close
157163
end
158-
return
159-
ensure
160-
response.output.close
161164
end
162-
end
163165

164-
output.flush
166+
output.flush
165167

166-
# If there is an upgrade handler, hand over
167-
# the connection to it and return
168-
if upgrade_handler = response.upgrade_handler
169-
upgrade_handler.call(output)
170-
return
168+
# If there is an upgrade handler, hand over
169+
# the connection to it and return
170+
if upgrade_handler = response.upgrade_handler
171+
upgrade_handler.call(output)
172+
return
173+
end
171174
end
172-
173-
break unless request.keep_alive?
175+
break unless request.as(HTTP::Request).keep_alive?
174176

175177
# Don't continue if the handler set `Connection` header to `close`
176178
break unless HTTP.keep_alive?(response)
177179

178180
# The request body is either FixedLengthContent or ChunkedContent.
179181
# In case it has not entirely been consumed by the handler, the connection is
180182
# closed the connection even if keep alive was requested.
181-
case body = request.body
183+
case body = request.as(HTTP::Request).body
182184
when FixedLengthContent
183185
if body.read_remaining > 0
184186
# Close the connection if there are bytes remaining

0 commit comments

Comments
 (0)