Skip to content
This repository was archived by the owner on Mar 23, 2025. It is now read-only.

Commit f0732c1

Browse files
authored
Merge pull request #321 from manicmaniac/log-http
Log HTTP
2 parents 99bb8c7 + 92131a2 commit f0732c1

File tree

9 files changed

+240
-13
lines changed

9 files changed

+240
-13
lines changed

ApolloDeveloperKit.xcodeproj/project.pbxproj

+12
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
5B53B14D24F9BFA000A946D4 /* Schema+EventStreamMessageConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B53B14C24F9BFA000A946D4 /* Schema+EventStreamMessageConvertible.swift */; };
5454
5B53B15324F9C33E00A946D4 /* EventStreamMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B53B15224F9C33E00A946D4 /* EventStreamMessageTests.swift */; };
5555
5B53B15524FBFD0D00A946D4 /* ApolloDeveloperKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B53B15424FBFD0D00A946D4 /* ApolloDeveloperKitTests.swift */; };
56+
5B57D689267004F600269F68 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B57D688267004F600269F68 /* Logger.swift */; };
5657
5B5EBB9C2510E31400D0D025 /* InterfaceAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5EBB9B2510E31400D0D025 /* InterfaceAddress.swift */; };
5758
5B5EBB9E2510E32B00D0D025 /* InterfaceAddressIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5EBB9D2510E32B00D0D025 /* InterfaceAddressIterator.swift */; };
5859
5B60660122D64790002A2013 /* ApolloDebugServerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B60660022D64790002A2013 /* ApolloDebugServerTests.swift */; };
@@ -224,6 +225,7 @@
224225
5B53B14C24F9BFA000A946D4 /* Schema+EventStreamMessageConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Schema+EventStreamMessageConvertible.swift"; sourceTree = "<group>"; };
225226
5B53B15224F9C33E00A946D4 /* EventStreamMessageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventStreamMessageTests.swift; sourceTree = "<group>"; };
226227
5B53B15424FBFD0D00A946D4 /* ApolloDeveloperKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloDeveloperKitTests.swift; sourceTree = "<group>"; };
228+
5B57D688267004F600269F68 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
227229
5B5EBB9B2510E31400D0D025 /* InterfaceAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceAddress.swift; sourceTree = "<group>"; };
228230
5B5EBB9D2510E32B00D0D025 /* InterfaceAddressIterator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceAddressIterator.swift; sourceTree = "<group>"; };
229231
5B60660022D64790002A2013 /* ApolloDebugServerTests.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = ApolloDebugServerTests.swift; sourceTree = "<group>"; };
@@ -452,6 +454,7 @@
452454
5B53B14924F9BB7C00A946D4 /* EventStreamMessage */,
453455
5B67343D22BFF02200A09DF7 /* GraphQL */,
454456
5B7C983622BABA06000F4D7B /* JSON */,
457+
5B57D687267004E500269F68 /* Logger */,
455458
5BBA27942662FCFE00EBE185 /* Network */,
456459
5B53B15024F9C27A00A946D4 /* Schema */,
457460
5B7C983422BAB9E3000F4D7B /* Store */,
@@ -568,6 +571,14 @@
568571
path = EventStreamMessage;
569572
sourceTree = "<group>";
570573
};
574+
5B57D687267004E500269F68 /* Logger */ = {
575+
isa = PBXGroup;
576+
children = (
577+
5B57D688267004F600269F68 /* Logger.swift */,
578+
);
579+
path = Logger;
580+
sourceTree = "<group>";
581+
};
571582
5B67343D22BFF02200A09DF7 /* GraphQL */ = {
572583
isa = PBXGroup;
573584
children = (
@@ -880,6 +891,7 @@
880891
5B4F46092370A7D70039495A /* FileDescriptorDuplicator.swift in Sources */,
881892
5B05890A24EB5DC60071DB57 /* HTTPRequestMessage.swift in Sources */,
882893
5B207730236E098700817E45 /* HTTPChunkedResponse.swift in Sources */,
894+
5B57D689267004F600269F68 /* Logger.swift in Sources */,
883895
5B53B14B24F9BB9700A946D4 /* EventStreamMessage.swift in Sources */,
884896
5B2F84F122B4378B0025A211 /* ApolloDebugServer.swift in Sources */,
885897
5B3A83A722C87FA2002B4FFB /* HTTPServer.swift in Sources */,

ApolloDeveloperKit.xcodeproj/xcshareddata/xcschemes/ApolloDeveloperKit.xcscheme

+7
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@
8181
ReferencedContainer = "container:ApolloDeveloperKit.xcodeproj">
8282
</BuildableReference>
8383
</MacroExpansion>
84+
<EnvironmentVariables>
85+
<EnvironmentVariable
86+
key = "APOLLO_DEVELOPER_KIT_DIAGNOSTICS"
87+
value = "1"
88+
isEnabled = "YES">
89+
</EnvironmentVariable>
90+
</EnvironmentVariables>
8491
</LaunchAction>
8592
<ProfileAction
8693
buildConfiguration = "Release"

Sources/ApolloDeveloperKit/ApolloDebugServer.swift

+8-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ public class ApolloDebugServer {
178178
let message = String(data: notification.data, encoding: .utf8) else { return }
179179
let event = ConsoleEvent(data: message, type: eventType(for: notification.destination))
180180
let chunk = HTTPChunkedResponse(event: event)
181-
eventStreams.broadcast(data: chunk.data)
181+
Logger.withSuppressing(.http) {
182+
eventStreams.broadcast(data: chunk.data)
183+
}
182184
}
183185
}
184186

@@ -258,6 +260,7 @@ extension ApolloDebugServer: HTTPServerDelegate {
258260
let jsonObject = try JSONSerialization.jsonObject(with: body)
259261
let operationJSONObject = try Operation(jsonValue: jsonObject)
260262
let operation = AnyGraphQLOperation(operation: operationJSONObject)
263+
Logger.apollo?.info("Sending operation \(operation.operationName).")
261264
_ = networkTransport.send(operation: operation, cachePolicy: .fetchIgnoringCacheCompletely, contextIdentifier: nil, callbackQueue: .global()) { [weak self] result in
262265
guard let self = self else { return }
263266
do {
@@ -269,18 +272,22 @@ extension ApolloDebugServer: HTTPServerDelegate {
269272
options = []
270273
}
271274
let body = try JSONSerialization.data(withJSONObject: graphQLResult.jsonValue, options: options)
275+
Logger.apollo?.info("Received result \(body) for operation \(operation.operationName)")
272276
context.respondJSONData(body)
273277
} catch ResponseCodeInterceptor.ResponseCodeError.invalidResponseCode(let response?, let rawData) {
278+
Logger.apollo?.info("Received error response \(response.statusCode) for operation \(operation.operationName)")
274279
let stream = context.respond(proxying: response)
275280
if let rawData = rawData {
276281
stream.write(data: rawData)
277282
}
278283
stream.close()
279284
} catch let error {
285+
Logger.apollo?.info("Received error \(error) for operation \(operation.operationName)")
280286
self.respondBadRequest(context, jsError: ErrorLike(error: error))
281287
}
282288
}
283289
} catch let error {
290+
Logger.apollo?.info("Failed to parse GraphQL request \(error).")
284291
respondBadRequest(context, jsError: ErrorLike(error: error))
285292
}
286293
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//
2+
// Logger.swift
3+
// ApolloDeveloperKit
4+
//
5+
// Created by Ryosuke Ito on 6/9/21.
6+
// Copyright © 2021 Ryosuke Ito. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import asl
11+
import os.log
12+
13+
final class Logger {
14+
static let apollo = Logger(category: "apollo")
15+
static let http = Logger(category: "http")
16+
17+
private let logger: Any
18+
private var isSuppressed = false
19+
20+
init?(category: String) {
21+
guard ProcessInfo().environment.keys.contains("APOLLO_DEVELOPER_KIT_DIAGNOSTICS") else {
22+
return nil
23+
}
24+
let subsystem = "com.github.manicmaniac.ApolloDeveloperKit"
25+
if #available(macOS 10.12, iOS 10, *) {
26+
logger = OSLog(subsystem: subsystem, category: category)
27+
} else {
28+
logger = asl_new(UInt32(ASL_TYPE_MSG))!
29+
}
30+
}
31+
32+
static func withSuppressing(_ logger: Logger?, body: () throws -> Void) rethrows {
33+
try withExtendedLifetime(logger) {
34+
logger?.isSuppressed = true
35+
defer { logger?.isSuppressed = false }
36+
try body()
37+
}
38+
}
39+
40+
func debug(_ message: @autoclosure () -> String) {
41+
log(level: .debug, message())
42+
}
43+
44+
func info(_ message: @autoclosure () -> String) {
45+
log(level: .info, message())
46+
}
47+
48+
func error(_ message: @autoclosure () -> String) {
49+
log(level: .error, message())
50+
}
51+
52+
private func log(level: LogLevel, _ message: String) {
53+
if isSuppressed { return }
54+
if #available(macOS 10.12, iOS 10, *) {
55+
os_log("%@", log: logger as! OSLog, type: level.osLogType, message)
56+
} else {
57+
asl_vlog((logger as! asl_object_t), nil, level.aslLogLevel, "%@", getVaList([message]))
58+
}
59+
}
60+
61+
}
62+
63+
private enum LogLevel {
64+
case debug
65+
case info
66+
case error
67+
68+
@available(macOS 10.12, iOS 10, *)
69+
var osLogType: OSLogType {
70+
switch self {
71+
case .debug:
72+
return .debug
73+
case .info:
74+
return .info
75+
case .error:
76+
return .error
77+
}
78+
}
79+
80+
var aslLogLevel: Int32 {
81+
switch self {
82+
case .debug:
83+
return ASL_LEVEL_DEBUG
84+
case .info:
85+
return ASL_LEVEL_INFO
86+
case .error:
87+
return ASL_LEVEL_ERR
88+
}
89+
}
90+
}

