Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/file-filters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ run_unit_tests_for_prs: &run_unit_tests_for_prs
- "SentryTestUtils/**"
- "SentryTestUtilsDynamic/**"
- "SentryTestUtilsTests/**"
- "3rd-party-integrations/**"

# GH Actions
- ".github/workflows/test.yml"
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,37 @@ jobs:
device: "Apple TV"
scheme: "Sentry"

swiftlog-integration-unit-tests:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: We should consider adding a new workflow file for integrations separate to the main SDK tests, and to not further extend it

name: Integrations/Logs/SentrySwiftLog Unit Tests
if: needs.files-changed.outputs.run_unit_tests_for_prs == 'true'
needs: files-changed
runs-on: macos-15
steps:
- uses: actions/checkout@v6

- name: Select Xcode
run: ./scripts/ci-select-xcode.sh 16.4

- name: Setup local sentry-cocoa dependency
working-directory: 3rd-party-integrations/SwiftLog
run: swift package edit sentry-cocoa --path ../..

- name: Run SwiftLog tests
working-directory: 3rd-party-integrations/SwiftLog
run: swift test

- name: Archiving Raw Logs
uses: actions/upload-artifact@v5
if: ${{ failure() || cancelled() }}
with:
name: raw-output-swiftlog-integration
path: |
3rd-party-integrations/SwiftLog/.build/**/*.log

- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: New test job missing from required-check dependencies

The new swiftlog-integration-unit-tests job is not included in the unit-tests-required-check job's needs array. Since unit-tests-required-check is the required status check that gates merging, failures in the swiftlog integration tests won't block the PR from merging. The job runs but its result is never validated by the required check.

Fix in Cursor Fix in Web

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is relevant!

# This check validates that either all unit tests passed or were skipped, which allows us
# to make unit tests a required check with only running the unit tests when required.
# So, we don't have to run unit tests, for example, for Changelog or ReadMe changes.
Expand Down
8 changes: 8 additions & 0 deletions 3rd-party-integrations/SwiftLog/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
34 changes: 34 additions & 0 deletions 3rd-party-integrations/SwiftLog/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// swift-tools-version:6.0
import PackageDescription

let package = Package(
name: "SentrySwiftLog",
platforms: [.iOS(.v15), .macOS(.v10_14), .tvOS(.v15), .watchOS(.v8), .visionOS(.v1)],
products: [
.library(
name: "SentrySwiftLog",
targets: ["SentrySwiftLog"]
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-log", from: "1.5.0"),
.package(url: "https://github.com/getsentry/sentry-cocoa", from: "9.0.0")
],
targets: [
.target(
name: "SentrySwiftLog",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "Sentry", package: "sentry-cocoa")
]
),
.testTarget(
name: "SentrySwiftLogTests",
dependencies: [
"SentrySwiftLog",
.product(name: "Logging", package: "swift-log"),
.product(name: "Sentry", package: "sentry-cocoa")
]
)
]
)
187 changes: 187 additions & 0 deletions 3rd-party-integrations/SwiftLog/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Sentry Swift-Log Integration

A `swift-log` handler that forwards log entries to Sentry's structured logging system, automatically capturing application logs with full context including metadata, source location, and log levels.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Let's add an alert here already stating that this integration is mirrored from this repository as decided in #6902

That way when we build the mirror workflow, we don't have to patch the README


## Installation

### Swift Package Manager

Add the following dependencies to your `Package.swift`:

```swift
dependencies: [
.package(url: "https://github.com/getsentry/sentry-cocoa", from: "9.0.0"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Is this one really necessary? Wouldn't it be resolve as a transitive dependency anyways?

.package(url: "https://github.com/getsentry/sentry-cocoa-swiftlog", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-log", from: "1.5.0")
]
```

Then add the required products to your target dependencies:

