Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
kean committed Sep 2, 2024
1 parent fcb3143 commit 309ce11
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 45 deletions.
13 changes: 8 additions & 5 deletions Sources/Pulse/NetworkLogger/NetworkLogger+URLSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,44 @@ extension NetworkLogger {
/// If enabled, registers ``RemoteLoggerURLProtocol``
public var isMockingEnabled = true

/// A custom logger to be used instead of ``NetworkLogger/shared``.
public var logger: NetworkLogger?

/// Creates default options.
public init() {}
}

public final class URLSession {
/// The underlying `URLSession`.
public let session: Foundation.URLSession
var logger: NetworkLogger { options.logger ?? .shared}
var logger: NetworkLogger { _logger ?? .shared }
private let _logger: NetworkLogger?
private let options: URLSessionOptions

/// - parameter logger: A custom logger to use instead of ``NetworkLogger/shared``.
public convenience init(
configuration: URLSessionConfiguration,
logger: NetworkLogger? = nil,
options: URLSessionOptions = .init()
) {
self.init(configuration: configuration, delegate: nil, delegateQueue: nil, options: options)
}

/// - parameter logger: A custom logger to use instead of ``NetworkLogger/shared``.
public init(
configuration: URLSessionConfiguration,
delegate: (any URLSessionDelegate)?,
delegateQueue: OperationQueue? = nil,
logger: NetworkLogger? = nil,
options: URLSessionOptions = .init()
) {
if options.isMockingEnabled {
configuration.protocolClasses = [RemoteLoggerURLProtocol.self] + (configuration.protocolClasses ?? [])
}
self.session = Foundation.URLSession(
configuration: configuration,
delegate: URLSessionProxyDelegate(logger: options.logger, delegate: delegate),
delegate: URLSessionProxyDelegate(logger: logger, delegate: delegate),
delegateQueue: delegateQueue
)
self.options = options
self._logger = logger
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Pulse/Pulse.docc/Articles/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ NetworkLogger.enableProxy()
#endif
```

> Note: **PulseProxy** uses method swizzling and private APIs and it is not recommended that you include it in the production builds of your app.
> note: **PulseProxy** uses method swizzling and private APIs and it is not recommended that you include it in the production builds of your app.
- **Option 2 (Recommended)**. Use ``NetworkLogger/URLSession``, a thin wrapper on top of `URLSession`.

Expand All @@ -45,7 +45,7 @@ session = URLSession(configuration: .default)
#endif
```

> Tip: See <doc:NetworkLogging-Article> for more information about how to configure network logging if your app does not use `URLSession` directly, how to further customize it, how to capture and display decoding errors, and more. Pulse is modular and will accommodate almost any system.
> tip: See <doc:NetworkLogging-Article> for more information about how to configure network logging if your app does not use `URLSession` directly, how to further customize it, how to capture and display decoding errors, and more. Pulse is modular and will accommodate almost any system.
### 2.2. Collect Regular Messages

Expand Down
71 changes: 34 additions & 37 deletions Sources/Pulse/Pulse.docc/Articles/NetworkLogging-Article.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ Pulse works on the `URLSession` level, and it needs access to its callbacks to l

The first step is to capture network traffic.

- **Option 1 (Quickest)**. If you are evaluating the framework, the quickest way to get started is with a proxy from the **PulseProxy** module.
### Option 1 (Quickest)

If you are evaluating the framework, the quickest way to get started is with a proxy from the **PulseProxy** module.

```swift
import PulseProxy
Expand All @@ -23,9 +25,11 @@ NetworkLogger.enableProxy()
#endif
```

> Important: **PulseProxy** uses method swizzling and private APIs, and it is not recommended that you include it in the production builds of your app. It is also not guaranteed to continue working with new versions of the system SDKs.
> important: **PulseProxy** uses method swizzling and private APIs, and it is not recommended that you include it in the production builds of your app. It is also not guaranteed to continue working with new versions of the system SDKs.
### Option 2 (Recommended)

- **Option 2 (Recommended)**. Use ``NetworkLogger/URLSession``, a thin wrapper on top of `URLSession`.
Use ``NetworkLogger/URLSession``, a thin wrapper on top of `URLSession`.

```swift
import Pulse
Expand All @@ -40,16 +44,18 @@ session = URLSession(configuration: .default)

``NetworkLogger/URLSession`` is the best way to integrate Pulse because it supports all `URLSession` APIs, including the new Async/Await methods. It also makes it easy to remove it conditionally.

- **Option 3.** Use ``URLSessionProxyDelegate``.
### Option 3

If you use a delegate-based `URLSession` that doesn't rely on any of its convenience APIs, such as [Alamofire](https://github.com/Alamofire/Alamofire), you can record its traffic using a proxy delegate.
If you use a delegate-based `URLSession` that doesn't rely on any of its convenience APIs, such as [Alamofire](https://github.com/Alamofire/Alamofire), you can record its traffic using ``NetworkLogger/URLSessionProxyDelegate``.

```swift
let delegate = URLSessionProxyDelegate(delegate: <#YourSessionDelegate#>)
let delegate = NetworkLogger.URLSessionProxyDelegate(delegate: <#YourSessionDelegate#>)
let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)
```

- **Option 4 (Manual).** Use ``NetworkLogger`` directly.
> important: This method supports a limited subset of scenarios and doesn't work with `URLSession` Async/Await APIs.
### Option 4 (Manual)

If none of the convenience APIs described earlier work for you, you can use the underlying ``NetworkLogger`` directly. For example, here is how you can use it with Alamofire's `EventMonitor`:

Expand Down Expand Up @@ -79,41 +85,26 @@ struct NetworkLoggerEventMonitor: EventMonitor {
}
```

> tip: Make sure to capture [`URLSessionTaskMetrics`](https://developer.apple.com/documentation/foundation/urlsessiontaskmetrics) as Pulse makes a great use of them and many of the features won't work without them.
## Session Proxy (Experimental)

To capture _all_ network traffic from _all_ session, including `URLSession.shared`, you can try using ``Experimental/URLSessionProxy``.

```swift
Experimental.URLSessionProxy.shared.isEnabled = true
```

> warning: As clearly communicate by its namespace, it's an experimental feature and it might negatively affect your networking. The way it works is by registering a custom [URLProtocol](https://developer.apple.com/documentation/foundation/urlprotocol) and using a secondary URLSession instance in it, but it can be a useful tool.
## Configure Logging

> note: Alternatively, you can give the following swizzle-based [approach](https://gist.github.com/kean/3154a5bde8e0c5e9dc3322f21ba86757) a try that is less intrusive but requires more swizzling and can't be shipped with the production code.
### Recod Decoding Errors

## Recoding Decoding Errors

The network requests usually can only be considered successful when the app was able to decode the response data. With Pulse, you can do just that and when you open the response body, it'll even highlight the part of the response that's causing the decoding error.
The network requests can only be considered successful when the app decodes the response data. With Pulse, you can do just that, and when you open the response body, it'll even highlight the part of the response causing the decoding error.

```swift
// Initial setup
let logger = NetworkLogger(configuration: .init(isWaitingForDecoding: true))
let delegate = URLSessionProxyDelegate(logger: logger, delegate: YourURLSessionDelegate()))
// ... create session
let logger = NetworkLogger {
$0.isWaitingForDecoding = true
}
let session = NetworkLogger.URLSession(configuration: .default, logger: logger)

// Somewhere else in the app where decoding is done.
// Add this to the code that performs decoding of the responses.
logger.logTask(task, didFinishDecodingWithError: decodingError)
```

## Exclude Information From Logs

There is usually some sensitive information in network requests, such as passwords, access tokens, and more. It's important to keep it safe.

> tip: It's recommended to use Pulse _only_ in the debug mode.
### Exclude Information From Logs

``NetworkLogger`` captures data safely in a local database and it never leaves your device. Logs are never written to the system's logging system. But of course, logs are meant to be viewed and shared, which is why PulseUI provides sharing options. In case the logs do leave your device, it's best to redact any sensitive information.
``NetworkLogger`` captures data safely in a local database, and it never leaves your device. Logs are never written to the system's logging system. But, of course, logs are meant to be viewed and shared, which is why PulseUI provides sharing options. In case the logs do leave your device, it's best to redact any sensitive information. 

``NetworkLogger/Configuration`` has a set of convenience APIs for managing what information is included or excluded from the logs.

Expand All @@ -139,15 +130,21 @@ let logger = NetworkLogger {
}
```

> tip: "Include" and "exclude" patterns support basic wildcards (`*`), but you can also turns them into full-featured regex patterns using ``NetworkLogger/Configuration/isRegexEnabled``.
You can then replace the default decoder with your custom instance:

```swift
NetworkLogger.shared = logger
```

> Tip: "Include" and "exclude" patterns support basic wildcards (`*`), but you can also turn them into full-featured regex patterns using ``NetworkLogger/Configuration/isRegexEnabled``
If the built-in configuration options don't cover all of your use-cases, you can set ``NetworkLogger/Configuration/willHandleEvent`` closure that provides you complete control for filtering out and updating the events.
If the built-in configuration options don't cover all of your use cases, you can set the ``NetworkLogger/Configuration/willHandleEvent`` closure that provides you complete control for filtering out and updating the events.

> important: If you redact information manually from requests or responses, make sure to also update ``NetworkLogger/Metrics`` because individual transactions within metrics contain recorded request and response pairs.
> important: If you redact information manually from requests or responses, also update ``NetworkLogger/Metrics`` because individual transactions within metrics contain recorded request and response pairs.
## Trace in Xcode Console
### Trace in Xcode Console

While Pulse doesn't print anything in the Xcode Console by default, it's easy to enable such logging for network requests. ``LoggerStore`` re-translates all of the log events that it processes using ``LoggerStore/events`` publisher that you can leverage to log some of the recoded information in the Xcode Console.
Pulse doesn't print anything in the Xcode Console by default, but it's easy to enable logging for network requests. ``LoggerStore`` re-translates all of the log events that it processes using ``LoggerStore/events`` publisher that you can leverage.

```swift
func register(store: LoggerStore) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Pulse/Pulse.docc/Pulse.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ Logger and network inspector for Apple platforms.
### Essentials

- <doc:GettingStarted>
- <doc:NetworkLogging-Article>
- ``LoggerStore``

### Network Logging

- <doc:NetworkLogging-Article>
- ``NetworkLogger``
- ``URLSessionProtocol``
- ``URLSessionProxyDelegate``
Expand Down

0 comments on commit 309ce11

Please sign in to comment.