Sources/ApolloDeveloperKit/WebServer/HTTPConnection.swift

+30-1
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@ final class HTTPConnection {
2727
weak var delegate: HTTPConnectionDelegate?
2828
private let incomingRequest = HTTPRequestMessage()
2929
private let socket: Socket
30+
private let address: Data
3031
private var eventQueue = ArraySlice<Event>()
3132
private let eventQueueLock = NSLock()
3233

33-
init(httpVersion: String, nativeHandle: CFSocketNativeHandle) throws {
34+
init(httpVersion: String, nativeHandle: CFSocketNativeHandle, address: Data) throws {
3435
self.httpVersion = httpVersion
36+
self.address = address
3537
let socket = try Socket(nativeHandle: nativeHandle, callbackTypes: [.dataCallBack, .writeCallBack])
3638
self.socket = socket
3739
socket.isNonBlocking = true
@@ -44,6 +46,33 @@ final class HTTPConnection {
4446
}
4547
}
4648

49+
// MARK: CustomStringConvertible
50+
51+
extension HTTPConnection: CustomStringConvertible {
52+
var description: String {
53+
let address = self.address.withUnsafeBytes { $0.load(as: sockaddr.self) }
54+
let numericAddress: String
55+
let port: in_port_t
56+
switch Int32(address.sa_family) {
57+
case AF_INET:
58+
var buffer = [CChar](repeating: 0, count: Int(INET_ADDRSTRLEN))
59+
var address = self.address.withUnsafeBytes { $0.load(as: sockaddr_in.self) }
60+
inet_ntop(AF_INET, &address.sin_addr, &buffer, socklen_t(buffer.count))
61+
numericAddress = String(cString: buffer)
62+
port = address.sin_port.bigEndian
63+
case AF_INET6:
64+
var buffer = [CChar](repeating: 0, count: Int(INET6_ADDRSTRLEN))
65+
var address = self.address.withUnsafeBytes { $0.load(as: sockaddr_in6.self) }
66+
inet_ntop(AF_INET6, &address.sin6_addr, &buffer, socklen_t(buffer.count))
67+
numericAddress = String(cString: buffer)
68+
port = address.sin6_port.bigEndian
69+
default:
70+
fatalError("Unexpected address family: \(address.sa_family).")
71+
}
72+
return "HTTP connection to (\(numericAddress):\(port))"
73+
}
74+
}
75+
4776
// MARK: HTTPOutputStream
4877

4978
extension HTTPConnection: HTTPOutputStream {

Sources/ApolloDeveloperKit/WebServer/HTTPOutputStreamSet.swift

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ final class HTTPOutputStreamSet: Sequence {
1919
for stream in self {
2020
stream.write(data: data)
2121
}
22+
Logger.http?.debug("Broadcasted \(data) to \(hashTable.count) streams.")
2223
}
2324

2425
func makeIterator() -> AnyIterator<HTTPOutputStream> {

Sources/ApolloDeveloperKit/WebServer/HTTPRequestContext.swift

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ final class HTTPRequestContext {
5656
}
5757

5858
func respond(statusCode: Int) -> HTTPOutputStream {
59+
defer { Logger.http?.info("Send status \(statusCode) in \(connection).") }
5960
let message = HTTPResponseMessage(statusCode: statusCode, statusDescription: nil, httpVersion: version)
6061
for (headerField, value) in responseHeaderFields {
6162
message.setValue(value, for: headerField)

Sources/ApolloDeveloperKit/WebServer/HTTPServer.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ final class HTTPServer {
106106
socket.schedule(in: .current, forMode: .default)
107107
return socket
108108
}
109+
Logger.http?.info("Server has been started at port \(port).")
109110
}
110111

111112
/**
@@ -144,6 +145,7 @@ final class HTTPServer {
144145
}
145146
socket?.invalidate()
146147
socket = nil
148+
Logger.http?.info("Server has been stopped.")
147149
}
148150

149151
private var port: UInt16? {
@@ -226,23 +228,26 @@ extension HTTPServer: HTTPConnectionDelegate {
226228
func httpConnection(_ connection: HTTPConnection, didReceive request: HTTPRequestMessage) {
227229
let context = HTTPRequestContext(request: request, connection: connection)
228230
delegate?.server(self, didReceiveRequest: context)
231+
Logger.http?.info("Received \(request.requestMethod ?? "unknown method") \(request.requestURL?.absoluteString ?? "unknown URL") in \(connection).")
229232
}
230233

231234
func httpConnectionWillClose(_ connection: HTTPConnection) {
232235
connections.remove(connection)
236+
Logger.http?.info("Closed \(connection).")
233237
}
234238

235239
func httpConnection(_ connection: HTTPConnection, didFailToHandle request: HTTPRequestMessage, error: Error) {
236240
let context = HTTPRequestContext(request: request, connection: connection)
237241
delegate?.server(self, didFailToHandle: context, error: error)
242+
Logger.http?.info("Failed to handle \(request.requestMethod ?? "unknown method") \(request.requestURL?.absoluteString ?? "unknown URL") in \(connection).")
238243
}
239244
}
240245

241246
// MARK: SocketDelegate
242247

243248
extension HTTPServer: SocketDelegate {
244249
func socket(_ socket: Socket, didAccept nativeHandle: CFSocketNativeHandle, address: Data) {
245-
guard let connection = try? HTTPConnection(httpVersion: kCFHTTPVersion1_1 as String, nativeHandle: nativeHandle) else {
250+
guard let connection = try? HTTPConnection(httpVersion: kCFHTTPVersion1_1 as String, nativeHandle: nativeHandle, address: address) else {
246251
return
247252
}
248253
connection.delegate = self

0 commit comments

Comments
 (0)