```swift
.target(
name: "YourTarget",
dependencies: [
.product(name: "Sentry", package: "sentry-cocoa"), // Required for SentrySDK initialization
.product(name: "SentrySwiftLog", package: "sentry-cocoa-swiftlog"),
.product(name: "Logging", package: "swift-log") // Required for Logger and LoggingSystem
]
)
```

## Quick Start

### 1. Initialize Sentry SDK

First, initialize the Sentry SDK with logs enabled:

```swift
import Sentry

SentrySDK.start { options in
options.dsn = "YOUR_DSN"
options.enableLogs = true // Required for logging integration
}
```

### 2. Register SentryLogHandler

Bootstrap the logging system with `SentryLogHandler`:

```swift
import Logging

LoggingSystem.bootstrap { _ in
return SentryLogHandler(logLevel: .info)
}
```

### 3. Use the Logger

Create and use loggers throughout your application:

```swift
let logger = Logger(label: "com.example.app")

logger.info("User logged in", metadata: ["userId": "12345"])
logger.error("Payment failed", metadata: ["errorCode": 500])
logger.warning("API rate limit approaching", metadata: ["remaining": 10])
```

## Configuration

### Log Level Threshold

Set the minimum log level for messages to be sent to Sentry:

```swift
// Only send info level and above
let handler = SentryLogHandler(logLevel: .info)

// Send all logs including trace and debug
let handler = SentryLogHandler(logLevel: .trace)
```

Messages below the configured threshold will be filtered out and not sent to Sentry.

### Handler Metadata

Add metadata that will be included with all log entries:

```swift
var handler = SentryLogHandler(logLevel: .info)
handler.metadata["app_version"] = "1.0.0"
handler.metadata["environment"] = "production"

LoggingSystem.bootstrap { _ in handler }
```

Handler metadata is merged with call-site metadata, with call-site metadata taking precedence.

### Metadata Subscript Access

You can also access metadata using subscript syntax:

```swift
var handler = SentryLogHandler(logLevel: .info)
handler[metadataKey: "app_version"] = "1.0.0"
let version = handler[metadataKey: "app_version"]
```

## Log Level Mapping

`swift-log` levels are automatically mapped to Sentry log levels:

| swift-log Level | Sentry Log Level |
| --------------- | ---------------- |
| `.trace` | `.trace` |
| `.debug` | `.debug` |
| `.info` | `.info` |
| `.notice` | `.info` |
| `.warning` | `.warn` |
| `.error` | `.error` |
| `.critical` | `.fatal` |

## Metadata Handling

The handler supports all `swift-log` metadata types:

### String Metadata

```swift
logger.info("User action", metadata: [
"userId": "12345",
"action": "purchase"
])
```

### Dictionary Metadata

```swift
logger.info("User profile", metadata: [
"user": [
"id": "12345",
"name": "John Doe"
]
])
```

### Array Metadata

```swift
logger.info("Tags", metadata: [
"tags": ["production", "api", "v2"]
])
```

### String Convertible Metadata

```swift
logger.info("Metrics", metadata: [
"count": 42,
"enabled": true,
"score": 3.14159
])
```

All metadata is automatically prefixed with `swift-log.` in Sentry attributes (e.g., `swift-log.userId`, `swift-log.user.id`).

## Automatic Attributes

The handler automatically includes the following attributes with every log entry:

- `sentry.origin`: `"auto.logging.swift-log"`
- `swift-log.level`: The original swift-log level
- `swift-log.source`: The log source
- `swift-log.file`: The source file name
- `swift-log.function`: The function name
- `swift-log.line`: The line number

## Documentation

- [Sentry Cocoa SDK Documentation](https://docs.sentry.io/platforms/apple/)
- [Sentry Logs Documentation](https://docs.sentry.io/platforms/apple/logs/)

## License

This integration follows the same license as the Sentry Cocoa SDK. See the [LICENSE](https://github.com/getsentry/sentry-cocoa/blob/main/LICENSE.md) file for details.
Loading
Loading