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
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,38 @@ jobs:
if: failure()
run: ./scripts/ci-diagnostics.sh

# This will be replaced once #6945 is merged.
pulse-integration-unit-tests:
name: SentryPulse 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/SentryPulse
run: swift package edit sentry-cocoa --path ../..

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

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

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

# 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
100 changes: 100 additions & 0 deletions 3rd-party-integrations/SentryPulse/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# --- macOS ---

# General
.DS_Store
__MACOSX/
.AppleDouble
.LSOverride
Icon[]

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

# --- Swift ---

# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## User settings
xcuserdata/

## Obj-C/Swift specific
*.hmap

## App packaging
*.ipa
*.dSYM.zip
*.dSYM

## Playgrounds
timeline.xctimeline
playground.xcworkspace

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm

.build/

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace
Comment on lines +64 to +73
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can also safely remove the Pods folder


# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build/
Comment on lines +75 to +80
Copy link
Contributor

Choose a reason for hiding this comment

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

We shouldn't need carthage anymore

Copy link
Member

Choose a reason for hiding this comment

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


# fastlane
#
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

# --- Xcode ---

## User settings
xcuserdata/

# Archive
*.xcarchive
34 changes: 34 additions & 0 deletions 3rd-party-integrations/SentryPulse/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: "SentryPulse",
platforms: [.iOS(.v15), .macOS(.v13), .tvOS(.v15), .watchOS(.v9), .visionOS(.v1)],
products: [
.library(
name: "SentryPulse",
targets: ["SentryPulse"]
)
],
dependencies: [
.package(url: "https://github.com/kean/Pulse", from: "5.0.0"),
.package(url: "https://github.com/getsentry/sentry-cocoa", from: "9.0.0")
],
targets: [
.target(
name: "SentryPulse",
dependencies: [
.product(name: "Pulse", package: "Pulse"),
.product(name: "Sentry", package: "sentry-cocoa")
]
),
.testTarget(
name: "SentryPulseTests",
dependencies: [
"SentryPulse",
.product(name: "Pulse", package: "Pulse"),
.product(name: "Sentry", package: "sentry-cocoa")
]
)
]
)
111 changes: 111 additions & 0 deletions 3rd-party-integrations/SentryPulse/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Sentry Pulse Integration

A [Pulse](https://github.com/kean/Pulse) integration that automatically forwards log entries to Sentry's structured logging system, capturing application logs with full context including metadata, source location, and log levels.

> [!NOTE]
> This repo is a mirror of [github.com/getsentry/sentry-cocoa](https://github.com/getsentry/sentry-cocoa). The source code lives in `3rd-party-integrations/SentryPulse/`. This allows users to import only what they need via SPM while keeping all integration code in the main repository.

## Installation

### Swift Package Manager

Add the following dependencies to your `Package.swift` or Xcode package manager:

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

Choose a reason for hiding this comment

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

l: Versions will probably be in sync with sentry-cocoa, so it should say 9.0.0 at least

]
```

## Quick Start

```swift
import Sentry
import Pulse
import SentryPulse

SentrySDK.start { options in
options.dsn = "YOUR_DSN"
options.enableLogs = true
}

SentryPulse.start()

let logger = LoggerStore.shared.makeLogger(label: "com.example.app")
logger.info("User logged in", metadata: ["userId": "12345"])
logger.error("Payment failed", metadata: ["errorCode": 500])
```

## Configuration

### Custom LoggerStore

By default, `SentryPulse.start()` uses `LoggerStore.shared`. You can specify a custom `LoggerStore`:

```swift
let customStore = try LoggerStore(storeURL: customURL, options: [.inMemory])
SentryPulse.start(loggerStore: customStore)
```

### Lifecycle Management

The integration automatically observes Pulse's `LoggerStore.events` publisher and forwards all `.messageStored` events to Sentry. You can stop the integration if needed:

```swift
SentryPulse.stop()
SentryPulse.start()
```

Calling `start()` multiple times has no effect - the integration is started only once.

## Log Level Mapping

Pulse log levels are automatically mapped to Sentry log levels:

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

## Metadata Handling

All Pulse metadata is automatically forwarded to Sentry with the `pulse.` prefix:

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

The metadata will appear in Sentry as `pulse.userId` and `pulse.action`.

Pulse metadata is already converted to `[String: String]` format before being forwarded, ensuring compatibility with Sentry's attribute system.

## Automatic Attributes

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

- `sentry.origin`: `"auto.logging.pulse"`
- `pulse.level`: The original Pulse level name
- `pulse.label`: The logger label
- `pulse.file`: The source file name (if available)
- `pulse.function`: The function name (if available)
- `pulse.line`: The line number

All Pulse metadata is prefixed with `pulse.` in Sentry attributes (e.g., `pulse.userId`, `pulse.action`).

## Documentation

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

## 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