diff --git a/.craft.yml b/.craft.yml index 04d1af925d..51ef0dd728 100644 --- a/.craft.yml +++ b/.craft.yml @@ -1,9 +1,12 @@ -minVersion: 0.29.2 +minVersion: 1.21.0 changelogPolicy: auto artifactProvider: name: none targets: - name: pub-dev + # This is temporarily needed because we keep the package:web dependency implicit + # See https://github.com/getsentry/sentry-dart/pull/2113 for more context + skipValidation: true packages: dart: flutter: @@ -13,6 +16,7 @@ targets: sqflite: hive: drift: + isar: - name: github - name: registry sdks: @@ -24,3 +28,4 @@ targets: pub:sentry_sqflite: pub:sentry_drift: pub:sentry_hive: + pub:sentry_isar: diff --git a/.github/actions/coverage/action.yml b/.github/actions/coverage/action.yml new file mode 100644 index 0000000000..5989db8aac --- /dev/null +++ b/.github/actions/coverage/action.yml @@ -0,0 +1,41 @@ +name: Dart tests +description: Run Dart Tests and collect coverage +inputs: + directory: + description: The directory to run tests in + required: false + default: '' + coverage: + description: Codecov name + required: false + default: '' + min-coverage: + description: Minimum coverage percentage + required: false + default: '0' + token: + description: Codecov token + required: true + +runs: + using: composite + + steps: + - name: Format coverage info + if: ${{ inputs.coverage != '' }} + run: dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib + shell: bash + working-directory: ${{ inputs.directory }} + + - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v3 + if: ${{ inputs.coverage != '' }} + with: + name: ${{ inputs.coverage != '' }} + files: ./${{ inputs.directory }}/coverage/lcov.info + token: ${{ inputs.token }} + + - uses: VeryGoodOpenSource/very_good_coverage@c953fca3e24a915e111cc6f55f03f756dcb3964c # pin@v3.0.0 + if: ${{ inputs.coverage != '' }} + with: + path: './${{ inputs.directory }}/coverage/lcov.info' + min_coverage: ${{ inputs.min-coverage }} diff --git a/.github/actions/dart-test/action.yml b/.github/actions/dart-test/action.yml new file mode 100644 index 0000000000..bb13fa0300 --- /dev/null +++ b/.github/actions/dart-test/action.yml @@ -0,0 +1,40 @@ +name: Dart tests +description: Run Dart tests +inputs: + directory: + description: The directory to run tests in + required: false + default: '' + web: + description: Whether to run tests for web + required: false + default: 'true' + +runs: + using: composite + + steps: + - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30 # pin@v1 + with: + sdk: ${{ matrix.sdk }} + + - run: dart pub get + shell: bash + working-directory: ${{ inputs.directory }} + + - name: Test VM + run: dart test -p vm ${{ (runner.os == 'Linux' && matrix.sdk == 'stable' && '--coverage=coverage') || '' }} --test-randomize-ordering-seed=random --chain-stack-traces + shell: bash + working-directory: ${{ inputs.directory }} + + - name: Test dart2js + if: ${{ inputs.web == 'true' }} + run: dart test -p chrome --test-randomize-ordering-seed=random --chain-stack-traces + shell: bash + working-directory: ${{ inputs.directory }} + + - name: Test dart2wasm + if: ${{ inputs.web == 'true' && (matrix.sdk == 'stable' || matrix.sdk == 'beta') && runner.os != 'Windows' }} + run: dart test -p chrome --compiler dart2wasm --test-randomize-ordering-seed=random --chain-stack-traces + shell: bash + working-directory: ${{ inputs.directory }} diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 6218eaa27a..5ae2d469a1 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -32,16 +32,16 @@ jobs: working-directory: ${{ inputs.package }} steps: - uses: actions/checkout@v4 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # pin@v1 if: ${{ inputs.sdk == 'dart' }} - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 if: ${{ inputs.sdk == 'flutter' }} - run: ${{ inputs.sdk }} pub get - run: dart format --set-exit-if-changed ./ - + - name: dart analyze - uses: invertase/github-action-dart-analyzer@1cda5922c6369263b1c7e2fbe281f69704f4d63e # pin@v2.0.0 + uses: invertase/github-action-dart-analyzer@e981b01a458d0bab71ee5da182e5b26687b7101b # pin@v3.0.0 with: annotate: true fatal-infos: true @@ -56,7 +56,7 @@ jobs: # which ignores pubspec.yaml `dependency_overrides`. Because of that, all `release/*` branches are failing, # because the package cannot find the "about to be released" version of our sentry-dart package that it depends on. if: ${{ !startsWith(github.ref, 'refs/heads/release/') && inputs.panaThreshold > 0 }} - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 timeout-minutes: 20 steps: - uses: actions/checkout@v4 @@ -65,7 +65,7 @@ jobs: working-directory: ${{ inputs.package }} run: | sed -i.bak 's|sentry:.*|sentry:\n path: /github/workspace/dart|g' pubspec.yaml - - uses: axel-op/dart-package-analyzer@7a6c3c66bce78d82b729a1ffef2d9458fde6c8d2 # pin@v3 + - uses: axel-op/dart-package-analyzer@56afb7e6737bd2b7cee05382ae7f0e8111138080 # pin@v3 id: analysis with: githubToken: ${{ secrets.GITHUB_TOKEN }} @@ -78,6 +78,6 @@ jobs: PERCENTAGE=$(( $TOTAL * 100 / $TOTAL_MAX )) if (( $PERCENTAGE < ${{ inputs.panaThreshold }} )) then - echo Score too low! + echo "Score too low ($PERCENTAGE % is less than the expected ${{ inputs.panaThreshold }} %)!" exit 1 fi diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 32b805a524..8f2c2f2b10 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -5,85 +5,67 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "dio/**" - - "file/**" - - "sqflite/**" - - "hive/**" - - "drift/**" + paths: + - '!**/*.md' + - '!**/class-diagram.svg' + - '.github/workflows/dart.yml' + - 'dart/**' jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} build: - name: Build ${{matrix.sdk}} on ${{matrix.os}} - runs-on: ${{ matrix.os }} + name: Dart ${{matrix.sdk}} on ${{matrix.os}} + runs-on: ${{ matrix.os }}-latest timeout-minutes: 30 - defaults: - run: - shell: bash - working-directory: ./dart strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - sdk: [stable, beta] - exclude: - - os: windows-latest - sdk: beta - - os: macos-latest - sdk: beta + os: [ubuntu] + sdk: + - '2.18' + - '2.19' + - '3.0' + - '3.1' + - '3.2' + - '3.3' + - '3.4' + - stable + - beta + include: + - os: windows + sdk: stable + - os: macos + sdk: stable steps: - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 - with: - sdk: ${{ matrix.sdk }} - uses: actions/checkout@v4 - - name: Test (VM and browser) - run: | - dart pub get - dart test -p chrome --test-randomize-ordering-seed=random --chain-stack-traces - dart test -p vm --coverage=coverage --test-randomize-ordering-seed=random --chain-stack-traces - dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib + - uses: ./.github/actions/dart-test + with: + directory: dart - - name: Install webdev - if: runner.os != 'Windows' - run: dart pub global activate webdev + - uses: ./.github/actions/coverage + if: runner.os == 'Linux' && matrix.sdk == 'stable' + with: + token: ${{ secrets.CODECOV_TOKEN }} + directory: dart + coverage: sentry + min-coverage: 85 - name: Build example + working-directory: dart/example run: | - cd example dart pub get dart compile aot-snapshot bin/example.dart - - name: Build Web example - if: runner.os != 'Windows' - run: | - cd example_web - dart pub get - webdev build - - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 - if: runner.os == 'Linux' && matrix.sdk == 'stable' - with: - name: sentry - files: ./dart/coverage/lcov.info - - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 - if: runner.os == 'Linux' && matrix.sdk == 'stable' - with: - path: "./dart/coverage/lcov.info" - min_coverage: 85 - analyze: uses: ./.github/workflows/analyze.yml with: package: dart + panaThreshold: 87 diff --git a/.github/workflows/diagrams.yml b/.github/workflows/diagrams.yml index b4f403b78c..19f35ee46f 100644 --- a/.github/workflows/diagrams.yml +++ b/.github/workflows/diagrams.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest name: "Create class diagrams of all packages" steps: - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # pin@v1 with: sdk: stable @@ -47,6 +47,10 @@ jobs: working-directory: ./hive run: lakos . -i "{test/**,example/**}" | dot -Tsvg -o class-diagram.svg + - name: isar + working-directory: ./isar + run: lakos . -i "{test/**,example/**}" | dot -Tsvg -o class-diagram.svg + # Source: https://stackoverflow.com/a/58035262 - name: Extract branch name shell: bash diff --git a/.github/workflows/dio.yml b/.github/workflows/dio.yml index 6b011213e0..8aa8e578cd 100644 --- a/.github/workflows/dio.yml +++ b/.github/workflows/dio.yml @@ -5,21 +5,19 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "flutter/**" - - "file/**" - - "sqflite/**" - - "hive/**" - - "drift/**" + paths: + - '!**/*.md' + - '!**/class-diagram.svg' + - '.github/workflows/dio.yml' + - 'dart/**' + - 'dio/**' jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -27,10 +25,6 @@ jobs: name: Build ${{matrix.sdk}} on ${{matrix.os}} runs-on: ${{ matrix.os }} timeout-minutes: 30 - defaults: - run: - shell: bash - working-directory: ./dio strategy: fail-fast: false matrix: @@ -42,29 +36,19 @@ jobs: - os: macos-latest sdk: beta steps: - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 - with: - sdk: ${{ matrix.sdk }} - uses: actions/checkout@v4 - - name: Test (VM and browser) - run: | - dart pub get - dart test -p chrome --test-randomize-ordering-seed=random --chain-stack-traces - dart test -p vm --coverage=coverage --test-randomize-ordering-seed=random --chain-stack-traces - dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib - - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 - if: runner.os == 'Linux' && matrix.sdk == 'stable' + - uses: ./.github/actions/dart-test with: - name: sentry_dio - files: ./dio/coverage/lcov.info + directory: dio - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 + - uses: ./.github/actions/coverage if: runner.os == 'Linux' && matrix.sdk == 'stable' with: - path: "./dio/coverage/lcov.info" - min_coverage: 81 + token: ${{ secrets.CODECOV_TOKEN }} + directory: dio + coverage: sentry_dio + min-coverage: 81 analyze: uses: ./.github/workflows/analyze.yml diff --git a/.github/workflows/drift.yml b/.github/workflows/drift.yml index 3f2285bb7c..a1aa8ac4bd 100644 --- a/.github/workflows/drift.yml +++ b/.github/workflows/drift.yml @@ -5,20 +5,19 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "flutter/**" - - "dio/**" - - "file/**" - - "sqflite/**" + paths: + - "!**/*.md" + - "!**/class-diagram.svg" + - ".github/workflows/drift.yml" + - "dart/**" + - "drift/**" jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -60,11 +59,14 @@ jobs: # Bad CPU type in executable - os: macos-latest sdk: beta + # Exclude beta for windows for now until the flutter set up action does not fail anymore + - os: windows-latest + sdk: beta steps: - uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 if: ${{ matrix.target == 'android' }} with: java-version: "11" @@ -78,7 +80,7 @@ jobs: sudo apt install -y network-manager upower if: matrix.os == 'ubuntu-latest' && matrix.target == 'linux' - - uses: subosito/flutter-action@48cafc24713cca54bbe03cdc3a423187d413aafa # pin@v2.10.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: channel: ${{ matrix.sdk }} @@ -94,14 +96,15 @@ jobs: cd drift flutter test --coverage --test-randomize-ordering-seed=random - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 + - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v3 if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' with: name: sentry_drift file: ./drift/coverage/lcov.info functionalities: "search" # remove after https://github.com/codecov/codecov-action/issues/600 + token: ${{ secrets.CODECOV_TOKEN }} - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 + - uses: VeryGoodOpenSource/very_good_coverage@c953fca3e24a915e111cc6f55f03f756dcb3964c # pin@v3.0.0 if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' with: path: "./drift/coverage/lcov.info" diff --git a/.github/workflows/e2e_dart.yml b/.github/workflows/e2e_dart.yml index 9deb9a3eaf..4329e6d29c 100644 --- a/.github/workflows/e2e_dart.yml +++ b/.github/workflows/e2e_dart.yml @@ -5,18 +5,15 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "dio/**" - - "flutter/**" - - "file/**" - - "sqflite/**" - - "hive/**" - - "drift/**" + paths: + - "!**/*.md" + - "!**/class-diagram.svg" + - ".github/workflows/e2e_dart.yml" + - "dart/**" + - "e2e_test/**" env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_AUTH_TOKEN_E2E: ${{ secrets.SENTRY_AUTH_TOKEN_E2E }} SENTRY_DIST: 1 jobs: @@ -24,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -40,7 +37,7 @@ jobs: matrix: sdk: [stable, beta] steps: - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # pin@v1 with: sdk: ${{ matrix.sdk }} - uses: actions/checkout@v4 diff --git a/.github/workflows/file.yml b/.github/workflows/file.yml index f9f03aa5cf..6d5cd8f8c9 100644 --- a/.github/workflows/file.yml +++ b/.github/workflows/file.yml @@ -5,21 +5,20 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "flutter/**" - - "dio/**" - - "sqflite/**" - - "hive/**" - - "drift/**" + paths: + - '!**/*.md' + - '!**/class-diagram.svg' + - '.github/workflows/file.yml' + - 'dart/**' + - 'flutter/**' + - 'file/**' jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -27,10 +26,6 @@ jobs: name: Build ${{matrix.sdk}} on ${{matrix.os}} runs-on: ${{ matrix.os }} timeout-minutes: 30 - defaults: - run: - shell: bash - working-directory: ./file strategy: fail-fast: false matrix: @@ -42,28 +37,20 @@ jobs: - os: macos-latest sdk: beta steps: - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 - with: - sdk: ${{ matrix.sdk }} - uses: actions/checkout@v4 - - name: Test VM - run: | - dart pub get - dart test -p vm --coverage=coverage --test-randomize-ordering-seed=random --chain-stack-traces - dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib - - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 - if: runner.os == 'Linux' && matrix.sdk == 'stable' + - uses: ./.github/actions/dart-test with: - name: sentry_file - files: ./file/coverage/lcov.info + directory: file + web: false - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 + - uses: ./.github/actions/coverage if: runner.os == 'Linux' && matrix.sdk == 'stable' with: - path: "./file/coverage/lcov.info" - min_coverage: 55 + token: ${{ secrets.CODECOV_TOKEN }} + directory: file + coverage: sentry_file + min-coverage: 55 analyze: uses: ./.github/workflows/analyze.yml diff --git a/.github/workflows/flutter-symbols.yml b/.github/workflows/flutter-symbols.yml index fba63c6cac..ec374f551f 100644 --- a/.github/workflows/flutter-symbols.yml +++ b/.github/workflows/flutter-symbols.yml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # pin@v1 - run: dart pub get @@ -33,7 +33,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # pin@v1 - run: dart pub get @@ -51,7 +51,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} - name: Upload updated status cache of processed files - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: flutter-symbol-collector-database diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 6c48bf4747..32130d4765 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -5,27 +5,26 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "dio/**" - - "file/**" - - "sqflite/**" - - "hive/**" - - "drift/**" + paths: + - '.github/workflows/flutter.yml' + - '!**/*.md' + - '!**/class-diagram.svg' + - 'dart/**' + - 'flutter/**' + - 'metrics/flutter.properties' jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} build: - name: "${{ matrix.target }} | ${{ matrix.os }} | ${{ matrix.sdk }}" - runs-on: ${{ matrix.os }} + name: '${{ matrix.target }} | ${{ matrix.os }} | ${{ matrix.sdk }}' + runs-on: ${{ matrix.os }}-latest timeout-minutes: 30 defaults: run: @@ -33,57 +32,45 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - target: ["ios", "android", "web", "macos", "linux", "windows"] - sdk: ["stable", "beta"] + target: [android, ios, macos, linux, windows, web] + sdk: [stable, beta] + # Specify which platform to run on for each target: + include: + - target: android + os: ubuntu + - target: ios + os: macos + - target: macos + os: macos + - target: linux + os: ubuntu + - target: windows + os: windows + - target: web + os: ubuntu + # Exclude beta for windows for now until the flutter set up action does not fail anymore exclude: - - os: ubuntu-latest - target: ios - - os: ubuntu-latest - target: macos - - os: ubuntu-latest - target: windows - - os: windows-latest - target: ios - - os: windows-latest - target: android - - os: windows-latest - target: web - - os: windows-latest - target: macos - - os: windows-latest - target: linux - # macos-latest is taking hours due to limited resources - - os: macos-latest - target: android - - os: macos-latest - target: web - - os: macos-latest - target: linux - - os: macos-latest - target: windows - # Bad CPU type in executable - - os: macos-latest + - target: windows sdk: beta steps: - uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 if: ${{ matrix.target == 'android' }} with: - java-version: "11" - distribution: "adopt" + java-version: '11' + distribution: 'adopt' # Install required dependencies for Flutter on Linux on Ubuntu - - name: "Setup Linux" + - name: 'Setup Linux' run: | sudo apt update sudo apt install -y cmake dbus libblkid-dev libgtk-3-dev liblzma-dev ninja-build pkg-config xvfb sudo apt install -y network-manager upower - if: matrix.os == 'ubuntu-latest' && matrix.target == 'linux' + if: matrix.target == 'linux' - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: channel: ${{ matrix.sdk }} @@ -95,31 +82,33 @@ jobs: flutter pub get - name: Test chrome - if: runner.os == 'Linux' + if: matrix.target == 'web' run: | cd flutter flutter test --platform chrome --test-randomize-ordering-seed=random --exclude-tags canvasKit flutter test --platform chrome --test-randomize-ordering-seed=random --tags canvasKit --web-renderer canvaskit - name: Test VM with coverage + if: matrix.target == 'linux' || matrix.target == 'macos' || matrix.target == 'windows' run: | cd flutter flutter test --coverage --test-randomize-ordering-seed=random dart run remove_from_coverage -f coverage/lcov.info -r 'binding.dart' - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 - if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' + - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v3 + if: matrix.sdk == 'stable' && matrix.target == 'linux' with: name: sentry_flutter file: ./flutter/coverage/lcov.info functionalities: "search" # remove after https://github.com/codecov/codecov-action/issues/600 + token: ${{ secrets.CODECOV_TOKEN }} - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 - if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' + - uses: VeryGoodOpenSource/very_good_coverage@c953fca3e24a915e111cc6f55f03f756dcb3964c # pin@v3.0.0 + if: matrix.sdk == 'stable' && matrix.target == 'linux' with: - path: "./flutter/coverage/lcov.info" + path: './flutter/coverage/lcov.info' min_coverage: 90 - exclude: "lib/src/native/cocoa/binding.dart" + exclude: 'lib/src/native/cocoa/binding.dart' - name: Build ${{ matrix.target }} run: | @@ -155,6 +144,7 @@ jobs: with: package: flutter sdk: flutter + panaThreshold: 87 pod-lint: runs-on: macos-latest @@ -189,7 +179,7 @@ jobs: - uses: actions/checkout@v4 - name: ktlint - uses: ScaCap/action-ktlint@0ff81efa49425bd0df46caabd8005aafdc8f2cf2 # pin@1.8.0 + uses: ScaCap/action-ktlint@7bfa4928cf705b83700c91fecc0e1a3a4c0e99ad # pin@1.8.3 with: github_token: ${{ secrets.github_token }} reporter: github-pr-review @@ -202,6 +192,6 @@ jobs: steps: - uses: actions/checkout@v4 # To recreate baseline run: detekt -i flutter/android,flutter/example/android -b flutter/config/detekt-bl.xml -cb - - uses: natiginfo/action-detekt-all@68eb02dd9f2c2686d5026f5957756064424261a9 # pin@1.23.3 + - uses: natiginfo/action-detekt-all@b9daaf58ff7a4885ff92ba612c3ea72bf1abeadb # pin@1.23.6 with: args: -i flutter/android,flutter/example/android --baseline flutter/config/detekt-bl.xml --jvm-target 1.8 --build-upon-default-config --all-rules diff --git a/.github/workflows/flutter_integration_test.yml b/.github/workflows/flutter_integration_test.yml new file mode 100644 index 0000000000..f51af5d341 --- /dev/null +++ b/.github/workflows/flutter_integration_test.yml @@ -0,0 +1,119 @@ +name: flutter integration tests +on: + # Currently broken, enable after fixing + workflow_dispatch + # push: + # branches: + # - main + # - release/** + # pull_request: + # paths-ignore: +# - 'file/**' + +jobs: + cancel-previous-workflow: + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 + with: + access_token: ${{ github.token }} + + test-android: + runs-on: macos-latest + timeout-minutes: 30 + defaults: + run: + working-directory: ./flutter/example + strategy: + fail-fast: false + matrix: + sdk: [ "stable", "beta" ] + steps: + - name: checkout + uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + distribution: "adopt" + java-version: "11" + + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 + with: + channel: ${{ matrix.sdk }} + + - name: flutter upgrade + run: flutter upgrade + + - name: flutter pub get + run: flutter pub get + + - name: Gradle cache + uses: gradle/gradle-build-action@66535aaf56f831b35e3a8481c9c99b665b84dd45 # pin@v3.4.2 + + - name: AVD cache + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-21 + + - name: create AVD and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@77986be26589807b8ebab3fde7bbf5c60dabec32 #pin@v2.31.0 + with: + working-directory: ./flutter/example + api-level: 21 + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: false + arch: x86_64 + profile: Nexus 6 + script: echo 'Generated AVD snapshot for caching.' + + - name: launch android emulator & run android integration test + uses: reactivecircus/android-emulator-runner@77986be26589807b8ebab3fde7bbf5c60dabec32 #pin@v2.31.0 + with: + working-directory: ./flutter/example + api-level: 21 + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + arch: x86_64 + profile: Nexus 6 + script: flutter test integration_test/integration_test.dart --verbose + + test-ios: + runs-on: macos-13 + timeout-minutes: 30 + defaults: + run: + working-directory: ./flutter/example + strategy: + fail-fast: false + matrix: + # 'beta' is flaky because of https://github.com/flutter/flutter/issues/124340 + sdk: [ "stable" ] + steps: + - name: checkout + uses: actions/checkout@v4 + + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 + with: + channel: ${{ matrix.sdk }} + + - name: flutter upgrade + run: flutter upgrade + + - name: flutter pub get + run: flutter pub get + + - name: launch ios simulator + run: | + simulator_id=$(xcrun simctl create sentryPhone com.apple.CoreSimulator.SimDeviceType.iPhone-14 com.apple.CoreSimulator.SimRuntime.iOS-16-2) + xcrun simctl boot ${simulator_id} + + - name: run ios integration test + run: flutter test integration_test/integration_test.dart --verbose diff --git a/.github/workflows/flutter_test.yml b/.github/workflows/flutter_test.yml index 6a1806189f..d5b894ab36 100644 --- a/.github/workflows/flutter_test.yml +++ b/.github/workflows/flutter_test.yml @@ -5,9 +5,12 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "file/**" + paths: + - "!**/*.md" + - "!**/class-diagram.svg" + - ".github/workflows/flutter_test.yml" + - "dart/**" + - "flutter/**" env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} @@ -17,12 +20,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} test-android: - runs-on: macos-latest + runs-on: macos-13 timeout-minutes: 30 defaults: run: @@ -35,12 +38,12 @@ jobs: - name: checkout uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: "adopt" - java-version: "11" + java-version: "17" - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: channel: ${{ matrix.sdk }} @@ -51,10 +54,10 @@ jobs: run: flutter pub get - name: Gradle cache - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@66535aaf56f831b35e3a8481c9c99b665b84dd45 # pin@v3.0.0 - name: AVD cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: avd-cache with: path: | @@ -64,7 +67,7 @@ jobs: - name: create AVD and generate snapshot for caching if: steps.avd-cache.outputs.cache-hit != 'true' - uses: reactivecircus/android-emulator-runner@d94c3fbe4fe6a29e4a5ba47c12fb47677c73656b #pin@v2.28.0 + uses: reactivecircus/android-emulator-runner@77986be26589807b8ebab3fde7bbf5c60dabec32 #pin@v2.31.0 with: working-directory: ./flutter/example api-level: 31 @@ -81,7 +84,7 @@ jobs: run: flutter build apk --debug - name: launch android emulator & run android native test - uses: reactivecircus/android-emulator-runner@d94c3fbe4fe6a29e4a5ba47c12fb47677c73656b #pin@v2.28.0 + uses: reactivecircus/android-emulator-runner@77986be26589807b8ebab3fde7bbf5c60dabec32 #pin@v2.31.0 with: working-directory: ./flutter/example/android api-level: 31 @@ -94,7 +97,7 @@ jobs: script: ./gradlew testDebugUnitTest - name: launch android emulator & run android integration test - uses: reactivecircus/android-emulator-runner@d94c3fbe4fe6a29e4a5ba47c12fb47677c73656b #pin@v2.28.0 + uses: reactivecircus/android-emulator-runner@77986be26589807b8ebab3fde7bbf5c60dabec32 #pin@v2.31.0 with: working-directory: ./flutter/example api-level: 31 @@ -108,7 +111,7 @@ jobs: cocoa: name: "${{ matrix.target }} | ${{ matrix.sdk }}" - runs-on: macos-13 + runs-on: macos-latest-xlarge timeout-minutes: 30 defaults: run: @@ -122,7 +125,7 @@ jobs: - name: checkout uses: actions/checkout@v4 - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: channel: ${{ matrix.sdk }} diff --git a/.github/workflows/format-and-fix.yml b/.github/workflows/format-and-fix.yml index 89fc66cede..e58b9bde7f 100644 --- a/.github/workflows/format-and-fix.yml +++ b/.github/workflows/format-and-fix.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -30,9 +30,9 @@ jobs: working-directory: ${{ matrix.package.name }} steps: - uses: actions/checkout@v4 - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 + - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # pin@v1 if: ${{ matrix.package.sdk == 'dart' }} - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 if: ${{ matrix.package.sdk == 'flutter' }} - run: ${{ matrix.package.sdk }} pub get diff --git a/.github/workflows/hive.yml b/.github/workflows/hive.yml index 42b434d30e..9200a4ab0a 100644 --- a/.github/workflows/hive.yml +++ b/.github/workflows/hive.yml @@ -5,20 +5,19 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "flutter/**" - - "dio/**" - - "file/**" - - "sqflite/**" + paths: + - '!**/*.md' + - '!**/class-diagram.svg' + - '.github/workflows/hive.yml' + - 'dart/**' + - 'hive/**' jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # pin@0.11.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -26,10 +25,6 @@ jobs: name: Build ${{matrix.sdk}} on ${{matrix.os}} runs-on: ${{ matrix.os }} timeout-minutes: 30 - defaults: - run: - shell: bash - working-directory: ./hive strategy: fail-fast: false matrix: @@ -41,28 +36,20 @@ jobs: - os: macos-latest sdk: beta steps: - - uses: dart-lang/setup-dart@6a218f2413a3e78e9087f638a238f6b40893203d # pin@v1 - with: - sdk: ${{ matrix.sdk }} - - uses: actions/checkout@v3 - - - name: Test VM - run: | - dart pub get - dart test -p vm --coverage=coverage --test-randomize-ordering-seed=random --chain-stack-traces - dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib + - uses: actions/checkout@v4 - - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # pin@v3 - if: runner.os == 'Linux' && matrix.sdk == 'stable' + - uses: ./.github/actions/dart-test with: - name: sentry_hive - files: ./hive/coverage/lcov.info + directory: hive + web: false - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 + - uses: ./.github/actions/coverage if: runner.os == 'Linux' && matrix.sdk == 'stable' with: - path: "./hive/coverage/lcov.info" - min_coverage: 55 + token: ${{ secrets.CODECOV_TOKEN }} + directory: hive + coverage: sentry_hive + min-coverage: 55 analyze: uses: ./.github/workflows/analyze.yml diff --git a/.github/workflows/isar.yml b/.github/workflows/isar.yml new file mode 100644 index 0000000000..06d5b18c8e --- /dev/null +++ b/.github/workflows/isar.yml @@ -0,0 +1,117 @@ +name: sentry-isar +on: + push: + branches: + - main + - release/** + pull_request: + paths: + - "!**/*.md" + - "!**/class-diagram.svg" + - ".github/workflows/isar.yml" + - "dart/**" + - "isar/**" + +jobs: + cancel-previous-workflow: + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 + with: + access_token: ${{ github.token }} + + build: + name: ${{ matrix.target }} | ${{ matrix.os }} | ${{ matrix.sdk }} + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + defaults: + run: + shell: bash + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + target: ["ios", "android", "macos", "linux", "windows"] + sdk: ["stable", "beta"] + exclude: + - os: ubuntu-latest + target: ios + - os: ubuntu-latest + target: macos + - os: ubuntu-latest + target: windows + - os: windows-latest + target: ios + - os: windows-latest + target: android + - os: windows-latest + target: macos + - os: windows-latest + target: linux + # macos-latest is taking hours due to limited resources + - os: macos-latest + target: android + - os: macos-latest + target: linux + - os: macos-latest + target: windows + # Bad CPU type in executable + - os: macos-latest + sdk: beta + # Exclude beta for windows for now until the flutter set up action does not fail anymore + - os: windows-latest + sdk: beta + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + if: ${{ matrix.target == 'android' }} + with: + java-version: "11" + distribution: "adopt" + + # Install required dependencies for Flutter on Linux on Ubuntu + - name: "Setup Linux" + run: | + sudo apt update + sudo apt install -y cmake dbus libblkid-dev libgtk-3-dev liblzma-dev ninja-build pkg-config xvfb + sudo apt install -y network-manager upower + if: matrix.os == 'ubuntu-latest' && matrix.target == 'linux' + + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 + with: + channel: ${{ matrix.sdk }} + + - run: flutter upgrade + + - name: Pub Get + run: | + cd isar + flutter pub get + + - name: Test VM with coverage + run: | + cd isar + flutter test -j 1 --coverage --test-randomize-ordering-seed=random + + - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v3 + if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' + with: + name: sentry_isar + file: ./isar/coverage/lcov.info + functionalities: "search" # remove after https://github.com/codecov/codecov-action/issues/600 + token: ${{ secrets.CODECOV_TOKEN }} + + - uses: VeryGoodOpenSource/very_good_coverage@c953fca3e24a915e111cc6f55f03f756dcb3964c # pin@v3.0.0 + if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' + with: + path: "./isar/coverage/lcov.info" + min_coverage: 55 + + analyze: + uses: ./.github/workflows/analyze.yml + with: + package: isar + sdk: flutter diff --git a/.github/workflows/logging.yml b/.github/workflows/logging.yml index 8529b2db12..803b205dd4 100644 --- a/.github/workflows/logging.yml +++ b/.github/workflows/logging.yml @@ -5,21 +5,19 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "dio/**" - - "flutter/**" - - "file/**" - - "sqflite/**" - - "hive/**" - - "drift/**" + paths: + - '!**/*.md' + - '!**/class-diagram.svg' + - '.github/workflows/logging.yml' + - 'dart/**' + - 'logging/**' jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -27,10 +25,6 @@ jobs: name: Build ${{matrix.sdk}} on ${{matrix.os}} runs-on: ${{ matrix.os }} timeout-minutes: 30 - defaults: - run: - shell: bash - working-directory: ./logging strategy: fail-fast: false matrix: @@ -42,28 +36,19 @@ jobs: - os: macos-latest sdk: beta steps: - - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d # pin@v1 - with: - sdk: ${{ matrix.sdk }} - uses: actions/checkout@v4 - - name: Test (VM and browser) - run: | - dart pub get - dart test -p chrome --test-randomize-ordering-seed=random --chain-stack-traces - dart test -p vm --coverage=coverage --test-randomize-ordering-seed=random --chain-stack-traces - dart pub run coverage:format_coverage --lcov --in=coverage --out=coverage/lcov.info --packages=.dart_tool/package_config.json --report-on=lib - - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 - if: runner.os == 'Linux' && matrix.sdk == 'stable' + - uses: ./.github/actions/dart-test with: - name: sentry_logging - files: ./logging/coverage/lcov.info + directory: logging - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 if: runner.os == 'Linux' && matrix.sdk == 'stable' + - uses: ./.github/actions/coverage + if: runner.os == 'Linux' && matrix.sdk == 'stable' with: - path: "./logging/coverage/lcov.info" - min_coverage: 90 + token: ${{ secrets.CODECOV_TOKEN }} + directory: logging + coverage: sentry_logging + min-coverage: 90 analyze: uses: ./.github/workflows/analyze.yml diff --git a/.github/workflows/metrics.yml b/.github/workflows/metrics.yml index 5e461d86eb..c4249f186e 100644 --- a/.github/workflows/metrics.yml +++ b/.github/workflows/metrics.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -53,19 +53,19 @@ jobs: echo "flutter=$version" >> "$GITHUB_OUTPUT" - name: Install Flutter v${{ steps.conf.outputs.flutter }} - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: flutter-version: ${{ steps.conf.outputs.flutter }} - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 if: ${{ matrix.platform == 'android' }} with: - java-version: "11" + java-version: "17" distribution: "adopt" - run: ./metrics/prepare.sh - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: app-plain-cache with: path: ${{ matrix.appPlain }} diff --git a/.github/workflows/min_version_test.yml b/.github/workflows/min_version_test.yml index b9116cdc52..10d5e73bf5 100644 --- a/.github/workflows/min_version_test.yml +++ b/.github/workflows/min_version_test.yml @@ -5,19 +5,20 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "file/**" - - "sqflite/**" - - "hive/**" - - "drift/**" + paths: + - "!**/*.md" + - "!**/class-diagram.svg" + - ".github/workflows/min_version_test.yml" + - "dart/**" + - "flutter/**" + - "min_version_test/**" jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -28,12 +29,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: "adopt" java-version: "11" - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: flutter-version: "3.0.0" @@ -50,7 +51,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: flutter-version: "3.0.0" @@ -67,7 +68,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: flutter-version: "3.0.0" diff --git a/.github/workflows/sqflite.yml b/.github/workflows/sqflite.yml index 5da5b7e557..feac37bd80 100644 --- a/.github/workflows/sqflite.yml +++ b/.github/workflows/sqflite.yml @@ -5,21 +5,19 @@ on: - main - release/** pull_request: - paths-ignore: - - "**/*.md" - - "logging/**" - - "flutter/**" - - "dio/**" - - "file/**" - - "hive/**" - - "drift/**" + paths: + - "!**/*.md" + - "!**/class-diagram.svg" + - ".github/workflows/logging.yml" + - "dart/**" + - "sqflite/**" jobs: cancel-previous-workflow: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs - uses: styfle/cancel-workflow-action@01ce38bf961b4e243a6342cbade0dbc8ba3f0432 # pin@0.12.0 + uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa # pin@0.12.1 with: access_token: ${{ github.token }} @@ -61,11 +59,14 @@ jobs: # Bad CPU type in executable - os: macos-latest sdk: beta + # Exclude beta for windows for now until the flutter set up action does not fail anymore + - os: windows-latest + sdk: beta steps: - uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 if: ${{ matrix.target == 'android' }} with: java-version: "11" @@ -79,7 +80,7 @@ jobs: sudo apt install -y network-manager upower if: matrix.os == 'ubuntu-latest' && matrix.target == 'linux' - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 with: channel: ${{ matrix.sdk }} @@ -95,14 +96,15 @@ jobs: cd sqflite flutter test --coverage --test-randomize-ordering-seed=random - - uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # pin@v3 + - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # pin@v3 if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' with: name: sentry_sqflite file: ./sqflite/coverage/lcov.info functionalities: "search" # remove after https://github.com/codecov/codecov-action/issues/600 + token: ${{ secrets.CODECOV_TOKEN }} - - uses: VeryGoodOpenSource/very_good_coverage@e5c91bc7ce9843e87c800b3bcafdfb86fbe28491 # pin@v2.1.0 + - uses: VeryGoodOpenSource/very_good_coverage@c953fca3e24a915e111cc6f55f03f756dcb3964c # pin@v3.0.0 if: runner.os == 'Linux' && matrix.sdk == 'stable' && matrix.target == 'linux' with: path: "./sqflite/coverage/lcov.info" diff --git a/.github/workflows/testflight.yml b/.github/workflows/testflight.yml new file mode 100644 index 0000000000..0cac9d620f --- /dev/null +++ b/.github/workflows/testflight.yml @@ -0,0 +1,57 @@ +name: Upload to Testflight +on: + push: + branches: + - main + - release/** + pull_request: + paths: + - '.github/workflows/testflight.yml' + +jobs: + upload_to_testflight: + name: Build and Upload to Testflight + runs-on: macos-13 + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 + - run: xcodes select 15.0.1 + - uses: ruby/setup-ruby@3a77c29278ae80936b4cb030fefc7d21c96c786f # pin@v1.185.0 + with: + ruby-version: '2.7.5' + bundler-cache: true + + - name: flutter + working-directory: ./flutter/example + run: | + flutter upgrade + flutter pub get + flutter build ios --no-codesign --obfuscate --split-debug-info=. + + - name: Install Fastlane + working-directory: ./flutter/example/ios + run: bundle install + + - name: Bump, Build & Upload App to TestFlight + working-directory: ./flutter/example/ios + env: + APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }} + APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} + APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }} + FASTLANE_BUNDLE_VERSION: ${{ github.run_number }} + FASTLANE_KEYCHAIN_PASSWORD: ${{ secrets.FASTLANE_KEYCHAIN_PASSWORD }} + MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }} + MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_LOG_LEVEL: DEBUG + run: | + bundle exec fastlane bump_build_number + bundle exec fastlane build_release + bundle exec fastlane upload_testflight + + - name: Upload Symbols to Sentry + working-directory: ./flutter/example + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: flutter packages pub run sentry_dart_plugin \ No newline at end of file diff --git a/.github/workflows/web-example-ghpages.yml b/.github/workflows/web-example-ghpages.yml index 106c52615d..afdcb154c6 100644 --- a/.github/workflows/web-example-ghpages.yml +++ b/.github/workflows/web-example-ghpages.yml @@ -14,7 +14,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@2783a3f08e1baf891508463f8c6653c258246225 # pin@v2.12.0 + - uses: subosito/flutter-action@44ac965b96f18d999802d4b807e3256d5a3f9fa1 # pin@v2.16.0 - uses: bluefireteam/flutter-gh-pages@57815b17b371455ec1a98f075b71b4c6ba0a938c # pin@v8 with: workingDir: flutter/example diff --git a/.gitignore b/.gitignore index 60bf635a0c..2965c68572 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ pubspec.lock build/ .cxx/ .vscode/ - +.fvm/ .test_coverage.dart dart/coverage/* @@ -24,6 +24,7 @@ flutter/coverage/* sqflite/coverage/* drift/coverage/* hive/coverage/* +isar/coverage/* pubspec.lock Podfile.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index 20779133ae..75b24a6314 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,331 @@ # Changelog +## 8.3.0 + +### Fixes + +- Load contexts integration not setting `SentryUser` ([#2089](https://github.com/getsentry/sentry-dart/pull/2089)) +- Change app start span description from `Cold start` to `Cold Start` and `Warm start` to `Warm Start` ([#2076](https://github.com/getsentry/sentry-dart/pull/2076)) +- Parse `PlatformException` from details instead of message ([#2052](https://github.com/getsentry/sentry-dart/pull/2052)) + +### Dependencies + +- Bump `sqflite` minimum version from `^2.0.0` to `^2.2.8` ([#2075](https://github.com/getsentry/sentry-dart/pull/2075)) + - This is not a breaking change since we are using api internally that is only valid from that version. +- Bump Cocoa SDK from v8.25.2 to v8.29.0 ([#2060](https://github.com/getsentry/sentry-dart/pull/2060), [#2092](https://github.com/getsentry/sentry-dart/pull/2092), [#2100](https://github.com/getsentry/sentry-dart/pull/2100)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8290) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.25.2...8.29.0) +- Bump Android SDK from v7.9.0 to v7.10.0 ([#2090](https://github.com/getsentry/sentry-dart/pull/2090)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7100) + - [diff](https://github.com/getsentry/sentry-java/compare/7.9.0...7.10.0) + +## 8.2.0 + +### Enhancements + +- Include sentry frames in stacktraces to enable SDK crash detection ([#2050](https://github.com/getsentry/sentry-dart/pull/2050)) + +### Fixes + +- Event processor blocking transactions from being sent if `autoAppStart` is false ([#2028](https://github.com/getsentry/sentry-dart/pull/2028)) + +### Features + +- Create app start transaction when no `SentryNavigatorObserver` is present ([#2017](https://github.com/getsentry/sentry-dart/pull/2017)) +- Adds native spans to app start transaction ([#2027](https://github.com/getsentry/sentry-dart/pull/2027)) +- Adds app start spans to first transaction ([#2009](https://github.com/getsentry/sentry-dart/pull/2009)) + +### Fixes + +- Fix `PlatformException` title parsing ([#2033](https://github.com/getsentry/sentry-dart/pull/2033)) + +### Dependencies + +- Bump Cocoa SDK from v8.25.0 to v8.25.2 ([#2042](https://github.com/getsentry/sentry-dart/pull/2042)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8252) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.25.0...8.25.2) +- Bump Android SDK from v7.8.0 to v7.9.0 ([#2049](https://github.com/getsentry/sentry-dart/pull/2049)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#790) + - [diff](https://github.com/getsentry/sentry-java/compare/7.8.0...7.9.0) + +## 8.1.0 + +### Features + +- Set snapshot to `true` if stacktrace is not provided ([#2000](https://github.com/getsentry/sentry-dart/pull/2000)) + - If the stacktrace is not provided, the Sentry SDK will fetch the current stacktrace via `StackTrace.current` and the snapshot will be set to `true` - **this may change the grouping behavior** + - `snapshot = true` means it's a synthetic exception, reflecting the current state of the thread rather than the stack trace of a real exception + +### Fixes + +- Timing metric aggregates metrics in the created span ([#1994](https://github.com/getsentry/sentry-dart/pull/1994)) + +### Dependencies + +- Bump Cocoa SDK from v8.21.0 to v8.25.0 ([#2018](https://github.com/getsentry/sentry-dart/pull/2018)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8250) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.21.0...8.25.0) +- Expand dependency range of `package_info_plus` to allow an open range starting from version 1 ([#2010](https://github.com/getsentry/sentry-dart/pull/2010)) + +## 8.0.0 + +This release contains breaking changes, please read the changelog carefully. + +*Changes from the latest v7 release are included in this major release* + +### Breaking Changes + +- Bump iOS minimum deployment target from **11** to **12** ([#1821](https://github.com/getsentry/sentry-dart/pull/1821)) +- Mark exceptions not handled by the user as `handled: false` ([#1535](https://github.com/getsentry/sentry-dart/pull/1535)) + - This will affect your release health data, and is therefore considered a breaking change. +- Refrain from overwriting the span status for unfinished spans ([#1577](https://github.com/getsentry/sentry-dart/pull/1577)) + - Older self-hosted sentry instances will drop transactions containing unfinished spans. + - This change was introduced in [relay/#1690](https://github.com/getsentry/relay/pull/1690) and released with [22.12.0](https://github.com/getsentry/relay/releases/tag/22.12.0) +- Do not leak extensions of external classes ([#1576](https://github.com/getsentry/sentry-dart/pull/1576)) +- Make `hint` non-nullable in `BeforeSendCallback`, `BeforeBreadcrumbCall` and `EventProcessor` ([#1574](https://github.com/getsentry/sentry-dart/pull/1574)) + - This will affect your callbacks, making this a breaking change. +- Load Device Contexts from Sentry Java ([#1616](https://github.com/getsentry/sentry-dart/pull/1616)) + - Now the device context from Android is available in `BeforeSendCallback` +- Set ip_address to {{auto}} by default, even if sendDefaultPII is disabled ([#1665](https://github.com/getsentry/sentry-dart/pull/1665)) + - Instead use the "Prevent Storing of IP Addresses" option in the "Security & Privacy" project settings on sentry.io + +### Features + +- Add support for exception aggregates ([#1866](https://github.com/getsentry/sentry-dart/pull/1866)) + +## 7.20.0 + +### Build + +- Bump compileSdkVersion to 34 in Gradle buildscripts ([#1980](https://github.com/getsentry/sentry-dart/pull/1980)) + +### Features + +- Add textScale(r) value to Flutter context ([#1886](https://github.com/getsentry/sentry-dart/pull/1886)) + +### Dependencies + +- Expand dependency range of `package_info_plus` to include major version 7 ([#1984](https://github.com/getsentry/sentry-dart/pull/1984)) +- Bump Android SDK from v7.6.0 to v7.8.0 ([#1977](https://github.com/getsentry/sentry-dart/pull/1977)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#780) + - [diff](https://github.com/getsentry/sentry-java/compare/7.6.0...7.8.0) + +## 7.19.0 + +### Features + +- Experimental: Add support for Sentry Developer Metrics ([#1940](https://github.com/getsentry/sentry-dart/pull/1940), [#1949](https://github.com/getsentry/sentry-dart/pull/1949), [#1954](https://github.com/getsentry/sentry-dart/pull/1954), [#1958](https://github.com/getsentry/sentry-dart/pull/1958)) + Use the Metrics API to track processing time, download sizes, user signups, and conversion rates and correlate them back to tracing data in order to get deeper insights and solve issues faster. Our API supports counters, distributions, sets, gauges and timers, and it's easy to get started: + ```dart + Sentry.metrics() + .increment( + 'button_login_click', // key + value: 1.0, + unit: null, + tags: {"provider": "e-mail"} + ); + ``` + To learn more about Sentry Developer Metrics, head over to our [Dart](https://docs.sentry.io/platforms/dart/metrics/) and [Flutter](https://docs.sentry.io/platforms/flutter/metrics/) docs page. + +### Dependencies + +- Expand `package_info_plus` version range to `6.0.0` ([#1948](https://github.com/getsentry/sentry-dart/pull/1948)) + +### Improvements + +- Set `sentry_flutter.podspec` version from `pubspec.yaml` ([#1941](https://github.com/getsentry/sentry-dart/pull/1941)) + +## 7.18.0 + +### Features + +- Add TTFD (time to full display), which allows you to measure the time it takes to render the full screen ([#1920](https://github.com/getsentry/sentry-dart/pull/1920)) + - Requires using the [routing instrumentation](https://docs.sentry.io/platforms/flutter/integrations/routing-instrumentation/). + - Set `enableTimeToFullDisplayTracing = true` in your `SentryFlutterOptions` to enable TTFD + - Manually report the end of the full display by calling `SentryFlutter.reportFullyDisplayed()` + - If not reported within 30 seconds, the span will be automatically finish with the status `deadline_exceeded` +- Add TTID (time to initial display), which allows you to measure the time it takes to render the first frame of your screen ([#1910](https://github.com/getsentry/sentry-dart/pull/1910)) + - Requires using the [routing instrumentation](https://docs.sentry.io/platforms/flutter/integrations/routing-instrumentation/). + - Introduces two modes: + - `automatic` mode is enabled by default for all screens and will yield only an approximation result. + - `manual` mode requires manual instrumentation and will yield a more accurate result. + - To use `manual` mode, you need to wrap your desired widget: `SentryDisplayWidget(child: MyScreen())`. + - You can mix and match both modes in your app. + - Other significant fixes + - `didPop` doesn't trigger a new transaction + - Change transaction operation name to `ui.load` instead of `navigation` +- Add override `captureFailedRequests` option ([#1931](https://github.com/getsentry/sentry-dart/pull/1931)) + - The `dio` integration and `SentryHttpClient` now take an additional `captureFailedRequests` option. + - This is useful if you want to disable this option on native and only enable it on `dio` for example. + +### Improvements + +- Update root name for navigator observer ([#1934](https://github.com/getsentry/sentry-dart/pull/1934)) + - The root name for transactions is now `root /` instead of `root ("/")`. + +### Dependencies + +- Bump Android SDK from v7.5.0 to v7.6.0 ([#1927](https://github.com/getsentry/sentry-dart/pull/1927)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#760) + - [diff](https://github.com/getsentry/sentry-java/compare/7.5.0...7.6.0) + +## 7.17.0 + +### Fixes + +- Fix transaction end timestamp trimming ([#1916](https://github.com/getsentry/sentry-dart/pull/1916)) + - Transaction end timestamps are now correctly trimmed to the latest child span end timestamp +- remove transitive dart:io reference for web ([#1898](https://github.com/getsentry/sentry-dart/pull/1898)) + +### Features + +- Use `recordHttpBreadcrumbs` to set iOS `enableNetworkBreadcrumbs` ([#1884](https://github.com/getsentry/sentry-dart/pull/1884)) +- Apply `beforeBreadcrumb` on native iOS crumbs ([#1914](https://github.com/getsentry/sentry-dart/pull/1914)) +- Add `maxQueueSize` to limit the number of unawaited events sent to Sentry ([#1868](https://github.com/getsentry/sentry-dart/pull/1868)) + +### Improvements + +- App start is now fetched within integration instead of event processor ([#1905](https://github.com/getsentry/sentry-dart/pull/1905)) + +### Dependencies + +- Bump Cocoa SDK from v8.20.0 to v8.21.0 ([#1909](https://github.com/getsentry/sentry-dart/pull/1909)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8210) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.20.0...8.21.0) +- Bump Android SDK from v7.3.0 to v7.5.0 ([#1907](https://github.com/getsentry/sentry-dart/pull/1907)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#750) + - [diff](https://github.com/getsentry/sentry-java/compare/7.3.0...7.5.0) + +## 7.16.1 + +### Fixes + +- Remove Flutter dependency from Drift integration ([#1867](https://github.com/getsentry/sentry-dart/pull/1867)) +- Remove dead code, cold start bool is now always present ([#1861](https://github.com/getsentry/sentry-dart/pull/1861)) +- Fix iOS "Arithmetic Overflow" ([#1874](https://github.com/getsentry/sentry-dart/pull/1874)) + +### Dependencies + +- Bump Cocoa SDK from v8.19.0 to v8.20.0 ([#1856](https://github.com/getsentry/sentry-dart/pull/1856)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8200) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.19.0...8.20.0) + +## 8.0.0-beta.2 + +### Breaking Changes + +- Bump iOS minimum deployment target from **11** to **12** ([#1821](https://github.com/getsentry/sentry-dart/pull/1821)) +- Mark exceptions not handled by the user as `handled: false` ([#1535](https://github.com/getsentry/sentry-dart/pull/1535)) + - This will affect your release health data, and is therefore considered a breaking change. +- Refrain from overwriting the span status for unfinished spans ([#1577](https://github.com/getsentry/sentry-dart/pull/1577)) + - Older self-hosted sentry instances will drop transactions containing unfinished spans. + - This change was introduced in [relay/#1690](https://github.com/getsentry/relay/pull/1690) and released with [22.12.0](https://github.com/getsentry/relay/releases/tag/22.12.0) +- Do not leak extensions of external classes ([#1576](https://github.com/getsentry/sentry-dart/pull/1576)) +- Make `hint` non-nullable in `BeforeSendCallback`, `BeforeBreadcrumbCall` and `EventProcessor` ([#1574](https://github.com/getsentry/sentry-dart/pull/1574)) + - This will affect your callbacks, making this a breaking change. +- Load Device Contexts from Sentry Java ([#1616](https://github.com/getsentry/sentry-dart/pull/1616)) + - Now the device context from Android is available in `BeforeSendCallback` +- Set ip_address to {{auto}} by default, even if sendDefaultPII is disabled ([#1665](https://github.com/getsentry/sentry-dart/pull/1665)) + - Instead use the "Prevent Storing of IP Addresses" option in the "Security & Privacy" project settings on sentry.io + +### Fixes + +- Remove Flutter dependency from Drift integration ([#1867](https://github.com/getsentry/sentry-dart/pull/1867)) +- Remove dead code, cold start bool is now always present ([#1861](https://github.com/getsentry/sentry-dart/pull/1861)) +- Fix iOS "Arithmetic Overflow" ([#1874](https://github.com/getsentry/sentry-dart/pull/1874)) + +### Dependencies + +- Bump Cocoa SDK from v8.19.0 to v8.20.0 ([#1856](https://github.com/getsentry/sentry-dart/pull/1856)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8200) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.19.0...8.20.0) + +## 8.0.0-beta.1 + +This release is replaced by `8.0.0-beta.2` + +## 7.16.0 + +### Features + +- Add `SentryWidget` ([#1846](https://github.com/getsentry/sentry-dart/pull/1846)) + - Prefer to use `SentryWidget` now instead of `SentryScreenshotWidget` and `SentryUserInteractionWidget` directly +- Performance monitoring support for Isar ([#1726](https://github.com/getsentry/sentry-dart/pull/1726)) +- Tracing without performance for Dio integration ([#1837](https://github.com/getsentry/sentry-dart/pull/1837)) +- Accept `Map` in `Hint` class ([#1807](https://github.com/getsentry/sentry-dart/pull/1807)) + - Please check if everything works as expected when using `Hint` + - Factory constructor `Hint.withMap(Map map)` now takes `Map` instead of `Map` + - Method `hint.addAll(Map keysAndValues)` now takes `Map` instead of `Map` + - Method `set(String key, dynamic value)` now takes value of `dynamic` instead of `Object` + - Method `hint.get(String key)` now returns `dynamic` instead of `Object?` + +### Dependencies + +- Bump Cocoa SDK from v8.18.0 to v8.19.0 ([#1803](https://github.com/getsentry/sentry-dart/pull/1844)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8190) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.18.0...8.19.0) +- Bump Android SDK from v7.2.0 to v7.3.0 ([#1852](https://github.com/getsentry/sentry-dart/pull/1852)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#730) + - [diff](https://github.com/getsentry/sentry-java/compare/7.2.0...7.3.0) + +## 7.15.0 + +### Features + +- Add [Spotlight](https://spotlightjs.com/about/) support ([#1786](https://github.com/getsentry/sentry-dart/pull/1786)) + - Set `options.spotlight = Spotlight(enabled: true)` to enable Spotlight +- Add `ConnectivityIntegration` for web ([#1765](https://github.com/getsentry/sentry-dart/pull/1765)) + - We only get the info if online/offline on web platform. The added breadcrumb is set to either `wifi` or `none`. +- Add isar breadcrumbs ([#1800](https://github.com/getsentry/sentry-dart/pull/1800)) +- Starting with Flutter 3.16, Sentry adds the [`appFlavor`](https://api.flutter.dev/flutter/services/appFlavor-constant.html) to the `flutter_context` ([#1799](https://github.com/getsentry/sentry-dart/pull/1799)) +- Add beforeScreenshotCallback to SentryFlutterOptions ([#1805](https://github.com/getsentry/sentry-dart/pull/1805)) +- Add support for `readTransaction` in `sqflite` ([#1819](https://github.com/getsentry/sentry-dart/pull/1819)) + +### Dependencies + +- Bump Android SDK from v7.0.0 to v7.2.0 ([#1788](https://github.com/getsentry/sentry-dart/pull/1788), [#1815](https://github.com/getsentry/sentry-dart/pull/1815)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#720) + - [diff](https://github.com/getsentry/sentry-java/compare/7.0.0...7.2.0) +- Bump Cocoa SDK from v8.17.2 to v8.18.0 ([#1803](https://github.com/getsentry/sentry-dart/pull/1803)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8180) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.17.2...8.18.0) + +## 7.14.0 + +- Add option to opt out of fatal level for automatically collected errors ([#1738](https://github.com/getsentry/sentry-dart/pull/1738)) + +### Fixes + +- Add debug_meta to all events ([#1756](https://github.com/getsentry/sentry-dart/pull/1756)) + - Fixes obfuscated stacktraces when `captureMessage` or `captureEvent` is called with `attachStacktrace` option + +### Features + +- Add option to opt out of fatal level for automatically collected errors ([#1738](https://github.com/getsentry/sentry-dart/pull/1738)) +- Add `Hive` breadcrumbs ([#1773](https://github.com/getsentry/sentry-dart/pull/1773)) + +### Dependencies + +- Bump Android SDK from v6.34.0 to v7.0.0 ([#1768](https://github.com/getsentry/sentry-dart/pull/1768)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#700) + - [diff](https://github.com/getsentry/sentry-java/compare/6.34.0...7.0.0) +- Bump Cocoa SDK from v8.15.2 to v8.17.2 ([#1761](https://github.com/getsentry/sentry-dart/pull/1761), [#1771](https://github.com/getsentry/sentry-dart/pull/1771), [#1787](https://github.com/getsentry/sentry-dart/pull/1787)) + - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8172) + - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.15.2...8.17.2) + +## 7.13.2 + +### Fixes + +- Fix SIGSEV, SIGABRT and SIGBUS crashes happening after/around the August Google Play System update, see [#2955](https://github-redirect.dependabot.com/getsentry/sentry-java/issues/2955) for more details (fix provided by Native SDK bump) + +### Dependencies + +- Update package-info-plus constraint to include 5.0.1 ([#1749](https://github.com/getsentry/sentry-dart/pull/1749)) +- Bump Android SDK from v6.33.1 to v6.34.0 ([#1746](https://github.com/getsentry/sentry-dart/pull/1746)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#6340) + - [diff](https://github.com/getsentry/sentry-java/compare/6.33.1...6.34.0) + ## 7.13.1 ### Fixes @@ -8,7 +334,7 @@ ## 7.13.0 -### Fixes +### Fixes - Fixes setting the correct locale to contexts with navigatorKey ([#1724](https://github.com/getsentry/sentry-dart/pull/1724)) - If you have a selected locale in e.g MaterialApp, this fix will retrieve the correct locale for the event context. @@ -234,7 +560,7 @@ ### Features -- Add `SentryIOOverridesIntegration` that automatically wraps `File` into `SentryFile` ([#1362](https://github.com/getsentry/sentry-dart/pull/1362)) +- Add `SentryIOOverridesIntegration` that automatically wraps `File` into `SentryFile` ([#1362](https://github.com/getsentry/sentry-dart/pull/1362)) ```dart import 'package:sentry_file/sentry_file.dart'; @@ -923,8 +1249,8 @@ options.beforeSend = (event, {hint}) { ### Fixes -* Scope.clone incorrectly accesses tags ([#978](https://github.com/getsentry/sentry-dart/pull/978)) -* beforeBreadcrumb was not adding the mutated breadcrumb ([#982](https://github.com/getsentry/sentry-dart/pull/982)) +- Scope.clone incorrectly accesses tags ([#978](https://github.com/getsentry/sentry-dart/pull/978)) +- beforeBreadcrumb was not adding the mutated breadcrumb ([#982](https://github.com/getsentry/sentry-dart/pull/982)) ### Features @@ -939,25 +1265,26 @@ options.beforeSend = (event, {hint}) { ### Features -* Bump Flutter's min. supported version from 1.17.0 to 2.0.0 ([#966](https://github.com/getsentry/sentry-dart/pull/966)) +- Bump Flutter's min. supported version from 1.17.0 to 2.0.0 ([#966](https://github.com/getsentry/sentry-dart/pull/966)) This should not break anything since the Dart's min. version is already 2.12.0 and Flutter 2.0.0 uses Dart 2.12.0 ### Fixes -* Back compatibility of Object.hash for Dart 2.12.0 ([#966](https://github.com/getsentry/sentry-dart/pull/966)) -* Fix back compatibility for OnErrorIntegration integration ([#965](https://github.com/getsentry/sentry-dart/pull/965)) +- Back compatibility of Object.hash for Dart 2.12.0 ([#966](https://github.com/getsentry/sentry-dart/pull/966)) +- Fix back compatibility for OnErrorIntegration integration ([#965](https://github.com/getsentry/sentry-dart/pull/965)) ## 6.8.1 ### Fixes -* `Scope#setContexts` pasing a List value would't not work ([#932](https://github.com/getsentry/sentry-dart/pull/932)) +- `Scope#setContexts` pasing a List value would't not work ([#932](https://github.com/getsentry/sentry-dart/pull/932)) ### Features -* Add integration for `PlatformDispatcher.onError` ([#915](https://github.com/getsentry/sentry-dart/pull/915)) -- Bump Cocoa SDK to v7.22.0 ([#960](https://github.com/getsentry/sentry-dart/pull/960)) +- Add integration for `PlatformDispatcher.onError` ([#915](https://github.com/getsentry/sentry-dart/pull/915)) + +* Bump Cocoa SDK to v7.22.0 ([#960](https://github.com/getsentry/sentry-dart/pull/960)) - [changelog](https://github.com/getsentry/sentry-cocoa/blob/master/CHANGELOG.md#7220) - [diff](https://github.com/getsentry/sentry-cocoa/compare/7.21.0...7.22.0) @@ -965,23 +1292,23 @@ This should not break anything since the Dart's min. version is already 2.12.0 a ### Fixes -* Missing OS context for iOS events ([#958](https://github.com/getsentry/sentry-dart/pull/958)) -* Fix: `Scope#clone` calls the Native bridges again via the `scopeObserver` ([#959](https://github.com/getsentry/sentry-dart/pull/959)) +- Missing OS context for iOS events ([#958](https://github.com/getsentry/sentry-dart/pull/958)) +- Fix: `Scope#clone` calls the Native bridges again via the `scopeObserver` ([#959](https://github.com/getsentry/sentry-dart/pull/959)) ### Features -* Dio Integration adds response data ([#934](https://github.com/getsentry/sentry-dart/pull/934)) +- Dio Integration adds response data ([#934](https://github.com/getsentry/sentry-dart/pull/934)) ## 6.7.0 ### Fixes -* Maps with Key Object, Object would fail during serialization if not String, Object ([#935](https://github.com/getsentry/sentry-dart/pull/935)) -* Breadcrumbs "Concurrent Modification" ([#948](https://github.com/getsentry/sentry-dart/pull/948)) -* Duplicative Screen size changed breadcrumbs ([#888](https://github.com/getsentry/sentry-dart/pull/888)) -* Duplicated Android Breadcrumbs with no Mechanism ([#954](https://github.com/getsentry/sentry-dart/pull/954)) -* Fix windows native method need default result ([#943](https://github.com/getsentry/sentry-dart/pull/943)) -* Add request instead of response data to `SentryRequest` in `DioEventProcessor` [#933](https://github.com/getsentry/sentry-dart/pull/933) +- Maps with Key Object, Object would fail during serialization if not String, Object ([#935](https://github.com/getsentry/sentry-dart/pull/935)) +- Breadcrumbs "Concurrent Modification" ([#948](https://github.com/getsentry/sentry-dart/pull/948)) +- Duplicative Screen size changed breadcrumbs ([#888](https://github.com/getsentry/sentry-dart/pull/888)) +- Duplicated Android Breadcrumbs with no Mechanism ([#954](https://github.com/getsentry/sentry-dart/pull/954)) +- Fix windows native method need default result ([#943](https://github.com/getsentry/sentry-dart/pull/943)) +- Add request instead of response data to `SentryRequest` in `DioEventProcessor` [#933](https://github.com/getsentry/sentry-dart/pull/933) ### Features @@ -996,7 +1323,7 @@ This should not break anything since the Dart's min. version is already 2.12.0 a ### Fixes -* Context Escape with ScopeCallback ([#925](https://github.com/getsentry/sentry-dart/pull/925)) +- Context Escape with ScopeCallback ([#925](https://github.com/getsentry/sentry-dart/pull/925)) ## 6.6.2 @@ -1011,419 +1338,419 @@ This should not break anything since the Dart's min. version is already 2.12.0 a ### Fixes -* Send DidBecomeActiveNotification when OOM enabled (#905) -* `dio.addSentry` hangs if `dsn` is empty and SDK NoOp ([#920](https://github.com/getsentry/sentry-dart/pull/920)) -* addBreadcrumb throws on Android API < 24 because of NewApi usage ([#923](https://github.com/getsentry/sentry-dart/pull/923)) -* [`sentry_dio`](https://pub.dev/packages/sentry_dio) is promoted to GA and not experimental anymore ([#914](https://github.com/getsentry/sentry-dart/pull/914)) +- Send DidBecomeActiveNotification when OOM enabled (#905) +- `dio.addSentry` hangs if `dsn` is empty and SDK NoOp ([#920](https://github.com/getsentry/sentry-dart/pull/920)) +- addBreadcrumb throws on Android API < 24 because of NewApi usage ([#923](https://github.com/getsentry/sentry-dart/pull/923)) +- [`sentry_dio`](https://pub.dev/packages/sentry_dio) is promoted to GA and not experimental anymore ([#914](https://github.com/getsentry/sentry-dart/pull/914)) ## 6.6.1 ### Fixes -* Filter out app starts with more than 60s (#895) +- Filter out app starts with more than 60s (#895) ## 6.6.0 ### Fixes -* Bump: Sentry-Cocoa to 7.18.0 and Sentry-Android to 6.1.2 (#892) -* Fix: Add missing iOS contexts (#761) -* Fix serialization of threads (#844) -* Fix: `SentryAssetBundle` on Flutter >= 3.1 (#877) +- Bump: Sentry-Cocoa to 7.18.0 and Sentry-Android to 6.1.2 (#892) +- Fix: Add missing iOS contexts (#761) +- Fix serialization of threads (#844) +- Fix: `SentryAssetBundle` on Flutter >= 3.1 (#877) ### Features -* Feat: Client Reports (#829) -* Feat: Allow manual init of the Native SDK (#765) -* Feat: Attach Isolate name to thread context (#847) -* Feat: Add Android thread to platform stacktraces (#853) -* Feat: Sync Scope to Native (#858) +- Feat: Client Reports (#829) +- Feat: Allow manual init of the Native SDK (#765) +- Feat: Attach Isolate name to thread context (#847) +- Feat: Add Android thread to platform stacktraces (#853) +- Feat: Sync Scope to Native (#858) ### Sentry Self-hosted Compatibility -* Starting with version `6.6.0` of `sentry`, [Sentry's version >= v21.9.0](https://github.com/getsentry/self-hosted/releases) is required or you have to manually disable sending client reports via the `sendClientReports` option. This only applies to self-hosted Sentry. If you are using [sentry.io](https://sentry.io), no action is needed. +- Starting with version `6.6.0` of `sentry`, [Sentry's version >= v21.9.0](https://github.com/getsentry/self-hosted/releases) is required or you have to manually disable sending client reports via the `sendClientReports` option. This only applies to self-hosted Sentry. If you are using [sentry.io](https://sentry.io), no action is needed. ## 6.6.0-beta.4 -* Bump: Sentry-Cocoa to 7.17.0 and Sentry-Android to 6.1.1 (#891) +- Bump: Sentry-Cocoa to 7.17.0 and Sentry-Android to 6.1.1 (#891) ## 6.6.0-beta.3 -* Bump: Sentry-Cocoa to 7.16.1 (#886) +- Bump: Sentry-Cocoa to 7.16.1 (#886) ## 6.6.0-beta.2 -* Fix: Add user setter back in the scope (#883) -* Fix: clear method sets all properties synchronously (#882) +- Fix: Add user setter back in the scope (#883) +- Fix: clear method sets all properties synchronously (#882) ## 6.6.0-beta.1 -* Feat: Sync Scope to Native (#858) +- Feat: Sync Scope to Native (#858) ## 6.6.0-alpha.3 -* Feat: Attach Isolate name to thread context (#847) -* Fix: `SentryAssetBundle` on Flutter >= 3.1 (#877) -* Feat: Add Android thread to platform stacktraces (#853) -* Fix: Rename auto initialize property (#857) -* Bump: Sentry-Android to 6.0.0 (#879) +- Feat: Attach Isolate name to thread context (#847) +- Fix: `SentryAssetBundle` on Flutter >= 3.1 (#877) +- Feat: Add Android thread to platform stacktraces (#853) +- Fix: Rename auto initialize property (#857) +- Bump: Sentry-Android to 6.0.0 (#879) ## 6.6.0-alpha.2 -* Fix serialization of threads (#844) -* Feat: Allow manual init of the Native SDK (#765) +- Fix serialization of threads (#844) +- Feat: Allow manual init of the Native SDK (#765) ## 6.6.0-alpha.1 -* Feat: Client Reports (#829) -* Fix: Add missing iOS contexts (#761) +- Feat: Client Reports (#829) +- Fix: Add missing iOS contexts (#761) ### Sentry Self-hosted Compatibility -* Starting with version `6.6.0` of `sentry`, [Sentry's version >= v21.9.0](https://github.com/getsentry/self-hosted/releases) is required or you have to manually disable sending client reports via the `sendClientReports` option. This only applies to self-hosted Sentry. If you are using [sentry.io](https://sentry.io), no action is needed. +- Starting with version `6.6.0` of `sentry`, [Sentry's version >= v21.9.0](https://github.com/getsentry/self-hosted/releases) is required or you have to manually disable sending client reports via the `sendClientReports` option. This only applies to self-hosted Sentry. If you are using [sentry.io](https://sentry.io), no action is needed. ## 6.5.1 -* Update event contexts (#838) +- Update event contexts (#838) ## 6.5.0 -* No documented changes. +- No documented changes. ## 6.5.0-beta.2 -* Fix: Do not set the transaction to scope if no op (#828) +- Fix: Do not set the transaction to scope if no op (#828) ## 6.5.0-beta.1 -* No documented changes. +- No documented changes. ## 6.5.0-alpha.3 -* Feat: Support for platform stacktraces on Android (#788) +- Feat: Support for platform stacktraces on Android (#788) ## 6.5.0-alpha.2 -* Bump: Sentry-Android to 5.7.0 and Sentry-Cocoa to 7.11.0 (#796) -* Fix: Dio event processor safelly bails if no DioError in the exception list (#795) +- Bump: Sentry-Android to 5.7.0 and Sentry-Cocoa to 7.11.0 (#796) +- Fix: Dio event processor safelly bails if no DioError in the exception list (#795) ## 6.5.0-alpha.1 -* Feat: Mobile Vitals - Native App Start (#749) -* Feat: Mobile Vitals - Native Frames (#772) +- Feat: Mobile Vitals - Native App Start (#749) +- Feat: Mobile Vitals - Native Frames (#772) ## 6.4.0 ### Various fixes & improvements -* Fix: Missing userId on iOS when userId is not set (#782) by @marandaneto -* Allow to set startTimestamp & endTimestamp manually to SentrySpan (#676) by @fatihergin +- Fix: Missing userId on iOS when userId is not set (#782) by @marandaneto +- Allow to set startTimestamp & endTimestamp manually to SentrySpan (#676) by @fatihergin ## 6.4.0-beta.3 -* Feat: Allow to set startTimestamp & endTimestamp manually to SentrySpan (#676) -* Bump: Sentry-Cocoa to 7.10.0 (#777) -* Feat: Additional Dart/Flutter context information (#778) -* Bump: Kotlin plugin to 1.5.31 (#763) -* Fix: Missing userId on iOS when userId is not set (#782) +- Feat: Allow to set startTimestamp & endTimestamp manually to SentrySpan (#676) +- Bump: Sentry-Cocoa to 7.10.0 (#777) +- Feat: Additional Dart/Flutter context information (#778) +- Bump: Kotlin plugin to 1.5.31 (#763) +- Fix: Missing userId on iOS when userId is not set (#782) ## 6.4.0-beta.2 -* No documented changes. +- No documented changes. ## 6.4.0-beta.1 -* Fix: Disable log by default in debug mode (#753) -* [Dio] Ref: Replace FailedRequestAdapter with FailedRequestInterceptor (#728) -* Fix: Add missing return values - dart analyzer (#742) -* Feat: Add `DioEventProcessor` which improves DioError crash reports (#718) -* Fix: Do not report duplicated packages and integrations (#760) -* Feat: Allow manual init of the Native SDK or no Native SDK at all (#765) +- Fix: Disable log by default in debug mode (#753) +- [Dio] Ref: Replace FailedRequestAdapter with FailedRequestInterceptor (#728) +- Fix: Add missing return values - dart analyzer (#742) +- Feat: Add `DioEventProcessor` which improves DioError crash reports (#718) +- Fix: Do not report duplicated packages and integrations (#760) +- Feat: Allow manual init of the Native SDK or no Native SDK at all (#765) ## 6.3.0 -* Feat: Support maxSpan for performance API and expose SentryOptions through Hub (#716) -* Fix: await ZonedGuard integration to run (#732) -* Fix: `sentry_logging` incorrectly setting SDK name (#725) -* Bump: Sentry-Android to 5.6.1 and Sentry-Cocoa to 7.9.0 (#736) -* Feat: Support Attachment.addToTransactions (#709) -* Fix: captureTransaction should return emptyId when transaction is discarded (#713) -* Add `SentryAssetBundle` for automatic spans for asset loading (#685) -* Fix: `maxRequestBodySize` should be `never` by default when using the FailedRequestClientAdapter directly (#701) -* Feat: Add support for [Dio](https://pub.dev/packages/dio) (#688) -* Fix: Use correct data/extras type in tracer (#693) -* Fix: Do not throw when Throwable type is not supported for associating errors to a transaction (#692) -* Feat: Automatically create transactions when navigating between screens (#643) +- Feat: Support maxSpan for performance API and expose SentryOptions through Hub (#716) +- Fix: await ZonedGuard integration to run (#732) +- Fix: `sentry_logging` incorrectly setting SDK name (#725) +- Bump: Sentry-Android to 5.6.1 and Sentry-Cocoa to 7.9.0 (#736) +- Feat: Support Attachment.addToTransactions (#709) +- Fix: captureTransaction should return emptyId when transaction is discarded (#713) +- Add `SentryAssetBundle` for automatic spans for asset loading (#685) +- Fix: `maxRequestBodySize` should be `never` by default when using the FailedRequestClientAdapter directly (#701) +- Feat: Add support for [Dio](https://pub.dev/packages/dio) (#688) +- Fix: Use correct data/extras type in tracer (#693) +- Fix: Do not throw when Throwable type is not supported for associating errors to a transaction (#692) +- Feat: Automatically create transactions when navigating between screens (#643) ## 6.3.0-beta.4 -* Feat: Support Attachment.addToTransactions (#709) -* Fix: captureTransaction should return emptyId when transaction is discarded (#713) +- Feat: Support Attachment.addToTransactions (#709) +- Fix: captureTransaction should return emptyId when transaction is discarded (#713) ## 6.3.0-beta.3 -* Feat: Auto transactions duration trimming (#702) -* Add `SentryAssetBundle` for automatic spans for asset loading (#685) -* Feat: Configure idle transaction duration (#705) -* Fix: `maxRequestBodySize` should be `never` by default when using the FailedRequestClientAdapter directly (#701) +- Feat: Auto transactions duration trimming (#702) +- Add `SentryAssetBundle` for automatic spans for asset loading (#685) +- Feat: Configure idle transaction duration (#705) +- Fix: `maxRequestBodySize` should be `never` by default when using the FailedRequestClientAdapter directly (#701) ## 6.3.0-beta.2 -* Feat: Improve configuration options of `SentryNavigatorObserver` (#684) -* Feat: Add support for [Dio](https://pub.dev/packages/dio) (#688) -* Bump: Sentry-Android to 5.5.2 and Sentry-Cocoa to 7.8.0 (#696) +- Feat: Improve configuration options of `SentryNavigatorObserver` (#684) +- Feat: Add support for [Dio](https://pub.dev/packages/dio) (#688) +- Bump: Sentry-Android to 5.5.2 and Sentry-Cocoa to 7.8.0 (#696) ## 6.3.0-beta.1 -* Enha: Replace flutter default root name '/' with 'root' (#678) -* Fix: Use 'navigation' instead of 'ui.load' for auto transaction operation (#675) -* Fix: Use correct data/extras type in tracer (#693) -* Fix: Do not throw when Throwable type is not supported for associating errors to a transaction (#692) +- Enha: Replace flutter default root name '/' with 'root' (#678) +- Fix: Use 'navigation' instead of 'ui.load' for auto transaction operation (#675) +- Fix: Use correct data/extras type in tracer (#693) +- Fix: Do not throw when Throwable type is not supported for associating errors to a transaction (#692) ## 6.3.0-alpha.1 -* Feat: Automatically create transactions when navigating between screens (#643) +- Feat: Automatically create transactions when navigating between screens (#643) ## 6.2.2 -* Fix: ConcurrentModificationError in when finishing span (#664) -* Feat: Add enableNdkScopeSync Android support (#665) +- Fix: ConcurrentModificationError in when finishing span (#664) +- Feat: Add enableNdkScopeSync Android support (#665) ## 6.2.1 -* Fix: `sentry_logging` works now on web (#660) -* Fix: `sentry_logging` timestamps are in UTC (#660) -* Fix: `sentry_logging` Level.Off is never recorded (#660) -* Fix: Rate limiting fallback to retryAfterHeader (#658) +- Fix: `sentry_logging` works now on web (#660) +- Fix: `sentry_logging` timestamps are in UTC (#660) +- Fix: `sentry_logging` Level.Off is never recorded (#660) +- Fix: Rate limiting fallback to retryAfterHeader (#658) ## 6.2.0 -* Feat: Integration for `logging` (#631) -* Feat: Add logger name to `SentryLogger` and send errors in integrations to the registered logger (#641) +- Feat: Integration for `logging` (#631) +- Feat: Add logger name to `SentryLogger` and send errors in integrations to the registered logger (#641) ## 6.1.2 -* Fix: Remove is Enum check to support older Dart versions (#635) +- Fix: Remove is Enum check to support older Dart versions (#635) ## 6.1.1 -* Fix: Transaction serialization if not encodable (#633) +- Fix: Transaction serialization if not encodable (#633) ## 6.1.0 -* Bump: Sentry-Android to 5.3.0 and Sentry-Cocoa to 7.5.1 (#629) -* Fix: event.origin tag for macOS and other Apple platforms (#622) -* Feat: Add current route as transaction (#615) -* Feat: Add Breadcrumbs for Flutters `debugPrint` (#618) -* Feat: Enrich Dart context with isolate name (#600) -* Feat: Sentry Performance for HTTP client (#603) -* Performance API for Dart/Flutter (#530) +- Bump: Sentry-Android to 5.3.0 and Sentry-Cocoa to 7.5.1 (#629) +- Fix: event.origin tag for macOS and other Apple platforms (#622) +- Feat: Add current route as transaction (#615) +- Feat: Add Breadcrumbs for Flutters `debugPrint` (#618) +- Feat: Enrich Dart context with isolate name (#600) +- Feat: Sentry Performance for HTTP client (#603) +- Performance API for Dart/Flutter (#530) ### Breaking Changes: -* `SentryEvent` inherits from the `SentryEventLike` mixin -* `Scope#transaction` sets and reads from the `Scope#span` object if bound to the Scope +- `SentryEvent` inherits from the `SentryEventLike` mixin +- `Scope#transaction` sets and reads from the `Scope#span` object if bound to the Scope ## 6.1.0-beta.1 -* Feat: Add current route as transaction (#615) -* Feat: Add Breadcrumbs for Flutters `debugPrint` (#618) +- Feat: Add current route as transaction (#615) +- Feat: Add Breadcrumbs for Flutters `debugPrint` (#618) ## 6.1.0-alpha.2 -* Bump Sentry Android SDK to [5.2.0](https://github.com/getsentry/sentry-dart/pull/594) (#594) +- Bump Sentry Android SDK to [5.2.0](https://github.com/getsentry/sentry-dart/pull/594) (#594) - [changelog](https://github.com/getsentry/sentry-java/blob/5.2.0/CHANGELOG.md) - [diff](https://github.com/getsentry/sentry-java/compare/5.1.2...5.2.0) -* Feat: Enrich Dart context with isolate name (#600) -* Feat: Sentry Performance for HTTP client (#603) +- Feat: Enrich Dart context with isolate name (#600) +- Feat: Sentry Performance for HTTP client (#603) ## 6.1.0-alpha.1 -* Performance API for Dart/Flutter (#530) +- Performance API for Dart/Flutter (#530) ### Breaking Changes: -* `SentryEvent` inherits from the `SentryEventLike` mixin -* `Scope#transaction` sets and reads from the `Scope#span` object if bound to the Scope +- `SentryEvent` inherits from the `SentryEventLike` mixin +- `Scope#transaction` sets and reads from the `Scope#span` object if bound to the Scope ## 6.0.1 -* Fix: Set custom SentryHttpClientError when HTTP error is captured without an exception (#580) -* Bump: Android AGP 4.1 (#586) -* Bump: Sentry Cocoa to 7.3.0 (#589) +- Fix: Set custom SentryHttpClientError when HTTP error is captured without an exception (#580) +- Bump: Android AGP 4.1 (#586) +- Bump: Sentry Cocoa to 7.3.0 (#589) ## 6.0.0 -* Fix: Update `SentryUser` according to docs (#561) -* Feat: Enable or disable reporting of packages (#563) -* Bump: Sentry-Cocoa to 7.2.7 (#578) -* Bump: Sentry-Android to 5.1.2 (#578) -* Fix: Read Sentry config from environment variables as fallback (#567) +- Fix: Update `SentryUser` according to docs (#561) +- Feat: Enable or disable reporting of packages (#563) +- Bump: Sentry-Cocoa to 7.2.7 (#578) +- Bump: Sentry-Android to 5.1.2 (#578) +- Fix: Read Sentry config from environment variables as fallback (#567) ## 6.0.0-beta.4 ### Breaking Changes: -* Feat: Lists of exceptions and threads (#524) -* Feat: Collect more information for exceptions collected via `FlutterError.onError` (#538) -* Feat: Add maxAttachmentSize option (#553) -* Feat: HTTP breadcrumbs have the request & response size if available (#552) +- Feat: Lists of exceptions and threads (#524) +- Feat: Collect more information for exceptions collected via `FlutterError.onError` (#538) +- Feat: Add maxAttachmentSize option (#553) +- Feat: HTTP breadcrumbs have the request & response size if available (#552) ## 6.0.0-beta.3 -* Fix: Re-initialization of Flutter SDK (#526) -* Enhancement: Call `toString()` on all non-serializable fields (#528) -* Fix: Always call `Flutter.onError` in order to not swallow messages (#533) -* Bump: Android SDK to 5.1.0-beta.6 (#535) +- Fix: Re-initialization of Flutter SDK (#526) +- Enhancement: Call `toString()` on all non-serializable fields (#528) +- Fix: Always call `Flutter.onError` in order to not swallow messages (#533) +- Bump: Android SDK to 5.1.0-beta.6 (#535) ## 6.0.0-beta.2 -* Fix: Serialization of Flutter Context (#520) -* Feat: Add support for attachments (#505) -* Feat: Add support for User Feedback (#506) +- Fix: Serialization of Flutter Context (#520) +- Feat: Add support for attachments (#505) +- Feat: Add support for User Feedback (#506) ## 6.0.0-beta.1 -* Feat: Browser detection (#502) -* Feat: Enrich events with more context (#452) -* Feat: Add Culture Context (#491) -* Feat: Add DeduplicationEventProcessor (#498) -* Feat: Capture failed requests as event (#473) -* Feat: `beforeSend` callback accepts async code (#494) +- Feat: Browser detection (#502) +- Feat: Enrich events with more context (#452) +- Feat: Add Culture Context (#491) +- Feat: Add DeduplicationEventProcessor (#498) +- Feat: Capture failed requests as event (#473) +- Feat: `beforeSend` callback accepts async code (#494) ### Breaking Changes: -* Ref: EventProcessor changed to an interface (#489) -* Feat: Support envelope based transport for events (#391) - * The method signature of `Transport` changed from `Future send(SentryEvent event)` to `Future send(SentryEnvelope envelope)` -* Remove `Sentry.currentHub` (#490) -* Ref: Rename `cacheDirSize` to `maxCacheItems` and add `maxCacheItems` for iOS (#495) -* Ref: Add error and stacktrace parameter to logger (#503) -* Feat: Change timespans to Durations in SentryOptions (#504) -* Feat: `beforeSend` callback accepts async code (#494) +- Ref: EventProcessor changed to an interface (#489) +- Feat: Support envelope based transport for events (#391) + - The method signature of `Transport` changed from `Future send(SentryEvent event)` to `Future send(SentryEnvelope envelope)` +- Remove `Sentry.currentHub` (#490) +- Ref: Rename `cacheDirSize` to `maxCacheItems` and add `maxCacheItems` for iOS (#495) +- Ref: Add error and stacktrace parameter to logger (#503) +- Feat: Change timespans to Durations in SentryOptions (#504) +- Feat: `beforeSend` callback accepts async code (#494) ### Sentry Self Hosted Compatibility -* Since version `6.0.0` of the `sentry`, [Sentry's version >= v20.6.0](https://github.com/getsentry/self-hosted/releases) is required. This only applies to on-premise Sentry, if you are using sentry.io no action is needed. +- Since version `6.0.0` of the `sentry`, [Sentry's version >= v20.6.0](https://github.com/getsentry/self-hosted/releases) is required. This only applies to on-premise Sentry, if you are using sentry.io no action is needed. ## 5.1.0 -* Fix: Merge user from event and scope (#467) -* Feature: Allow setting of default values for in-app-frames via `SentryOptions.considerInAppFramesByDefault` (#482) -* Bump: sentry-android to v5.0.1 (#486) -* Bump: Sentry-Cocoa to 7.1.3 for iOS and macOS (#488) +- Fix: Merge user from event and scope (#467) +- Feature: Allow setting of default values for in-app-frames via `SentryOptions.considerInAppFramesByDefault` (#482) +- Bump: sentry-android to v5.0.1 (#486) +- Bump: Sentry-Cocoa to 7.1.3 for iOS and macOS (#488) ## 5.1.0-beta.1 -* Fix: `Sentry.close()` closes native SDK integrations (#388) -* Feat: Support for macOS (#389) -* Feat: Support for Linux (#402) -* Feat: Support for Windows (#407) -* Fix: Mark `Sentry.currentHub` as deprecated (#406) -* Fix: Set console logger as default logger in debug mode (#413) -* Fix: Use name from pubspec.yaml for release if package id is not available (#411) -* Feat: `SentryHttpClient` tracks the duration which a request takes and logs failed requests (#414) -* Bump: sentry-cocoa to v7.0.0 (#424) -* Feat: Support for Out-of-Memory-Tracking on macOS/iOS (#424) -* Fix: Trim `\u0000` from Windows package info (#420) -* Feature: Log calls to `print()` as Breadcrumbs (#439) -* Fix: `dist` was read from `SENTRY_DSN`, now it's read from `SENTRY_DIST` (#442) -* Bump: sentry-cocoa to v7.0.3 (#445) -* Fix: Fix adding integrations on web (#450) -* Fix: Use `log()` instead of `print()` for SDK logging (#453) -* Bump: sentry-android to v5.0.0-beta.2 (#457) -* Feature: Add `withScope` callback to capture methods (#463) -* Fix: Add missing properties `language`, `screenHeightPixels` and `screenWidthPixels` to `SentryDevice` (#465) +- Fix: `Sentry.close()` closes native SDK integrations (#388) +- Feat: Support for macOS (#389) +- Feat: Support for Linux (#402) +- Feat: Support for Windows (#407) +- Fix: Mark `Sentry.currentHub` as deprecated (#406) +- Fix: Set console logger as default logger in debug mode (#413) +- Fix: Use name from pubspec.yaml for release if package id is not available (#411) +- Feat: `SentryHttpClient` tracks the duration which a request takes and logs failed requests (#414) +- Bump: sentry-cocoa to v7.0.0 (#424) +- Feat: Support for Out-of-Memory-Tracking on macOS/iOS (#424) +- Fix: Trim `\u0000` from Windows package info (#420) +- Feature: Log calls to `print()` as Breadcrumbs (#439) +- Fix: `dist` was read from `SENTRY_DSN`, now it's read from `SENTRY_DIST` (#442) +- Bump: sentry-cocoa to v7.0.3 (#445) +- Fix: Fix adding integrations on web (#450) +- Fix: Use `log()` instead of `print()` for SDK logging (#453) +- Bump: sentry-android to v5.0.0-beta.2 (#457) +- Feature: Add `withScope` callback to capture methods (#463) +- Fix: Add missing properties `language`, `screenHeightPixels` and `screenWidthPixels` to `SentryDevice` (#465) ### Sentry Self Hosted Compatibility -* This version of the `sentry` Dart package requires [Sentry server >= v20.6.0](https://github.com/getsentry/self-hosted/releases). This only applies to on-premise Sentry, if you are using sentry.io no action is needed. +- This version of the `sentry` Dart package requires [Sentry server >= v20.6.0](https://github.com/getsentry/self-hosted/releases). This only applies to on-premise Sentry, if you are using sentry.io no action is needed. ## 5.0.0 -* Sound null safety -* Fix: event.origin and event.environment tags have wrong value for iOS (#365) and (#369) -* Fix: Fix deprecated `registrar.messenger` call in `SentryFlutterWeb` (#364) -* Fix: Enable breadcrumb recording mechanism based on platform (#366) -* Feat: Send default PII options (#360) -* Bump: sentry-cocoa to v6.2.1 (#360) -* Feat: Migration from `package_info` to `package_info_plus` plugin (#370) -* Fix: Set `SentryOptions.debug` in `sentry` (#376) -* Fix: Read all environment variables in `sentry` (#375) +- Sound null safety +- Fix: event.origin and event.environment tags have wrong value for iOS (#365) and (#369) +- Fix: Fix deprecated `registrar.messenger` call in `SentryFlutterWeb` (#364) +- Fix: Enable breadcrumb recording mechanism based on platform (#366) +- Feat: Send default PII options (#360) +- Bump: sentry-cocoa to v6.2.1 (#360) +- Feat: Migration from `package_info` to `package_info_plus` plugin (#370) +- Fix: Set `SentryOptions.debug` in `sentry` (#376) +- Fix: Read all environment variables in `sentry` (#375) ### Breaking Changes: -* Return type of `Sentry.close()` changed from `void` to `Future` and `Integration.close()` changed from `void` to `FutureOr` (#395) -* Remove deprecated member `enableLifecycleBreadcrumbs`. Use `enableAppLifecycleBreadcrumbs` instead. (#366) +- Return type of `Sentry.close()` changed from `void` to `Future` and `Integration.close()` changed from `void` to `FutureOr` (#395) +- Remove deprecated member `enableLifecycleBreadcrumbs`. Use `enableAppLifecycleBreadcrumbs` instead. (#366) ## 4.1.0-nullsafety.1 -* Bump: sentry-android to v4.3.0 (#343) -* Fix: Multiple FlutterError.onError calls in FlutterErrorIntegration (#345) -* Fix: Pass hint to EventProcessors (#356) -* Fix: EventProcessors were not dropping events when returning null (#353) +- Bump: sentry-android to v4.3.0 (#343) +- Fix: Multiple FlutterError.onError calls in FlutterErrorIntegration (#345) +- Fix: Pass hint to EventProcessors (#356) +- Fix: EventProcessors were not dropping events when returning null (#353) ### Breaking Changes: -* Fix: Plugin Registrant class moved to barrel file (#358) - * This changed the import from `import 'package:sentry_flutter/src/sentry_flutter_web.dart';` +- Fix: Plugin Registrant class moved to barrel file (#358) + - This changed the import from `import 'package:sentry_flutter/src/sentry_flutter_web.dart';` to `import 'package:sentry_flutter/sentry_flutter_web.dart';` - * This could lead to breaking changes. Typically it shouldn't because the referencing file is auto-generated. -* Fix: Prefix classes with Sentry (#357) - * A couple of classes were often conflicting with user's code. + - This could lead to breaking changes. Typically it shouldn't because the referencing file is auto-generated. +- Fix: Prefix classes with Sentry (#357) + - A couple of classes were often conflicting with user's code. Thus this change renames the following classes: - * `App` -> `SentryApp` - * `Browser` -> `SentryBrowser` - * `Device` -> `SentryDevice` - * `Gpu` -> `SentryGpu` - * `Integration` -> `SentryIntegration` - * `Message` -> `SentryMessage` - * `OperatingSystem` -> `SentryOperatingSystem` - * `Request` -> `SentryRequest` - * `User` -> `SentryUser` - * `Orientation` -> `SentryOrientation` + - `App` -> `SentryApp` + - `Browser` -> `SentryBrowser` + - `Device` -> `SentryDevice` + - `Gpu` -> `SentryGpu` + - `Integration` -> `SentryIntegration` + - `Message` -> `SentryMessage` + - `OperatingSystem` -> `SentryOperatingSystem` + - `Request` -> `SentryRequest` + - `User` -> `SentryUser` + - `Orientation` -> `SentryOrientation` ## 4.1.0-nullsafety.0 -* Fix: Do not append stack trace to the exception if there are no frames -* Fix: Empty DSN disables the SDK and runs the App -* Feat: sentry and sentry_flutter null-safety thanks to @ueman and @fzyzcjy +- Fix: Do not append stack trace to the exception if there are no frames +- Fix: Empty DSN disables the SDK and runs the App +- Feat: sentry and sentry_flutter null-safety thanks to @ueman and @fzyzcjy ## 4.0.6 -* Fix: captureMessage defaults SentryLevel to info -* Fix: SentryEvent.throwable returns the unwrapped throwable instead of the throwableMechanism -* Feat: Support enableNativeCrashHandling on iOS +- Fix: captureMessage defaults SentryLevel to info +- Fix: SentryEvent.throwable returns the unwrapped throwable instead of the throwableMechanism +- Feat: Support enableNativeCrashHandling on iOS ## 4.0.5 -* Bump: sentry-android to v4.0.0 -* Fix: Pana Flutter upper bound deprecation -* Fix: sentry_flutter static analysis (pana) using stable version +- Bump: sentry-android to v4.0.0 +- Fix: Pana Flutter upper bound deprecation +- Fix: sentry_flutter static analysis (pana) using stable version ## 4.0.4 -* Fix: Call WidgetsFlutterBinding.ensureInitialized() within runZoneGuarded +- Fix: Call WidgetsFlutterBinding.ensureInitialized() within runZoneGuarded ## 4.0.3 -* Fix: Auto session tracking start on iOS #274 -* Bump: Sentry-cocoa to 6.1.4 +- Fix: Auto session tracking start on iOS #274 +- Bump: Sentry-cocoa to 6.1.4 ## 4.0.2 -* Fix: Mark session as `errored` in iOS #270 -* Fix: Pass auto session tracking interval to iOS -* Fix: Deprecated binaryMessenger (MethodChannel member) for Flutter Web -* Ref: Make `WidgetsFlutterBinding.ensureInitialized();` the first thing the Sentry SDK calls. -* Bump: Sentry-cocoa to 6.0.12 -* Feat: Respect FlutterError silent flag #248 -* Bump: Android SDK to v3.2.1 #273 +- Fix: Mark session as `errored` in iOS #270 +- Fix: Pass auto session tracking interval to iOS +- Fix: Deprecated binaryMessenger (MethodChannel member) for Flutter Web +- Ref: Make `WidgetsFlutterBinding.ensureInitialized();` the first thing the Sentry SDK calls. +- Bump: Sentry-cocoa to 6.0.12 +- Feat: Respect FlutterError silent flag #248 +- Bump: Android SDK to v3.2.1 #273 ## 4.0.1 -* Ref: Changed category of Flutter lifecycle tracking [#240](https://github.com/getsentry/sentry-dart/issues/240) -* Fix: Envelope length should be based on the UTF8 array instead of String length +- Ref: Changed category of Flutter lifecycle tracking [#240](https://github.com/getsentry/sentry-dart/issues/240) +- Fix: Envelope length should be based on the UTF8 array instead of String length ## 4.0.0 @@ -1433,100 +1760,100 @@ New features not offered by <= v4.0.0: ### Dart SDK -* Sentry's [Unified API](https://develop.sentry.dev/sdk/unified-api/). -* Complete Sentry's [Protocol](https://develop.sentry.dev/sdk/event-payloads/) available. -* [Dart SDK](https://docs.sentry.io/platforms/dart/) docs. -* Automatic [HTTP Breadcrumbs](https://docs.sentry.io/platforms/dart/usage/advanced-usage/#automatic-breadcrumbs) for [http.Client](https://pub.dev/documentation/http/latest/http/Client-class.html) -* No boilerplate for `runZonedGuarded` and `Isolate.current.addErrorListener` -* All events are enriched with [Scope's Contexts](https://develop.sentry.dev/sdk/event-payloads/#scope-interfaces), this includes Breadcrumbs, tags, User, etc... +- Sentry's [Unified API](https://develop.sentry.dev/sdk/unified-api/). +- Complete Sentry's [Protocol](https://develop.sentry.dev/sdk/event-payloads/) available. +- [Dart SDK](https://docs.sentry.io/platforms/dart/) docs. +- Automatic [HTTP Breadcrumbs](https://docs.sentry.io/platforms/dart/usage/advanced-usage/#automatic-breadcrumbs) for [http.Client](https://pub.dev/documentation/http/latest/http/Client-class.html) +- No boilerplate for `runZonedGuarded` and `Isolate.current.addErrorListener` +- All events are enriched with [Scope's Contexts](https://develop.sentry.dev/sdk/event-payloads/#scope-interfaces), this includes Breadcrumbs, tags, User, etc... ### Flutter SDK -* The Flutter SDK is built on top of the Dart SDK, so it includes all the available features, plus -* [Flutter SDK](https://docs.sentry.io/platforms/flutter/) docs. -* Automatic [NavigatorObserver Breadcrumbs](https://docs.sentry.io/platforms/flutter/usage/advanced-usage/#automatic-breadcrumbs) -* Automatic [Device's Breadcrumbs](https://docs.sentry.io/platforms/flutter/usage/advanced-usage/#automatic-breadcrumbs) through the Android and iOS SDKs or via Sentry's `WidgetsBindingObserver` wrapper -* No boilerplate for `FlutterError.onError` -* All events are enriched with [Contexts's data](https://develop.sentry.dev/sdk/event-payloads/contexts/), this includes Device's, OS, App info, etc... -* Offline caching -* [Release health](https://docs.sentry.io/product/releases/health/) -* Captures not only Dart and Flutter errors, but also errors caused on the native platforms, Like Kotlin, Java, C and C++ for Android and Swift, ObjC, C, C++ for iOS -* Supports Fatal crashes, Event is going to be sent on App's restart -* Supports `split-debug-info` for Android only -* Flutter Android, iOS and limited support for Flutter Web +- The Flutter SDK is built on top of the Dart SDK, so it includes all the available features, plus +- [Flutter SDK](https://docs.sentry.io/platforms/flutter/) docs. +- Automatic [NavigatorObserver Breadcrumbs](https://docs.sentry.io/platforms/flutter/usage/advanced-usage/#automatic-breadcrumbs) +- Automatic [Device's Breadcrumbs](https://docs.sentry.io/platforms/flutter/usage/advanced-usage/#automatic-breadcrumbs) through the Android and iOS SDKs or via Sentry's `WidgetsBindingObserver` wrapper +- No boilerplate for `FlutterError.onError` +- All events are enriched with [Contexts's data](https://develop.sentry.dev/sdk/event-payloads/contexts/), this includes Device's, OS, App info, etc... +- Offline caching +- [Release health](https://docs.sentry.io/product/releases/health/) +- Captures not only Dart and Flutter errors, but also errors caused on the native platforms, Like Kotlin, Java, C and C++ for Android and Swift, ObjC, C, C++ for iOS +- Supports Fatal crashes, Event is going to be sent on App's restart +- Supports `split-debug-info` for Android only +- Flutter Android, iOS and limited support for Flutter Web Improvements: -* Feat: Added a copyWith method to all the protocol classes +- Feat: Added a copyWith method to all the protocol classes Packages were released on [sentry pubdev](https://pub.dev/packages/sentry) and [sentry_flutter pubdev](https://pub.dev/packages/sentry_flutter) ### Sentry Self Hosted Compatibility -* Since version `4.0.0` of the `sentry_flutter`, [Sentry's version >= v20.6.0](https://github.com/getsentry/self-hosted/releases) is required. This only applies to on-premise Sentry, if you are using sentry.io no action is needed. +- Since version `4.0.0` of the `sentry_flutter`, [Sentry's version >= v20.6.0](https://github.com/getsentry/self-hosted/releases) is required. This only applies to on-premise Sentry, if you are using sentry.io no action is needed. ## 4.0.0-beta.2 -* Ref: Remove duplicated attachStackTrace field -* Fix: Flutter Configurations should be able to mutate the SentryFlutterOptions -* Enhancement: Add SentryWidgetsBindingObserver, an Integration that captures certain window and device events. -* Enhancement: Set `options.environment` on SDK init based on the flags (kReleaseMode, kDebugMode, kProfileMode or SENTRY_ENVIRONMENT). -* Feature: SentryHttpClient to capture HTTP requests as breadcrumbs -* Ref: Only assign non-null option values in Android native integration in order preserve default values -* Enhancement: Add 'attachThreads' in options. When enabled, threads are attached to all logged events for Android -* Ref: Rename typedef `Logger` to `SentryLogger` to prevent name clashes with logging packages -* Fix: Scope Event processors should be awaited -* Fix: Package usage as git dependency +- Ref: Remove duplicated attachStackTrace field +- Fix: Flutter Configurations should be able to mutate the SentryFlutterOptions +- Enhancement: Add SentryWidgetsBindingObserver, an Integration that captures certain window and device events. +- Enhancement: Set `options.environment` on SDK init based on the flags (kReleaseMode, kDebugMode, kProfileMode or SENTRY_ENVIRONMENT). +- Feature: SentryHttpClient to capture HTTP requests as breadcrumbs +- Ref: Only assign non-null option values in Android native integration in order preserve default values +- Enhancement: Add 'attachThreads' in options. When enabled, threads are attached to all logged events for Android +- Ref: Rename typedef `Logger` to `SentryLogger` to prevent name clashes with logging packages +- Fix: Scope Event processors should be awaited +- Fix: Package usage as git dependency ### Breaking changes -* `Logger` typedef is renamed to `SentryLogger` -* `attachStackTrace` is renamed to `attachStacktrace` +- `Logger` typedef is renamed to `SentryLogger` +- `attachStackTrace` is renamed to `attachStacktrace` ## 4.0.0-beta.1 -* Fix: StackTrace frames with 'package' uri.scheme are inApp by default #185 -* Fix: Missing App's StackTrace frames for Flutter errors -* Enhancement: Add isolateErrorIntegration and runZonedGuardedIntegration to default integrations in sentry-dart -* Fix: Breadcrumb list is a plain list instead of a values list #201 -* Ref: Remove deprecated classes (Flutter Plugin for Android) and cleaning up #186 -* Fix: Handle immutable event lists and maps -* Fix: NDK integration was being disabled by a typo -* Fix: Missing toList for debug meta #192 -* Enhancement: NavigationObserver to record Breadcrumbs for navigation events #197 -* Fix: Integrations should be closeable -* Feat: Support split-debug-info for Android #191 -* Fix: the event payload must never serialize null or empty fields -* Ref: Make hints optional +- Fix: StackTrace frames with 'package' uri.scheme are inApp by default #185 +- Fix: Missing App's StackTrace frames for Flutter errors +- Enhancement: Add isolateErrorIntegration and runZonedGuardedIntegration to default integrations in sentry-dart +- Fix: Breadcrumb list is a plain list instead of a values list #201 +- Ref: Remove deprecated classes (Flutter Plugin for Android) and cleaning up #186 +- Fix: Handle immutable event lists and maps +- Fix: NDK integration was being disabled by a typo +- Fix: Missing toList for debug meta #192 +- Enhancement: NavigationObserver to record Breadcrumbs for navigation events #197 +- Fix: Integrations should be closeable +- Feat: Support split-debug-info for Android #191 +- Fix: the event payload must never serialize null or empty fields +- Ref: Make hints optional ### Breaking changes -* `Sentry.init` and `SentryFlutter.init` have an optional callback argument which runs the host App after Sentry initialization. -* `Integration` is an `Interface` instead of a pure Function -* `Hints` are optional arguments -* Sentry Dart SDK adds an `IsolateError` handler by default +- `Sentry.init` and `SentryFlutter.init` have an optional callback argument which runs the host App after Sentry initialization. +- `Integration` is an `Interface` instead of a pure Function +- `Hints` are optional arguments +- Sentry Dart SDK adds an `IsolateError` handler by default ## 4.0.0-alpha.2 -* Enhancement: `Contexts` were added to the `Scope` #154 -* Fix: App. would hang if `debug` mode was enabled and refactoring ##157 -* Enhancement: Sentry Protocol v7 -* Enhancement: Added missing Protocol fields, `Request`, `SentryStackTrace`...) #155 -* Feat: Added `attachStackTrace` options to attach stack traces on `captureMessage` calls -* Feat: Flutter SDK has the Native SDKs embedded (Android and Apple) #158 +- Enhancement: `Contexts` were added to the `Scope` #154 +- Fix: App. would hang if `debug` mode was enabled and refactoring ##157 +- Enhancement: Sentry Protocol v7 +- Enhancement: Added missing Protocol fields, `Request`, `SentryStackTrace`...) #155 +- Feat: Added `attachStackTrace` options to attach stack traces on `captureMessage` calls +- Feat: Flutter SDK has the Native SDKs embedded (Android and Apple) #158 ### Breaking changes -* `Sentry.init` returns a `Future`. -* Dart min. SDK is `2.8.0` -* Flutter min. SDK is `1.17.0` -* Timestamp has millis precision. -* For better groupping, add your own package to the `addInAppInclude` list, e.g. `options.addInAppInclude('sentry_flutter_example');` -* A few classes of the `Protocol` were renamed. +- `Sentry.init` returns a `Future`. +- Dart min. SDK is `2.8.0` +- Flutter min. SDK is `1.17.0` +- Timestamp has millis precision. +- For better groupping, add your own package to the `addInAppInclude` list, e.g. `options.addInAppInclude('sentry_flutter_example');` +- A few classes of the `Protocol` were renamed. ### Sentry Self Hosted Compatibility -* Since version `4.0.0` of the `sentry_flutter`, `Sentry` version >= `v20.6.0` is required. This only applies to on-premise Sentry, if you are using sentry.io no action is needed. +- Since version `4.0.0` of the `sentry_flutter`, `Sentry` version >= `v20.6.0` is required. This only applies to on-premise Sentry, if you are using sentry.io no action is needed. ## 4.0.0-alpha.1 @@ -1534,10 +1861,10 @@ First Release of Sentry's new SDK for Dart/Flutter. New features not offered by <= v4.0.0: -* Sentry's [Unified API](https://develop.sentry.dev/sdk/unified-api/). -* Complete Sentry [Protocol](https://develop.sentry.dev/sdk/event-payloads/) available. -* Docs and Migration is under review on this [PR](https://github.com/getsentry/sentry-docs/pull/2599) -* For all the breaking changes follow this [PR](https://github.com/getsentry/sentry-dart/pull/117), they'll be soon available on the Migration page. +- Sentry's [Unified API](https://develop.sentry.dev/sdk/unified-api/). +- Complete Sentry [Protocol](https://develop.sentry.dev/sdk/event-payloads/) available. +- Docs and Migration is under review on this [PR](https://github.com/getsentry/sentry-docs/pull/2599) +- For all the breaking changes follow this [PR](https://github.com/getsentry/sentry-dart/pull/117), they'll be soon available on the Migration page. Packages were released on [pubdev](https://pub.dev/packages/sentry) @@ -1546,85 +1873,85 @@ Until then, the stable SDK offered by Sentry is at version [3.0.1](https://githu ## 3.0.1 -* Add support for Contexts in Sentry events +- Add support for Contexts in Sentry events ## 3.0.0+1 -* `pubspec.yaml` and example code clean-up. +- `pubspec.yaml` and example code clean-up. ## 3.0.0 -* Support Web - * `SentryClient` from `package:sentry/sentry.dart` with conditional import - * `SentryBrowserClient` for web from `package:sentry/browser_client.dart` - * `SentryIOClient` for VM and Flutter from `package:sentry/io_client.dart` +- Support Web + - `SentryClient` from `package:sentry/sentry.dart` with conditional import + - `SentryBrowserClient` for web from `package:sentry/browser_client.dart` + - `SentryIOClient` for VM and Flutter from `package:sentry/io_client.dart` ## 2.3.1 -* Support non-standard port numbers and paths in DSN URL. +- Support non-standard port numbers and paths in DSN URL. ## 2.3.0 -* Add [breadcrumb](https://docs.sentry.io/development/sdk-dev/event-payloads/breadcrumbs/) support. +- Add [breadcrumb](https://docs.sentry.io/development/sdk-dev/event-payloads/breadcrumbs/) support. ## 2.2.0 -* Add a `stackFrameFilter` argument to `SentryClient`'s `capture` method (96be842). -* Clean-up code using pre-Dart 2 API (91c7706, b01ebf8). +- Add a `stackFrameFilter` argument to `SentryClient`'s `capture` method (96be842). +- Clean-up code using pre-Dart 2 API (91c7706, b01ebf8). ## 2.1.1 -* Defensively copy internal maps event attributes to +- Defensively copy internal maps event attributes to avoid shared mutable state (https://github.com/flutter/sentry/commit/044e4c1f43c2d199ed206e5529e2a630c90e4434) ## 2.1.0 -* Support DNS format without secret key. -* Remove dependency on `package:quiver`. -* The `clock` argument to `SentryClient` constructor _should_ now be +- Support DNS format without secret key. +- Remove dependency on `package:quiver`. +- The `clock` argument to `SentryClient` constructor _should_ now be `ClockProvider` (but still accepts `Clock` for backwards compatibility). ## 2.0.2 -* Add support for user context in Sentry events. +- Add support for user context in Sentry events. ## 2.0.1 -* Invert stack frames to be compatible with Sentry's default culprit detection. +- Invert stack frames to be compatible with Sentry's default culprit detection. ## 2.0.0 -* Fixed deprecation warnings for Dart 2 -* Refactored tests to work with Dart 2 +- Fixed deprecation warnings for Dart 2 +- Refactored tests to work with Dart 2 ## 1.0.0 -* first and last Dart 1-compatible release (we may fix bugs on a separate branch if there's demand) -* fix code for Dart 2 +- first and last Dart 1-compatible release (we may fix bugs on a separate branch if there's demand) +- fix code for Dart 2 ## 0.0.6 -* use UTC in the `timestamp` field +- use UTC in the `timestamp` field ## 0.0.5 -* remove sub-seconds from the timestamp +- remove sub-seconds from the timestamp ## 0.0.4 -* parse and report async gaps in stack traces +- parse and report async gaps in stack traces ## 0.0.3 -* environment attributes -* auto-generate event_id and timestamp for events +- environment attributes +- auto-generate event_id and timestamp for events ## 0.0.2 -* parse and report stack traces -* use x-sentry-error HTTP response header -* gzip outgoing payloads by default +- parse and report stack traces +- use x-sentry-error HTTP response header +- gzip outgoing payloads by default ## 0.0.1 -* basic ability to send exception reports to Sentry.io +- basic ability to send exception reports to Sentry.io diff --git a/LICENSE b/LICENSE index 8566a0280c..ed77f4ccbb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Sentry +Copyright (c) 2020-2024 Sentry Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 8ab372fc5a..a9d1e1c4a2 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,21 @@ Sentry SDK for Dart and Flutter [![codecov](https://codecov.io/gh/getsentry/sentry-dart/branch/main/graph/badge.svg?token=J0QX0LPmwy)](https://codecov.io/gh/getsentry/sentry-dart) -| package | build | pub | likes | popularity | pub points | -| ------- | ------- | ------- | ------- | ------- | ------- | -| sentry | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-dart/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-dart) | [![pub package](https://img.shields.io/pub/v/sentry.svg)](https://pub.dev/packages/sentry) | [![likes](https://img.shields.io/pub/likes/sentry?logo=dart)](https://pub.dev/packages/sentry/score) | [![popularity](https://img.shields.io/pub/popularity/sentry?logo=dart)](https://pub.dev/packages/sentry/score) | [![pub points](https://img.shields.io/pub/points/sentry?logo=dart)](https://pub.dev/packages/sentry/score) +| package | build | pub | likes | popularity | pub points | +|----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------| ------- | ------- | +| sentry | [![build](https://github.com/getsentry/sentry-dart/actions/workflows/dart.yml/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-dart) | [![pub package](https://img.shields.io/pub/v/sentry.svg)](https://pub.dev/packages/sentry) | [![likes](https://img.shields.io/pub/likes/sentry?logo=dart)](https://pub.dev/packages/sentry/score) | [![popularity](https://img.shields.io/pub/popularity/sentry?logo=dart)](https://pub.dev/packages/sentry/score) | [![pub points](https://img.shields.io/pub/points/sentry?logo=dart)](https://pub.dev/packages/sentry/score) | sentry_flutter | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-flutter/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-flutter) | [![pub package](https://img.shields.io/pub/v/sentry_flutter.svg)](https://pub.dev/packages/sentry_flutter) | [![likes](https://img.shields.io/pub/likes/sentry_flutter?logo=dart)](https://pub.dev/packages/sentry_flutter/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_flutter?logo=dart)](https://pub.dev/packages/sentry_flutter/score) | [![pub points](https://img.shields.io/pub/points/sentry_flutter?logo=dart)](https://pub.dev/packages/sentry_flutter/score) -| sentry_logging | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-logging/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Alogging) | [![pub package](https://img.shields.io/pub/v/sentry_logging.svg)](https://pub.dev/packages/sentry_logging) | [![likes](https://img.shields.io/pub/likes/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) | [![pub points](https://img.shields.io/pub/points/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) -| sentry_dio | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-dio/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-dio) | [![pub package](https://img.shields.io/pub/v/sentry_dio.svg)](https://pub.dev/packages/sentry_dio) | [![likes](https://img.shields.io/pub/likes/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) | [![pub points](https://img.shields.io/pub/points/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) -| sentry_file | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-file/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-file) | [![pub package](https://img.shields.io/pub/v/sentry_file.svg)](https://pub.dev/packages/sentry_file) | [![likes](https://img.shields.io/pub/likes/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) | [![pub points](https://img.shields.io/pub/points/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) -| sentry_sqflite | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-sqflite/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-sqflite) | [![pub package](https://img.shields.io/pub/v/sentry_sqflite.svg)](https://pub.dev/packages/sentry_sqflite) | [![likes](https://img.shields.io/pub/likes/sentry_sqflite)](https://pub.dev/packages/sentry_sqflite/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_sqflite)](https://pub.dev/packages/sentry_sqflite/score) | [![pub points](https://img.shields.io/pub/points/sentry_sqflite)](https://pub.dev/packages/sentry_sqflite/score) +| sentry_logging | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-logging/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Alogging) | [![pub package](https://img.shields.io/pub/v/sentry_logging.svg)](https://pub.dev/packages/sentry_logging) | [![likes](https://img.shields.io/pub/likes/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) | [![pub points](https://img.shields.io/pub/points/sentry_logging?logo=dart)](https://pub.dev/packages/sentry_logging/score) +| sentry_dio | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-dio/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-dio) | [![pub package](https://img.shields.io/pub/v/sentry_dio.svg)](https://pub.dev/packages/sentry_dio) | [![likes](https://img.shields.io/pub/likes/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) | [![pub points](https://img.shields.io/pub/points/sentry_dio?logo=dart)](https://pub.dev/packages/sentry_dio/score) +| sentry_file | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-file/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-file) | [![pub package](https://img.shields.io/pub/v/sentry_file.svg)](https://pub.dev/packages/sentry_file) | [![likes](https://img.shields.io/pub/likes/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) | [![pub points](https://img.shields.io/pub/points/sentry_file?logo=dart)](https://pub.dev/packages/sentry_file/score) +| sentry_sqflite | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-sqflite/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-sqflite) | [![pub package](https://img.shields.io/pub/v/sentry_sqflite.svg)](https://pub.dev/packages/sentry_sqflite) | [![likes](https://img.shields.io/pub/likes/sentry_sqflite)](https://pub.dev/packages/sentry_sqflite/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_sqflite)](https://pub.dev/packages/sentry_sqflite/score) | [![pub points](https://img.shields.io/pub/points/sentry_sqflite)](https://pub.dev/packages/sentry_sqflite/score) +| sentry_drift | [![build](https://github.com/getsentry/sentry-dart/actions/workflows/drift.yml/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-drift) | [![pub package](https://img.shields.io/pub/v/sentry_drift.svg)](https://pub.dev/packages/sentry_drift) | [![likes](https://img.shields.io/pub/likes/sentry_drift)](https://pub.dev/packages/sentry_drift/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_drift)](https://pub.dev/packages/sentry_drift/score) | [![pub points](https://img.shields.io/pub/points/sentry_drift)](https://pub.dev/packages/sentry_drift/score) +| sentry_hive | [![build](https://github.com/getsentry/sentry-dart/actions/workflows/hive.yml/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-hive) | [![pub package](https://img.shields.io/pub/v/sentry_hive.svg)](https://pub.dev/packages/sentry_hive) | [![likes](https://img.shields.io/pub/likes/sentry_hive)](https://pub.dev/packages/sentry_hive/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_hive)](https://pub.dev/packages/sentry_hive/score) | [![pub points](https://img.shields.io/pub/points/sentry_hive)](https://pub.dev/packages/sentry_hive/score) +| sentry_isar | [![build](https://github.com/getsentry/sentry-dart/actions/workflows/isar.yml/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-isar) | [![pub package](https://img.shields.io/pub/v/sentry_isar.svg)](https://pub.dev/packages/sentry_isar) | [![likes](https://img.shields.io/pub/likes/sentry_isar)](https://pub.dev/packages/sentry_isar/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_isar)](https://pub.dev/packages/sentry_isar/score) | [![pub points](https://img.shields.io/pub/points/sentry_isar)](https://pub.dev/packages/sentry_isar/score) ##### Usage -For detailed usage, check out the inner [dart](https://github.com/getsentry/sentry-dart/tree/main/dart), [flutter](https://github.com/getsentry/sentry-dart/tree/main/flutter), [logging](https://github.com/getsentry/sentry-dart/tree/main/logging), [dio](https://github.com/getsentry/sentry-dart/tree/main/dio), [file](https://github.com/getsentry/sentry-dart/tree/main/file) and [sqflite](https://github.com/getsentry/sentry-dart/tree/main/sqflite) `README's` or our `Resources` section below. +For detailed usage, check out the inner [dart](https://github.com/getsentry/sentry-dart/tree/main/dart), [flutter](https://github.com/getsentry/sentry-dart/tree/main/flutter), [logging](https://github.com/getsentry/sentry-dart/tree/main/logging), [dio](https://github.com/getsentry/sentry-dart/tree/main/dio), [file](https://github.com/getsentry/sentry-dart/tree/main/file), [sqflite](https://github.com/getsentry/sentry-dart/tree/main/sqflite), [drift](https://github.com/getsentry/sentry-dart/tree/main/drift), [hive](https://github.com/getsentry/sentry-dart/tree/main/hive) and [isar](https://github.com/getsentry/sentry-dart/tree/main/isar) `README's` or our `Resources` section below. #### Blog posts @@ -45,3 +48,10 @@ For detailed usage, check out the inner [dart](https://github.com/getsentry/sent * [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) + +#### Apple Privacy Manifest + +Starting with [May 1st 2024](https://developer.apple.com/news/?id=3d8a9yyh), iOS apps are required to declare approved reasons to access certain APIs. This also includes third-party SDKs. +If you are using `sentry-flutter`, update to at least version `7.17.0` to get the updated `sentry-cocoa` native iOS/macOS SDK, supporting the privacy manifest. +All other used dependencies with file declarations are supported by Sentry packages. +Run [flutter pub upgrade](https://docs.flutter.dev/release/upgrade#upgrading-packages) to the latest compatible versions of all the dependencies. diff --git a/dart/README.md b/dart/README.md index e3cf3b6bb6..a6582faa16 100644 --- a/dart/README.md +++ b/dart/README.md @@ -184,8 +184,11 @@ Read more about [Automatic Instrumentation](https://docs.sentry.io/platforms/dar #### Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) -* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) -* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +#### Resources + +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) -* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) +* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) \ No newline at end of file diff --git a/dart/example/bin/example.dart b/dart/example/bin/example.dart index 5163f341f7..d7530f5874 100644 --- a/dart/example/bin/example.dart +++ b/dart/example/bin/example.dart @@ -104,7 +104,7 @@ Future decode() async { class TagEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, hint) { return event..tags?.addAll({'page-locale': 'en-us'}); } } diff --git a/dart/example_web/analysis_options.yaml b/dart/example_web/analysis_options.yaml new file mode 100644 index 0000000000..be16ace7d1 --- /dev/null +++ b/dart/example_web/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:lints/recommended.yaml + +analyzer: + errors: + path_does_not_exist: ignore diff --git a/dart/example_web/pubspec.yaml b/dart/example_web/pubspec.yaml index 2363aa83bb..7bcb64d06e 100644 --- a/dart/example_web/pubspec.yaml +++ b/dart/example_web/pubspec.yaml @@ -8,7 +8,7 @@ environment: dependencies: sentry: - path: ../../dart + path: ../../dart/ dev_dependencies: build_runner: ^2.4.2 diff --git a/dart/example_web/web/main.dart b/dart/example_web/web/main.dart index c396be5e83..3034effe9b 100644 --- a/dart/example_web/web/main.dart +++ b/dart/example_web/web/main.dart @@ -129,7 +129,7 @@ Future parseData() async { class TagEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return event..tags?.addAll({'page-locale': 'en-us'}); } } diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index 9d06bb7e2a..f416d0b797 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -3,6 +3,8 @@ // found in the LICENSE file. /// A pure Dart client for Sentry.io crash reporting. +library sentry_dart; + export 'src/run_zoned_guarded_integration.dart'; export 'src/hub.dart'; // useful for tests @@ -47,4 +49,8 @@ export 'src/utils/http_header_utils.dart'; // ignore: invalid_export_of_internal_element export 'src/sentry_trace_origins.dart'; // ignore: invalid_export_of_internal_element +export 'src/sentry_span_operations.dart'; +// ignore: invalid_export_of_internal_element export 'src/utils.dart'; +// spotlight debugging +export 'src/spotlight.dart'; diff --git a/dart/lib/src/client_reports/client_report_recorder.dart b/dart/lib/src/client_reports/client_report_recorder.dart index 76ae9f03eb..d064941f84 100644 --- a/dart/lib/src/client_reports/client_report_recorder.dart +++ b/dart/lib/src/client_reports/client_report_recorder.dart @@ -46,6 +46,7 @@ class _QuantityKey { int get hashCode => Object.hash(reason.hashCode, category.hashCode); @override + // ignore: non_nullable_equals_parameter bool operator ==(dynamic other) { return other is _QuantityKey && other.reason == reason && diff --git a/dart/lib/src/client_reports/discard_reason.dart b/dart/lib/src/client_reports/discard_reason.dart index 1b990f8dd2..81c3a45dd0 100644 --- a/dart/lib/src/client_reports/discard_reason.dart +++ b/dart/lib/src/client_reports/discard_reason.dart @@ -12,24 +12,3 @@ enum DiscardReason { cacheOverflow, rateLimitBackoff, } - -extension OutcomeExtension on DiscardReason { - String toStringValue() { - switch (this) { - case DiscardReason.beforeSend: - return 'before_send'; - case DiscardReason.eventProcessor: - return 'event_processor'; - case DiscardReason.sampleRate: - return 'sample_rate'; - case DiscardReason.networkError: - return 'network_error'; - case DiscardReason.queueOverflow: - return 'queue_overflow'; - case DiscardReason.cacheOverflow: - return 'cache_overflow'; - case DiscardReason.rateLimitBackoff: - return 'ratelimit_backoff'; - } - } -} diff --git a/dart/lib/src/client_reports/discarded_event.dart b/dart/lib/src/client_reports/discarded_event.dart index 0b989aa4cf..01caa31ca2 100644 --- a/dart/lib/src/client_reports/discarded_event.dart +++ b/dart/lib/src/client_reports/discarded_event.dart @@ -13,9 +13,55 @@ class DiscardedEvent { Map toJson() { return { - 'reason': reason.toStringValue(), - 'category': category.toStringValue(), + 'reason': reason._toStringValue(), + 'category': category._toStringValue(), 'quantity': quantity, }; } } + +extension _OutcomeExtension on DiscardReason { + String _toStringValue() { + switch (this) { + case DiscardReason.beforeSend: + return 'before_send'; + case DiscardReason.eventProcessor: + return 'event_processor'; + case DiscardReason.sampleRate: + return 'sample_rate'; + case DiscardReason.networkError: + return 'network_error'; + case DiscardReason.queueOverflow: + return 'queue_overflow'; + case DiscardReason.cacheOverflow: + return 'cache_overflow'; + case DiscardReason.rateLimitBackoff: + return 'ratelimit_backoff'; + } + } +} + +extension _DataCategoryExtension on DataCategory { + String _toStringValue() { + switch (this) { + case DataCategory.all: + return '__all__'; + case DataCategory.dataCategoryDefault: + return 'default'; + case DataCategory.error: + return 'error'; + case DataCategory.session: + return 'session'; + case DataCategory.transaction: + return 'transaction'; + case DataCategory.attachment: + return 'attachment'; + case DataCategory.security: + return 'security'; + case DataCategory.unknown: + return 'unknown'; + case DataCategory.metricBucket: + return 'metric_bucket'; + } + } +} diff --git a/dart/lib/src/event_processor.dart b/dart/lib/src/event_processor.dart index 94fcd77fd8..45005d7b0e 100644 --- a/dart/lib/src/event_processor.dart +++ b/dart/lib/src/event_processor.dart @@ -8,7 +8,7 @@ import 'protocol.dart'; /// null in case the event will be dropped and not sent. abstract class EventProcessor { FutureOr apply( - SentryEvent event, { - Hint? hint, - }); + SentryEvent event, + Hint hint, + ); } diff --git a/dart/lib/src/event_processor/deduplication_event_processor.dart b/dart/lib/src/event_processor/deduplication_event_processor.dart index 5c3bd4606e..8706082cf5 100644 --- a/dart/lib/src/event_processor/deduplication_event_processor.dart +++ b/dart/lib/src/event_processor/deduplication_event_processor.dart @@ -26,7 +26,7 @@ class DeduplicationEventProcessor implements EventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart b/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart index 03623d7f0b..52243a8572 100644 --- a/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart +++ b/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart @@ -7,18 +7,16 @@ EnricherEventProcessor enricherEventProcessor(SentryOptions options) { return IoEnricherEventProcessor(options); } -/// Enriches [SentryEvents] with various kinds of information. +/// Enriches [SentryEvent]s with various kinds of information. /// Uses Darts [Platform](https://api.dart.dev/stable/dart-io/Platform-class.html) /// class to read information. class IoEnricherEventProcessor implements EnricherEventProcessor { - IoEnricherEventProcessor( - this._options, - ); + IoEnricherEventProcessor(this._options); final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { // If there's a native integration available, it probably has better // information available than Flutter. diff --git a/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart b/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart index fe2684d593..e51cff4b71 100644 --- a/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart +++ b/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart @@ -21,7 +21,7 @@ class WebEnricherEventProcessor implements EnricherEventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { // Web has no native integration, so no need to check for it final contexts = event.contexts.copyWith( @@ -50,9 +50,7 @@ class WebEnricherEventProcessor implements EnricherEventProcessor { final url = request?.url ?? _window.location.toString(); return (request ?? SentryRequest(url: url)) - .copyWith( - headers: header, - ) + .copyWith(headers: header) .sanitized(); } diff --git a/dart/lib/src/event_processor/exception/io_exception_event_processor.dart b/dart/lib/src/event_processor/exception/io_exception_event_processor.dart index 0f7763f35e..bb4049c00e 100644 --- a/dart/lib/src/event_processor/exception/io_exception_event_processor.dart +++ b/dart/lib/src/event_processor/exception/io_exception_event_processor.dart @@ -14,7 +14,7 @@ class IoExceptionEventProcessor implements ExceptionEventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { final throwable = event.throwable; if (throwable is HttpException) { return _applyHttpException(throwable, event); diff --git a/dart/lib/src/event_processor/exception/web_exception_event_processor.dart b/dart/lib/src/event_processor/exception/web_exception_event_processor.dart index ad57c9f5c2..6ce3be0fe0 100644 --- a/dart/lib/src/event_processor/exception/web_exception_event_processor.dart +++ b/dart/lib/src/event_processor/exception/web_exception_event_processor.dart @@ -8,5 +8,5 @@ ExceptionEventProcessor exceptionEventProcessor(SentryOptions _) => class WebExcptionEventProcessor implements ExceptionEventProcessor { @override - SentryEvent apply(SentryEvent event, {Hint? hint}) => event; + SentryEvent apply(SentryEvent event, Hint hint) => event; } diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 87620d7ba1..9df1b38365 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,4 +1,5 @@ import 'sentry_attachment/sentry_attachment.dart'; +import 'sentry_options.dart'; /// Hints are used in [BeforeSendCallback], [BeforeBreadcrumbCallback] and /// event processors. @@ -11,8 +12,8 @@ import 'sentry_attachment/sentry_attachment.dart'; /// Example: /// /// ```dart -/// options.beforeSend = (event, {hint}) { -/// final syntheticException = hint?.get(TypeCheckHint.syntheticException); +/// options.beforeSend = (event, hint) { +/// final syntheticException = hint.get(TypeCheckHint.syntheticException); /// if (syntheticException is FlutterErrorDetails) { /// // Do something with hint data /// } @@ -28,19 +29,19 @@ import 'sentry_attachment/sentry_attachment.dart'; /// ```dart /// import 'dart:convert'; /// -/// options.beforeSend = (event, {hint}) { +/// options.beforeSend = (event, hint) { /// final text = 'This event should not be sent happen in prod. Investigate.'; /// final textAttachment = SentryAttachment.fromIntList( /// utf8.encode(text), /// 'event_info.txt', /// contentType: 'text/plain', /// ); -/// hint?.attachments.add(textAttachment); +/// hint.attachments.add(textAttachment); /// return event; /// }; /// ``` class Hint { - final Map _internalStorage = {}; + final Map _internalStorage = {}; final List attachments = []; @@ -62,7 +63,7 @@ class Hint { return hint; } - factory Hint.withMap(Map map) { + factory Hint.withMap(Map map) { final hint = Hint(); hint.addAll(map); return hint; @@ -80,17 +81,19 @@ class Hint { return hint; } - // Objects + // Key/Value Storage - void addAll(Map keysAndValues) { - _internalStorage.addAll(keysAndValues); + void addAll(Map keysAndValues) { + final withoutNullValues = + keysAndValues.map((key, value) => MapEntry(key, value ?? "null")); + _internalStorage.addAll(withoutNullValues); } - void set(String key, Object value) { - _internalStorage[key] = value; + void set(String key, dynamic value) { + _internalStorage[key] = value ?? "null"; } - Object? get(String key) { + dynamic get(String key) { return _internalStorage[key]; } diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 98df59194f..446b88826c 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -73,15 +73,18 @@ class FailedRequestClient extends BaseClient { this.failedRequestTargets = SentryHttpClient.defaultFailedRequestTargets, Client? client, Hub? hub, + bool? captureFailedRequests, }) : _hub = hub ?? HubAdapter(), - _client = client ?? Client() { - if (_hub.options.captureFailedRequests) { + _client = client ?? Client(), + _captureFailedRequests = captureFailedRequests { + if (captureFailedRequests ?? _hub.options.captureFailedRequests) { _hub.options.sdk.addIntegration('HTTPClientError'); } } final Client _client; final Hub _hub; + final bool? _captureFailedRequests; /// Describes which HTTP status codes should be considered as a failed /// requests. @@ -129,13 +132,13 @@ class FailedRequestClient extends BaseClient { StackTrace? stackTrace, StreamedResponse? response, Duration duration) async { - if (!_hub.options.captureFailedRequests) { + if (!(_captureFailedRequests ?? _hub.options.captureFailedRequests)) { return; } // Only check `failedRequestStatusCodes` & `failedRequestTargets` if no exception was thrown. if (exception == null) { - if (!failedRequestStatusCodes.containsStatusCode(statusCode)) { + if (!failedRequestStatusCodes._containsStatusCode(statusCode)) { return; } if (!containsTargetOrMatchesRegExp( @@ -246,7 +249,7 @@ class FailedRequestClient extends BaseClient { } extension _ListX on List { - bool containsStatusCode(int? statusCode) { + bool _containsStatusCode(int? statusCode) { if (statusCode == null) { return false; } diff --git a/dart/lib/src/http_client/sentry_http_client.dart b/dart/lib/src/http_client/sentry_http_client.dart index c3b3346fb7..35fcae4b4f 100644 --- a/dart/lib/src/http_client/sentry_http_client.dart +++ b/dart/lib/src/http_client/sentry_http_client.dart @@ -73,6 +73,9 @@ import 'failed_request_client.dart'; /// Remarks: /// HTTP traffic can contain PII (personal identifiable information). /// Read more on data scrubbing [here](https://docs.sentry.io/product/data-management-settings/advanced-datascrubbing/). +/// +/// The constructor parameter `captureFailedRequests` will override what you +/// have configured in options. /// ``` class SentryHttpClient extends BaseClient { static const defaultFailedRequestStatusCodes = [ @@ -86,6 +89,7 @@ class SentryHttpClient extends BaseClient { List failedRequestStatusCodes = defaultFailedRequestStatusCodes, List failedRequestTargets = defaultFailedRequestTargets, + bool? captureFailedRequests, }) { _hub = hub ?? HubAdapter(); @@ -96,6 +100,7 @@ class SentryHttpClient extends BaseClient { failedRequestTargets: failedRequestTargets, hub: _hub, client: innerClient, + captureFailedRequests: captureFailedRequests, ); if (_hub.options.isTracingEnabled()) { diff --git a/dart/lib/src/hub.dart b/dart/lib/src/hub.dart index 42291d1c87..a8e06e28ed 100644 --- a/dart/lib/src/hub.dart +++ b/dart/lib/src/hub.dart @@ -2,6 +2,9 @@ import 'dart:async'; import 'dart:collection'; import 'package:meta/meta.dart'; +import 'metrics/metric.dart'; +import 'metrics/metrics_aggregator.dart'; +import 'metrics/metrics_api.dart'; import 'profiling.dart'; import 'propagation_context.dart'; import 'transport/data_category.dart'; @@ -38,6 +41,14 @@ class Hub { late final _WeakMap _throwableToSpan; + late final MetricsApi _metricsApi; + + @internal + MetricsApi get metricsApi => _metricsApi; + + @internal + MetricsAggregator? get metricsAggregator => _peek().client.metricsAggregator; + factory Hub(SentryOptions options) { _validateOptions(options); @@ -49,6 +60,7 @@ class Hub { _stack.add(_StackItem(_getClient(_options), Scope(_options))); _isEnabled = true; _throwableToSpan = _WeakMap(_options); + _metricsApi = MetricsApi(hub: this); } static void _validateOptions(SentryOptions options) { @@ -554,6 +566,42 @@ class Hub { return sentryId; } + @internal + Future captureMetrics( + Map> metricsBuckets) async { + var sentryId = SentryId.empty(); + + if (!_isEnabled) { + _options.logger( + SentryLevel.warning, + "Instance is disabled and this 'captureMetrics' call is a no-op.", + ); + } else if (!_options.enableMetrics) { + _options.logger( + SentryLevel.info, + "Metrics are disabled and this 'captureMetrics' call is a no-op.", + ); + } else if (metricsBuckets.isEmpty) { + _options.logger( + SentryLevel.info, + "Metrics are empty and this 'captureMetrics' call is a no-op.", + ); + } else { + final item = _peek(); + try { + sentryId = await item.client.captureMetrics(metricsBuckets); + } catch (exception, stackTrace) { + _options.logger( + SentryLevel.error, + 'Error while capturing metrics.', + exception: exception, + stackTrace: stackTrace, + ); + } + } + return sentryId; + } + @internal void setSpanContext( dynamic throwable, diff --git a/dart/lib/src/hub_adapter.dart b/dart/lib/src/hub_adapter.dart index 8a9107ae54..6b2ece3c53 100644 --- a/dart/lib/src/hub_adapter.dart +++ b/dart/lib/src/hub_adapter.dart @@ -4,6 +4,9 @@ import 'package:meta/meta.dart'; import 'hint.dart'; import 'hub.dart'; +import 'metrics/metric.dart'; +import 'metrics/metrics_aggregator.dart'; +import 'metrics/metrics_api.dart'; import 'profiling.dart'; import 'protocol.dart'; import 'scope.dart'; @@ -23,6 +26,10 @@ class HubAdapter implements Hub { @internal SentryOptions get options => Sentry.currentHub.options; + @override + @internal + MetricsApi get metricsApi => Sentry.currentHub.metricsApi; + factory HubAdapter() { return _instance; } @@ -181,4 +188,12 @@ class HubAdapter implements Hub { @override Scope get scope => Sentry.currentHub.scope; + + @override + Future captureMetrics(Map> metricsBuckets) => + Sentry.currentHub.captureMetrics(metricsBuckets); + + @override + MetricsAggregator? get metricsAggregator => + Sentry.currentHub.metricsAggregator; } diff --git a/dart/lib/src/metrics/local_metrics_aggregator.dart b/dart/lib/src/metrics/local_metrics_aggregator.dart new file mode 100644 index 0000000000..92076ef807 --- /dev/null +++ b/dart/lib/src/metrics/local_metrics_aggregator.dart @@ -0,0 +1,37 @@ +import 'dart:core'; +import 'package:meta/meta.dart'; +import '../protocol/metric_summary.dart'; +import 'metric.dart'; + +@internal +class LocalMetricsAggregator { + // format: > + final Map> _buckets = {}; + + void add(final Metric metric, final num value) { + final bucket = + _buckets.putIfAbsent(metric.getSpanAggregationKey(), () => {}); + + bucket.update(metric.getCompositeKey(), (m) => m..add(value), + ifAbsent: () => Metric.fromType( + type: MetricType.gauge, + key: metric.key, + value: value, + unit: metric.unit, + tags: metric.tags) as GaugeMetric); + } + + Map> getSummaries() { + final Map> summaries = {}; + for (final entry in _buckets.entries) { + final String exportKey = entry.key; + + final metricSummaries = entry.value.values + .map((gauge) => MetricSummary.fromGauge(gauge)) + .toList(); + + summaries[exportKey] = metricSummaries; + } + return summaries; + } +} diff --git a/dart/lib/src/metrics/metric.dart b/dart/lib/src/metrics/metric.dart new file mode 100644 index 0000000000..fdea81cbf4 --- /dev/null +++ b/dart/lib/src/metrics/metric.dart @@ -0,0 +1,291 @@ +import 'dart:math'; + +import 'package:meta/meta.dart'; + +import '../../sentry.dart'; + +final RegExp unitRegex = RegExp('[^\\w]+'); +final RegExp nameRegex = RegExp('[^\\w-.]+'); +final RegExp tagKeyRegex = RegExp('[^\\w-./]+'); + +/// Base class for metrics. +/// Each metric is identified by a [key]. Its [type] describes its behaviour. +/// A [unit] (defaults to [SentryMeasurementUnit.none]) describes the values +/// being tracked. Optional [tags] can be added. The [timestamp] is the time +/// when the metric was emitted. +@internal +abstract class Metric { + final MetricType type; + final String key; + final SentryMeasurementUnit unit; + final Map tags; + + Metric({ + required this.type, + required this.key, + required this.unit, + required this.tags, + }); + + factory Metric.fromType({ + required final MetricType type, + required final String key, + required final num value, + required final SentryMeasurementUnit unit, + required final Map tags, + }) { + switch (type) { + case MetricType.counter: + return CounterMetric._(value: value, key: key, unit: unit, tags: tags); + case MetricType.gauge: + return GaugeMetric._(value: value, key: key, unit: unit, tags: tags); + case MetricType.set: + return SetMetric._(value: value, key: key, unit: unit, tags: tags); + case MetricType.distribution: + return DistributionMetric._( + value: value, key: key, unit: unit, tags: tags); + } + } + + /// Add a value to the metric. + add(num value); + + /// Return the weight of the current metric. + int getWeight(); + + /// Serialize the value into a list of Objects to be converted into a String. + Iterable _serializeValue(); + + /// Encodes the metric in the statsd format + /// See github.com/statsd/statsd#usage and + /// getsentry.github.io/relay/relay_metrics/index.html + /// for more details about the format. + /// + /// Example format: key@none:1|c|#myTag:myValue|T1710844170 + /// key@unit:value1:value2|type|#tagKey1:tagValue1,tagKey2:tagValue2,|TbucketKey + /// + /// [bucketKey] is the key of the metric bucket that will be sent to Sentry, + /// and it's appended at the end of the encoded metric. + String encodeToStatsd(int bucketKey) { + final buffer = StringBuffer(); + buffer.write(_sanitizeName(key)); + buffer.write("@"); + + final sanitizeUnitName = _sanitizeUnit(unit.name); + buffer.write(sanitizeUnitName); + + for (final value in _serializeValue()) { + buffer.write(":"); + buffer.write(value.toString()); + } + + buffer.write("|"); + buffer.write(type.statsdType); + + if (tags.isNotEmpty) { + buffer.write("|#"); + final serializedTags = tags.entries + .map((tag) => + '${_sanitizeTagKey(tag.key)}:${_sanitizeTagValue(tag.value)}') + .join(','); + buffer.write(serializedTags); + } + + buffer.write("|T"); + buffer.write(bucketKey); + + return buffer.toString(); + } + + /// Return a key created by [key], [type], [unit] and [tags]. + /// This key should be used to retrieve the metric to update in aggregation. + String getCompositeKey() { + final String serializedTags = tags.entries.map((e) { + // We escape the ',' from the key and the value, as we will join the tags + // with a ',' to create the composite key. + String escapedKey = e.key.replaceAll(',', '\\,'); + String escapedValue = e.value.replaceAll(',', '\\,'); + return '$escapedKey=$escapedValue'; + }).join(','); + + return ('${type.statsdType}_${key}_${unit.name}_$serializedTags'); + } + + /// Return a key created by [key], [type] and [unit]. + /// This key should be used to aggregate the metric locally in a span. + String getSpanAggregationKey() => '${type.statsdType}:$key@${unit.name}'; + + /// Remove forbidden characters from the metric key and tag key. + String _sanitizeName(String input) => input.replaceAll(nameRegex, '_'); + + /// Remove forbidden characters from the tag value. + String _sanitizeTagKey(String input) => input.replaceAll(tagKeyRegex, ''); + + /// Remove forbidden characters from the metric unit. + String _sanitizeUnit(String input) => input.replaceAll(unitRegex, ''); + + String _sanitizeTagValue(String input) { + // see https://develop.sentry.dev/sdk/metrics/#tag-values-replacement-map + // Line feed -> \n + // Carriage return -> \r + // Tab -> \t + // Backslash -> \\ + // Pipe -> \\u{7c} + // Comma -> \\u{2c} + final buffer = StringBuffer(); + for (int i = 0; i < input.length; i++) { + final ch = input[i]; + if (ch == '\n') { + buffer.write("\\n"); + } else if (ch == '\r') { + buffer.write("\\r"); + } else if (ch == '\t') { + buffer.write("\\t"); + } else if (ch == '\\') { + buffer.write("\\\\"); + } else if (ch == '|') { + buffer.write("\\u{7c}"); + } else if (ch == ',') { + buffer.write("\\u{2c}"); + } else { + buffer.write(ch); + } + } + return buffer.toString(); + } +} + +/// Metric [MetricType.counter] that tracks a value that can only be incremented. +@internal +class CounterMetric extends Metric { + num value; + + CounterMetric._({ + required this.value, + required super.key, + required super.unit, + required super.tags, + }) : super(type: MetricType.counter); + + @override + add(num value) => this.value += value; + + @override + Iterable _serializeValue() => [value]; + + @override + int getWeight() => 1; +} + +/// Metric [MetricType.gauge] that tracks a value that can go up and down. +@internal +class GaugeMetric extends Metric { + num _last; + num _minimum; + num _maximum; + num _sum; + int _count; + + GaugeMetric._({ + required num value, + required super.key, + required super.unit, + required super.tags, + }) : _last = value, + _minimum = value, + _maximum = value, + _sum = value, + _count = 1, + super(type: MetricType.gauge); + + @override + add(num value) { + _last = value; + _minimum = min(_minimum, value); + _maximum = max(_maximum, value); + _sum += value; + _count++; + } + + @override + Iterable _serializeValue() => + [_last, _minimum, _maximum, _sum, _count]; + + @override + int getWeight() => 5; + + @visibleForTesting + num get last => _last; + num get minimum => _minimum; + num get maximum => _maximum; + num get sum => _sum; + int get count => _count; +} + +/// Metric [MetricType.set] that tracks a set of values on which you can perform +/// aggregations such as count_unique. +@internal +class SetMetric extends Metric { + final Set _values = {}; + + SetMetric._( + {required num value, + required super.key, + required super.unit, + required super.tags}) + : super(type: MetricType.set) { + add(value); + } + + @override + add(num value) => _values.add(value.toInt()); + + @override + Iterable _serializeValue() => _values; + + @override + int getWeight() => _values.length; + + @visibleForTesting + Set get values => _values; +} + +/// Metric [MetricType.distribution] that tracks a list of values. +@internal +class DistributionMetric extends Metric { + final List _values = []; + + DistributionMetric._( + {required num value, + required super.key, + required super.unit, + required super.tags}) + : super(type: MetricType.distribution) { + add(value); + } + + @override + add(num value) => _values.add(value); + + @override + Iterable _serializeValue() => _values; + + @override + int getWeight() => _values.length; + + @visibleForTesting + List get values => _values; +} + +/// The metric type and its associated statsd encoded value. +@internal +enum MetricType { + counter('c'), + gauge('g'), + distribution('d'), + set('s'); + + final String statsdType; + + const MetricType(this.statsdType); +} diff --git a/dart/lib/src/metrics/metrics_aggregator.dart b/dart/lib/src/metrics/metrics_aggregator.dart new file mode 100644 index 0000000000..ef763eae35 --- /dev/null +++ b/dart/lib/src/metrics/metrics_aggregator.dart @@ -0,0 +1,207 @@ +import 'dart:async'; +import 'dart:collection'; +import 'dart:math'; + +import 'package:meta/meta.dart'; + +import '../../sentry.dart'; +import 'local_metrics_aggregator.dart'; +import 'metric.dart'; + +/// Class that aggregates all metrics into time buckets and sends them. +@internal +class MetricsAggregator { + static final _defaultFlushShiftMs = + (Random().nextDouble() * (_rollupInSeconds * 1000)).toInt(); + static const _defaultFlushInterval = Duration(seconds: 5); + static const _defaultMaxWeight = 100000; + static const int _rollupInSeconds = 10; + + final Duration _flushInterval; + final int _flushShiftMs; + final SentryOptions _options; + final Hub _hub; + final int _maxWeight; + int _totalWeight = 0; + bool _isClosed = false; + Completer? _flushCompleter; + Timer? _flushTimer; + + /// The key for this map is the timestamp of the bucket, rounded down to the + /// nearest RollupInSeconds. So it aggregates all the metrics over a certain + /// time period. The Value is a map of the metrics, each of which has a key + /// that uniquely identifies it within the time period. + /// The [SplayTreeMap] is used so that bucket keys are ordered. + final SplayTreeMap> _buckets = SplayTreeMap(); + + MetricsAggregator({ + required SentryOptions options, + Hub? hub, + @visibleForTesting Duration? flushInterval, + @visibleForTesting int? flushShiftMs, + @visibleForTesting int? maxWeight, + }) : _options = options, + _hub = hub ?? HubAdapter(), + _flushInterval = flushInterval ?? _defaultFlushInterval, + _flushShiftMs = flushShiftMs ?? _defaultFlushShiftMs, + _maxWeight = maxWeight ?? _defaultMaxWeight; + + /// Creates or update an existing Counter metric with [value]. + /// The metric to update is identified using [key], [unit] and [tags]. + /// The [timestamp] represents when the metric was emitted. + void emit( + MetricType metricType, + String key, + num value, + SentryMeasurementUnit unit, + Map tags, { + LocalMetricsAggregator? localMetricsAggregator, + }) { + if (_isClosed) { + return; + } + + // run before metric callback if set + if (_options.beforeMetricCallback != null) { + try { + final shouldEmit = _options.beforeMetricCallback!(key, tags: tags); + if (!shouldEmit) { + _options.logger( + SentryLevel.info, + 'Metric was dropped by beforeMetric', + ); + return; + } + } catch (exception, stackTrace) { + _options.logger( + SentryLevel.error, + 'The BeforeMetric callback threw an exception', + exception: exception, + stackTrace: stackTrace, + ); + if (_options.automatedTestMode) { + rethrow; + } + } + } + + final bucketKey = _getBucketKey(_options.clock()); + final bucket = _buckets.putIfAbsent(bucketKey, () => {}); + final metric = Metric.fromType( + type: metricType, key: key, value: value, unit: unit, tags: tags); + + final oldWeight = bucket[metric.getCompositeKey()]?.getWeight() ?? 0; + final addedWeight = metric.getWeight(); + _totalWeight += addedWeight - oldWeight; + + // Update the existing metric in the bucket. + // If absent, add the newly created metric to the bucket. + bucket.update( + metric.getCompositeKey(), + (m) => m..add(value), + ifAbsent: () => metric, + ); + + // For sets, we only record that a value has been added to the set but not which one. + // See develop docs: https://develop.sentry.dev/sdk/metrics/#sets + final localAggregator = + localMetricsAggregator ?? (_hub.getSpan()?.localMetricsAggregator); + localAggregator?.add( + metric, metricType == MetricType.set ? addedWeight : value); + + // Schedule the metrics flushing. + _scheduleFlush(); + } + + void _scheduleFlush() { + if (!_isClosed && _buckets.isNotEmpty) { + if (_isOverWeight()) { + _flushTimer?.cancel(); + _flush(false); + return; + } + if (_flushTimer?.isActive != true) { + _flushCompleter = Completer(); + _flushTimer = Timer(_flushInterval, () => _flush(false)); + } + } + } + + bool _isOverWeight() => _totalWeight >= _maxWeight; + + int getBucketWeight(final Map bucket) { + int weight = 0; + for (final metric in bucket.values) { + weight += metric.getWeight(); + } + return weight; + } + + /// Flush the metrics, then schedule next flush again. + void _flush(bool force) async { + if (!force && _isOverWeight()) { + _options.logger(SentryLevel.info, + "Metrics: total weight exceeded, flushing all buckets"); + force = true; + } + + final flushableBucketKeys = _getFlushableBucketKeys(force); + if (flushableBucketKeys.isEmpty) { + _options.logger(SentryLevel.debug, 'Metrics: nothing to flush'); + } else { + final Map> bucketsToFlush = {}; + + for (final flushableBucketKey in flushableBucketKeys) { + final bucket = _buckets.remove(flushableBucketKey); + if (bucket != null && bucket.isNotEmpty) { + _totalWeight -= getBucketWeight(bucket); + bucketsToFlush[flushableBucketKey] = bucket.values; + } + } + await _hub.captureMetrics(bucketsToFlush); + } + + // Notify flush completed and reschedule flushing + _flushTimer?.cancel(); + _flushTimer = null; + flushCompleter?.complete(null); + _flushCompleter = null; + _scheduleFlush(); + } + + /// Return a list of bucket keys to flush. + List _getFlushableBucketKeys(bool force) { + if (force) { + return buckets.keys.toList(); + } + // Flushable buckets are all buckets with timestamp lower than the current + // one (so now - rollupInSeconds), minus a random duration (flushShiftMs). + final maxTimestampToFlush = _options.clock().subtract(Duration( + seconds: _rollupInSeconds, + milliseconds: _flushShiftMs, + )); + final maxKeyToFlush = _getBucketKey(maxTimestampToFlush); + + // takeWhile works because we use a SplayTreeMap and keys are ordered. + // toList() is needed because takeWhile is lazy and we want to remove items + // from the buckets with these keys. + return _buckets.keys.takeWhile((value) => value <= maxKeyToFlush).toList(); + } + + /// The timestamp of the bucket, rounded down to the nearest RollupInSeconds. + int _getBucketKey(DateTime timestamp) { + final seconds = timestamp.millisecondsSinceEpoch ~/ 1000; + return (seconds ~/ _rollupInSeconds) * _rollupInSeconds; + } + + @visibleForTesting + SplayTreeMap> get buckets => _buckets; + + @visibleForTesting + Completer? get flushCompleter => _flushCompleter; + + void close() { + _flush(true); + _isClosed = true; + } +} diff --git a/dart/lib/src/metrics/metrics_api.dart b/dart/lib/src/metrics/metrics_api.dart new file mode 100644 index 0000000000..9f9e8305f2 --- /dev/null +++ b/dart/lib/src/metrics/metrics_api.dart @@ -0,0 +1,186 @@ +import 'dart:async'; +import 'dart:convert'; +import '../../sentry.dart'; +import '../utils/crc32_utils.dart'; +import 'metric.dart'; + +/// Public APIs to emit Sentry metrics. +class MetricsApi { + MetricsApi({Hub? hub}) : _hub = hub ?? HubAdapter(); + + final Hub _hub; + + /// Emits a Counter metric, identified by [key], increasing it by [value]. + /// Counters track a value that can only be incremented. + /// You can set the [unit] and the optional [tags] to associate to the metric. + void increment(final String key, + {final double value = 1.0, + final SentryMeasurementUnit? unit, + final Map? tags}) { + _hub.metricsAggregator?.emit( + MetricType.counter, + key, + value, + unit ?? SentryMeasurementUnit.none, + _enrichWithDefaultTags(tags), + ); + } + + /// Emits a Gauge metric, identified by [key], adding [value] to it. + /// Gauges track a value that can go up and down. + /// You can set the [unit] and the optional [tags] to associate to the metric. + void gauge(final String key, + {required final double value, + final SentryMeasurementUnit? unit, + final Map? tags}) { + _hub.metricsAggregator?.emit( + MetricType.gauge, + key, + value, + unit ?? SentryMeasurementUnit.none, + _enrichWithDefaultTags(tags), + ); + } + + /// Emits a Distribution metric, identified by [key], adding [value] to it. + /// Distributions track a list of values. + /// You can set the [unit] and the optional [tags] to associate to the metric. + void distribution(final String key, + {required final double value, + final SentryMeasurementUnit? unit, + final Map? tags}) { + _hub.metricsAggregator?.emit( + MetricType.distribution, + key, + value, + unit ?? SentryMeasurementUnit.none, + _enrichWithDefaultTags(tags), + ); + } + + /// Emits a Set metric, identified by [key], adding [value] or the CRC32 + /// checksum of [stringValue] to it. + /// Providing both [value] and [stringValue] adds both values to the metric. + /// Sets track a set of values to perform aggregations such as count_unique. + /// You can set the [unit] and the optional [tags] to associate to the metric. + void set(final String key, + {final int? value, + final String? stringValue, + final SentryMeasurementUnit? unit, + final Map? tags}) { + if (value != null) { + _hub.metricsAggregator?.emit( + MetricType.set, + key, + value, + unit ?? SentryMeasurementUnit.none, + _enrichWithDefaultTags(tags), + ); + } + if (stringValue != null && stringValue.isNotEmpty) { + final intValue = Crc32Utils.getCrc32(utf8.encode(stringValue)); + + _hub.metricsAggregator?.emit( + MetricType.set, + key, + intValue, + unit ?? SentryMeasurementUnit.none, + _enrichWithDefaultTags(tags), + ); + } + if (value == null && (stringValue == null || stringValue.isEmpty)) { + _hub.options.logger( + SentryLevel.info, 'No value provided. No metric will be emitted.'); + } + } + + /// Enrich user tags adding default tags + /// + /// Currently adds release, environment and transaction. + Map _enrichWithDefaultTags(Map? userTags) { + // We create another map, in case the userTags is unmodifiable. + final Map tags = Map.from(userTags ?? {}); + if (!_hub.options.enableDefaultTagsForMetrics) { + return tags; + } + // Enrich tags with default values (without overwriting user values) + _putIfAbsentIfNotNull(tags, 'release', _hub.options.release); + _putIfAbsentIfNotNull(tags, 'environment', _hub.options.environment); + _putIfAbsentIfNotNull(tags, 'transaction', _hub.scope.transaction); + return tags; + } + + /// Call [map.putIfAbsent] with [key] and [value] if [value] is not null. + _putIfAbsentIfNotNull(Map map, K key, V? value) { + if (value != null) { + map.putIfAbsent(key, () => value); + } + } + + /// Emits a Distribution metric, identified by [key], with the time it takes + /// to run [function]. + /// You can set the [unit] and the optional [tags] to associate to the metric. + void timing(final String key, + {required FutureOr Function() function, + final DurationSentryMeasurementUnit unit = + DurationSentryMeasurementUnit.second, + final Map? tags}) async { + // Start a span for the metric + final span = _hub.getSpan()?.startChild('metric.timing', description: key); + // Set the user tags to the span as well + if (span != null && tags != null) { + for (final entry in tags.entries) { + span.setTag(entry.key, entry.value); + } + } + final before = _hub.options.clock(); + try { + if (function is Future Function()) { + await function(); + } else { + function(); + } + } finally { + final after = _hub.options.clock(); + Duration duration = after.difference(before); + // If we have a span, we use its duration as value for the emitted metric + if (span != null) { + await span.finish(); + duration = + span.endTimestamp?.difference(span.startTimestamp) ?? duration; + } + final value = _convertMicrosTo(unit, duration.inMicroseconds); + + _hub.metricsAggregator?.emit( + MetricType.distribution, + key, + value, + unit, + _enrichWithDefaultTags(tags), + localMetricsAggregator: span?.localMetricsAggregator, + ); + } + } + + double _convertMicrosTo( + final DurationSentryMeasurementUnit unit, final int micros) { + switch (unit) { + case DurationSentryMeasurementUnit.nanoSecond: + return micros * 1000; + case DurationSentryMeasurementUnit.microSecond: + return micros.toDouble(); + case DurationSentryMeasurementUnit.milliSecond: + return micros / 1000.0; + case DurationSentryMeasurementUnit.second: + return micros / 1000000.0; + case DurationSentryMeasurementUnit.minute: + return micros / 60000000.0; + case DurationSentryMeasurementUnit.hour: + return micros / 3600000000.0; + case DurationSentryMeasurementUnit.day: + return micros / 86400000000.0; + case DurationSentryMeasurementUnit.week: + return micros / 86400000000.0 / 7.0; + } + } +} diff --git a/dart/lib/src/noop_hub.dart b/dart/lib/src/noop_hub.dart index 06d31e7da2..30f68ca895 100644 --- a/dart/lib/src/noop_hub.dart +++ b/dart/lib/src/noop_hub.dart @@ -4,6 +4,9 @@ import 'package:meta/meta.dart'; import 'hint.dart'; import 'hub.dart'; +import 'metrics/metric.dart'; +import 'metrics/metrics_aggregator.dart'; +import 'metrics/metrics_api.dart'; import 'profiling.dart'; import 'protocol.dart'; import 'scope.dart'; @@ -13,16 +16,24 @@ import 'sentry_user_feedback.dart'; import 'tracing.dart'; class NoOpHub implements Hub { - NoOpHub._(); + NoOpHub._() { + _metricsApi = MetricsApi(hub: this); + } static final NoOpHub _instance = NoOpHub._(); final _options = SentryOptions.empty(); + late final MetricsApi _metricsApi; + @override @internal SentryOptions get options => _options; + @override + @internal + MetricsApi get metricsApi => _metricsApi; + factory NoOpHub() { return _instance; } @@ -131,4 +142,14 @@ class NoOpHub implements Hub { @override Scope get scope => Scope(_options); + + @override + @internal + Future captureMetrics( + Map> metricsBuckets) async => + SentryId.empty(); + + @override + @internal + MetricsAggregator? get metricsAggregator => null; } diff --git a/dart/lib/src/noop_sentry_client.dart b/dart/lib/src/noop_sentry_client.dart index 593d63f74b..5a8c04bbae 100644 --- a/dart/lib/src/noop_sentry_client.dart +++ b/dart/lib/src/noop_sentry_client.dart @@ -1,6 +1,10 @@ import 'dart:async'; +import 'package:meta/meta.dart'; + import 'hint.dart'; +import 'metrics/metric.dart'; +import 'metrics/metrics_aggregator.dart'; import 'protocol.dart'; import 'scope.dart'; import 'sentry_client.dart'; @@ -63,4 +67,14 @@ class NoOpSentryClient implements SentryClient { SentryTraceContextHeader? traceContext, }) async => SentryId.empty(); + + @override + @internal + Future captureMetrics( + Map> metricsBuckets) async => + SentryId.empty(); + + @override + @internal + MetricsAggregator? get metricsAggregator => null; } diff --git a/dart/lib/src/noop_sentry_span.dart b/dart/lib/src/noop_sentry_span.dart index 2156aeb678..45d72b94c9 100644 --- a/dart/lib/src/noop_sentry_span.dart +++ b/dart/lib/src/noop_sentry_span.dart @@ -1,3 +1,4 @@ +import 'metrics/local_metrics_aggregator.dart'; import 'protocol.dart'; import 'tracing.dart'; import 'utils.dart'; @@ -95,4 +96,7 @@ class NoOpSentrySpan extends ISentrySpan { @override void scheduleFinish() {} + + @override + LocalMetricsAggregator? get localMetricsAggregator => null; } diff --git a/dart/lib/src/protocol.dart b/dart/lib/src/protocol.dart index 3dac1a6f3c..6d89823721 100644 --- a/dart/lib/src/protocol.dart +++ b/dart/lib/src/protocol.dart @@ -8,6 +8,7 @@ export 'protocol/sentry_device.dart'; export 'protocol/dsn.dart'; export 'protocol/sentry_gpu.dart'; export 'protocol/mechanism.dart'; +export 'protocol/metric_summary.dart'; export 'protocol/sentry_message.dart'; export 'protocol/sentry_operating_system.dart'; export 'protocol/sentry_request.dart'; diff --git a/dart/lib/src/protocol/mechanism.dart b/dart/lib/src/protocol/mechanism.dart index 2c06c954f6..22a6356800 100644 --- a/dart/lib/src/protocol/mechanism.dart +++ b/dart/lib/src/protocol/mechanism.dart @@ -44,6 +44,38 @@ class Mechanism { /// This may be because they are created at a central place (like a crash handler), and are all called the same: Error, Segfault etc. When the flag is set, Sentry will then try to use other information (top in-app frame function) rather than exception type and value in the UI for the primary event display. This flag should be set for all "segfaults" for instance as every single error group would look very similar otherwise. final bool? synthetic; + /// An optional boolean value, set `true` when the exception is the exception + /// group type specific to the platform or language. + /// The default is false when omitted. + /// For example, exceptions of type [PlatformException](https://api.flutter.dev/flutter/services/PlatformException-class.html) + /// have set it to `true`, others are set to `false`. + final bool? isExceptionGroup; + + /// An optional string value describing the source of the exception. + /// + /// The SDK should populate this with the name of the property or attribute of + /// the parent exception that this exception was acquired from. + /// In the case of an array, it should include the zero-based array index as + /// well. + final String? source; + + /// An optional numeric value providing an ID for the exception relative to + /// this specific event. + /// + /// The SDK should assign simple incrementing integers to each exception in + /// the tree, starting with 0 for the root of the tree. + /// In other words, when flattened into the list provided in the exception + /// values on the event, the last exception in the list should have ID 0, + /// the previous one should have ID 1, the next previous should have ID 2, etc. + final int? exceptionId; + + /// An optional numeric value pointing at the [exceptionId] that is the parent + /// of this exception. + /// + /// The SDK should assign this to all exceptions except the root exception + /// (the last to be listed in the exception values). + final int? parentId; + Mechanism({ required this.type, this.description, @@ -52,6 +84,10 @@ class Mechanism { this.synthetic, Map? meta, Map? data, + this.isExceptionGroup, + this.source, + this.exceptionId, + this.parentId, }) : _meta = meta != null ? Map.from(meta) : null, _data = data != null ? Map.from(data) : null; @@ -63,6 +99,10 @@ class Mechanism { Map? meta, Map? data, bool? synthetic, + bool? isExceptionGroup, + String? source, + int? exceptionId, + int? parentId, }) => Mechanism( type: type ?? this.type, @@ -72,6 +112,10 @@ class Mechanism { meta: meta ?? this.meta, data: data ?? this.data, synthetic: synthetic ?? this.synthetic, + isExceptionGroup: isExceptionGroup ?? this.isExceptionGroup, + source: source ?? this.source, + exceptionId: exceptionId ?? this.exceptionId, + parentId: parentId ?? this.parentId, ); /// Deserializes a [Mechanism] from JSON [Map]. @@ -94,6 +138,10 @@ class Mechanism { meta: meta, data: data, synthetic: json['synthetic'], + isExceptionGroup: json['is_exception_group'], + source: json['source'], + exceptionId: json['exception_id'], + parentId: json['parent_id'], ); } @@ -107,6 +155,10 @@ class Mechanism { if (_meta?.isNotEmpty ?? false) 'meta': _meta, if (_data?.isNotEmpty ?? false) 'data': _data, if (synthetic != null) 'synthetic': synthetic, + if (isExceptionGroup != null) 'is_exception_group': isExceptionGroup, + if (source != null) 'source': source, + if (exceptionId != null) 'exception_id': exceptionId, + if (parentId != null) 'parent_id': parentId, }; } } diff --git a/dart/lib/src/protocol/metric_summary.dart b/dart/lib/src/protocol/metric_summary.dart new file mode 100644 index 0000000000..b0c617fb30 --- /dev/null +++ b/dart/lib/src/protocol/metric_summary.dart @@ -0,0 +1,43 @@ +import '../metrics/metric.dart'; + +class MetricSummary { + final num min; + final num max; + final num sum; + final int count; + final Map? tags; + + MetricSummary.fromGauge(GaugeMetric gauge) + : min = gauge.minimum, + max = gauge.maximum, + sum = gauge.sum, + count = gauge.count, + tags = gauge.tags; + + const MetricSummary( + {required this.min, + required this.max, + required this.sum, + required this.count, + required this.tags}); + + /// Deserializes a [MetricSummary] from JSON [Map]. + factory MetricSummary.fromJson(Map data) => MetricSummary( + min: data['min'], + max: data['max'], + count: data['count'], + sum: data['sum'], + tags: data['tags']?.cast(), + ); + + /// Produces a [Map] that can be serialized to JSON. + Map toJson() { + return { + 'min': min, + 'max': max, + 'count': count, + 'sum': sum, + if (tags?.isNotEmpty ?? false) 'tags': tags, + }; + } +} diff --git a/dart/lib/src/protocol/sentry_app.dart b/dart/lib/src/protocol/sentry_app.dart index b5163e5856..24501ce540 100644 --- a/dart/lib/src/protocol/sentry_app.dart +++ b/dart/lib/src/protocol/sentry_app.dart @@ -19,6 +19,7 @@ class SentryApp { this.appMemory, this.inForeground, this.viewNames, + this.textScale, }); /// Human readable application name, as it appears on the platform. @@ -52,6 +53,9 @@ class SentryApp { /// The names of the currently visible views. final List? viewNames; + /// The current text scale. Only available on Flutter. + final double? textScale; + /// Deserializes a [SentryApp] from JSON [Map]. factory SentryApp.fromJson(Map data) { final viewNamesJson = data['view_names'] as List?; @@ -68,6 +72,7 @@ class SentryApp { appMemory: data['app_memory'], inForeground: data['in_foreground'], viewNames: viewNamesJson?.map((e) => e as String).toList(), + textScale: data['text_scale'], ); } @@ -84,6 +89,7 @@ class SentryApp { if (appMemory != null) 'app_memory': appMemory!, if (inForeground != null) 'in_foreground': inForeground!, if (viewNames != null && viewNames!.isNotEmpty) 'view_names': viewNames!, + if (textScale != null) 'text_scale': textScale!, }; } @@ -98,6 +104,7 @@ class SentryApp { appMemory: appMemory, inForeground: inForeground, viewNames: viewNames, + textScale: textScale, ); SentryApp copyWith({ @@ -111,6 +118,7 @@ class SentryApp { int? appMemory, bool? inForeground, List? viewNames, + double? textScale, }) => SentryApp( name: name ?? this.name, @@ -123,5 +131,6 @@ class SentryApp { appMemory: appMemory ?? this.appMemory, inForeground: inForeground ?? this.inForeground, viewNames: viewNames ?? this.viewNames, + textScale: textScale ?? this.textScale, ); } diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index 9689c8a974..b5ee7d003c 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import '../utils/iterable_extension.dart'; +import '../utils/iterable_utils.dart'; import '../utils/http_sanitizer.dart'; /// The Request interface contains information on a HTTP request related to the event. @@ -85,9 +85,10 @@ class SentryRequest { _headers = headers != null ? Map.from(headers) : null, // Look for a 'Set-Cookie' header (case insensitive) if not given. cookies = cookies ?? - headers?.entries - .firstWhereOrNull((e) => e.key.toLowerCase() == 'cookie') - ?.value, + IterableUtils.firstWhereOrNull( + headers?.entries, + (MapEntry e) => e.key.toLowerCase() == 'cookie', + )?.value, _env = env != null ? Map.from(env) : null, _other = other != null ? Map.from(other) : null; diff --git a/dart/lib/src/protocol/sentry_response.dart b/dart/lib/src/protocol/sentry_response.dart index 91faaa37eb..6008ea8730 100644 --- a/dart/lib/src/protocol/sentry_response.dart +++ b/dart/lib/src/protocol/sentry_response.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; import 'contexts.dart'; -import '../utils/iterable_extension.dart'; +import '../utils/iterable_utils.dart'; /// The response interface contains information on a HTTP request related to the event. @immutable @@ -53,9 +53,11 @@ class SentryResponse { _headers = headers != null ? Map.from(headers) : null, // Look for a 'Set-Cookie' header (case insensitive) if not given. cookies = cookies ?? - headers?.entries - .firstWhereOrNull((e) => e.key.toLowerCase() == 'set-cookie') - ?.value; + IterableUtils.firstWhereOrNull( + headers?.entries, + (MapEntry e) => + e.key.toLowerCase() == 'set-cookie', + )?.value; /// Deserializes a [SentryResponse] from JSON [Map]. factory SentryResponse.fromJson(Map json) { diff --git a/dart/lib/src/protocol/sentry_span.dart b/dart/lib/src/protocol/sentry_span.dart index e03410d715..780578d182 100644 --- a/dart/lib/src/protocol/sentry_span.dart +++ b/dart/lib/src/protocol/sentry_span.dart @@ -1,6 +1,7 @@ import 'dart:async'; import '../hub.dart'; +import '../metrics/local_metrics_aggregator.dart'; import '../protocol.dart'; import '../sentry_tracer.dart'; @@ -12,6 +13,7 @@ typedef OnFinishedCallback = Future Function({DateTime? endTimestamp}); class SentrySpan extends ISentrySpan { final SentrySpanContext _context; DateTime? _endTimestamp; + Map>? _metricSummaries; late final DateTime _startTimestamp; final Hub _hub; @@ -22,6 +24,7 @@ class SentrySpan extends ISentrySpan { SpanStatus? _status; final Map _tags = {}; OnFinishedCallback? _finishedCallback; + late final LocalMetricsAggregator? _localMetricsAggregator; @override final SentryTracesSamplingDecision? samplingDecision; @@ -37,6 +40,9 @@ class SentrySpan extends ISentrySpan { _startTimestamp = startTimestamp?.toUtc() ?? _hub.options.clock(); _finishedCallback = finishedCallback; _origin = _context.origin; + _localMetricsAggregator = _hub.options.enableSpanLocalMetricAggregation + ? LocalMetricsAggregator() + : null; } @override @@ -65,6 +71,7 @@ class SentrySpan extends ISentrySpan { if (_throwable != null) { _hub.setSpanContext(_throwable, this, _tracer.name); } + _metricSummaries = _localMetricsAggregator?.getSummaries(); await _finishedCallback?.call(endTimestamp: _endTimestamp); return super.finish(status: status, endTimestamp: _endTimestamp); } @@ -154,6 +161,9 @@ class SentrySpan extends ISentrySpan { @override set origin(String? origin) => _origin = origin; + @override + LocalMetricsAggregator? get localMetricsAggregator => _localMetricsAggregator; + Map toJson() { final json = _context.toJson(); json['start_timestamp'] = @@ -174,6 +184,16 @@ class SentrySpan extends ISentrySpan { if (_origin != null) { json['origin'] = _origin; } + + final metricSummariesMap = _metricSummaries?.entries ?? Iterable.empty(); + if (metricSummariesMap.isNotEmpty) { + final map = {}; + for (final entry in metricSummariesMap) { + final summary = entry.value.map((e) => e.toJson()); + map[entry.key] = summary.toList(growable: false); + } + json['_metrics_summary'] = map; + } return json; } diff --git a/dart/lib/src/protocol/sentry_transaction.dart b/dart/lib/src/protocol/sentry_transaction.dart index 986169ce46..eea319aa41 100644 --- a/dart/lib/src/protocol/sentry_transaction.dart +++ b/dart/lib/src/protocol/sentry_transaction.dart @@ -13,49 +13,40 @@ class SentryTransaction extends SentryEvent { @internal final SentryTracer tracer; late final Map measurements; + late final Map>? metricSummaries; late final SentryTransactionInfo? transactionInfo; SentryTransaction( this.tracer, { - SentryId? eventId, + super.eventId, DateTime? timestamp, - String? platform, - String? serverName, - String? release, - String? dist, - String? environment, + super.platform, + super.serverName, + super.release, + super.dist, + super.environment, String? transaction, dynamic throwable, Map? tags, @Deprecated( 'Additional Data is deprecated in favor of structured [Contexts] and should be avoided when possible') Map? extra, - SentryUser? user, - Contexts? contexts, - List? breadcrumbs, - SdkVersion? sdk, - SentryRequest? request, + super.user, + super.contexts, + super.breadcrumbs, + super.sdk, + super.request, String? type, Map? measurements, + Map>? metricSummaries, SentryTransactionInfo? transactionInfo, }) : super( - eventId: eventId, timestamp: timestamp ?? tracer.endTimestamp, - platform: platform, - serverName: serverName, - release: release, - dist: dist, - environment: environment, transaction: transaction ?? tracer.name, throwable: throwable ?? tracer.throwable, tags: tags ?? tracer.tags, // ignore: deprecated_member_use_from_same_package extra: extra ?? tracer.data, - user: user, - contexts: contexts, - breadcrumbs: breadcrumbs, - sdk: sdk, - request: request, type: _type, ) { startTimestamp = tracer.startTimestamp; @@ -63,8 +54,10 @@ class SentryTransaction extends SentryEvent { final spanContext = tracer.context; spans = tracer.children; this.measurements = measurements ?? {}; + this.metricSummaries = + metricSummaries ?? tracer.localMetricsAggregator?.getSummaries(); - this.contexts.trace = spanContext.toTraceContext( + contexts.trace = spanContext.toTraceContext( sampled: tracer.samplingDecision?.sampled, status: tracer.status, ); @@ -96,6 +89,16 @@ class SentryTransaction extends SentryEvent { json['transaction_info'] = transactionInfo.toJson(); } + final metricSummariesMap = metricSummaries?.entries ?? Iterable.empty(); + if (metricSummariesMap.isNotEmpty) { + final map = {}; + for (final entry in metricSummariesMap) { + final summary = entry.value.map((e) => e.toJson()); + map[entry.key] = summary.toList(growable: false); + } + json['_metrics_summary'] = map; + } + return json; } @@ -134,6 +137,7 @@ class SentryTransaction extends SentryEvent { List? threads, String? type, Map? measurements, + Map>? metricSummaries, SentryTransactionInfo? transactionInfo, }) => SentryTransaction( @@ -159,6 +163,9 @@ class SentryTransaction extends SentryEvent { type: type ?? this.type, measurements: (measurements != null ? Map.from(measurements) : null) ?? this.measurements, + metricSummaries: + (metricSummaries != null ? Map.from(metricSummaries) : null) ?? + this.metricSummaries, transactionInfo: transactionInfo ?? this.transactionInfo, ); } diff --git a/dart/lib/src/run_zoned_guarded_integration.dart b/dart/lib/src/run_zoned_guarded_integration.dart index ba70fc2472..20f0857e3b 100644 --- a/dart/lib/src/run_zoned_guarded_integration.dart +++ b/dart/lib/src/run_zoned_guarded_integration.dart @@ -44,13 +44,15 @@ class RunZonedGuardedIntegration extends Integration { stackTrace: stackTrace, ); - // runZonedGuarded doesn't crash the App. - final mechanism = Mechanism(type: 'runZonedGuarded', handled: true); + // runZonedGuarded doesn't crash the app, but is not handled by the user. + final mechanism = Mechanism(type: 'runZonedGuarded', handled: false); final throwableMechanism = ThrowableMechanism(mechanism, exception); final event = SentryEvent( throwable: throwableMechanism, - level: SentryLevel.fatal, + level: options.markAutomaticallyCollectedErrorsAsFatal + ? SentryLevel.fatal + : SentryLevel.error, timestamp: hub.options.clock(), ); diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart index 4f36895131..3fef9a92a2 100644 --- a/dart/lib/src/scope.dart +++ b/dart/lib/src/scope.dart @@ -150,7 +150,7 @@ class Scope { Scope(this._options); - Breadcrumb? _addBreadCrumbSync(Breadcrumb breadcrumb, {Hint? hint}) { + Breadcrumb? _addBreadCrumbSync(Breadcrumb breadcrumb, Hint hint) { // bail out if maxBreadcrumbs is zero if (_options.maxBreadcrumbs == 0) { return null; @@ -162,7 +162,7 @@ class Scope { try { processedBreadcrumb = _options.beforeBreadcrumb!( processedBreadcrumb, - hint: hint, + hint, ); if (processedBreadcrumb == null) { _options.logger( @@ -196,7 +196,7 @@ class Scope { /// Adds a breadcrumb to the breadcrumbs queue Future addBreadcrumb(Breadcrumb breadcrumb, {Hint? hint}) async { - final addedBreadcrumb = _addBreadCrumbSync(breadcrumb, hint: hint); + final addedBreadcrumb = _addBreadCrumbSync(breadcrumb, hint ?? Hint()); if (addedBreadcrumb != null) { await _callScopeObservers((scopeObserver) async => await scopeObserver.addBreadcrumb(addedBreadcrumb)); @@ -282,9 +282,9 @@ class Scope { } Future applyToEvent( - SentryEvent event, { - Hint? hint, - }) async { + SentryEvent event, + Hint hint, + ) async { event = event.copyWith( transaction: event.transaction ?? transaction, user: _mergeUsers(user, event.user), @@ -332,7 +332,7 @@ class Scope { SentryEvent? processedEvent = event; for (final processor in _eventProcessors) { try { - final e = processor.apply(processedEvent!, hint: hint); + final e = processor.apply(processedEvent!, hint); if (e is Future) { processedEvent = await e; } else { @@ -442,7 +442,7 @@ class Scope { } for (final breadcrumb in List.from(_breadcrumbs)) { - clone._addBreadCrumbSync(breadcrumb); + clone._addBreadCrumbSync(breadcrumb, Hint()); } for (final eventProcessor in List.from(_eventProcessors)) { diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index 88fdd42996..1873cd6308 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:meta/meta.dart'; +import 'metrics/metrics_api.dart'; import 'run_zoned_guarded_integration.dart'; import 'event_processor/enricher/enricher_event_processor.dart'; import 'environment/environment_variables.dart'; @@ -306,6 +307,9 @@ class Sentry { /// Gets the current active transaction or span bound to the scope. static ISentrySpan? getSpan() => _hub.getSpan(); + /// Gets access to the metrics API for the current hub. + static MetricsApi metrics() => _hub.metricsApi; + @internal static Hub get currentHub => _hub; } diff --git a/dart/lib/src/sentry_attachment/io_sentry_attachment.dart b/dart/lib/src/sentry_attachment/io_sentry_attachment.dart index a1e2585556..ae07b51508 100644 --- a/dart/lib/src/sentry_attachment/io_sentry_attachment.dart +++ b/dart/lib/src/sentry_attachment/io_sentry_attachment.dart @@ -24,12 +24,10 @@ class IoSentryAttachment extends SentryAttachment { IoSentryAttachment.fromFile( File file, { String? filename, - String? attachmentType, - String? contentType, + super.attachmentType, + super.contentType, }) : super.fromLoader( loader: () => file.readAsBytes(), filename: filename ?? file.uri.pathSegments.last, - attachmentType: attachmentType, - contentType: contentType, ); } diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 62d2072b85..63fcbfb421 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -1,6 +1,9 @@ import 'dart:async'; import 'dart:math'; import 'package:meta/meta.dart'; +import 'utils/stacktrace_utils.dart'; +import 'metrics/metric.dart'; +import 'metrics/metrics_aggregator.dart'; import 'sentry_baggage.dart'; import 'sentry_attachment/sentry_attachment.dart'; @@ -16,6 +19,8 @@ import 'sentry_options.dart'; import 'sentry_stack_trace_factory.dart'; import 'transport/http_transport.dart'; import 'transport/noop_transport.dart'; +import 'transport/spotlight_http_transport.dart'; +import 'transport/task_queue.dart'; import 'utils/isolate_utils.dart'; import 'version.dart'; import 'sentry_envelope.dart'; @@ -23,7 +28,7 @@ import 'client_reports/client_report_recorder.dart'; import 'client_reports/discard_reason.dart'; import 'transport/data_category.dart'; -/// Default value for [User.ipAddress]. It gets set when an event does not have +/// Default value for [SentryUser.ipAddress]. It gets set when an event does not have /// a user and IP address. Only applies if [SentryOptions.sendDefaultPii] is set /// to true. const _defaultIpAddress = '{{auto}}'; @@ -31,9 +36,15 @@ const _defaultIpAddress = '{{auto}}'; /// Logs crash reports and events to the Sentry.io service. class SentryClient { final SentryOptions _options; + late final _taskQueue = TaskQueue( + _options.maxQueueSize, + _options.logger, + ); final Random? _random; + late final MetricsAggregator? _metricsAggregator; + static final _sentryId = Future.value(SentryId.empty()); SentryExceptionFactory get _exceptionFactory => _options.exceptionFactory; @@ -49,12 +60,21 @@ class SentryClient { final rateLimiter = RateLimiter(options); options.transport = HttpTransport(options, rateLimiter); } + if (options.spotlight.enabled) { + options.transport = SpotlightHttpTransport(options, options.transport); + } return SentryClient._(options); } /// Instantiates a client using [SentryOptions] SentryClient._(this._options) - : _random = _options.sampleRate == null ? null : Random(); + : _random = _options.sampleRate == null ? null : Random(), + _metricsAggregator = _options.enableMetrics + ? MetricsAggregator(options: _options) + : null; + + @internal + MetricsAggregator? get metricsAggregator => _metricsAggregator; /// Reports an [event] to Sentry.io. Future captureEvent( @@ -77,7 +97,7 @@ class SentryClient { hint ??= Hint(); if (scope != null) { - preparedEvent = await scope.applyToEvent(preparedEvent, hint: hint); + preparedEvent = await scope.applyToEvent(preparedEvent, hint); } else { _options.logger( SentryLevel.debug, 'No scope to apply on event was provided'); @@ -90,8 +110,8 @@ class SentryClient { preparedEvent = await _runEventProcessors( preparedEvent, + hint, eventProcessors: _options.eventProcessors, - hint: hint, ); // dropped by event processors @@ -99,9 +119,11 @@ class SentryClient { return _sentryId; } + preparedEvent = _createUserOrSetDefaultIpAddress(preparedEvent); + preparedEvent = await _runBeforeSend( preparedEvent, - hint: hint, + hint, ); // dropped by beforeSend @@ -109,8 +131,6 @@ class SentryClient { return _sentryId; } - preparedEvent = _eventWithoutBreadcrumbsIfNeeded(preparedEvent); - var attachments = List.from(scope?.attachments ?? []); attachments.addAll(hint.attachments); var screenshot = hint.screenshot; @@ -158,8 +178,6 @@ class SentryClient { platform: event.platform ?? sdkPlatform(_options.platformChecker.isWeb), ); - event = _applyDefaultPii(event); - if (event is SentryTransaction) { return event; } @@ -218,7 +236,7 @@ class SentryClient { // therefore add it to the threads. // https://develop.sentry.dev/sdk/event-payloads/stacktrace/ if (stackTrace != null || _options.attachStacktrace) { - stackTrace ??= StackTrace.current; + stackTrace ??= getCurrentStackTrace(); final frames = _stackTraceFactory.getStackFrames(stackTrace); if (frames.isNotEmpty) { @@ -238,20 +256,13 @@ class SentryClient { return event; } - /// This modifies the users IP address according - /// to [SentryOptions.sendDefaultPii]. - SentryEvent _applyDefaultPii(SentryEvent event) { - if (!_options.sendDefaultPii) { - return event; - } + SentryEvent _createUserOrSetDefaultIpAddress(SentryEvent event) { var user = event.user; if (user == null) { - user = SentryUser(ipAddress: _defaultIpAddress); - return event.copyWith(user: user); + return event.copyWith(user: SentryUser(ipAddress: _defaultIpAddress)); } else if (event.user?.ipAddress == null) { return event.copyWith(user: user.copyWith(ipAddress: _defaultIpAddress)); } - return event; } @@ -302,9 +313,11 @@ class SentryClient { SentryTransaction? preparedTransaction = _prepareEvent(transaction) as SentryTransaction; + final hint = Hint(); + if (scope != null) { - preparedTransaction = - await scope.applyToEvent(preparedTransaction) as SentryTransaction?; + preparedTransaction = await scope.applyToEvent(preparedTransaction, hint) + as SentryTransaction?; } else { _options.logger( SentryLevel.debug, 'No scope to apply on transaction was provided'); @@ -317,6 +330,7 @@ class SentryClient { preparedTransaction = await _runEventProcessors( preparedTransaction, + hint, eventProcessors: _options.eventProcessors, ) as SentryTransaction?; @@ -326,15 +340,13 @@ class SentryClient { } preparedTransaction = - await _runBeforeSend(preparedTransaction) as SentryTransaction?; + await _runBeforeSend(preparedTransaction, hint) as SentryTransaction?; // dropped by beforeSendTransaction if (preparedTransaction == null) { return _sentryId; } - preparedTransaction = _eventWithoutBreadcrumbsIfNeeded(preparedTransaction); - final attachments = scope?.attachments .where((element) => element.addToTransactions) .toList(); @@ -370,12 +382,27 @@ class SentryClient { return _attachClientReportsAndSend(envelope); } - void close() => _options.httpClient.close(); + /// Reports the [metricsBuckets] to Sentry.io. + Future captureMetrics( + Map> metricsBuckets) async { + final envelope = SentryEnvelope.fromMetrics( + metricsBuckets, + _options.sdk, + dsn: _options.dsn, + ); + final id = await _attachClientReportsAndSend(envelope); + return id ?? SentryId.empty(); + } + + void close() { + _metricsAggregator?.close(); + _options.httpClient.close(); + } Future _runBeforeSend( - SentryEvent event, { - Hint? hint, - }) async { + SentryEvent event, + Hint hint, + ) async { SentryEvent? eventOrTransaction = event; final beforeSend = _options.beforeSend; @@ -392,7 +419,7 @@ class SentryClient { eventOrTransaction = e; } } else if (beforeSend != null) { - final e = beforeSend(event, hint: hint); + final e = beforeSend(event, hint); if (e is Future) { eventOrTransaction = await e; } else { @@ -423,14 +450,14 @@ class SentryClient { } Future _runEventProcessors( - SentryEvent event, { - Hint? hint, + SentryEvent event, + Hint hint, { required List eventProcessors, }) async { SentryEvent? processedEvent = event; for (final processor in eventProcessors) { try { - final e = processor.apply(processedEvent!, hint: hint); + final e = processor.apply(processedEvent!, hint); if (e is Future) { processedEvent = await e; } else { @@ -473,43 +500,12 @@ class SentryClient { _options.recorder.recordLostEvent(reason, category); } - T _eventWithoutBreadcrumbsIfNeeded(T event) { - if (_shouldRemoveBreadcrumbs(event)) { - return event.copyWith(breadcrumbs: []) as T; - } else { - return event; - } - } - - /// We do this to avoid duplicate breadcrumbs on Android as sentry-android applies the breadcrumbs - /// from the native scope onto every envelope sent through it. This scope will contain the breadcrumbs - /// sent through the scope sync feature. This causes duplicate breadcrumbs. - /// We then remove the breadcrumbs in all cases but if it is handled == false, - /// this is a signal that the app would crash and android would lose the breadcrumbs by the time the app is restarted to read - /// the envelope. - bool _shouldRemoveBreadcrumbs(SentryEvent event) { - if (_options.platformChecker.isWeb) { - return false; - } - - final isAndroid = _options.platformChecker.platform.isAndroid; - final enableScopeSync = _options.enableScopeSync; - - if (!isAndroid || !enableScopeSync) { - return false; - } - - final mechanisms = - (event.exceptions ?? []).map((e) => e.mechanism).whereType(); - final hasNoMechanism = mechanisms.isEmpty; - final hasOnlyHandledMechanism = - mechanisms.every((e) => (e.handled ?? true)); - return hasNoMechanism || hasOnlyHandledMechanism; - } - Future _attachClientReportsAndSend(SentryEnvelope envelope) { final clientReport = _options.recorder.flush(); envelope.addClientReport(clientReport); - return _options.transport.send(envelope); + return _taskQueue.enqueue( + () => _options.transport.send(envelope), + SentryId.empty(), + ); } } diff --git a/dart/lib/src/sentry_envelope.dart b/dart/lib/src/sentry_envelope.dart index eb62aeec47..7835b7859e 100644 --- a/dart/lib/src/sentry_envelope.dart +++ b/dart/lib/src/sentry_envelope.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'client_reports/client_report.dart'; +import 'metrics/metric.dart'; import 'protocol.dart'; import 'sentry_item_type.dart'; import 'sentry_options.dart'; @@ -20,7 +21,7 @@ class SentryEnvelope { /// All items contained in the envelope. final List items; - /// Create an [SentryEnvelope] with containing one [SentryEnvelopeItem] which holds the [SentryEvent] data. + /// Create a [SentryEnvelope] containing one [SentryEnvelopeItem] which holds the [SentryEvent] data. factory SentryEnvelope.fromEvent( SentryEvent event, SdkVersion sdkVersion, { @@ -59,7 +60,7 @@ class SentryEnvelope { ); } - /// Create an [SentryEnvelope] with containing one [SentryEnvelopeItem] which holds the [SentryTransaction] data. + /// Create a [SentryEnvelope] containing one [SentryEnvelopeItem] which holds the [SentryTransaction] data. factory SentryEnvelope.fromTransaction( SentryTransaction transaction, SdkVersion sdkVersion, { @@ -82,6 +83,22 @@ class SentryEnvelope { ); } + /// Create a [SentryEnvelope] containing one [SentryEnvelopeItem] which holds the [Metric] data. + factory SentryEnvelope.fromMetrics( + Map> metricsBuckets, + SdkVersion sdkVersion, { + String? dsn, + }) { + return SentryEnvelope( + SentryEnvelopeHeader( + SentryId.newId(), + sdkVersion, + dsn: dsn, + ), + [SentryEnvelopeItem.fromMetrics(metricsBuckets)], + ); + } + /// Stream binary data representation of `Envelope` file encoded. Stream> envelopeStream(SentryOptions options) async* { yield utf8JsonEncoder.convert(header.toJson()); diff --git a/dart/lib/src/sentry_envelope_item.dart b/dart/lib/src/sentry_envelope_item.dart index 5e38a7123d..019e1e0a08 100644 --- a/dart/lib/src/sentry_envelope_item.dart +++ b/dart/lib/src/sentry_envelope_item.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'client_reports/client_report.dart'; +import 'metrics/metric.dart'; import 'protocol.dart'; import 'utils.dart'; import 'sentry_attachment/sentry_attachment.dart'; @@ -13,7 +14,7 @@ import 'sentry_user_feedback.dart'; class SentryEnvelopeItem { SentryEnvelopeItem(this.header, this.dataFactory); - /// Creates an [SentryEnvelopeItem] which sends [SentryTransaction]. + /// Creates a [SentryEnvelopeItem] which sends [SentryTransaction]. factory SentryEnvelopeItem.fromTransaction(SentryTransaction transaction) { final cachedItem = _CachedItem(() async => utf8JsonEncoder.convert(transaction.toJson())); @@ -27,7 +28,7 @@ class SentryEnvelopeItem { } factory SentryEnvelopeItem.fromAttachment(SentryAttachment attachment) { - final cachedItem = _CachedItem(() => attachment.bytes); + final cachedItem = _CachedItem(() async => attachment.bytes); final header = SentryEnvelopeItemHeader( SentryItemType.attachment, @@ -39,7 +40,7 @@ class SentryEnvelopeItem { return SentryEnvelopeItem(header, cachedItem.getData); } - /// Create an [SentryEnvelopeItem] which sends [SentryUserFeedback]. + /// Create a [SentryEnvelopeItem] which sends [SentryUserFeedback]. factory SentryEnvelopeItem.fromUserFeedback(SentryUserFeedback feedback) { final cachedItem = _CachedItem(() async => utf8JsonEncoder.convert(feedback.toJson())); @@ -52,7 +53,7 @@ class SentryEnvelopeItem { return SentryEnvelopeItem(header, cachedItem.getData); } - /// Create an [SentryEnvelopeItem] which holds the [SentryEvent] data. + /// Create a [SentryEnvelopeItem] which holds the [SentryEvent] data. factory SentryEnvelopeItem.fromEvent(SentryEvent event) { final cachedItem = _CachedItem(() async => utf8JsonEncoder.convert(event.toJson())); @@ -67,7 +68,7 @@ class SentryEnvelopeItem { ); } - /// Create an [SentryEnvelopeItem] which holds the [ClientReport] data. + /// Create a [SentryEnvelopeItem] which holds the [ClientReport] data. factory SentryEnvelopeItem.fromClientReport(ClientReport clientReport) { final cachedItem = _CachedItem(() async => utf8JsonEncoder.convert(clientReport.toJson())); @@ -82,6 +83,28 @@ class SentryEnvelopeItem { ); } + /// Creates a [SentryEnvelopeItem] which holds several [Metric] data. + factory SentryEnvelopeItem.fromMetrics(Map> buckets) { + final cachedItem = _CachedItem(() async { + final statsd = StringBuffer(); + // Encode all metrics of a bucket in statsd format, using the bucket key, + // which is the timestamp of the bucket. + for (final bucket in buckets.entries) { + final encodedMetrics = + bucket.value.map((metric) => metric.encodeToStatsd(bucket.key)); + statsd.write(encodedMetrics.join('\n')); + } + return utf8.encode(statsd.toString()); + }); + + final header = SentryEnvelopeItemHeader( + SentryItemType.statsd, + cachedItem.getDataLength, + contentType: 'application/octet-stream', + ); + return SentryEnvelopeItem(header, cachedItem.getData); + } + /// Header with info about type and length of data in bytes. final SentryEnvelopeItemHeader header; @@ -109,16 +132,11 @@ class SentryEnvelopeItem { class _CachedItem { _CachedItem(this._dataFactory); - final FutureOr> Function() _dataFactory; + final Future> Function() _dataFactory; List? _data; Future> getData() async { - final data = _dataFactory(); - if (data is Future>) { - _data ??= await data; - } else { - _data ??= data; - } + _data ??= await _dataFactory(); return _data!; } diff --git a/dart/lib/src/sentry_exception_factory.dart b/dart/lib/src/sentry_exception_factory.dart index 24ad5ae571..a8e1a80498 100644 --- a/dart/lib/src/sentry_exception_factory.dart +++ b/dart/lib/src/sentry_exception_factory.dart @@ -1,3 +1,5 @@ +import 'utils/stacktrace_utils.dart'; + import 'recursive_exception_cause_extractor.dart'; import 'protocol.dart'; import 'sentry_options.dart'; @@ -38,10 +40,9 @@ class SentryExceptionFactory { // hence we check again if stackTrace is null and if not, read the current stack trace // but only if attachStacktrace is enabled if (_options.attachStacktrace) { - // TODO: snapshot=true if stackTrace is null - // Requires a major breaking change because of grouping if (stackTrace == null || stackTrace == StackTrace.empty) { - stackTrace = StackTrace.current; + snapshot = true; + stackTrace = getCurrentStackTrace(); } } diff --git a/dart/lib/src/sentry_isolate.dart b/dart/lib/src/sentry_isolate.dart index 898904cd27..9998544d5b 100644 --- a/dart/lib/src/sentry_isolate.dart +++ b/dart/lib/src/sentry_isolate.dart @@ -69,12 +69,15 @@ class SentryIsolate { stackTrace == null ? null : StackTrace.fromString(stackTrace), ); - // Isolate errors don't crash the App. - final mechanism = Mechanism(type: 'isolateError', handled: true); + // Isolate errors don't crash the app, but is not handled by the user. + final mechanism = Mechanism(type: 'isolateError', handled: false); final throwableMechanism = ThrowableMechanism(mechanism, throwable); + final event = SentryEvent( throwable: throwableMechanism, - level: SentryLevel.fatal, + level: hub.options.markAutomaticallyCollectedErrorsAsFatal + ? SentryLevel.fatal + : SentryLevel.error, timestamp: hub.options.clock(), ); diff --git a/dart/lib/src/sentry_item_type.dart b/dart/lib/src/sentry_item_type.dart index 6215cbb78f..18dbc8f4ad 100644 --- a/dart/lib/src/sentry_item_type.dart +++ b/dart/lib/src/sentry_item_type.dart @@ -5,5 +5,6 @@ class SentryItemType { static const String transaction = 'transaction'; static const String clientReport = 'client_report'; static const String profile = 'profile'; + static const String statsd = 'statsd'; static const String unknown = '__unknown__'; } diff --git a/dart/lib/src/sentry_measurement.dart b/dart/lib/src/sentry_measurement.dart index 481c513e9b..663197654d 100644 --- a/dart/lib/src/sentry_measurement.dart +++ b/dart/lib/src/sentry_measurement.dart @@ -39,6 +39,20 @@ class SentryMeasurement { value = duration.inMilliseconds, unit = DurationSentryMeasurementUnit.milliSecond; + /// Duration of the time to initial display in milliseconds + SentryMeasurement.timeToInitialDisplay(Duration duration) + : assert(!duration.isNegative), + name = 'time_to_initial_display', + value = duration.inMilliseconds, + unit = DurationSentryMeasurementUnit.milliSecond; + + /// Duration of the time to full display in milliseconds + SentryMeasurement.timeToFullDisplay(Duration duration) + : assert(!duration.isNegative), + name = 'time_to_full_display', + value = duration.inMilliseconds, + unit = DurationSentryMeasurementUnit.milliSecond; + final String name; final num value; final SentryMeasurementUnit? unit; diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 27d95fb9f3..956f81c056 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -81,6 +81,20 @@ class SentryOptions { _maxSpans = maxSpans; } + int _maxQueueSize = 30; + + /// Returns the max number of events Sentry will send when calling capture + /// methods in a tight loop. Default is 30. + int get maxQueueSize => _maxQueueSize; + + /// Sets how many unawaited events can be sent by Sentry. (e.g. capturing + /// events in a tight loop) at once. If you need to send more, please use the + /// await keyword. + set maxQueueSize(int count) { + assert(count > 0); + _maxQueueSize = count; + } + /// Configures up to which size request bodies should be included in events. /// This does not change whether an event is captured. MaxRequestBodySize maxRequestBodySize = MaxRequestBodySize.never; @@ -151,6 +165,10 @@ class SentryOptions { /// to the scope. When nothing is returned from the function, the breadcrumb is dropped BeforeBreadcrumbCallback? beforeBreadcrumb; + /// This function is called right before a metric is about to be emitted. + /// Can return true to emit the metric, or false to drop it. + BeforeMetricCallback? beforeMetricCallback; + /// Sets the release. SDK will try to automatically configure a release out of the box /// See [docs for further information](https://docs.sentry.io/platforms/flutter/configuration/releases/) String? release; @@ -248,11 +266,13 @@ class SentryOptions { /// - In an browser environment this can be requests which fail because of CORS. /// - In an mobile or desktop application this can be requests which failed /// because the connection was interrupted. - /// Use with [SentryHttpClient] or `sentry_dio` integration for this to work + /// Use with [SentryHttpClient] or `sentry_dio` integration for this to work, + /// or iOS native where it sets the value to `enableCaptureFailedRequests`. bool captureFailedRequests = true; /// Whether to records requests as breadcrumbs. This is on by default. - /// It only has an effect when the SentryHttpClient or dio integration is in use + /// It only has an effect when the SentryHttpClient or dio integration is in + /// use, or iOS native where it sets the value to `enableNetworkBreadcrumbs`. bool recordHttpBreadcrumbs = true; /// Whether [SentryEvent] deduplication is enabled. @@ -364,11 +384,65 @@ class SentryOptions { /// are set. bool? enableTracing; + /// Enables sending developer metrics to Sentry. + /// More on https://develop.sentry.dev/delightful-developer-metrics/. + /// Example: + /// ```dart + /// Sentry.metrics.counter('myMetric'); + /// ``` + @experimental + bool enableMetrics = false; + + @experimental + bool _enableDefaultTagsForMetrics = true; + + /// Enables enriching metrics with default tags. Requires [enableMetrics]. + /// More on https://develop.sentry.dev/delightful-developer-metrics/sending-metrics-sdk/#automatic-tags-extraction + /// Currently adds release, environment and transaction name. + @experimental + bool get enableDefaultTagsForMetrics => + enableMetrics && _enableDefaultTagsForMetrics; + + /// Enables enriching metrics with default tags. Requires [enableMetrics]. + /// More on https://develop.sentry.dev/delightful-developer-metrics/sending-metrics-sdk/#automatic-tags-extraction + /// Currently adds release, environment and transaction name. + @experimental + set enableDefaultTagsForMetrics(final bool enableDefaultTagsForMetrics) => + _enableDefaultTagsForMetrics = enableDefaultTagsForMetrics; + + @experimental + bool _enableSpanLocalMetricAggregation = true; + + /// Enables span metrics aggregation. Requires [enableMetrics]. + /// More on https://develop.sentry.dev/sdk/metrics/#span-aggregation + @experimental + bool get enableSpanLocalMetricAggregation => + enableMetrics && _enableSpanLocalMetricAggregation; + + /// Enables span metrics aggregation. Requires [enableMetrics]. + /// More on https://develop.sentry.dev/sdk/metrics/#span-aggregation + @experimental + set enableSpanLocalMetricAggregation( + final bool enableSpanLocalMetricAggregation) => + _enableSpanLocalMetricAggregation = enableSpanLocalMetricAggregation; + /// Only for internal use. Changed SDK behaviour when set to true: /// - Rethrow exceptions that occur in user provided closures @internal bool automatedTestMode = false; + /// Errors that the SDK automatically collects, for example in + /// [SentryIsolate], have `level` [SentryLevel.fatal] set per default. + /// Settings this to `false` will set the `level` to [SentryLevel.error]. + bool markAutomaticallyCollectedErrorsAsFatal = true; + + /// The Spotlight configuration. + /// Disabled by default. + /// ```dart + /// spotlight = Spotlight(enabled: true) + /// ``` + Spotlight spotlight = Spotlight(enabled: false); + SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { platformChecker = checker; @@ -455,9 +529,9 @@ class SentryOptions { /// This function is called with an SDK specific event object and can return a modified event /// object or nothing to skip reporting the event typedef BeforeSendCallback = FutureOr Function( - SentryEvent event, { - Hint? hint, -}); + SentryEvent event, + Hint hint, +); /// This function is called with an SDK specific transaction object and can return a modified transaction /// object or nothing to skip reporting the transaction @@ -468,8 +542,15 @@ typedef BeforeSendTransactionCallback = FutureOr Function( /// This function is called with an SDK specific breadcrumb object before the breadcrumb is added /// to the scope. When nothing is returned from the function, the breadcrumb is dropped typedef BeforeBreadcrumbCallback = Breadcrumb? Function( - Breadcrumb? breadcrumb, { - Hint? hint, + Breadcrumb? breadcrumb, + Hint hint, +); + +/// This function is called right before a metric is about to be emitted. +/// Can return true to emit the metric, or false to drop it. +typedef BeforeMetricCallback = bool Function( + String key, { + Map? tags, }); /// Used to provide timestamp for logging. diff --git a/dart/lib/src/sentry_span_interface.dart b/dart/lib/src/sentry_span_interface.dart index cdc121f849..1d142c45b9 100644 --- a/dart/lib/src/sentry_span_interface.dart +++ b/dart/lib/src/sentry_span_interface.dart @@ -1,5 +1,6 @@ import 'package:meta/meta.dart'; +import 'metrics/local_metrics_aggregator.dart'; import 'protocol.dart'; import 'tracing.dart'; @@ -46,6 +47,9 @@ abstract class ISentrySpan { /// See https://develop.sentry.dev/sdk/performance/trace-origin set origin(String? origin); + @internal + LocalMetricsAggregator? get localMetricsAggregator; + /// Returns the end timestamp if finished DateTime? get endTimestamp; diff --git a/dart/lib/src/sentry_span_operations.dart b/dart/lib/src/sentry_span_operations.dart new file mode 100644 index 0000000000..27b1d22496 --- /dev/null +++ b/dart/lib/src/sentry_span_operations.dart @@ -0,0 +1,8 @@ +import 'package:meta/meta.dart'; + +@internal +class SentrySpanOperations { + static const String uiLoad = 'ui.load'; + static const String uiTimeToInitialDisplay = 'ui.load.initial_display'; + static const String uiTimeToFullDisplay = 'ui.load.full_display'; +} diff --git a/dart/lib/src/sentry_stack_trace_factory.dart b/dart/lib/src/sentry_stack_trace_factory.dart index fe6b3cc88b..9d4a42bffc 100644 --- a/dart/lib/src/sentry_stack_trace_factory.dart +++ b/dart/lib/src/sentry_stack_trace_factory.dart @@ -5,7 +5,7 @@ import 'noop_origin.dart' if (dart.library.html) 'origin.dart'; import 'protocol.dart'; import 'sentry_options.dart'; -/// converts [StackTrace] to [SentryStackFrames] +/// converts [StackTrace] to [SentryStackFrame]s class SentryStackTraceFactory { final SentryOptions _options; @@ -15,14 +15,6 @@ class SentryStackTraceFactory { static final SentryStackFrame _asynchronousGapFrameJson = SentryStackFrame(absPath: ''); - static const _sentryPackagesIdentifier = [ - 'sentry', - 'sentry_flutter', - 'sentry_logging', - 'sentry_dio', - 'sentry_file', - ]; - SentryStackTraceFactory(this._options); /// returns the [SentryStackFrame] list from a stackTrace ([StackTrace] or [String]) @@ -34,13 +26,9 @@ class SentryStackTraceFactory { for (var t = 0; t < chain.traces.length; t += 1) { final trace = chain.traces[t]; + // NOTE: We want to keep the Sentry frames for crash detection + // this does not affect grouping since they're not marked as inApp for (final frame in trace.frames) { - // we don't want to add our own frames - if (frame.package != null && - _sentryPackagesIdentifier.contains(frame.package)) { - continue; - } - final stackTraceFrame = encodeStackTraceFrame(frame); if (stackTraceFrame != null) { frames.add(stackTraceFrame); @@ -123,16 +111,18 @@ class SentryStackTraceFactory { absPath: abs, function: member, // https://docs.sentry.io/development/sdk-dev/features/#in-app-frames - inApp: isInApp(frame), + inApp: _isInApp(frame), fileName: fileName, package: frame.package, ); - if (frame.line != null && frame.line! >= 0) { + final line = frame.line; + if (line != null && line >= 0) { sentryStackFrame = sentryStackFrame.copyWith(lineNo: frame.line); } - if (frame.column != null && frame.column! >= 0) { + final column = frame.column; + if (column != null && column >= 0) { sentryStackFrame = sentryStackFrame.copyWith(colNo: frame.column); } return sentryStackFrame; @@ -153,11 +143,11 @@ class SentryStackTraceFactory { return frame.uri.pathSegments.last; } - return '${frame.uri}'; + return frame.uri.toString(); } /// whether this frame comes from the app and not from Dart core or 3rd party librairies - bool isInApp(Frame frame) { + bool _isInApp(Frame frame) { final scheme = frame.uri.scheme; if (scheme.isEmpty) { diff --git a/dart/lib/src/sentry_trace_origins.dart b/dart/lib/src/sentry_trace_origins.dart index 903348aa19..4377fa2c03 100644 --- a/dart/lib/src/sentry_trace_origins.dart +++ b/dart/lib/src/sentry_trace_origins.dart @@ -18,6 +18,8 @@ class SentryTraceOrigins { 'auto.db.sqflite.database_executor'; static const autoDbSqfliteDatabaseFactory = 'auto.db.sqflite.database_factory'; + static const autoDbIsar = 'auto.db.isar'; + static const autoDbIsarCollection = 'auto.db.isar.collection'; static const autoDbHive = 'auto.db.hive'; static const autoDbHiveBoxBase = 'auto.db.hive.box_base'; static const autoDbHiveLazyBox = 'auto.db.hive.lazy_box'; @@ -25,4 +27,6 @@ class SentryTraceOrigins { static const autoDbDriftQueryExecutor = 'auto.db.drift.query.executor'; static const autoDbDriftTransactionExecutor = 'auto.db.drift.transaction.executor'; + static const autoUiTimeToDisplay = 'auto.ui.time_to_display'; + static const manualUiTimeToDisplay = 'manual.ui.time_to_display'; } diff --git a/dart/lib/src/sentry_tracer.dart b/dart/lib/src/sentry_tracer.dart index 6012a13bfb..2326db0716 100644 --- a/dart/lib/src/sentry_tracer.dart +++ b/dart/lib/src/sentry_tracer.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:meta/meta.dart'; import '../sentry.dart'; +import 'metrics/local_metrics_aggregator.dart'; import 'profiling.dart'; import 'sentry_tracer_finish_status.dart'; import 'utils/sample_rate_format.dart'; @@ -49,9 +50,9 @@ class SentryTracer extends ISentrySpan { /// highest timestamp of child spans, trimming the duration of the /// transaction. This is useful to discard extra time in the transaction that /// is not accounted for in child spans, like what happens in the - /// [SentryNavigatorObserver] idle transactions, where we finish the - /// transaction after a given "idle time" and we don't want this "idle time" - /// to be part of the transaction. + /// [SentryNavigatorObserver](https://pub.dev/documentation/sentry_flutter/latest/sentry_flutter/SentryNavigatorObserver-class.html) + /// idle transactions, where we finish the transaction after a given + /// "idle time" and we don't want this "idle time" to be part of the transaction. SentryTracer( SentryTransactionContext transactionContext, this._hub, { @@ -99,28 +100,25 @@ class SentryTracer extends ISentrySpan { _children.removeWhere( (span) => !_hasSpanSuitableTimestamps(span, commonEndTimestamp)); - // finish unfinished spans otherwise transaction gets dropped - final spansToBeFinished = _children.where((span) => !span.finished); - for (final span in spansToBeFinished) { - await span.finish( - status: SpanStatus.deadlineExceeded(), - endTimestamp: commonEndTimestamp, - ); - } - var _rootEndTimestamp = commonEndTimestamp; + + // Trim the end timestamp of the transaction to the very last timestamp of child spans if (_trimEnd && children.isNotEmpty) { - final childEndTimestamps = children - .where((child) => child.endTimestamp != null) - .map((child) => child.endTimestamp!); - - if (childEndTimestamps.isNotEmpty) { - final oldestChildEndTimestamp = - childEndTimestamps.reduce((a, b) => a.isAfter(b) ? a : b); - if (_rootEndTimestamp.isAfter(oldestChildEndTimestamp)) { - _rootEndTimestamp = oldestChildEndTimestamp; + DateTime? latestEndTime; + + for (final child in children) { + final childEndTimestamp = child.endTimestamp; + if (childEndTimestamp != null) { + if (latestEndTime == null || + childEndTimestamp.isAfter(latestEndTime)) { + latestEndTime = child.endTimestamp; + } } } + + if (latestEndTime != null) { + _rootEndTimestamp = latestEndTime; + } } // the callback should run before because if the span is finished, @@ -407,4 +405,8 @@ class SentryTracer extends ISentrySpan { }); } } + + @override + LocalMetricsAggregator? get localMetricsAggregator => + _rootSpan.localMetricsAggregator; } diff --git a/dart/lib/src/sentry_transaction_context.dart b/dart/lib/src/sentry_transaction_context.dart index 66024459f5..32ab0324b7 100644 --- a/dart/lib/src/sentry_transaction_context.dart +++ b/dart/lib/src/sentry_transaction_context.dart @@ -15,21 +15,16 @@ class SentryTransactionContext extends SentrySpanContext { SentryTransactionContext( this.name, String operation, { - String? description, + super.description, this.parentSamplingDecision, - SentryId? traceId, - SpanId? spanId, - SpanId? parentSpanId, + super.traceId, + super.spanId, + super.parentSpanId, this.transactionNameSource, this.samplingDecision, - String? origin, + super.origin, }) : super( operation: operation, - description: description, - traceId: traceId, - spanId: spanId, - parentSpanId: parentSpanId, - origin: origin, ); factory SentryTransactionContext.fromSentryTrace( diff --git a/dart/lib/src/spotlight.dart b/dart/lib/src/spotlight.dart new file mode 100644 index 0000000000..b106ed3547 --- /dev/null +++ b/dart/lib/src/spotlight.dart @@ -0,0 +1,21 @@ +import 'platform_checker.dart'; + +/// Spotlight configuration class. +class Spotlight { + /// Whether to enable Spotlight for local development. + bool enabled; + + /// The Spotlight Sidecar URL. + /// Defaults to http://10.0.2.2:8969/stream due to Emulator on Android. + /// Otherwise defaults to http://localhost:8969/stream. + String url; + + Spotlight({required this.enabled, String? url}) + : url = url ?? _defaultSpotlightUrl(); +} + +String _defaultSpotlightUrl() { + return (PlatformChecker().platform.isAndroid + ? 'http://10.0.2.2:8969/stream' + : 'http://localhost:8969/stream'); +} diff --git a/dart/lib/src/transport/data_category.dart b/dart/lib/src/transport/data_category.dart index 1843acfacb..ecdb1c9500 100644 --- a/dart/lib/src/transport/data_category.dart +++ b/dart/lib/src/transport/data_category.dart @@ -7,48 +7,6 @@ enum DataCategory { transaction, attachment, security, + metricBucket, unknown } - -extension DataCategoryExtension on DataCategory { - static DataCategory fromStringValue(String stringValue) { - switch (stringValue) { - case '__all__': - return DataCategory.all; - case 'default': - return DataCategory.dataCategoryDefault; - case 'error': - return DataCategory.error; - case 'session': - return DataCategory.session; - case 'transaction': - return DataCategory.transaction; - case 'attachment': - return DataCategory.attachment; - case 'security': - return DataCategory.security; - } - return DataCategory.unknown; - } - - String toStringValue() { - switch (this) { - case DataCategory.all: - return '__all__'; - case DataCategory.dataCategoryDefault: - return 'default'; - case DataCategory.error: - return 'error'; - case DataCategory.session: - return 'session'; - case DataCategory.transaction: - return 'transaction'; - case DataCategory.attachment: - return 'attachment'; - case DataCategory.security: - return 'security'; - case DataCategory.unknown: - return 'unknown'; - } - } -} diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index acf0e6cf64..90dd8949ce 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -2,11 +2,9 @@ import 'dart:async'; import 'dart:convert'; import 'package:http/http.dart'; +import '../utils/transport_utils.dart'; +import 'http_transport_request_handler.dart'; -import '../client_reports/client_report_recorder.dart'; -import '../client_reports/discard_reason.dart'; -import 'data_category.dart'; -import 'noop_encode.dart' if (dart.library.io) 'encode.dart'; import '../noop_client.dart'; import '../protocol.dart'; import '../sentry_options.dart'; @@ -18,15 +16,9 @@ import 'rate_limiter.dart'; class HttpTransport implements Transport { final SentryOptions _options; - final Dsn _dsn; - final RateLimiter _rateLimiter; - final ClientReportRecorder _recorder; - - late _CredentialBuilder _credentialBuilder; - - final Map _headers; + final HttpTransportRequestHandler _requestHandler; factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) { if (options.httpClient is NoOpClient) { @@ -37,17 +29,8 @@ class HttpTransport implements Transport { } HttpTransport._(this._options, this._rateLimiter) - : _dsn = Dsn.parse(_options.dsn!), - _recorder = _options.recorder, - _headers = _buildHeaders( - _options.platformChecker.isWeb, - _options.sentryClientName, - ) { - _credentialBuilder = _CredentialBuilder( - _dsn, - _options.sentryClientName, - ); - } + : _requestHandler = HttpTransportRequestHandler( + _options, Dsn.parse(_options.dsn!).postUri); @override Future send(SentryEnvelope envelope) async { @@ -57,63 +40,31 @@ class HttpTransport implements Transport { } filteredEnvelope.header.sentAt = _options.clock(); - final streamedRequest = await _createStreamedRequest(filteredEnvelope); + final streamedRequest = + await _requestHandler.createRequest(filteredEnvelope); + final response = await _options.httpClient .send(streamedRequest) .then(Response.fromStream); _updateRetryAfterLimits(response); - if (response.statusCode != 200) { - // body guard to not log the error as it has performance impact to allocate - // the body String. - if (_options.debug) { - _options.logger( - SentryLevel.error, - 'API returned an error, statusCode = ${response.statusCode}, ' - 'body = ${response.body}', - ); - } - - if (response.statusCode >= 400 && response.statusCode != 429) { - _recorder.recordLostEvent( - DiscardReason.networkError, DataCategory.error); - } - - return SentryId.empty(); - } else { - _options.logger( - SentryLevel.debug, - 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully.', - ); - } + TransportUtils.logResponse(_options, envelope, response, target: 'Sentry'); - final eventId = json.decode(response.body)['id']; - if (eventId == null) { - return null; + if (response.statusCode == 200) { + return _parseEventId(response); } - return SentryId.fromId(eventId); + return SentryId.empty(); } - Future _createStreamedRequest( - SentryEnvelope envelope) async { - final streamedRequest = StreamedRequest('POST', _dsn.postUri); - - if (_options.compressPayload) { - final compressionSink = compressInSink(streamedRequest.sink, _headers); - envelope - .envelopeStream(_options) - .listen(compressionSink.add) - .onDone(compressionSink.close); - } else { - envelope - .envelopeStream(_options) - .listen(streamedRequest.sink.add) - .onDone(streamedRequest.sink.close); + SentryId? _parseEventId(Response response) { + try { + final eventId = json.decode(response.body)['id']; + return eventId != null ? SentryId.fromId(eventId) : null; + } catch (e) { + _options.logger(SentryLevel.error, 'Error parsing response: $e'); + return null; } - streamedRequest.headers.addAll(_credentialBuilder.configure(_headers)); - - return streamedRequest; } void _updateRetryAfterLimits(Response response) { @@ -131,51 +82,3 @@ class HttpTransport implements Transport { sentryRateLimitHeader, retryAfterHeader, response.statusCode); } } - -class _CredentialBuilder { - final String _authHeader; - - _CredentialBuilder._(String authHeader) : _authHeader = authHeader; - - factory _CredentialBuilder(Dsn dsn, String sdkIdentifier) { - final authHeader = _buildAuthHeader( - publicKey: dsn.publicKey, - secretKey: dsn.secretKey, - sdkIdentifier: sdkIdentifier, - ); - - return _CredentialBuilder._(authHeader); - } - - static String _buildAuthHeader({ - required String publicKey, - String? secretKey, - required String sdkIdentifier, - }) { - var header = 'Sentry sentry_version=7, sentry_client=$sdkIdentifier, ' - 'sentry_key=$publicKey'; - - if (secretKey != null) { - header += ', sentry_secret=$secretKey'; - } - - return header; - } - - Map configure(Map headers) { - return headers - ..addAll( - {'X-Sentry-Auth': _authHeader}, - ); - } -} - -Map _buildHeaders(bool isWeb, String sdkIdentifier) { - final headers = {'Content-Type': 'application/x-sentry-envelope'}; - // NOTE(lejard_h) overriding user agent on VM and Flutter not sure why - // for web it use browser user agent - if (!isWeb) { - headers['User-Agent'] = sdkIdentifier; - } - return headers; -} diff --git a/dart/lib/src/transport/http_transport_request_handler.dart b/dart/lib/src/transport/http_transport_request_handler.dart new file mode 100644 index 0000000000..4aa50898c5 --- /dev/null +++ b/dart/lib/src/transport/http_transport_request_handler.dart @@ -0,0 +1,98 @@ +import 'dart:async'; + +import 'package:http/http.dart'; +import 'package:meta/meta.dart'; + +import 'noop_encode.dart' if (dart.library.io) 'encode.dart'; +import '../protocol.dart'; +import '../sentry_options.dart'; +import '../sentry_envelope.dart'; + +@internal +class HttpTransportRequestHandler { + final SentryOptions _options; + final Dsn _dsn; + final Map _headers; + final Uri _requestUri; + late _CredentialBuilder _credentialBuilder; + + HttpTransportRequestHandler(this._options, this._requestUri) + : _dsn = Dsn.parse(_options.dsn!), + _headers = _buildHeaders( + _options.platformChecker.isWeb, + _options.sentryClientName, + ) { + _credentialBuilder = _CredentialBuilder( + _dsn, + _options.sentryClientName, + ); + } + + Future createRequest(SentryEnvelope envelope) async { + final streamedRequest = StreamedRequest('POST', _requestUri); + + if (_options.compressPayload) { + final compressionSink = compressInSink(streamedRequest.sink, _headers); + envelope + .envelopeStream(_options) + .listen(compressionSink.add) + .onDone(compressionSink.close); + } else { + envelope + .envelopeStream(_options) + .listen(streamedRequest.sink.add) + .onDone(streamedRequest.sink.close); + } + + streamedRequest.headers.addAll(_credentialBuilder.configure(_headers)); + return streamedRequest; + } +} + +Map _buildHeaders(bool isWeb, String sdkIdentifier) { + final headers = {'Content-Type': 'application/x-sentry-envelope'}; + // NOTE(lejard_h) overriding user agent on VM and Flutter not sure why + // for web it use browser user agent + if (!isWeb) { + headers['User-Agent'] = sdkIdentifier; + } + return headers; +} + +class _CredentialBuilder { + final String _authHeader; + + _CredentialBuilder._(String authHeader) : _authHeader = authHeader; + + factory _CredentialBuilder(Dsn dsn, String sdkIdentifier) { + final authHeader = _buildAuthHeader( + publicKey: dsn.publicKey, + secretKey: dsn.secretKey, + sdkIdentifier: sdkIdentifier, + ); + + return _CredentialBuilder._(authHeader); + } + + static String _buildAuthHeader({ + required String publicKey, + String? secretKey, + required String sdkIdentifier, + }) { + var header = 'Sentry sentry_version=7, sentry_client=$sdkIdentifier, ' + 'sentry_key=$publicKey'; + + if (secretKey != null) { + header += ', sentry_secret=$secretKey'; + } + + return header; + } + + Map configure(Map headers) { + return headers + ..addAll( + {'X-Sentry-Auth': _authHeader}, + ); + } +} diff --git a/dart/lib/src/transport/rate_limit.dart b/dart/lib/src/transport/rate_limit.dart index 8f41b91d81..00284a3ba7 100644 --- a/dart/lib/src/transport/rate_limit.dart +++ b/dart/lib/src/transport/rate_limit.dart @@ -2,8 +2,10 @@ import 'data_category.dart'; /// `RateLimit` containing limited `DataCategory` and duration in milliseconds. class RateLimit { - RateLimit(this.category, this.duration); + RateLimit(this.category, this.duration, {List? namespaces}) + : namespaces = (namespaces?..removeWhere((e) => e.isEmpty)) ?? []; final DataCategory category; final Duration duration; + final List namespaces; } diff --git a/dart/lib/src/transport/rate_limit_parser.dart b/dart/lib/src/transport/rate_limit_parser.dart index 63f4f179d1..1cf1a7e3e1 100644 --- a/dart/lib/src/transport/rate_limit_parser.dart +++ b/dart/lib/src/transport/rate_limit_parser.dart @@ -14,6 +14,7 @@ class RateLimitParser { if (rateLimitHeader == null) { return []; } + // example: 2700:metric_bucket:organization:quota_exceeded:custom,... final rateLimits = []; final rateLimitValues = rateLimitHeader.toLowerCase().split(','); for (final rateLimitValue in rateLimitValues) { @@ -29,8 +30,18 @@ class RateLimitParser { if (allCategories.isNotEmpty) { final categoryValues = allCategories.split(';'); for (final categoryValue in categoryValues) { - final category = DataCategoryExtension.fromStringValue(categoryValue); - if (category != DataCategory.unknown) { + final category = _DataCategoryExtension._fromStringValue( + categoryValue); // Metric buckets rate limit can have namespaces + if (category == DataCategory.metricBucket) { + final namespaces = durationAndCategories.length > 4 + ? durationAndCategories[4] + : null; + rateLimits.add(RateLimit( + category, + duration, + namespaces: namespaces?.trim().split(','), + )); + } else if (category != DataCategory.unknown) { rateLimits.add(RateLimit(category, duration)); } } @@ -56,3 +67,27 @@ class RateLimitParser { } } } + +extension _DataCategoryExtension on DataCategory { + static DataCategory _fromStringValue(String stringValue) { + switch (stringValue) { + case '__all__': + return DataCategory.all; + case 'default': + return DataCategory.dataCategoryDefault; + case 'error': + return DataCategory.error; + case 'session': + return DataCategory.session; + case 'transaction': + return DataCategory.transaction; + case 'attachment': + return DataCategory.attachment; + case 'security': + return DataCategory.security; + case 'metric_bucket': + return DataCategory.metricBucket; + } + return DataCategory.unknown; + } +} diff --git a/dart/lib/src/transport/rate_limiter.dart b/dart/lib/src/transport/rate_limiter.dart index 6d4d3c3e9a..ef9b168edd 100644 --- a/dart/lib/src/transport/rate_limiter.dart +++ b/dart/lib/src/transport/rate_limiter.dart @@ -64,6 +64,11 @@ class RateLimiter { } for (final rateLimit in rateLimits) { + if (rateLimit.category == DataCategory.metricBucket && + rateLimit.namespaces.isNotEmpty && + !rateLimit.namespaces.contains('custom')) { + continue; + } _applyRetryAfterOnlyIfLonger( rateLimit.category, DateTime.fromMillisecondsSinceEpoch( @@ -111,6 +116,10 @@ class RateLimiter { return DataCategory.attachment; case 'transaction': return DataCategory.transaction; + // The envelope item type used for metrics is statsd, + // whereas the client report category is metric_bucket + case 'statsd': + return DataCategory.metricBucket; default: return DataCategory.unknown; } diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart new file mode 100644 index 0000000000..f51e77d478 --- /dev/null +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -0,0 +1,52 @@ +import 'package:http/http.dart'; +import '../utils/transport_utils.dart'; +import 'http_transport_request_handler.dart'; + +import '../../sentry.dart'; +import '../noop_client.dart'; + +/// Spotlight HTTP transport decorator that sends Sentry envelopes to both Sentry and Spotlight. +class SpotlightHttpTransport extends Transport { + final SentryOptions _options; + final Transport _transport; + final HttpTransportRequestHandler _requestHandler; + + factory SpotlightHttpTransport(SentryOptions options, Transport transport) { + if (options.httpClient is NoOpClient) { + options.httpClient = Client(); + } + return SpotlightHttpTransport._(options, transport); + } + + SpotlightHttpTransport._(this._options, this._transport) + : _requestHandler = HttpTransportRequestHandler( + _options, Uri.parse(_options.spotlight.url)); + + @override + Future send(SentryEnvelope envelope) async { + try { + await _sendToSpotlight(envelope); + } catch (e) { + _options.logger( + SentryLevel.warning, 'Failed to send envelope to Spotlight: $e'); + } + return _transport.send(envelope); + } + + Future _sendToSpotlight(SentryEnvelope envelope) async { + envelope.header.sentAt = _options.clock(); + + // Screenshots do not work currently https://github.com/getsentry/spotlight/issues/274 + envelope.items + .removeWhere((element) => element.header.contentType == 'image/png'); + + final spotlightRequest = await _requestHandler.createRequest(envelope); + + final response = await _options.httpClient + .send(spotlightRequest) + .then(Response.fromStream); + + TransportUtils.logResponse(_options, envelope, response, + target: 'Spotlight'); + } +} diff --git a/dart/lib/src/transport/task_queue.dart b/dart/lib/src/transport/task_queue.dart new file mode 100644 index 0000000000..386a4980f2 --- /dev/null +++ b/dart/lib/src/transport/task_queue.dart @@ -0,0 +1,29 @@ +import 'dart:async'; + +import '../../sentry.dart'; + +typedef Task = Future Function(); + +class TaskQueue { + TaskQueue(this._maxQueueSize, this._logger); + + final int _maxQueueSize; + final SentryLogger _logger; + + int _queueCount = 0; + + Future enqueue(Task task, T fallbackResult) async { + if (_queueCount >= _maxQueueSize) { + _logger(SentryLevel.warning, + 'Task dropped due to backpressure. Avoid capturing in a tight loop.'); + return fallbackResult; + } else { + _queueCount++; + try { + return await task(); + } finally { + _queueCount--; + } + } + } +} diff --git a/dart/lib/src/utils/crc32_utils.dart b/dart/lib/src/utils/crc32_utils.dart new file mode 100644 index 0000000000..8e6f63fd53 --- /dev/null +++ b/dart/lib/src/utils/crc32_utils.dart @@ -0,0 +1,313 @@ +// Adapted from the archive library (https://pub.dev/packages/archive) +// https://github.com/brendan-duncan/archive/blob/21c864efe0df2b7fd962b59ff0a714c96732bf7d/lib/src/util/crc32.dart +// +// The MIT License +// +// Copyright (c) 2013-2021 Brendan Duncan. +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/// Util class to compute the CRC-32 checksum of a given array. +class Crc32Utils { + /// Get the CRC-32 checksum of the given array. You can append bytes to an + /// already computed crc by specifying the previous [crc] value. + static int getCrc32(List array, [int crc = 0]) { + var len = array.length; + crc = crc ^ 0xffffffff; + var ip = 0; + while (len >= 8) { + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + len -= 8; + } + if (len > 0) { + do { + crc = _crc32Table[(crc ^ array[ip++]) & 0xff] ^ (crc >> 8); + } while (--len > 0); + } + return crc ^ 0xffffffff; + } +} + +// Precomputed CRC table for faster calculations. +const List _crc32Table = [ + 0, + 1996959894, + 3993919788, + 2567524794, + 124634137, + 1886057615, + 3915621685, + 2657392035, + 249268274, + 2044508324, + 3772115230, + 2547177864, + 162941995, + 2125561021, + 3887607047, + 2428444049, + 498536548, + 1789927666, + 4089016648, + 2227061214, + 450548861, + 1843258603, + 4107580753, + 2211677639, + 325883990, + 1684777152, + 4251122042, + 2321926636, + 335633487, + 1661365465, + 4195302755, + 2366115317, + 997073096, + 1281953886, + 3579855332, + 2724688242, + 1006888145, + 1258607687, + 3524101629, + 2768942443, + 901097722, + 1119000684, + 3686517206, + 2898065728, + 853044451, + 1172266101, + 3705015759, + 2882616665, + 651767980, + 1373503546, + 3369554304, + 3218104598, + 565507253, + 1454621731, + 3485111705, + 3099436303, + 671266974, + 1594198024, + 3322730930, + 2970347812, + 795835527, + 1483230225, + 3244367275, + 3060149565, + 1994146192, + 31158534, + 2563907772, + 4023717930, + 1907459465, + 112637215, + 2680153253, + 3904427059, + 2013776290, + 251722036, + 2517215374, + 3775830040, + 2137656763, + 141376813, + 2439277719, + 3865271297, + 1802195444, + 476864866, + 2238001368, + 4066508878, + 1812370925, + 453092731, + 2181625025, + 4111451223, + 1706088902, + 314042704, + 2344532202, + 4240017532, + 1658658271, + 366619977, + 2362670323, + 4224994405, + 1303535960, + 984961486, + 2747007092, + 3569037538, + 1256170817, + 1037604311, + 2765210733, + 3554079995, + 1131014506, + 879679996, + 2909243462, + 3663771856, + 1141124467, + 855842277, + 2852801631, + 3708648649, + 1342533948, + 654459306, + 3188396048, + 3373015174, + 1466479909, + 544179635, + 3110523913, + 3462522015, + 1591671054, + 702138776, + 2966460450, + 3352799412, + 1504918807, + 783551873, + 3082640443, + 3233442989, + 3988292384, + 2596254646, + 62317068, + 1957810842, + 3939845945, + 2647816111, + 81470997, + 1943803523, + 3814918930, + 2489596804, + 225274430, + 2053790376, + 3826175755, + 2466906013, + 167816743, + 2097651377, + 4027552580, + 2265490386, + 503444072, + 1762050814, + 4150417245, + 2154129355, + 426522225, + 1852507879, + 4275313526, + 2312317920, + 282753626, + 1742555852, + 4189708143, + 2394877945, + 397917763, + 1622183637, + 3604390888, + 2714866558, + 953729732, + 1340076626, + 3518719985, + 2797360999, + 1068828381, + 1219638859, + 3624741850, + 2936675148, + 906185462, + 1090812512, + 3747672003, + 2825379669, + 829329135, + 1181335161, + 3412177804, + 3160834842, + 628085408, + 1382605366, + 3423369109, + 3138078467, + 570562233, + 1426400815, + 3317316542, + 2998733608, + 733239954, + 1555261956, + 3268935591, + 3050360625, + 752459403, + 1541320221, + 2607071920, + 3965973030, + 1969922972, + 40735498, + 2617837225, + 3943577151, + 1913087877, + 83908371, + 2512341634, + 3803740692, + 2075208622, + 213261112, + 2463272603, + 3855990285, + 2094854071, + 198958881, + 2262029012, + 4057260610, + 1759359992, + 534414190, + 2176718541, + 4139329115, + 1873836001, + 414664567, + 2282248934, + 4279200368, + 1711684554, + 285281116, + 2405801727, + 4167216745, + 1634467795, + 376229701, + 2685067896, + 3608007406, + 1308918612, + 956543938, + 2808555105, + 3495958263, + 1231636301, + 1047427035, + 2932959818, + 3654703836, + 1088359270, + 936918000, + 2847714899, + 3736837829, + 1202900863, + 817233897, + 3183342108, + 3401237130, + 1404277552, + 615818150, + 3134207493, + 3453421203, + 1423857449, + 601450431, + 3009837614, + 3294710456, + 1567103746, + 711928724, + 3020668471, + 3272380065, + 1510334235, + 755167117 +]; diff --git a/dart/lib/src/utils/http_sanitizer.dart b/dart/lib/src/utils/http_sanitizer.dart index c131cc0c4e..2e5de505a9 100644 --- a/dart/lib/src/utils/http_sanitizer.dart +++ b/dart/lib/src/utils/http_sanitizer.dart @@ -60,7 +60,7 @@ class HttpSanitizer { } } -extension UriPath on Uri { +extension _UriPath on Uri { String _urlWithRedactedAuth() { var buffer = ''; if (scheme.isNotEmpty) { @@ -78,6 +78,7 @@ extension UriPath on Uri { } } +@internal extension SanitizedSentryRequest on SentryRequest { SentryRequest sanitized() { final urlDetails = HttpSanitizer.sanitizeUrl(url) ?? UrlDetails(); diff --git a/dart/lib/src/utils/isolate_utils.dart b/dart/lib/src/utils/isolate_utils.dart index ce523b0d63..3e9c4b20bc 100644 --- a/dart/lib/src/utils/isolate_utils.dart +++ b/dart/lib/src/utils/isolate_utils.dart @@ -1,4 +1,7 @@ +import 'package:meta/meta.dart'; + import '_io_get_isolate_name.dart' if (dart.library.html) '_web_get_isolate_name.dart' as isolate_getter; +@internal String? getIsolateName() => isolate_getter.getIsolateName(); diff --git a/dart/lib/src/utils/iterable_extension.dart b/dart/lib/src/utils/iterable_extension.dart deleted file mode 100644 index 34c2c60943..0000000000 --- a/dart/lib/src/utils/iterable_extension.dart +++ /dev/null @@ -1,8 +0,0 @@ -extension IterableExtension on Iterable { - T? firstWhereOrNull(bool Function(T item) predicate) { - for (var item in this) { - if (predicate(item)) return item; - } - return null; - } -} diff --git a/dart/lib/src/utils/iterable_utils.dart b/dart/lib/src/utils/iterable_utils.dart new file mode 100644 index 0000000000..c2fb5e5c69 --- /dev/null +++ b/dart/lib/src/utils/iterable_utils.dart @@ -0,0 +1,17 @@ +import 'package:meta/meta.dart'; + +@internal +class IterableUtils { + static T? firstWhereOrNull( + Iterable? iterable, + bool Function(T item) test, + ) { + if (iterable == null) { + return null; + } + for (var item in iterable) { + if (test(item)) return item; + } + return null; + } +} diff --git a/dart/lib/src/utils/sample_rate_format.dart b/dart/lib/src/utils/sample_rate_format.dart index 4abb79edd8..e69163f30b 100644 --- a/dart/lib/src/utils/sample_rate_format.dart +++ b/dart/lib/src/utils/sample_rate_format.dart @@ -1,3 +1,4 @@ +// ignore: dangling_library_doc_comments /// Code ported & adapted from `intl` package /// https://pub.dev/packages/intl /// diff --git a/dart/lib/src/utils/stacktrace_utils.dart b/dart/lib/src/utils/stacktrace_utils.dart new file mode 100644 index 0000000000..acc1cccf44 --- /dev/null +++ b/dart/lib/src/utils/stacktrace_utils.dart @@ -0,0 +1,10 @@ +import 'package:meta/meta.dart'; + +// A wrapper function around StackTrace.current so we can ignore it in the SDK +// crash detection. Otherwise, the SDK crash detection would have to ignore the +// method calling StackTrace.current, and it can't detect crashes in that +// method. +// You can read about the SDK crash detection here: +// https://github.com/getsentry/sentry/blob/master/src/sentry/utils/sdk_crashes/README.rst +@internal +StackTrace getCurrentStackTrace() => StackTrace.current; diff --git a/dart/lib/src/utils/transport_utils.dart b/dart/lib/src/utils/transport_utils.dart new file mode 100644 index 0000000000..fa2f20096a --- /dev/null +++ b/dart/lib/src/utils/transport_utils.dart @@ -0,0 +1,32 @@ +import 'package:http/http.dart'; + +import '../client_reports/discard_reason.dart'; +import '../protocol.dart'; +import '../sentry_envelope.dart'; +import '../sentry_options.dart'; +import '../transport/data_category.dart'; + +class TransportUtils { + static void logResponse( + SentryOptions options, SentryEnvelope envelope, Response response, + {required String target}) { + if (response.statusCode != 200) { + if (options.debug) { + options.logger( + SentryLevel.error, + 'Error, statusCode = ${response.statusCode}, body = ${response.body}', + ); + } + + if (response.statusCode >= 400 && response.statusCode != 429) { + options.recorder + .recordLostEvent(DiscardReason.networkError, DataCategory.error); + } + } else { + options.logger( + SentryLevel.debug, + 'Envelope ${envelope.header.eventId ?? "--"} was sent successfully to $target.', + ); + } + } +} diff --git a/dart/lib/src/version.dart b/dart/lib/src/version.dart index ae1db0d901..961566fdc3 100644 --- a/dart/lib/src/version.dart +++ b/dart/lib/src/version.dart @@ -9,7 +9,7 @@ library version; /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; String sdkName(bool isWeb) => isWeb ? _browserSdkName : _ioSdkName; diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml index 4dc923be94..41aa1b7d0c 100644 --- a/dart/pubspec.yaml +++ b/dart/pubspec.yaml @@ -1,5 +1,5 @@ name: sentry -version: 7.13.1 +version: 8.3.0 description: > A crash reporting library for Dart that sends crash reports to Sentry.io. This library supports Dart VM and Web. For Flutter consider sentry_flutter instead. @@ -11,6 +11,14 @@ documentation: https://docs.sentry.io/platforms/dart/ environment: sdk: '>=2.17.0 <4.0.0' +platforms: + android: + ios: + macos: + linux: + windows: + web: + dependencies: http: '>=0.13.0 <2.0.0' meta: ^1.3.0 @@ -20,7 +28,7 @@ dependencies: dev_dependencies: build_runner: ^2.4.2 mockito: ^5.1.0 - lints: ^2.0.0 + lints: ^4.0.0 test: ^1.21.1 yaml: ^3.1.0 # needed for version match (code and pubspec) collection: ^1.16.0 diff --git a/dart/test/environment_test.dart b/dart/test/environment_test.dart index e4bf97fea7..b16225d1dd 100644 --- a/dart/test/environment_test.dart +++ b/dart/test/environment_test.dart @@ -39,7 +39,7 @@ void main() { test('SentryOptions are overriden by environment', () async { final options = SentryOptions(); options.environmentVariables = MockEnvironmentVariables( - dsn: 'foo-bar', + dsn: fakeDsn, environment: 'staging', release: 'release-9.8.7', dist: 'bar', @@ -51,7 +51,7 @@ void main() { options: options, ); - expect(options.dsn, 'foo-bar'); + expect(options.dsn, fakeDsn); expect(options.environment, 'staging'); expect(options.release, 'release-9.8.7'); expect(options.dist, 'bar'); diff --git a/dart/test/event_processor/deduplication_event_processor_test.dart b/dart/test/event_processor/deduplication_event_processor_test.dart index 54592351bb..3e17fe4065 100644 --- a/dart/test/event_processor/deduplication_event_processor_test.dart +++ b/dart/test/event_processor/deduplication_event_processor_test.dart @@ -15,16 +15,16 @@ void main() { final sut = fixture.getSut(true); var ogEvent = _createEvent('foo'); - expect(sut.apply(ogEvent), isNotNull); - expect(sut.apply(ogEvent), isNull); + expect(sut.apply(ogEvent, Hint()), isNotNull); + expect(sut.apply(ogEvent, Hint()), isNull); }); test('does not deduplicate if disabled', () { final sut = fixture.getSut(false); var ogEvent = _createEvent('foo'); - expect(sut.apply(ogEvent), isNotNull); - expect(sut.apply(ogEvent), isNotNull); + expect(sut.apply(ogEvent, Hint()), isNotNull); + expect(sut.apply(ogEvent, Hint()), isNotNull); }); test('does not deduplicate if different events', () { @@ -32,16 +32,16 @@ void main() { var fooEvent = _createEvent('foo'); var barEvent = _createEvent('bar'); - expect(sut.apply(fooEvent), isNotNull); - expect(sut.apply(barEvent), isNotNull); + expect(sut.apply(fooEvent, Hint()), isNotNull); + expect(sut.apply(barEvent, Hint()), isNotNull); }); test('does not deduplicate transaction', () { final sut = fixture.getSut(true); final transaction = _createTransaction(fixture.hub); - expect(sut.apply(transaction), isNotNull); - expect(sut.apply(transaction), isNotNull); + expect(sut.apply(transaction, Hint()), isNotNull); + expect(sut.apply(transaction, Hint()), isNotNull); }); test('exceptions to keep for deduplication', () { @@ -51,10 +51,10 @@ void main() { var barEvent = _createEvent('bar'); var fooBarEvent = _createEvent('foo bar'); - expect(sut.apply(fooEvent), isNotNull); - expect(sut.apply(barEvent), isNotNull); - expect(sut.apply(fooBarEvent), isNotNull); - expect(sut.apply(fooEvent), isNotNull); + expect(sut.apply(fooEvent, Hint()), isNotNull); + expect(sut.apply(barEvent, Hint()), isNotNull); + expect(sut.apply(fooBarEvent, Hint()), isNotNull); + expect(sut.apply(fooEvent, Hint()), isNotNull); }); test('integration test', () async { diff --git a/dart/test/event_processor/enricher/io_enricher_test.dart b/dart/test/event_processor/enricher/io_enricher_test.dart index 1704960edc..bdc6da2e4e 100644 --- a/dart/test/event_processor/enricher/io_enricher_test.dart +++ b/dart/test/event_processor/enricher/io_enricher_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library dart_test; import 'package:sentry/sentry.dart'; import 'package:sentry/src/event_processor/enricher/io_enricher_event_processor.dart'; @@ -17,7 +18,7 @@ void main() { test('adds dart runtime', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.runtimes, isNotEmpty); final dartRuntime = event?.contexts.runtimes @@ -31,7 +32,7 @@ void main() { var event = SentryEvent(contexts: Contexts(runtimes: [runtime])); final enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.contexts.runtimes.contains(runtime), true); // second runtime is Dart runtime @@ -42,7 +43,7 @@ void main() { 'does not add device, os and culture if native integration is available', () { final enricher = fixture.getSut(hasNativeIntegration: true); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNull); expect(event?.contexts.operatingSystem, isNull); @@ -52,7 +53,7 @@ void main() { test('adds device, os and culture if no native integration is available', () { final enricher = fixture.getSut(hasNativeIntegration: false); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNotNull); expect(event?.contexts.operatingSystem, isNotNull); @@ -61,14 +62,14 @@ void main() { test('device has name', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device?.name, isNotNull); }); test('culture has locale and timezone', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.culture?.locale, isNotNull); expect(event?.contexts.culture?.timezone, isNotNull); @@ -76,7 +77,7 @@ void main() { test('os has name and version', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.operatingSystem?.name, isNotNull); expect(event?.contexts.operatingSystem?.version, isNotNull); @@ -84,7 +85,7 @@ void main() { test('adds Dart context with PII', () { final enricher = fixture.getSut(includePii: true); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); final dartContext = event?.contexts['dart_context']; expect(dartContext, isNotNull); @@ -97,7 +98,7 @@ void main() { test('adds Dart context without PII', () { final enricher = fixture.getSut(includePii: false); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); final dartContext = event?.contexts['dart_context']; expect(dartContext, isNotNull); @@ -131,7 +132,7 @@ void main() { hasNativeIntegration: false, ); - final event = enricher.apply(fakeEvent); + final event = enricher.apply(fakeEvent, Hint()); // contexts.device expect( diff --git a/dart/test/event_processor/enricher/web_enricher_test.dart b/dart/test/event_processor/enricher/web_enricher_test.dart index 60076e506a..cdc7310fab 100644 --- a/dart/test/event_processor/enricher/web_enricher_test.dart +++ b/dart/test/event_processor/enricher/web_enricher_test.dart @@ -1,4 +1,6 @@ @TestOn('browser') +library dart_test; + import 'dart:html' as html; import 'package:sentry/sentry.dart'; @@ -20,21 +22,21 @@ void main() { test('add path as transaction if transaction is null', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.transaction, isNotNull); }); test("don't overwrite transaction", () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent(transaction: 'foobar')); + final event = enricher.apply(SentryEvent(transaction: 'foobar'), Hint()); expect(event?.transaction, 'foobar'); }); test('add request with user-agent header', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.request?.headers['User-Agent'], isNotNull); expect(event?.request?.url, isNotNull); @@ -50,7 +52,7 @@ void main() { ), ); var enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.request?.headers['User-Agent'], isNotNull); expect(event.request?.headers['foo'], 'bar'); @@ -68,7 +70,7 @@ void main() { ), ); var enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.request?.headers['Authorization'], isNull); expect(event.request?.headers['authorization'], isNull); @@ -84,7 +86,7 @@ void main() { ), ); var enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.request?.headers['User-Agent'], 'best browser agent'); expect(event.request?.url, 'foo.bar'); @@ -92,14 +94,14 @@ void main() { test('adds device and os', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNotNull); }); test('adds Dart context', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); final dartContext = event?.contexts['dart_context']; expect(dartContext, isNotNull); @@ -108,14 +110,14 @@ void main() { test('device has screendensity', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device?.screenDensity, isNotNull); }); test('culture has timezone', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.culture?.timezone, isNotNull); }); @@ -142,7 +144,7 @@ void main() { final enricher = fixture.getSut(); - final event = enricher.apply(fakeEvent); + final event = enricher.apply(fakeEvent, Hint()); // contexts.device expect( diff --git a/dart/test/event_processor/exception/io_exception_event_processor_test.dart b/dart/test/event_processor/exception/io_exception_event_processor_test.dart index 14d2720df2..9523038638 100644 --- a/dart/test/event_processor/exception/io_exception_event_processor_test.dart +++ b/dart/test/event_processor/exception/io_exception_event_processor_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library dart_test; import 'dart:io'; @@ -23,6 +24,7 @@ void main() { uri: Uri.parse('https://example.org/foo/bar?foo=bar'), ), ), + Hint(), ); expect(event?.request, isNotNull); @@ -36,6 +38,7 @@ void main() { SentryEvent( throwable: HttpException(''), ), + Hint(), ); expect(event?.request, isNull); @@ -55,6 +58,7 @@ void main() { ), ), ), + Hint(), ); expect(event?.request, isNotNull); @@ -81,6 +85,7 @@ void main() { OSError('Oh no :(', 42), ), ), + Hint(), ); // Due to the test setup, there's no SentryException for the FileSystemException. diff --git a/dart/test/example_web_compile_test.dart b/dart/test/example_web_compile_test.dart new file mode 100644 index 0000000000..4199a47dda --- /dev/null +++ b/dart/test/example_web_compile_test.dart @@ -0,0 +1,88 @@ +@TestOn('vm') +library dart_test; + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:test/test.dart'; + +// Tests for the following issue +// https://github.com/getsentry/sentry-dart/issues/1893 +void main() { + group('Compile example_web', () { + test( + 'dart pub get and compilation should run successfully', + () async { + final result = await _runProcess('dart pub get', + workingDirectory: _exampleWebWorkingDir); + expect(result.exitCode, 0, + reason: 'Could run `dart pub get` for example_web. ' + 'Likely caused by outdated dependencies'); + // running this test locally require clean working directory + final cleanResult = await _runProcess('dart run build_runner clean', + workingDirectory: _exampleWebWorkingDir); + expect(cleanResult.exitCode, 0); + final compileResult = await _runProcess( + 'dart run build_runner build -r web -o build --delete-conflicting-outputs', + workingDirectory: _exampleWebWorkingDir); + expect(compileResult.exitCode, 0, + reason: 'Could not compile example_web project'); + expect( + compileResult.stdout, + isNot(contains( + 'Skipping compiling sentry_dart_web_example|web/main.dart')), + reason: + 'Could not compile main.dart, likely because of dart:io import.'); + expect( + compileResult.stdout, + contains( + 'build_web_compilers:entrypoint on web/main.dart:Compiled')); + }, + timeout: Timeout(const Duration(minutes: 1)), // double of detault timeout + ); + }); +} + +/// Runs [command] with command's stdout and stderr being forwrarded to +/// test runner's respective streams. It buffers stdout and returns it. +/// +/// Returns [_CommandResult] with exitCode and stdout as a single sting +Future<_CommandResult> _runProcess(String command, + {String workingDirectory = '.'}) async { + final parts = command.split(' '); + assert(parts.isNotEmpty); + final cmd = parts[0]; + final args = parts.skip(1).toList(); + final process = + await Process.start(cmd, args, workingDirectory: workingDirectory); + // forward standard streams + unawaited(stderr.addStream(process.stderr)); + final buffer = []; + final stdoutCompleter = Completer.sync(); + process.stdout.listen( + (units) { + buffer.addAll(units); + stdout.add(units); + }, + cancelOnError: true, + onDone: () { + stdoutCompleter.complete(); + }, + ); + await stdoutCompleter.future; + final processOut = utf8.decode(buffer); + int exitCode = await process.exitCode; + return _CommandResult(exitCode: exitCode, stdout: processOut); +} + +String get _exampleWebWorkingDir { + return '${Directory.current.path}${Platform.pathSeparator}example_web'; +} + +class _CommandResult { + final int exitCode; + final String stdout; + + const _CommandResult({required this.exitCode, required this.stdout}); +} diff --git a/dart/test/hint_test.dart b/dart/test/hint_test.dart index d46a022405..04c09a28a0 100644 --- a/dart/test/hint_test.dart +++ b/dart/test/hint_test.dart @@ -82,6 +82,23 @@ void main() { expect(sut.screenshot, attachment); expect(sut.viewHierarchy, attachment); }); + + test('Hint init with map null fallback', () { + final hint = Hint.withMap({'fixture-key': null}); + expect("null", hint.get("fixture-key")); + }); + + test('Hint addAll with map null fallback', () { + final hint = Hint(); + hint.addAll({'fixture-key': null}); + expect("null", hint.get("fixture-key")); + }); + + test('Hint set with null value fallback', () { + final hint = Hint(); + hint.set("fixture-key", null); + expect("null", hint.get("fixture-key")); + }); } class Fixture { diff --git a/dart/test/http_client/failed_request_client_test.dart b/dart/test/http_client/failed_request_client_test.dart index 4e6cac15b1..2ac9a74c8e 100644 --- a/dart/test/http_client/failed_request_client_test.dart +++ b/dart/test/http_client/failed_request_client_test.dart @@ -70,7 +70,12 @@ void main() { expect(eventCall.contexts.response, isNull); }); - test('event not reported if disabled', () async { + test( + 'exception does not gets reported if client throws but override disables capture', + () async { + fixture._hub.options.captureFailedRequests = true; + fixture._hub.options.sendDefaultPii = true; + final sut = fixture.getSut( client: createThrowingClient(), captureFailedRequests: false, @@ -84,10 +89,42 @@ void main() { expect(fixture.transport.calls, 0); }); + test('event not reported if disabled', () async { + fixture._hub.options.captureFailedRequests = false; + + final sut = fixture.getSut( + client: createThrowingClient(), + ); + + await expectLater( + () async => await sut.get(requestUri, headers: {'Cookie': 'foo=bar'}), + throwsException, + ); + + expect(fixture.transport.calls, 0); + }); + + test('event reported if disabled but overridden', () async { + fixture._hub.options.captureFailedRequests = false; + + final sut = fixture.getSut( + client: createThrowingClient(), + captureFailedRequests: true, + ); + + await expectLater( + () async => await sut.get(requestUri, headers: {'Cookie': 'foo=bar'}), + throwsException, + ); + + expect(fixture.transport.calls, 1); + }); + test('event not reported if not within the targets', () async { + fixture._hub.options.captureFailedRequests = true; + final sut = fixture.getSut( client: fixture.getClient(statusCode: 500), - captureFailedRequests: true, failedRequestTargets: const ["myapi.com"]); final response = await sut.get(requestUri); @@ -295,7 +332,7 @@ void main() { final sut = fixture.getSut(client: client); Hint? eventHint; - fixture.options.addEventProcessor(FunctionEventProcessor((event, {hint}) { + fixture.options.addEventProcessor(FunctionEventProcessor((event, hint) { eventHint = hint; return event; })); @@ -335,17 +372,16 @@ class Fixture { List failedRequestStatusCodes = const [ SentryStatusCode.defaultRange() ], - bool captureFailedRequests = true, List failedRequestTargets = const [".*"], + bool? captureFailedRequests, }) { final mc = client ?? getClient(); - _hub.options.captureFailedRequests = captureFailedRequests; return FailedRequestClient( - client: mc, - hub: _hub, - failedRequestStatusCodes: failedRequestStatusCodes, - failedRequestTargets: failedRequestTargets, - ); + client: mc, + hub: _hub, + failedRequestStatusCodes: failedRequestStatusCodes, + failedRequestTargets: failedRequestTargets, + captureFailedRequests: captureFailedRequests); } MockClient getClient( diff --git a/dart/test/http_client/sentry_http_client_test.dart b/dart/test/http_client/sentry_http_client_test.dart index 5952a02541..be9d8d7bd1 100644 --- a/dart/test/http_client/sentry_http_client_test.dart +++ b/dart/test/http_client/sentry_http_client_test.dart @@ -32,9 +32,10 @@ void main() { }); test('no captured event with default config', () async { + fixture.hub.options.captureFailedRequests = false; + final sut = fixture.getSut( client: createThrowingClient(), - captureFailedRequests: false, ); await expectLater(() async => await sut.get(requestUri), throwsException); @@ -43,6 +44,19 @@ void main() { expect(fixture.hub.addBreadcrumbCalls.length, 1); }); + test('captured event with override', () async { + fixture.hub.options.captureFailedRequests = false; + + final sut = fixture.getSut( + client: createThrowingClient(), + captureFailedRequests: true, + ); + + await expectLater(() async => await sut.get(requestUri), throwsException); + + expect(fixture.hub.captureEventCalls.length, 1); + }); + test('one captured event with when enabling $FailedRequestClient', () async { fixture.hub.options.captureFailedRequests = true; @@ -61,6 +75,20 @@ void main() { expect(fixture.hub.addBreadcrumbCalls.length, 1); }); + test( + 'no captured event with when enabling $FailedRequestClient with override', + () async { + fixture.hub.options.captureFailedRequests = true; + final sut = fixture.getSut( + client: createThrowingClient(), + captureFailedRequests: false, + ); + + await expectLater(() async => await sut.get(requestUri), throwsException); + + expect(fixture.hub.captureEventCalls.length, 0); + }); + test('close does get called for user defined client', () async { final mockHub = MockHub(); @@ -116,14 +144,14 @@ class Fixture { SentryHttpClient getSut({ MockClient? client, List badStatusCodes = const [], - bool captureFailedRequests = true, + bool? captureFailedRequests, }) { final mc = client ?? getClient(); - hub.options.captureFailedRequests = captureFailedRequests; return SentryHttpClient( client: mc, hub: hub, failedRequestStatusCodes: badStatusCodes, + captureFailedRequests: captureFailedRequests, ); } diff --git a/dart/test/hub_test.dart b/dart/test/hub_test.dart index 31698329d6..8dcc622654 100644 --- a/dart/test/hub_test.dart +++ b/dart/test/hub_test.dart @@ -81,6 +81,21 @@ void main() { expect(fixture.client.captureMessageCalls.first.scope, isNotNull); }); + test('should capture metrics', () async { + final hub = fixture.getSut(); + await hub.captureMetrics(fakeMetrics); + + expect(fixture.client.captureMetricsCalls.length, 1); + expect( + fixture.client.captureMetricsCalls.first.values, + [ + [fakeMetric], + [fakeMetric, fakeMetric2], + [fakeMetric, fakeMetric3, fakeMetric4], + ], + ); + }); + test('should save the lastEventId', () async { final hub = fixture.getSut(); final event = SentryEvent(); @@ -155,7 +170,7 @@ void main() { }); }); - group('Hub captures', () { + group('Hub transactions', () { late Fixture fixture; setUp(() { @@ -376,6 +391,14 @@ void main() { expect( fixture.client.captureTransactionCalls.first.traceContext, context); }); + }); + + group('Hub profiles', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); test('profiler is not started by default', () async { final hub = fixture.getSut(); @@ -432,14 +455,6 @@ void main() { verify(profiler.dispose()).called(1); verifyNever(profiler.finishFor(any)); }); - - test('returns scope', () async { - final hub = fixture.getSut(); - - final scope = hub.scope; - - expect(scope, isNotNull); - }); }); group('Hub scope', () { @@ -452,6 +467,11 @@ void main() { hub.bindClient(client); }); + test('returns scope', () async { + final scope = hub.scope; + expect(scope, isNotNull); + }); + test('should configure its scope', () async { await hub.configureScope((Scope scope) { scope @@ -681,6 +701,44 @@ void main() { expect(fixture.recorder.category, DataCategory.transaction); }); }); + + group('Metrics', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('should not capture metrics if enableMetric is false', () async { + final hub = fixture.getSut(enableMetrics: false, debug: true); + await hub.captureMetrics(fakeMetrics); + + expect(fixture.client.captureMetricsCalls, isEmpty); + expect(fixture.loggedMessage, + 'Metrics are disabled and this \'captureMetrics\' call is a no-op.'); + }); + + test('should not capture metrics if hub is closed', () async { + final hub = fixture.getSut(debug: true); + await hub.close(); + + expect(hub.isEnabled, false); + await hub.captureMetrics(fakeMetrics); + expect(fixture.loggedMessage, + 'Instance is disabled and this \'captureMetrics\' call is a no-op.'); + + expect(fixture.client.captureMetricsCalls, isEmpty); + }); + + test('should not capture metrics if metrics are empty', () async { + final hub = fixture.getSut(debug: true); + await hub.captureMetrics({}); + expect(fixture.loggedMessage, + 'Metrics are empty and this \'captureMetrics\' call is a no-op.'); + + expect(fixture.client.captureMetricsCalls, isEmpty); + }); + }); } class Fixture { @@ -692,17 +750,20 @@ class Fixture { late SentryTracer tracer; SentryLevel? loggedLevel; + String? loggedMessage; Object? loggedException; Hub getSut({ double? tracesSampleRate = 1.0, TracesSamplerCallback? tracesSampler, bool? sampled = true, + bool enableMetrics = true, bool debug = false, }) { options.tracesSampleRate = tracesSampleRate; options.tracesSampler = tracesSampler; options.debug = debug; + options.enableMetrics = enableMetrics; options.logger = mockLogger; // Enable logging in DiagnosticsLogger final hub = Hub(options); @@ -731,6 +792,7 @@ class Fixture { StackTrace? stackTrace, }) { loggedLevel = level; + loggedMessage = message; loggedException = exception; } } diff --git a/dart/test/initialization_test.dart b/dart/test/initialization_test.dart index 7eb8c15265..e6f9ddea23 100644 --- a/dart/test/initialization_test.dart +++ b/dart/test/initialization_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library dart_test; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; diff --git a/dart/test/metrics/local_metrics_aggregator_test.dart b/dart/test/metrics/local_metrics_aggregator_test.dart new file mode 100644 index 0000000000..42648fdaf2 --- /dev/null +++ b/dart/test/metrics/local_metrics_aggregator_test.dart @@ -0,0 +1,40 @@ +import 'package:sentry/src/metrics/local_metrics_aggregator.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +import '../mocks.dart'; + +void main() { + group('add', () { + late LocalMetricsAggregator aggregator; + + setUp(() { + aggregator = LocalMetricsAggregator(); + }); + + test('same metric multiple times aggregates them', () async { + aggregator.add(fakeMetric, 1); + aggregator.add(fakeMetric, 2); + final summaries = aggregator.getSummaries(); + expect(summaries.length, 1); + final summary = summaries.values.first; + expect(summary.length, 1); + }); + + test('same metric different tags aggregates summary bucket', () async { + aggregator.add(fakeMetric, 1); + aggregator.add(fakeMetric..tags.clear(), 2); + final summaries = aggregator.getSummaries(); + expect(summaries.length, 1); + final summary = summaries.values.first; + expect(summary.length, 2); + }); + + test('different metrics does not aggregate them', () async { + aggregator.add(fakeMetric, 1); + aggregator.add(fakeMetric2, 2); + final summaries = aggregator.getSummaries(); + expect(summaries.length, 2); + }); + }); +} diff --git a/dart/test/metrics/metric_test.dart b/dart/test/metrics/metric_test.dart new file mode 100644 index 0000000000..f3edc0486b --- /dev/null +++ b/dart/test/metrics/metric_test.dart @@ -0,0 +1,315 @@ +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/metrics/metric.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +import 'metrics_aggregator_test.dart'; + +void main() { + group('fromType', () { + test('counter creates a CounterMetric', () async { + final Metric metric = Metric.fromType( + type: MetricType.counter, + key: mockKey, + value: 1, + unit: mockUnit, + tags: mockTags); + expect(metric, isA()); + }); + + test('gauge creates a GaugeMetric', () async { + final Metric metric = Metric.fromType( + type: MetricType.gauge, + key: mockKey, + value: 1, + unit: mockUnit, + tags: mockTags); + expect(metric, isA()); + }); + + test('distribution creates a DistributionMetric', () async { + final Metric metric = Metric.fromType( + type: MetricType.distribution, + key: mockKey, + value: 1, + unit: mockUnit, + tags: mockTags); + expect(metric, isA()); + }); + + test('set creates a SetMetric', () async { + final Metric metric = Metric.fromType( + type: MetricType.set, + key: mockKey, + value: 1, + unit: mockUnit, + tags: mockTags); + expect(metric, isA()); + }); + }); + + group('Encode to statsd', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('encode CounterMetric', () async { + final int bucketKey = 10; + final expectedStatsd = + 'key_metric_@hour:2.1|c|#tag1:tag\\u{2c} value 1,key2:&@"13/-d_s|T10'; + final actualStatsd = fixture.counterMetric.encodeToStatsd(bucketKey); + expect(actualStatsd, expectedStatsd); + }); + + test('sanitize name', () async { + final metric = Metric.fromType( + type: MetricType.counter, + value: 2.1, + key: 'key£ - @# metric!', + unit: DurationSentryMeasurementUnit.day, + tags: {}, + ); + + final expectedStatsd = 'key_-_metric_@day:2.1|c|T10'; + expect(metric.encodeToStatsd(10), expectedStatsd); + }); + + test('sanitize unit', () async { + final metric = Metric.fromType( + type: MetricType.counter, + value: 2.1, + key: 'key', + unit: CustomSentryMeasurementUnit('weird-measurement name!'), + tags: {}, + ); + + final expectedStatsd = 'key@weirdmeasurementname:2.1|c|T10'; + expect(metric.encodeToStatsd(10), expectedStatsd); + }); + + test('sanitize tags', () async { + final metric = Metric.fromType( + type: MetricType.counter, + value: 2.1, + key: 'key', + unit: DurationSentryMeasurementUnit.day, + tags: {'tag1': 'tag, value 1', 'key 2': '&@"13/-d_s'}, + ); + + final expectedStatsd = + 'key@day:2.1|c|#tag1:tag\\u{2c} value 1,key2:&@"13/-d_s|T10'; + expect(metric.encodeToStatsd(10), expectedStatsd); + }); + }); + + group('getCompositeKey', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('escapes commas from tags', () async { + final Iterable tags = fixture.counterMetric.tags.values; + final joinedTags = tags.join(); + final Iterable expectedTags = + tags.map((e) => e.replaceAll(',', '\\,')); + final actualKey = fixture.counterMetric.getCompositeKey(); + + expect(joinedTags.contains(','), true); + expect(joinedTags.contains('\\,'), false); + expect(actualKey.contains('\\,'), true); + for (var tag in expectedTags) { + expect(actualKey.contains(tag), true); + } + }); + + test('CounterMetric', () async { + final expectedKey = + 'c_key metric!_hour_tag1=tag\\, value 1,key 2=&@"13/-d_s'; + final actualKey = fixture.counterMetric.getCompositeKey(); + expect(actualKey, expectedKey); + }); + + test('GaugeMetric', () async { + final expectedKey = + 'g_key metric!_hour_tag1=tag\\, value 1,key 2=&@"13/-d_s'; + final actualKey = fixture.gaugeMetric.getCompositeKey(); + expect(actualKey, expectedKey); + }); + + test('DistributionMetric', () async { + final expectedKey = + 'd_key metric!_hour_tag1=tag\\, value 1,key 2=&@"13/-d_s'; + final actualKey = fixture.distributionMetric.getCompositeKey(); + expect(actualKey, expectedKey); + }); + + test('SetMetric', () async { + final expectedKey = + 's_key metric!_hour_tag1=tag\\, value 1,key 2=&@"13/-d_s'; + final actualKey = fixture.setMetric.getCompositeKey(); + expect(actualKey, expectedKey); + }); + }); + + group('getSpanAggregationKey', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('CounterMetric', () async { + final expectedKey = 'c:key metric!@hour'; + final actualKey = fixture.counterMetric.getSpanAggregationKey(); + expect(actualKey, expectedKey); + }); + + test('GaugeMetric', () async { + final expectedKey = 'g:key metric!@hour'; + final actualKey = fixture.gaugeMetric.getSpanAggregationKey(); + expect(actualKey, expectedKey); + }); + + test('DistributionMetric', () async { + final expectedKey = 'd:key metric!@hour'; + final actualKey = fixture.distributionMetric.getSpanAggregationKey(); + expect(actualKey, expectedKey); + }); + + test('SetMetric', () async { + final expectedKey = 's:key metric!@hour'; + final actualKey = fixture.setMetric.getSpanAggregationKey(); + expect(actualKey, expectedKey); + }); + }); + + group('getWeight', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('counter always returns 1', () async { + final CounterMetric metric = fixture.counterMetric; + expect(metric.getWeight(), 1); + metric.add(5); + metric.add(2); + expect(metric.getWeight(), 1); + }); + + test('gauge always returns 5', () async { + final GaugeMetric metric = fixture.gaugeMetric; + expect(metric.getWeight(), 5); + metric.add(5); + metric.add(2); + expect(metric.getWeight(), 5); + }); + + test('distribution returns number of values', () async { + final DistributionMetric metric = fixture.distributionMetric; + expect(metric.getWeight(), 1); + metric.add(5); + // Repeated values are counted + metric.add(5); + expect(metric.getWeight(), 3); + }); + + test('set returns number of unique values', () async { + final SetMetric metric = fixture.setMetric; + expect(metric.getWeight(), 1); + metric.add(5); + // Repeated values are not counted + metric.add(5); + expect(metric.getWeight(), 2); + }); + }); + + group('add', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('counter increments', () async { + final CounterMetric metric = fixture.counterMetric; + expect(metric.value, 2.1); + metric.add(5); + metric.add(2); + expect(metric.value, 9.1); + }); + + test('gauge stores min, max, last, sum and count', () async { + final GaugeMetric metric = fixture.gaugeMetric; + expect(metric.minimum, 2.1); + expect(metric.maximum, 2.1); + expect(metric.last, 2.1); + expect(metric.sum, 2.1); + expect(metric.count, 1); + metric.add(1.4); + metric.add(5.4); + expect(metric.minimum, 1.4); + expect(metric.maximum, 5.4); + expect(metric.last, 5.4); + expect(metric.sum, 8.9); + expect(metric.count, 3); + }); + + test('distribution stores all values', () async { + final DistributionMetric metric = fixture.distributionMetric; + metric.add(2); + metric.add(4); + metric.add(4); + expect(metric.values, [2.1, 2, 4, 4]); + }); + + test('set stores unique int values', () async { + final SetMetric metric = fixture.setMetric; + metric.add(5); + // Repeated values are not counted + metric.add(5); + expect(metric.values, {2, 5}); + }); + }); +} + +class Fixture { + // We use a fractional number because on some platforms converting '2' to + // string return '2', while others '2.0', and we'd have issues testing. + final CounterMetric counterMetric = Metric.fromType( + type: MetricType.counter, + value: 2.1, + key: 'key metric!', + unit: DurationSentryMeasurementUnit.hour, + tags: {'tag1': 'tag, value 1', 'key 2': '&@"13/-d_s'}, + ) as CounterMetric; + + final GaugeMetric gaugeMetric = Metric.fromType( + type: MetricType.gauge, + value: 2.1, + key: 'key metric!', + unit: DurationSentryMeasurementUnit.hour, + tags: {'tag1': 'tag, value 1', 'key 2': '&@"13/-d_s'}, + ) as GaugeMetric; + + final DistributionMetric distributionMetric = Metric.fromType( + type: MetricType.distribution, + value: 2.1, + key: 'key metric!', + unit: DurationSentryMeasurementUnit.hour, + tags: {'tag1': 'tag, value 1', 'key 2': '&@"13/-d_s'}, + ) as DistributionMetric; + + final SetMetric setMetric = Metric.fromType( + type: MetricType.set, + value: 2.1, + key: 'key metric!', + unit: DurationSentryMeasurementUnit.hour, + tags: {'tag1': 'tag, value 1', 'key 2': '&@"13/-d_s'}, + ) as SetMetric; +} diff --git a/dart/test/metrics/metrics_aggregator_test.dart b/dart/test/metrics/metrics_aggregator_test.dart new file mode 100644 index 0000000000..5636e7ebf6 --- /dev/null +++ b/dart/test/metrics/metrics_aggregator_test.dart @@ -0,0 +1,493 @@ +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/metrics/metric.dart'; +import 'package:sentry/src/metrics/metrics_aggregator.dart'; +import 'package:test/test.dart'; + +import '../mocks.dart'; +import '../mocks/mock_hub.dart'; + +void main() { + group('emit', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('counter', () async { + final MetricsAggregator sut = fixture.getSut(); + final String key = 'metric key'; + final double value = 5; + final SentryMeasurementUnit unit = DurationSentryMeasurementUnit.minute; + final Map tags = {'tag1': 'val1', 'tag2': 'val2'}; + sut.emit(MetricType.counter, key, value, unit, tags); + + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.length, 1); + expect(metricsCaptured.first, isA()); + expect(metricsCaptured.first.type, MetricType.counter); + expect(metricsCaptured.first.key, key); + expect((metricsCaptured.first as CounterMetric).value, value); + expect(metricsCaptured.first.unit, unit); + expect(metricsCaptured.first.tags, tags); + }); + + test('gauge', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(type: MetricType.gauge); + + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.first, isA()); + expect(metricsCaptured.first.type, MetricType.gauge); + }); + + test('distribution', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(type: MetricType.distribution); + + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.first, isA()); + expect(metricsCaptured.first.type, MetricType.distribution); + }); + + test('set', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(type: MetricType.set); + + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.first, isA()); + expect(metricsCaptured.first.type, MetricType.set); + }); + }); + + group('span local aggregation', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('emit calls add', () async { + final MetricsAggregator sut = fixture.getSut(hub: fixture.hub); + final t = fixture.hub.startTransaction('test', 'op', bindToScope: true); + + var spanSummary = t.localMetricsAggregator?.getSummaries().values; + expect(spanSummary, isEmpty); + + sut.testEmit(); + + spanSummary = t.localMetricsAggregator?.getSummaries().values; + expect(spanSummary, isNotEmpty); + }); + + test('emit counter', () async { + final MetricsAggregator sut = fixture.getSut(hub: fixture.hub); + final t = fixture.hub.startTransaction('test', 'op', bindToScope: true); + + sut.testEmit(type: MetricType.counter, value: 1); + sut.testEmit(type: MetricType.counter, value: 4); + + final spanSummary = t.localMetricsAggregator?.getSummaries().values.first; + expect(spanSummary!.length, 1); + expect(spanSummary.first.sum, 5); + expect(spanSummary.first.min, 1); + expect(spanSummary.first.max, 4); + expect(spanSummary.first.count, 2); + expect(spanSummary.first.tags, mockTags); + }); + + test('emit distribution', () async { + final MetricsAggregator sut = fixture.getSut(hub: fixture.hub); + final t = fixture.hub.startTransaction('test', 'op', bindToScope: true); + + sut.testEmit(type: MetricType.distribution, value: 1); + sut.testEmit(type: MetricType.distribution, value: 4); + + final spanSummary = t.localMetricsAggregator?.getSummaries().values.first; + expect(spanSummary!.length, 1); + expect(spanSummary.first.sum, 5); + expect(spanSummary.first.min, 1); + expect(spanSummary.first.max, 4); + expect(spanSummary.first.count, 2); + expect(spanSummary.first.tags, mockTags); + }); + + test('emit gauge', () async { + final MetricsAggregator sut = fixture.getSut(hub: fixture.hub); + final t = fixture.hub.startTransaction('test', 'op', bindToScope: true); + + sut.testEmit(type: MetricType.gauge, value: 1); + sut.testEmit(type: MetricType.gauge, value: 4); + + final spanSummary = t.localMetricsAggregator?.getSummaries().values.first; + expect(spanSummary!.length, 1); + expect(spanSummary.first.sum, 5); + expect(spanSummary.first.min, 1); + expect(spanSummary.first.max, 4); + expect(spanSummary.first.count, 2); + expect(spanSummary.first.tags, mockTags); + }); + + test('emit set', () async { + final MetricsAggregator sut = fixture.getSut(hub: fixture.hub); + final t = fixture.hub.startTransaction('test', 'op', bindToScope: true); + + sut.testEmit(type: MetricType.set, value: 1); + sut.testEmit(type: MetricType.set, value: 4); + + final spanSummary = t.localMetricsAggregator?.getSummaries().values.first; + expect(spanSummary!.length, 1); + expect(spanSummary.first.sum, 2); + expect(spanSummary.first.min, 1); + expect(spanSummary.first.max, 1); + expect(spanSummary.first.count, 2); + expect(spanSummary.first.tags, mockTags); + }); + }); + + group('emit in same time bucket', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('same metric with different keys emit different metrics', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(key: mockKey); + sut.testEmit(key: mockKey2); + + final timeBuckets = sut.buckets; + final bucket = timeBuckets.values.first; + + expect(bucket.length, 2); + expect(bucket.values.firstWhere((e) => e.key == mockKey), isNotNull); + expect(bucket.values.firstWhere((e) => e.key == mockKey2), isNotNull); + }); + + test('same metric with different units emit different metrics', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(unit: mockUnit); + sut.testEmit(unit: mockUnit2); + + final timeBuckets = sut.buckets; + final bucket = timeBuckets.values.first; + + expect(bucket.length, 2); + expect(bucket.values.firstWhere((e) => e.unit == mockUnit), isNotNull); + expect(bucket.values.firstWhere((e) => e.unit == mockUnit2), isNotNull); + }); + + test('same metric with different tags emit different metrics', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(tags: mockTags); + sut.testEmit(tags: mockTags2); + + final timeBuckets = sut.buckets; + final bucket = timeBuckets.values.first; + + expect(bucket.length, 2); + expect(bucket.values.firstWhere((e) => e.tags == mockTags), isNotNull); + expect(bucket.values.firstWhere((e) => e.tags == mockTags2), isNotNull); + }); + + test('increment same metric emit only one counter', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(type: MetricType.counter, value: 1); + sut.testEmit(type: MetricType.counter, value: 2); + + final timeBuckets = sut.buckets; + final bucket = timeBuckets.values.first; + + expect(bucket.length, 1); + expect((bucket.values.first as CounterMetric).value, 3); + }); + }); + + group('time buckets', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('same metric in < 10 seconds interval emit only one metric', () async { + final MetricsAggregator sut = fixture.getSut(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(0); + sut.testEmit(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(9999); + sut.testEmit(); + + final timeBuckets = sut.buckets; + expect(timeBuckets.length, 1); + }); + + test('same metric in >= 10 seconds interval emit two metrics', () async { + final MetricsAggregator sut = fixture.getSut(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(0); + sut.testEmit(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10000); + sut.testEmit(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(20000); + sut.testEmit(); + + final timeBuckets = sut.buckets; + expect(timeBuckets.length, 3); + }); + }); + + group('flush metrics', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('emitting a metric schedules flushing', () async { + final MetricsAggregator sut = fixture.getSut(); + + expect(sut.flushCompleter, isNull); + sut.testEmit(); + expect(sut.flushCompleter, isNotNull); + }); + + test('flush calls hub captureMetrics', () async { + final MetricsAggregator sut = fixture.getSut(); + + // emit a metric + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(0); + sut.testEmit(); + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + + // mock clock to allow metric time aggregation + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10000); + // wait for flush + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isNotEmpty); + + Map> capturedMetrics = + fixture.mockHub.captureMetricsCalls.first.metricsBuckets; + Metric capturedMetric = capturedMetrics.values.first.first; + expect(capturedMetric.key, mockKey); + }); + + test('flush don\'t schedules flushing if no other metrics', () async { + final MetricsAggregator sut = fixture.getSut(); + + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(0); + sut.testEmit(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10000); + expect(sut.flushCompleter, isNotNull); + await sut.flushCompleter!.future; + expect(sut.flushCompleter, isNull); + }); + + test('flush schedules flushing if there are other metrics', () async { + final MetricsAggregator sut = fixture.getSut(); + + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(0); + sut.testEmit(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10000); + sut.testEmit(); + expect(sut.flushCompleter, isNotNull); + await sut.flushCompleter!.future; + // we expect the aggregator flushed metrics and schedules flushing again + expect(fixture.mockHub.captureMetricsCalls, isNotEmpty); + expect(sut.flushCompleter, isNotNull); + }); + + test('flush schedules flushing if no metric was captured', () async { + final MetricsAggregator sut = + fixture.getSut(flushInterval: Duration(milliseconds: 100)); + + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10000); + sut.testEmit(); + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10050); + + expect(sut.flushCompleter, isNotNull); + await sut.flushCompleter!.future; + // we expect the aggregator didn't flush anything and schedules flushing + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + expect(sut.flushCompleter, isNotNull); + }); + + test('flush ignores last 10 seconds', () async { + final MetricsAggregator sut = fixture.getSut(); + + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10000); + sut.testEmit(); + + // The 10 second bucket is not finished, so it shouldn't capture anything + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(19999); + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + + // The 10 second bucket finished, so it should capture metrics + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(20000); + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isNotEmpty); + }); + + test('flush ignores last flushShiftMs milliseconds', () async { + final MetricsAggregator sut = fixture.getSut(flushShiftMs: 4000); + + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(10000); + sut.testEmit(); + + // The 10 second bucket is not finished, so it shouldn't capture anything + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(19999); + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + + // The 10 second bucket finished, but flushShiftMs didn't pass, so it shouldn't capture anything + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(23999); + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + + // The 10 second bucket finished and flushShiftMs passed, so it should capture metrics + fixture.options.clock = () => DateTime.fromMillisecondsSinceEpoch(24000); + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isNotEmpty); + }); + + test('close flushes everything', () async { + final MetricsAggregator sut = fixture.getSut(); + sut.testEmit(); + sut.testEmit(type: MetricType.gauge); + // We have some metrics, but we don't flush them, yet + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + + // Closing the aggregator. Flush everything + sut.close(); + expect(fixture.mockHub.captureMetricsCalls, isNotEmpty); + expect(sut.buckets, isEmpty); + }); + }); + + group('beforeMetric', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('emits if not set', () async { + final MetricsAggregator sut = fixture.getSut(maxWeight: 4); + sut.testEmit(key: 'key1'); + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.length, 1); + expect(metricsCaptured.first.key, 'key1'); + }); + + test('drops if it return false', () async { + final MetricsAggregator sut = fixture.getSut(maxWeight: 4); + fixture.options.beforeMetricCallback = (key, {tags}) => key != 'key2'; + sut.testEmit(key: 'key1'); + sut.testEmit(key: 'key2'); + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.length, 1); + expect(metricsCaptured.first.key, 'key1'); + }); + + test('emits if it return true', () async { + final MetricsAggregator sut = fixture.getSut(maxWeight: 4); + fixture.options.beforeMetricCallback = (key, {tags}) => true; + sut.testEmit(key: 'key1'); + sut.testEmit(key: 'key2'); + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.length, 2); + expect(metricsCaptured.first.key, 'key1'); + expect(metricsCaptured.last.key, 'key2'); + }); + + test('emits if it throws', () async { + final MetricsAggregator sut = fixture.getSut(maxWeight: 4); + fixture.options.beforeMetricCallback = (key, {tags}) => throw Exception(); + sut.testEmit(key: 'key1'); + sut.testEmit(key: 'key2'); + final metricsCaptured = sut.buckets.values.first.values; + expect(metricsCaptured.length, 2); + expect(metricsCaptured.first.key, 'key1'); + expect(metricsCaptured.last.key, 'key2'); + }); + }); + + group('overweight', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('flush if exceeds maxWeight', () async { + final MetricsAggregator sut = fixture.getSut(maxWeight: 4); + sut.testEmit(type: MetricType.counter, key: 'key1'); + sut.testEmit(type: MetricType.counter, key: 'key2'); + sut.testEmit(type: MetricType.counter, key: 'key3'); + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + // After the 4th metric is emitted, the aggregator flushes immediately + sut.testEmit(type: MetricType.counter, key: 'key4'); + expect(fixture.mockHub.captureMetricsCalls, isNotEmpty); + }); + + test('does not flush if not exceeds maxWeight', () async { + final MetricsAggregator sut = fixture.getSut(maxWeight: 2); + // We are emitting the same metric, so no weight is added + sut.testEmit(type: MetricType.counter); + sut.testEmit(type: MetricType.counter); + sut.testEmit(type: MetricType.counter); + sut.testEmit(type: MetricType.counter); + await sut.flushCompleter!.future; + expect(fixture.mockHub.captureMetricsCalls, isEmpty); + }); + }); +} + +const String mockKey = 'metric key'; +const String mockKey2 = 'metric key 2'; +const double mockValue = 5; +const SentryMeasurementUnit mockUnit = DurationSentryMeasurementUnit.minute; +const SentryMeasurementUnit mockUnit2 = DurationSentryMeasurementUnit.second; +const Map mockTags = {'tag1': 'val1', 'tag2': 'val2'}; +const Map mockTags2 = {'tag1': 'val1'}; +final DateTime mockTimestamp = DateTime.fromMillisecondsSinceEpoch(1); + +class Fixture { + final options = SentryOptions(dsn: fakeDsn); + final mockHub = MockHub(); + late final hub = Hub(options); + + Fixture() { + options.tracesSampleRate = 1; + options.enableMetrics = true; + options.enableSpanLocalMetricAggregation = true; + } + + MetricsAggregator getSut({ + Hub? hub, + Duration flushInterval = const Duration(milliseconds: 1), + int flushShiftMs = 0, + int maxWeight = 100000, + }) { + return MetricsAggregator( + hub: hub ?? mockHub, + options: options, + flushInterval: flushInterval, + flushShiftMs: flushShiftMs, + maxWeight: maxWeight); + } +} + +extension _MetricsAggregatorUtils on MetricsAggregator { + testEmit({ + MetricType type = MetricType.counter, + String key = mockKey, + double value = mockValue, + SentryMeasurementUnit unit = mockUnit, + Map tags = mockTags, + }) { + emit(type, key, value, unit, tags); + } +} diff --git a/dart/test/metrics/metrics_api_test.dart b/dart/test/metrics/metrics_api_test.dart new file mode 100644 index 0000000000..8c53e66772 --- /dev/null +++ b/dart/test/metrics/metrics_api_test.dart @@ -0,0 +1,152 @@ +import 'dart:async'; + +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/metrics/metric.dart'; +import 'package:sentry/src/metrics/metrics_api.dart'; +import 'package:sentry/src/sentry_tracer.dart'; +import 'package:test/test.dart'; + +import '../mocks.dart'; +import '../mocks/mock_hub.dart'; + +void main() { + group('api', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('counter', () async { + MetricsApi api = fixture.getSut(); + api.increment('key'); + api.increment('key', value: 2.4); + + Iterable sentMetrics = + fixture.mockHub.metricsAggregator!.buckets.values.first.values; + expect(sentMetrics.first.type, MetricType.counter); + expect((sentMetrics.first as CounterMetric).value, 3.4); + }); + + test('gauge', () async { + MetricsApi api = fixture.getSut(); + api.gauge('key', value: 1.5); + api.gauge('key', value: 2.4); + + Iterable sentMetrics = + fixture.mockHub.metricsAggregator!.buckets.values.first.values; + expect(sentMetrics.first.type, MetricType.gauge); + expect((sentMetrics.first as GaugeMetric).minimum, 1.5); + expect((sentMetrics.first as GaugeMetric).maximum, 2.4); + expect((sentMetrics.first as GaugeMetric).last, 2.4); + expect((sentMetrics.first as GaugeMetric).sum, 3.9); + expect((sentMetrics.first as GaugeMetric).count, 2); + }); + + test('distribution', () async { + MetricsApi api = fixture.getSut(); + api.distribution('key', value: 1.5); + api.distribution('key', value: 2.4); + + Iterable sentMetrics = + fixture.mockHub.metricsAggregator!.buckets.values.first.values; + expect(sentMetrics.first.type, MetricType.distribution); + expect((sentMetrics.first as DistributionMetric).values, [1.5, 2.4]); + }); + + test('set', () async { + MetricsApi api = fixture.getSut(); + api.set('key', value: 1); + api.set('key', value: 2); + // This is ignored as it's a repeated value + api.set('key', value: 2); + // This adds both an int and a crc32 of the string to the metric + api.set('key', value: 4, stringValue: 'value'); + // No value provided. This does nothing + api.set('key'); + // Empty String provided. This does nothing + api.set('key', stringValue: ''); + + Iterable sentMetrics = + fixture.mockHub.metricsAggregator!.buckets.values.first.values; + expect(sentMetrics.first.type, MetricType.set); + expect((sentMetrics.first as SetMetric).values, {1, 2, 4, 494360628}); + }); + + test('timing emits distribution', () async { + final delay = Duration(milliseconds: 100); + final completer = Completer(); + MetricsApi api = fixture.getSut(); + + // The timing API tries to start a child span + expect(fixture.mockHub.getSpanCalls, 0); + api.timing('key', + function: () => Future.delayed(delay, () => completer.complete())); + expect(fixture.mockHub.getSpanCalls, 1); + + await completer.future; + Iterable sentMetrics = + fixture.mockHub.metricsAggregator!.buckets.values.first.values; + + // The timing API emits a distribution metric + expect(sentMetrics.first.type, MetricType.distribution); + // The default unit is second + expect(sentMetrics.first.unit, DurationSentryMeasurementUnit.second); + // It awaits for the function completion, which means 100 milliseconds in + // this case. Since the unit is second, its value (duration) is >= 0.1 + expect( + (sentMetrics.first as DistributionMetric).values.first >= 0.1, true); + }); + + test('timing starts a span', () async { + final delay = Duration(milliseconds: 100); + final completer = Completer(); + fixture._options.tracesSampleRate = 1; + fixture._options.enableMetrics = true; + MetricsApi api = fixture.getSut(hub: fixture.hub); + + // Start a transaction so that timing api can start a child span + final transaction = fixture.hub.startTransaction( + 'name', + 'operation', + bindToScope: true, + ) as SentryTracer; + expect(transaction.children, isEmpty); + + // Timing starts a span + api.timing('my key', + unit: DurationSentryMeasurementUnit.milliSecond, + function: () => Future.delayed(delay, () => completer.complete())); + final span = transaction.children.first; + expect(span.finished, false); + expect(span.context.operation, 'metric.timing'); + expect(span.context.description, 'my key'); + + // Timing finishes the span when the function is finished, which takes 100 milliseconds + await completer.future; + expect(span.finished, true); + final spanDuration = span.endTimestamp!.difference(span.startTimestamp); + expect(spanDuration.inMilliseconds >= 100, true); + await Future.delayed(Duration()); + + Iterable sentMetrics = + fixture.hub.metricsAggregator!.buckets.values.first.values; + + // The emitted metric value should be aggregated in the span + expect(span.localMetricsAggregator?.getSummaries(), isNotEmpty); + // The emitted metric value should match the span duration + expect(sentMetrics.first.unit, DurationSentryMeasurementUnit.milliSecond); + // Duration.inMilliseconds returns an int, so we have to assert it + expect((sentMetrics.first as DistributionMetric).values.first.toInt(), + spanDuration.inMilliseconds); + }); + }); +} + +class Fixture { + final _options = SentryOptions(dsn: fakeDsn); + final mockHub = MockHub(); + late final hub = Hub(_options); + + MetricsApi getSut({Hub? hub}) => MetricsApi(hub: hub ?? mockHub); +} diff --git a/dart/test/mocks.dart b/dart/test/mocks.dart index b5fdd59aa9..7c960c8a07 100644 --- a/dart/test/mocks.dart +++ b/dart/test/mocks.dart @@ -1,5 +1,6 @@ import 'package:mockito/annotations.dart'; import 'package:sentry/sentry.dart'; +import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/profiling.dart'; import 'package:sentry/src/transport/rate_limiter.dart'; @@ -97,10 +98,41 @@ final fakeEvent = SentryEvent( ), ); +final fakeMetric = Metric.fromType( + type: MetricType.counter, + value: 4, + key: 'key', + unit: DurationSentryMeasurementUnit.hour, + tags: {'tag1': 'value1', 'tag2': 'value2'}); +final fakeMetric2 = Metric.fromType( + type: MetricType.counter, + value: 2, + key: 'key', + unit: SentryMeasurementUnit.none, + tags: {'tag1': 'value1', 'tag2': 'value2'}); +final fakeMetric3 = Metric.fromType( + type: MetricType.counter, + value: 2, + key: 'key', + unit: SentryMeasurementUnit.none, + tags: {'tag1': 'value1'}); +final fakeMetric4 = Metric.fromType( + type: MetricType.counter, + value: 2, + key: 'key2', + unit: SentryMeasurementUnit.none, + tags: {'tag1': 'value1'}); + +final Map> fakeMetrics = { + 10: [fakeMetric], + 20: [fakeMetric, fakeMetric2], + 30: [fakeMetric, fakeMetric3, fakeMetric4], +}; + /// Always returns null and thus drops all events class DropAllEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return null; } } @@ -111,13 +143,13 @@ class FunctionEventProcessor implements EventProcessor { final EventProcessorFunction applyFunction; @override - SentryEvent? apply(SentryEvent event, {hint}) { - return applyFunction(event, hint: hint); + SentryEvent? apply(SentryEvent event, Hint hint) { + return applyFunction(event, hint); } } -typedef EventProcessorFunction = SentryEvent? Function(SentryEvent event, - {Hint? hint}); +typedef EventProcessorFunction = SentryEvent? Function( + SentryEvent event, Hint hint); var fakeEnvelope = SentryEnvelope.fromEvent( fakeEvent, diff --git a/dart/test/mocks/mock_hub.dart b/dart/test/mocks/mock_hub.dart index 351ad70672..c076251736 100644 --- a/dart/test/mocks/mock_hub.dart +++ b/dart/test/mocks/mock_hub.dart @@ -1,5 +1,7 @@ import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; +import 'package:sentry/src/metrics/metric.dart'; +import 'package:sentry/src/metrics/metrics_aggregator.dart'; import '../mocks.dart'; import 'mock_sentry_client.dart'; @@ -13,17 +15,23 @@ class MockHub with NoSuchMethodProvider implements Hub { List bindClientCalls = []; List userFeedbackCalls = []; List captureTransactionCalls = []; + List captureMetricsCalls = []; int closeCalls = 0; bool _isEnabled = true; int spanContextCals = 0; int getSpanCalls = 0; final _options = SentryOptions(dsn: fakeDsn); + late final MetricsAggregator _metricsAggregator = + MetricsAggregator(options: _options, hub: this); @override @internal SentryOptions get options => _options; + @override + MetricsAggregator? get metricsAggregator => _metricsAggregator; + /// Useful for tests. void reset() { captureEventCalls = []; @@ -35,6 +43,7 @@ class MockHub with NoSuchMethodProvider implements Hub { _isEnabled = true; spanContextCals = 0; captureTransactionCalls = []; + captureMetricsCalls = []; getSpanCalls = 0; } @@ -116,6 +125,13 @@ class MockHub with NoSuchMethodProvider implements Hub { return transaction.eventId; } + @override + Future captureMetrics( + Map> metricsBuckets) async { + captureMetricsCalls.add(CaptureMetricsCall(metricsBuckets)); + return SentryId.newId(); + } + @override Future captureUserFeedback(SentryUserFeedback userFeedback) async { userFeedbackCalls.add(userFeedback); diff --git a/dart/test/mocks/mock_sentry_client.dart b/dart/test/mocks/mock_sentry_client.dart index 7b08250193..248ea19032 100644 --- a/dart/test/mocks/mock_sentry_client.dart +++ b/dart/test/mocks/mock_sentry_client.dart @@ -1,4 +1,5 @@ import 'package:sentry/sentry.dart'; +import 'package:sentry/src/metrics/metric.dart'; import 'no_such_method_provider.dart'; @@ -9,6 +10,7 @@ class MockSentryClient with NoSuchMethodProvider implements SentryClient { List captureEnvelopeCalls = []; List captureTransactionCalls = []; List userFeedbackCalls = []; + List>> captureMetricsCalls = []; int closeCalls = 0; @override @@ -74,6 +76,12 @@ class MockSentryClient with NoSuchMethodProvider implements SentryClient { userFeedbackCalls.add(userFeedback); } + @override + Future captureMetrics(Map> metrics) async { + captureMetricsCalls.add(metrics); + return SentryId.newId(); + } + @override void close() { closeCalls = closeCalls + 1; @@ -149,3 +157,9 @@ class CaptureTransactionCall { CaptureTransactionCall(this.transaction, this.traceContext); } + +class CaptureMetricsCall { + final Map> metricsBuckets; + + CaptureMetricsCall(this.metricsBuckets); +} diff --git a/dart/test/mocks/mock_transport.dart b/dart/test/mocks/mock_transport.dart index 0ce6c9d896..fad9f43696 100644 --- a/dart/test/mocks/mock_transport.dart +++ b/dart/test/mocks/mock_transport.dart @@ -6,6 +6,7 @@ import 'package:test/expect.dart'; class MockTransport implements Transport { List envelopes = []; List events = []; + List statsdItems = []; int _calls = 0; String _exceptions = ''; @@ -27,8 +28,7 @@ class MockTransport implements Transport { // failure causes. Instead, we log them and check on access to [calls]. try { envelopes.add(envelope); - final event = await _eventFromEnvelope(envelope); - events.add(event); + await _eventFromEnvelope(envelope); } catch (e, stack) { _exceptions += '$e\n$stack\n\n'; rethrow; @@ -37,13 +37,18 @@ class MockTransport implements Transport { return envelope.header.eventId ?? SentryId.empty(); } - Future _eventFromEnvelope(SentryEnvelope envelope) async { + Future _eventFromEnvelope(SentryEnvelope envelope) async { final envelopeItemData = []; + final RegExp statSdRegex = RegExp('^(?!{).+@.+:.+\\|.+', multiLine: true); envelopeItemData.addAll(await envelope.items.first.envelopeItemStream()); final envelopeItem = utf8.decode(envelopeItemData).split('\n').last; - final envelopeItemJson = jsonDecode(envelopeItem) as Map; - return SentryEvent.fromJson(envelopeItemJson); + if (statSdRegex.hasMatch(envelopeItem)) { + statsdItems.add(envelopeItem); + } else { + final envelopeItemJson = jsonDecode(envelopeItem) as Map; + events.add(SentryEvent.fromJson(envelopeItemJson)); + } } void reset() { diff --git a/dart/test/protocol/mechanism_test.dart b/dart/test/protocol/mechanism_test.dart index 4b484d2ca3..857a0529a9 100644 --- a/dart/test/protocol/mechanism_test.dart +++ b/dart/test/protocol/mechanism_test.dart @@ -11,6 +11,10 @@ void main() { synthetic: true, meta: {'key': 'value'}, data: {'keyb': 'valueb'}, + isExceptionGroup: false, + exceptionId: 0, + parentId: 0, + source: 'source', ); final mechanismJson = { @@ -21,6 +25,10 @@ void main() { 'meta': {'key': 'value'}, 'data': {'keyb': 'valueb'}, 'synthetic': true, + 'is_exception_group': false, + 'source': 'source', + 'exception_id': 0, + 'parent_id': 0, }; group('json', () { @@ -51,6 +59,7 @@ void main() { expect(data.toJson(), copy.toJson()); }); + test('copyWith takes new values', () { final data = mechanism; @@ -62,6 +71,10 @@ void main() { synthetic: false, meta: {'key1': 'value1'}, data: {'keyb1': 'valueb1'}, + exceptionId: 1, + parentId: 1, + isExceptionGroup: false, + source: 'foo', ); expect('type1', copy.type); @@ -71,6 +84,10 @@ void main() { expect(false, copy.synthetic); expect({'key1': 'value1'}, copy.meta); expect({'keyb1': 'valueb1'}, copy.data); + expect(1, copy.exceptionId); + expect(1, copy.parentId); + expect(false, copy.isExceptionGroup); + expect('foo', copy.source); }); }); } diff --git a/dart/test/protocol/rate_limit_parser_test.dart b/dart/test/protocol/rate_limit_parser_test.dart index c898915e04..567dec34f0 100644 --- a/dart/test/protocol/rate_limit_parser_test.dart +++ b/dart/test/protocol/rate_limit_parser_test.dart @@ -75,6 +75,45 @@ void main() { expect(sut[0].duration.inMilliseconds, RateLimitParser.httpRetryAfterDefaultDelay.inMilliseconds); }); + + test('do not parse namespaces if not metric_bucket', () { + final sut = + RateLimitParser('1:transaction:organization:quota_exceeded:custom') + .parseRateLimitHeader(); + + expect(sut.length, 1); + expect(sut[0].category, DataCategory.transaction); + expect(sut[0].namespaces, isEmpty); + }); + + test('parse namespaces on metric_bucket', () { + final sut = + RateLimitParser('1:metric_bucket:organization:quota_exceeded:custom') + .parseRateLimitHeader(); + + expect(sut.length, 1); + expect(sut[0].category, DataCategory.metricBucket); + expect(sut[0].namespaces, isNotEmpty); + expect(sut[0].namespaces.first, 'custom'); + }); + + test('parse empty namespaces on metric_bucket', () { + final sut = + RateLimitParser('1:metric_bucket:organization:quota_exceeded:') + .parseRateLimitHeader(); + + expect(sut.length, 1); + expect(sut[0].category, DataCategory.metricBucket); + expect(sut[0].namespaces, isEmpty); + }); + + test('parse missing namespaces on metric_bucket', () { + final sut = RateLimitParser('1:metric_bucket').parseRateLimitHeader(); + + expect(sut.length, 1); + expect(sut[0].category, DataCategory.metricBucket); + expect(sut[0].namespaces, isEmpty); + }); }); group('parseRetryAfterHeader', () { diff --git a/dart/test/protocol/rate_limiter_test.dart b/dart/test/protocol/rate_limiter_test.dart index cc931d5b66..1f52a60003 100644 --- a/dart/test/protocol/rate_limiter_test.dart +++ b/dart/test/protocol/rate_limiter_test.dart @@ -228,6 +228,118 @@ void main() { expect(fixture.mockRecorder.category, DataCategory.transaction); expect(fixture.mockRecorder.reason, DiscardReason.rateLimitBackoff); }); + + test('dropping of metrics recorded', () { + final rateLimiter = fixture.getSut(); + + final metricsItem = SentryEnvelopeItem.fromMetrics({}); + final eventEnvelope = SentryEnvelope( + SentryEnvelopeHeader.newEventId(), + [metricsItem], + ); + + rateLimiter.updateRetryAfterLimits( + '1:metric_bucket:key, 5:metric_bucket:organization', null, 1); + + final result = rateLimiter.filter(eventEnvelope); + expect(result, isNull); + + expect(fixture.mockRecorder.category, DataCategory.metricBucket); + expect(fixture.mockRecorder.reason, DiscardReason.rateLimitBackoff); + }); + + group('apply rateLimit', () { + test('error', () { + final rateLimiter = fixture.getSut(); + fixture.dateTimeToReturn = 0; + + final eventItem = SentryEnvelopeItem.fromEvent(SentryEvent()); + final envelope = SentryEnvelope( + SentryEnvelopeHeader.newEventId(), + [eventItem], + ); + + rateLimiter.updateRetryAfterLimits( + '1:error:key, 5:error:organization', null, 1); + + expect(rateLimiter.filter(envelope), isNull); + }); + + test('transaction', () { + final rateLimiter = fixture.getSut(); + fixture.dateTimeToReturn = 0; + + final transaction = fixture.getTransaction(); + final eventItem = SentryEnvelopeItem.fromTransaction(transaction); + final envelope = SentryEnvelope( + SentryEnvelopeHeader.newEventId(), + [eventItem], + ); + + rateLimiter.updateRetryAfterLimits( + '1:transaction:key, 5:transaction:organization', null, 1); + + final result = rateLimiter.filter(envelope); + expect(result, isNull); + }); + + test('metrics', () { + final rateLimiter = fixture.getSut(); + fixture.dateTimeToReturn = 0; + + final metricsItem = SentryEnvelopeItem.fromMetrics({}); + final envelope = SentryEnvelope( + SentryEnvelopeHeader.newEventId(), + [metricsItem], + ); + + rateLimiter.updateRetryAfterLimits( + '1:metric_bucket:key, 5:metric_bucket:organization', null, 1); + + final result = rateLimiter.filter(envelope); + expect(result, isNull); + }); + + test('metrics with empty namespaces', () { + final rateLimiter = fixture.getSut(); + fixture.dateTimeToReturn = 0; + + final eventItem = SentryEnvelopeItem.fromEvent(SentryEvent()); + final metricsItem = SentryEnvelopeItem.fromMetrics({}); + final envelope = SentryEnvelope( + SentryEnvelopeHeader.newEventId(), + [eventItem, metricsItem], + ); + + rateLimiter.updateRetryAfterLimits( + '10:metric_bucket:key:quota_exceeded:', null, 1); + + final result = rateLimiter.filter(envelope); + expect(result, isNotNull); + expect(result!.items.length, 1); + expect(result.items.first.header.type, 'event'); + }); + + test('metrics with custom namespace', () { + final rateLimiter = fixture.getSut(); + fixture.dateTimeToReturn = 0; + + final eventItem = SentryEnvelopeItem.fromEvent(SentryEvent()); + final metricsItem = SentryEnvelopeItem.fromMetrics({}); + final envelope = SentryEnvelope( + SentryEnvelopeHeader.newEventId(), + [eventItem, metricsItem], + ); + + rateLimiter.updateRetryAfterLimits( + '10:metric_bucket:key:quota_exceeded:custom', null, 1); + + final result = rateLimiter.filter(envelope); + expect(result, isNotNull); + expect(result!.items.length, 1); + expect(result.items.first.header.type, 'event'); + }); + }); } class Fixture { diff --git a/dart/test/protocol/sentry_app_test.dart b/dart/test/protocol/sentry_app_test.dart index 6fd4236efc..0fdef8a780 100644 --- a/dart/test/protocol/sentry_app_test.dart +++ b/dart/test/protocol/sentry_app_test.dart @@ -15,6 +15,7 @@ void main() { deviceAppHash: 'fixture-deviceAppHash', inForeground: true, viewNames: ['fixture-viewName', 'fixture-viewName2'], + textScale: 2.0, ); final sentryAppJson = { @@ -27,6 +28,7 @@ void main() { 'device_app_hash': 'fixture-deviceAppHash', 'in_foreground': true, 'view_names': ['fixture-viewName', 'fixture-viewName2'], + 'text_scale': 2.0, }; group('json', () { @@ -42,6 +44,7 @@ void main() { expect(json['device_app_hash'], 'fixture-deviceAppHash'); expect(json['in_foreground'], true); expect(json['view_names'], ['fixture-viewName', 'fixture-viewName2']); + expect(json['text_scale'], 2.0); }); test('fromJson', () { final sentryApp = SentryApp.fromJson(sentryAppJson); @@ -56,6 +59,7 @@ void main() { expect(json['device_app_hash'], 'fixture-deviceAppHash'); expect(json['in_foreground'], true); expect(json['view_names'], ['fixture-viewName', 'fixture-viewName2']); + expect(json['text_scale'], 2.0); }); }); @@ -86,6 +90,7 @@ void main() { deviceAppHash: 'hash1', inForeground: true, viewNames: ['screen1'], + textScale: 3.0, ); expect('name1', copy.name); @@ -97,6 +102,7 @@ void main() { expect('hash1', copy.deviceAppHash); expect(true, copy.inForeground); expect(['screen1'], copy.viewNames); + expect(3.0, copy.textScale); }); }); } diff --git a/dart/test/run_zoned_guarded_integration_test.dart b/dart/test/run_zoned_guarded_integration_test.dart index 7e8045445d..dd3c2aa0f3 100644 --- a/dart/test/run_zoned_guarded_integration_test.dart +++ b/dart/test/run_zoned_guarded_integration_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library dart_test; import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; @@ -54,6 +55,23 @@ void main() { expect(onErrorCalled, true); }); + + test('sets level to error instead of fatal', () async { + final exception = StateError('error'); + final stackTrace = StackTrace.current; + + final hub = Hub(fixture.options); + final client = MockSentryClient(); + hub.bindClient(client); + + final sut = fixture.getSut(runner: () async {}); + + fixture.options.markAutomaticallyCollectedErrorsAsFatal = false; + await sut.captureError(hub, fixture.options, exception, stackTrace); + + final capturedEvent = client.captureEventCalls.last.event; + expect(capturedEvent.level, SentryLevel.error); + }); }); } diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart index 6f21e5e63c..66cc543b6b 100644 --- a/dart/test/scope_test.dart +++ b/dart/test/scope_test.dart @@ -98,6 +98,26 @@ void main() { expect(sut.breadcrumbs.last, breadcrumb); }); + test('beforeBreadcrumb called with user provided hint', () { + Hint? actual; + BeforeBreadcrumbCallback bb = (_, hint) { + actual = hint; + return null; + }; + final sut = fixture.getSut( + beforeBreadcrumbCallback: bb, + ); + + final breadcrumb = Breadcrumb( + message: 'test log', + timestamp: DateTime.utc(2019), + ); + final hint = Hint.withMap({'user-name': 'joe dirt'}); + sut.addBreadcrumb(breadcrumb, hint: hint); + + expect(actual?.get('user-name'), 'joe dirt'); + }); + test('Executes and drops $Breadcrumb', () { final sut = fixture.getSut( beforeBreadcrumbCallback: fixture.beforeBreadcrumbCallback, @@ -412,7 +432,7 @@ void main() { await scope.setContexts('theme', 'material'); await scope.setUser(scopeUser); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.user, scopeUser); expect(updatedEvent?.transaction, '/example/app'); @@ -433,7 +453,7 @@ void main() { final scope = Scope(SentryOptions(dsn: fakeDsn)) ..span = fixture.sentryTracer; - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.contexts['trace'] is SentryTraceContext, true); }); @@ -456,7 +476,7 @@ void main() { await scope.addBreadcrumb(breadcrumb); await scope.setUser(scopeUser); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.user, isNotNull); expect(updatedEvent?.user?.id, eventUser.id); @@ -504,7 +524,7 @@ void main() { SentryOperatingSystem(name: 'context-os'), ); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.contexts[SentryDevice.type].name, 'event-device'); expect(updatedEvent?.contexts[SentryApp.type].name, 'event-app'); @@ -534,7 +554,7 @@ void main() { await scope.setContexts('location', {'city': 'London'}); await scope.setContexts('items', [1, 2, 3]); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.contexts[SentryDevice.type].name, 'context-device'); expect(updatedEvent?.contexts[SentryApp.type].name, 'context-app'); @@ -559,7 +579,7 @@ void main() { final scope = Scope(SentryOptions(dsn: fakeDsn)) ..level = SentryLevel.error; - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.level, SentryLevel.error); }); @@ -569,7 +589,7 @@ void main() { final scope = Scope(SentryOptions(dsn: fakeDsn)) ..span = fixture.sentryTracer; - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.transaction, 'name'); }); @@ -581,7 +601,7 @@ void main() { sut.addEventProcessor(fixture.processor); final event = SentryEvent(); - var newEvent = await sut.applyToEvent(event); + var newEvent = await sut.applyToEvent(event, Hint()); expect(newEvent, isNull); }); @@ -590,7 +610,7 @@ void main() { var tr = SentryTransaction(fixture.sentryTracer); final scope = Scope(SentryOptions(dsn: fakeDsn))..fingerprint = ['test']; - final updatedTr = await scope.applyToEvent(tr); + final updatedTr = await scope.applyToEvent(tr, Hint()); expect(updatedTr?.fingerprint, isNull); }); @@ -599,7 +619,7 @@ void main() { var tr = SentryTransaction(fixture.sentryTracer); final scope = Scope(SentryOptions(dsn: fakeDsn))..level = SentryLevel.error; - final updatedTr = await scope.applyToEvent(tr); + final updatedTr = await scope.applyToEvent(tr, Hint()); expect(updatedTr?.level, isNull); }); @@ -608,7 +628,7 @@ void main() { var tr = SentryTransaction(fixture.sentryTracer); final scope = Scope(SentryOptions(dsn: fakeDsn))..level = SentryLevel.error; - final updatedTr = await scope.applyToEvent(tr); + final updatedTr = await scope.applyToEvent(tr, Hint()); expect(updatedTr?.contexts.trace?.sampled, isTrue); }); @@ -625,9 +645,9 @@ void main() { final sut = fixture.getSut( scopeObserver: fixture.mockScopeObserver, beforeBreadcrumbCallback: ( - Breadcrumb? breadcrumb, { - Hint? hint, - }) { + Breadcrumb? breadcrumb, + Hint hint, + ) { return breadcrumb?.copyWith(message: "modified"); }, ); @@ -698,9 +718,9 @@ void main() { final sut = fixture.getSut( beforeBreadcrumbCallback: ( - Breadcrumb? breadcrumb, { - Hint? hint, - }) { + Breadcrumb? breadcrumb, + Hint hint, + ) { throw exception; }, debug: true); @@ -722,9 +742,9 @@ void main() { final sut = fixture.getSut( beforeBreadcrumbCallback: ( - Breadcrumb? breadcrumb, { - Hint? hint, - }) { + Breadcrumb? breadcrumb, + Hint hint, + ) { if (numberOfBeforeBreadcrumbCalls > 0) { throw exception; } @@ -785,11 +805,11 @@ class Fixture { EventProcessor get processor => DropAllEventProcessor(); - Breadcrumb? beforeBreadcrumbCallback(Breadcrumb? breadcrumb, {Hint? hint}) => + Breadcrumb? beforeBreadcrumbCallback(Breadcrumb? breadcrumb, Hint hint) => null; - Breadcrumb? beforeBreadcrumbMutateCallback(Breadcrumb? breadcrumb, - {Hint? hint}) => + Breadcrumb? beforeBreadcrumbMutateCallback( + Breadcrumb? breadcrumb, Hint hint) => breadcrumb?.copyWith(message: 'new message'); void mockLogger( @@ -810,7 +830,7 @@ class AddTagsEventProcessor implements EventProcessor { AddTagsEventProcessor(this.tags); @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return event..tags?.addAll(tags); } } diff --git a/dart/test/sentry_attachment_io_test.dart b/dart/test/sentry_attachment_io_test.dart index 2752355a2b..29a0076bfe 100644 --- a/dart/test/sentry_attachment_io_test.dart +++ b/dart/test/sentry_attachment_io_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library dart_test; import 'dart:io'; diff --git a/dart/test/sentry_browser_test.dart b/dart/test/sentry_browser_test.dart index 8524019467..eaccfa1d03 100644 --- a/dart/test/sentry_browser_test.dart +++ b/dart/test/sentry_browser_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @TestOn('browser') +library dart_test; + import 'package:test/test.dart'; import 'test_utils.dart'; diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index cdbbd73950..b8c6bee716 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -8,10 +8,13 @@ import 'package:sentry/src/client_reports/client_report.dart'; import 'package:sentry/src/client_reports/discard_reason.dart'; import 'package:sentry/src/client_reports/discarded_event.dart'; import 'package:sentry/src/client_reports/noop_client_report_recorder.dart'; +import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:sentry/src/transport/data_category.dart'; +import 'package:sentry/src/utils/iterable_utils.dart'; +import 'package:sentry/src/transport/spotlight_http_transport.dart'; import 'package:test/test.dart'; import 'mocks.dart'; @@ -371,7 +374,7 @@ void main() { expect(capturedEvent.exceptions?[1].stackTrace, isNotNull); }); - test('should not capture sentry frames exception', () async { + test('should capture sentry frames exception', () async { fixture.options.addExceptionCauseExtractor( ExceptionWithCauseExtractor(), ); @@ -391,11 +394,11 @@ void main() { final capturedEnvelope = (fixture.transport).envelopes.first; final capturedEvent = await eventFromEnvelope(capturedEnvelope); - expect( - capturedEvent.exceptions?[1].stackTrace!.frames - .every((frame) => frame.package != 'sentry'), - true, - ); + final sentryFramesCount = capturedEvent.exceptions?[1].stackTrace!.frames + .where((frame) => frame.package == 'sentry') + .length; + + expect(sentryFramesCount, 2); }); }); @@ -404,6 +407,8 @@ void main() { Error error; + dynamic exception; + final stacktrace = ''' #0 baz (file:///pathto/test.dart:50:3) @@ -435,16 +440,6 @@ void main() { capturedEvent.exceptions?.first.stackTrace!.frames.first.lineNo, 46); expect(capturedEvent.exceptions?.first.stackTrace!.frames.first.colNo, 9); }); - }); - - group('SentryClient captures exception and stacktrace', () { - late Fixture fixture; - - dynamic exception; - - setUp(() { - fixture = Fixture(); - }); test('should capture exception', () async { try { @@ -453,12 +448,6 @@ void main() { exception = err; } - final stacktrace = ''' -#0 baz (file:///pathto/test.dart:50:3) - -#1 bar (file:///pathto/test.dart:46:9) - '''; - final client = fixture.getSut(); await client.captureException(exception, stackTrace: stacktrace); @@ -505,29 +494,29 @@ void main() { expect(capturedEvent.exceptions?.first.stackTrace, isNull); }); - test('should not capture sentry frames exception', () async { + test('should capture sentry frames exception', () async { try { throw Exception('Error'); } catch (err) { exception = err; } - final stacktrace = ''' -#0 init (package:sentry/sentry.dart:46:9) -#1 bar (file:///pathto/test.dart:46:9) + final stackTrace = ''' +#0 baz (file:///pathto/test.dart:50:3) +#1 bar (file:///pathto/test.dart:46:9) #2 capture (package:sentry/sentry.dart:46:9) '''; final client = fixture.getSut(); - await client.captureException(exception, stackTrace: stacktrace); + await client.captureException(exception, stackTrace: stackTrace); final capturedEnvelope = (fixture.transport).envelopes.first; final capturedEvent = await eventFromEnvelope(capturedEnvelope); expect( capturedEvent.exceptions?.first.stackTrace!.frames - .every((frame) => frame.package != 'sentry'), + .any((frame) => frame.package == 'sentry'), true, ); }); @@ -956,25 +945,14 @@ void main() { }); }); - group('SentryClient: apply default pii', () { + group('SentryClient: sets user & user ip', () { late Fixture fixture; setUp(() { fixture = Fixture(); }); - test('sendDefaultPii is disabled', () async { - final client = fixture.getSut(sendDefaultPii: false); - - await client.captureEvent(fakeEvent); - - final capturedEnvelope = fixture.transport.envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect(capturedEvent.user?.toJson(), fakeEvent.user?.toJson()); - }); - - test('sendDefaultPii is enabled and event has no user', () async { + test('event has no user', () async { final client = fixture.getSut(sendDefaultPii: true); var fakeEvent = SentryEvent(); @@ -988,8 +966,7 @@ void main() { expect(capturedEvent.user?.ipAddress, '{{auto}}'); }); - test('sendDefaultPii is enabled and event has a user with IP address', - () async { + test('event has a user with IP address', () async { final client = fixture.getSut(sendDefaultPii: true); await client.captureEvent(fakeEvent); @@ -1005,8 +982,7 @@ void main() { expect(capturedEvent.user?.email, fakeEvent.user!.email); }); - test('sendDefaultPii is enabled and event has a user without IP address', - () async { + test('event has a user without IP address', () async { final client = fixture.getSut(sendDefaultPii: true); final event = fakeEvent.copyWith(user: fakeUser); @@ -1169,7 +1145,7 @@ void main() { test('thrown error is handled', () async { final exception = Exception("before send exception"); - final beforeSendCallback = (SentryEvent event, {Hint? hint}) { + final beforeSendCallback = (SentryEvent event, Hint hint) { throw exception; }; @@ -1189,7 +1165,7 @@ void main() { setUp(() { fixture = Fixture(); fixture.options.addEventProcessor(FunctionEventProcessor( - (event, {hint}) => event + (event, hint) => event ..tags!.addAll({'theme': 'material'}) // ignore: deprecated_member_use_from_same_package ..extra!['host'] = '0.0.0.1' @@ -1231,8 +1207,8 @@ void main() { var executed = false; - final client = fixture.getSut( - eventProcessor: FunctionEventProcessor((event, {hint}) { + final client = + fixture.getSut(eventProcessor: FunctionEventProcessor((event, hint) { expect(myHint, hint); executed = true; return event; @@ -1246,8 +1222,8 @@ void main() { test('should create hint when none was provided', () async { var executed = false; - final client = fixture.getSut( - eventProcessor: FunctionEventProcessor((event, {hint}) { + final client = + fixture.getSut(eventProcessor: FunctionEventProcessor((event, hint) { expect(hint, isNotNull); executed = true; return event; @@ -1283,201 +1259,6 @@ void main() { }); }); - group('Breadcrumbs', () { - late Fixture fixture; - - setUp(() { - fixture = Fixture(); - }); - - test('Clears breadcrumbs on Android for transaction', () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final transaction = SentryTransaction( - fixture.tracer, - breadcrumbs: [ - Breadcrumb(), - ], - ); - await client.captureTransaction(transaction); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedTransaction = - await transactionFromEnvelope(capturedEnvelope); - - expect((capturedTransaction['breadcrumbs'] ?? []).isEmpty, true); - }); - - test('Clears breadcrumbs on Android if mechanism.handled is true for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: true, - ), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isEmpty, true); - }); - - test('Clears breadcrumbs on Android if mechanism.handled is null for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism(type: 'type'), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isEmpty, true); - }); - - test('Clears breadcrumbs on Android if theres no mechanism for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isEmpty, true); - }); - - test( - 'Does not clear breadcrumbs on Android if mechanism.handled is false for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: false, - ), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true); - }); - - test( - 'Does not clear breadcrumbs on Android if any mechanism.handled is false for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: true, - ), - ), - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: false, - ), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true); - }); - - test('web breadcrumbs exist on web Android devices', () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = MockPlatformChecker( - platform: MockPlatform.android(), - isWebValue: true, - ); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: true, - ), - ), - ], breadcrumbs: [ - Breadcrumb(), - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true); - }); - }); - group('ClientReportRecorder', () { late Fixture fixture; @@ -1557,8 +1338,10 @@ void main() { await sut.captureEvent(fakeEvent, hint: hint); final capturedEnvelope = (fixture.transport).envelopes.first; - final attachmentItem = capturedEnvelope.items.firstWhereOrNull( - (element) => element.header.type == SentryItemType.attachment); + final attachmentItem = IterableUtils.firstWhereOrNull( + capturedEnvelope.items, + (SentryEnvelopeItem e) => e.header.type == SentryItemType.attachment, + ); expect(attachmentItem?.header.attachmentType, SentryAttachment.typeAttachmentDefault); }); @@ -1706,6 +1489,50 @@ void main() { expect(capturedEnvelope.header.dsn, fixture.options.dsn); }); + + test('Spotlight enabled should set transport to SpotlightHttpTransport', + () async { + fixture.options.spotlight = Spotlight(enabled: true); + fixture.getSut(); + + expect(fixture.options.transport is SpotlightHttpTransport, true); + }); + }); + + group('Capture metrics', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('metricsAggregator is set if metrics are enabled', () async { + final client = fixture.getSut(enableMetrics: true); + expect(client.metricsAggregator, isNotNull); + }); + + test('metricsAggregator is null if metrics are disabled', () async { + final client = fixture.getSut(enableMetrics: false); + expect(client.metricsAggregator, isNull); + }); + + test('captureMetrics send statsd envelope', () async { + final client = fixture.getSut(); + await client.captureMetrics(fakeMetrics); + + final capturedStatsd = (fixture.transport).statsdItems.first; + expect(capturedStatsd, isNotNull); + }); + + test('close closes metricsAggregator', () async { + final client = fixture.getSut(); + client.close(); + expect(client.metricsAggregator, isNotNull); + client.metricsAggregator! + .emit(MetricType.counter, 'key', 1, SentryMeasurementUnit.none, {}); + // metricsAggregator is closed, so no metrics should be recorded + expect(client.metricsAggregator!.buckets, isEmpty); + }); }); } @@ -1729,9 +1556,9 @@ Future> transactionFromEnvelope( } SentryEvent? beforeSendCallbackDropEvent( - SentryEvent event, { - Hint? hint, -}) => + SentryEvent event, + Hint hint, +) => null; SentryTransaction? beforeSendTransactionCallbackDropEvent( @@ -1740,9 +1567,9 @@ SentryTransaction? beforeSendTransactionCallbackDropEvent( null; Future asyncBeforeSendCallbackDropEvent( - SentryEvent event, { - Hint? hint, -}) async { + SentryEvent event, + Hint hint, +) async { await Future.delayed(Duration(milliseconds: 200)); return null; } @@ -1753,7 +1580,7 @@ Future asyncBeforeSendTransactionCallbackDropEvent( return null; } -SentryEvent? beforeSendCallback(SentryEvent event, {Hint? hint}) { +SentryEvent? beforeSendCallback(SentryEvent event, Hint hint) { return event ..tags!.addAll({'theme': 'material'}) // ignore: deprecated_member_use_from_same_package @@ -1793,6 +1620,7 @@ class Fixture { bool sendDefaultPii = false, bool attachStacktrace = true, bool attachThreads = false, + bool enableMetrics = true, double? sampleRate, BeforeSendCallback? beforeSend, BeforeSendTransactionCallback? beforeSendTransaction, @@ -1809,6 +1637,7 @@ class Fixture { options.tracesSampleRate = 1.0; options.sendDefaultPii = sendDefaultPii; + options.enableMetrics = enableMetrics; options.attachStacktrace = attachStacktrace; options.attachThreads = attachThreads; options.sampleRate = sampleRate; @@ -1829,8 +1658,7 @@ class Fixture { return client; } - Future droppingBeforeSend(SentryEvent event, - {Hint? hint}) async { + Future droppingBeforeSend(SentryEvent event, Hint hint) async { return null; } @@ -1856,6 +1684,7 @@ class Fixture { class ExceptionWithCause { ExceptionWithCause(this.cause, this.stackTrace); + final dynamic cause; final dynamic stackTrace; } @@ -1870,6 +1699,7 @@ class ExceptionWithCauseExtractor class ExceptionWithStackTrace { ExceptionWithStackTrace(this.stackTrace); + final StackTrace stackTrace; } diff --git a/dart/test/sentry_envelope_item_test.dart b/dart/test/sentry_envelope_item_test.dart index 673f679740..c5a205c945 100644 --- a/dart/test/sentry_envelope_item_test.dart +++ b/dart/test/sentry_envelope_item_test.dart @@ -4,12 +4,14 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/client_reports/client_report.dart'; import 'package:sentry/src/client_reports/discard_reason.dart'; import 'package:sentry/src/client_reports/discarded_event.dart'; +import 'package:sentry/src/metrics/metric.dart'; import 'package:sentry/src/sentry_envelope_item_header.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:sentry/src/transport/data_category.dart'; import 'package:test/test.dart'; +import 'mocks.dart'; import 'mocks/mock_hub.dart'; void main() { @@ -109,5 +111,49 @@ void main() { expect(actualLength, expectedLength); expect(actualData, expectedData); }); + + test('fromUserFeedback', () async { + final userFeedback = SentryUserFeedback( + eventId: SentryId.newId(), + name: 'name', + comments: 'comments', + email: 'email'); + final sut = SentryEnvelopeItem.fromUserFeedback(userFeedback); + + final expectedData = utf8.encode(jsonEncode( + userFeedback.toJson(), + toEncodable: jsonSerializationFallback, + )); + final actualData = await sut.dataFactory(); + + final expectedLength = expectedData.length; + final actualLength = await sut.header.length(); + + expect(sut.header.contentType, 'application/json'); + expect(sut.header.type, SentryItemType.userFeedback); + expect(actualLength, expectedLength); + expect(actualData, expectedData); + }); + + test('fromMetrics', () async { + final sut = SentryEnvelopeItem.fromMetrics(fakeMetrics); + + final StringBuffer statsd = StringBuffer(); + for (MapEntry> bucket in fakeMetrics.entries) { + final Iterable encodedMetrics = + bucket.value.map((metric) => metric.encodeToStatsd(bucket.key)); + statsd.write(encodedMetrics.join('\n')); + } + final expectedData = utf8.encode(statsd.toString()); + final actualData = await sut.dataFactory(); + + final expectedLength = expectedData.length; + final actualLength = await sut.header.length(); + + expect(sut.header.contentType, 'application/octet-stream'); + expect(sut.header.type, SentryItemType.statsd); + expect(actualLength, expectedLength); + expect(actualData, expectedData); + }); }); } diff --git a/dart/test/sentry_envelope_test.dart b/dart/test/sentry_envelope_test.dart index 375f62846e..a24cab20c7 100644 --- a/dart/test/sentry_envelope_test.dart +++ b/dart/test/sentry_envelope_test.dart @@ -130,6 +130,63 @@ void main() { expect(actualItem, expectedItem); }); + test('fromUserFeedback', () async { + final eventId = SentryId.newId(); + final userFeedback = SentryUserFeedback( + eventId: eventId, name: 'name', email: 'email', comments: 'comments'); + final sdkVersion = + SdkVersion(name: 'fixture-name', version: 'fixture-version'); + final sut = SentryEnvelope.fromUserFeedback( + userFeedback, + sdkVersion, + dsn: fakeDsn, + ); + + final expectedEnvelopeItem = + SentryEnvelopeItem.fromUserFeedback(userFeedback); + + expect(sut.header.eventId, eventId); + expect(sut.header.sdkVersion, sdkVersion); + expect(sut.header.dsn, fakeDsn); + expect(sut.items[0].header.contentType, + expectedEnvelopeItem.header.contentType); + expect(sut.items[0].header.type, expectedEnvelopeItem.header.type); + expect(await sut.items[0].header.length(), + await expectedEnvelopeItem.header.length()); + + final actualItem = await sut.items[0].envelopeItemStream(); + + final expectedItem = await expectedEnvelopeItem.envelopeItemStream(); + + expect(actualItem, expectedItem); + }); + + test('fromMetrics', () async { + final sdkVersion = + SdkVersion(name: 'fixture-name', version: 'fixture-version'); + final sut = SentryEnvelope.fromMetrics( + fakeMetrics, + sdkVersion, + dsn: fakeDsn, + ); + + final expectedEnvelopeItem = SentryEnvelopeItem.fromMetrics(fakeMetrics); + + expect(sut.header.sdkVersion, sdkVersion); + expect(sut.header.dsn, fakeDsn); + expect(sut.items[0].header.contentType, + expectedEnvelopeItem.header.contentType); + expect(sut.items[0].header.type, expectedEnvelopeItem.header.type); + expect(await sut.items[0].header.length(), + await expectedEnvelopeItem.header.length()); + + final actualItem = await sut.items[0].envelopeItemStream(); + + final expectedItem = await expectedEnvelopeItem.envelopeItemStream(); + + expect(actualItem, expectedItem); + }); + test('max attachment size', () async { final attachment = SentryAttachment.fromLoader( loader: () => Uint8List.fromList([1, 2, 3, 4]), diff --git a/dart/test/sentry_envelope_vm_test.dart b/dart/test/sentry_envelope_vm_test.dart index a000c0c4e6..7854ffccb0 100644 --- a/dart/test/sentry_envelope_vm_test.dart +++ b/dart/test/sentry_envelope_vm_test.dart @@ -1,4 +1,6 @@ @TestOn('vm') +library dart_test; + import 'dart:convert'; import 'dart:io'; diff --git a/dart/test/sentry_exception_factory_test.dart b/dart/test/sentry_exception_factory_test.dart index a70a4c8820..cca350f2b4 100644 --- a/dart/test/sentry_exception_factory_test.dart +++ b/dart/test/sentry_exception_factory_test.dart @@ -188,6 +188,24 @@ void main() { expect(sentryException.value, isNull); }); + + test( + 'set snapshot to true when no stracktrace is present & attachStacktrace == true', + () { + final sentryException = + fixture.getSut(attachStacktrace: true).getSentryException(Object()); + + expect(sentryException.stackTrace!.snapshot, true); + }); + + test( + 'set snapshot to false when no stracktrace is present & attachStacktrace == false', + () { + final sentryException = + fixture.getSut(attachStacktrace: false).getSentryException(Object()); + + expect(sentryException.stackTrace!.snapshot, true); + }); } class CustomError extends Error {} @@ -268,7 +286,8 @@ isolate_instructions: 7526344980, vm_instructions: 752633f000 class Fixture { final options = SentryOptions(dsn: fakeDsn); - SentryExceptionFactory getSut() { + SentryExceptionFactory getSut({bool attachStacktrace = true}) { + options.attachStacktrace = true; return SentryExceptionFactory(options); } } diff --git a/dart/test/sentry_io_client_test.dart b/dart/test/sentry_io_client_test.dart index b2479a27c8..9ffe1f319c 100644 --- a/dart/test/sentry_io_client_test.dart +++ b/dart/test/sentry_io_client_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @TestOn('vm') +library dart_test; + import 'dart:io'; import 'package:test/test.dart'; diff --git a/dart/test/sentry_isolate_extension_test.dart b/dart/test/sentry_isolate_extension_test.dart index 415f67c797..626d7e525c 100644 --- a/dart/test/sentry_isolate_extension_test.dart +++ b/dart/test/sentry_isolate_extension_test.dart @@ -1,4 +1,6 @@ @TestOn('vm') +library dart_test; + import 'dart:isolate'; import 'package:sentry/src/sentry_isolate_extension.dart'; diff --git a/dart/test/sentry_isolate_test.dart b/dart/test/sentry_isolate_test.dart index 1b1939ac2f..6d41636303 100644 --- a/dart/test/sentry_isolate_test.dart +++ b/dart/test/sentry_isolate_test.dart @@ -1,6 +1,8 @@ @TestOn('vm') +library dart_test; import 'package:sentry/src/hub.dart'; +import 'package:sentry/src/protocol/sentry_level.dart'; import 'package:sentry/src/protocol/span_status.dart'; import 'package:sentry/src/sentry_isolate.dart'; import 'package:sentry/src/sentry_options.dart'; @@ -48,6 +50,23 @@ void main() { await span?.finish(); }); + + test('sets level to error instead of fatal', () async { + final exception = StateError('error'); + final stackTrace = StackTrace.current.toString(); + + final hub = Hub(fixture.options); + final client = MockSentryClient(); + hub.bindClient(client); + + fixture.options.markAutomaticallyCollectedErrorsAsFatal = false; + + await SentryIsolate.handleIsolateError( + hub, [exception.toString(), stackTrace]); + + final capturedEvent = client.captureEventCalls.last.event; + expect(capturedEvent.level, SentryLevel.error); + }); }); } diff --git a/dart/test/sentry_options_test.dart b/dart/test/sentry_options_test.dart index f6dec29e90..273366e442 100644 --- a/dart/test/sentry_options_test.dart +++ b/dart/test/sentry_options_test.dart @@ -127,4 +127,61 @@ void main() { expect(options.isTracingEnabled(), false); }); + + test('Spotlight is disabled by default', () { + final options = SentryOptions(dsn: fakeDsn); + + expect(options.spotlight.enabled, false); + }); + + test('metrics are disabled by default', () { + final options = SentryOptions(dsn: fakeDsn); + + expect(options.enableMetrics, false); + }); + + test('default tags for metrics are enabled by default', () { + final options = SentryOptions(dsn: fakeDsn); + options.enableMetrics = true; + + expect(options.enableDefaultTagsForMetrics, true); + }); + + test('default tags for metrics are disabled if metrics are disabled', () { + final options = SentryOptions(dsn: fakeDsn); + options.enableMetrics = false; + + expect(options.enableDefaultTagsForMetrics, false); + }); + + test('default tags for metrics are enabled if metrics are enabled, too', () { + final options = SentryOptions(dsn: fakeDsn); + options.enableMetrics = true; + options.enableDefaultTagsForMetrics = true; + + expect(options.enableDefaultTagsForMetrics, true); + }); + + test('span local metric aggregation is enabled by default', () { + final options = SentryOptions(dsn: fakeDsn); + options.enableMetrics = true; + + expect(options.enableSpanLocalMetricAggregation, true); + }); + + test('span local metric aggregation is disabled if metrics are disabled', () { + final options = SentryOptions(dsn: fakeDsn); + options.enableMetrics = false; + + expect(options.enableSpanLocalMetricAggregation, false); + }); + + test('span local metric aggregation is enabled if metrics are enabled, too', + () { + final options = SentryOptions(dsn: fakeDsn); + options.enableMetrics = true; + options.enableSpanLocalMetricAggregation = true; + + expect(options.enableSpanLocalMetricAggregation, true); + }); } diff --git a/dart/test/sentry_span_test.dart b/dart/test/sentry_span_test.dart index e878be5cf2..e161ceee2f 100644 --- a/dart/test/sentry_span_test.dart +++ b/dart/test/sentry_span_test.dart @@ -2,6 +2,7 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; +import 'mocks.dart'; import 'mocks/mock_hub.dart'; void main() { @@ -125,11 +126,14 @@ void main() { }); test('span serializes', () async { + fixture.hub.options.enableMetrics = true; + fixture.hub.options.enableSpanLocalMetricAggregation = true; final sut = fixture.getSut(); sut.setTag('test', 'test'); sut.setData('test', 'test'); sut.origin = 'manual'; + sut.localMetricsAggregator?.add(fakeMetric, 0); await sut.finish(status: SpanStatus.aborted()); @@ -141,6 +145,26 @@ void main() { expect(map['tags']['test'], 'test'); expect(map['status'], 'aborted'); expect(map['origin'], 'manual'); + expect(map['_metrics_summary'], isNotNull); + }); + + test('adding a metric after span finish does not serialize', () async { + fixture.hub.options.enableMetrics = true; + fixture.hub.options.enableSpanLocalMetricAggregation = true; + final sut = fixture.getSut(); + await sut.finish(status: SpanStatus.aborted()); + sut.localMetricsAggregator?.add(fakeMetric, 0); + + expect(sut.toJson()['_metrics_summary'], isNull); + }); + + test('adding a metric when option is disabled does not serialize', () async { + fixture.hub.options.enableMetrics = false; + final sut = fixture.getSut(); + sut.localMetricsAggregator?.add(fakeMetric, 0); + await sut.finish(status: SpanStatus.aborted()); + + expect(sut.toJson()['_metrics_summary'], isNull); }); test('finished returns false if not yet', () { @@ -271,6 +295,21 @@ void main() { final sut = fixture.getSut(); expect(sut.origin, 'manual'); }); + + test('localMetricsAggregator is set when option is enabled', () async { + fixture.hub.options.enableMetrics = true; + fixture.hub.options.enableSpanLocalMetricAggregation = true; + final sut = fixture.getSut(); + expect(fixture.hub.options.enableSpanLocalMetricAggregation, true); + expect(sut.localMetricsAggregator, isNotNull); + }); + + test('localMetricsAggregator is null when option is disabled', () async { + fixture.hub.options.enableSpanLocalMetricAggregation = false; + final sut = fixture.getSut(); + expect(fixture.hub.options.enableSpanLocalMetricAggregation, false); + expect(sut.localMetricsAggregator, null); + }); } class Fixture { diff --git a/dart/test/sentry_test.dart b/dart/test/sentry_test.dart index b041f19527..0a8dd5db27 100644 --- a/dart/test/sentry_test.dart +++ b/dart/test/sentry_test.dart @@ -21,9 +21,9 @@ void main() { final options = SentryOptions(dsn: fakeDsn)..automatedTestMode = true; await Sentry.init( options: options, - (options) => { - options.dsn = fakeDsn, - options.tracesSampleRate = 1.0, + (options) { + options.dsn = fakeDsn; + options.tracesSampleRate = 1.0; }, ); anException = Exception('anException'); @@ -129,6 +129,10 @@ void main() { expect(Sentry.getSpan(), isNull); }); + + test('should provide metrics API', () async { + expect(Sentry.metrics(), Sentry.currentHub.metricsApi); + }); }); group('Sentry is enabled or disabled', () { @@ -412,29 +416,7 @@ void main() { expect(sentryOptions.logger, isNot(dartLogger)); }); - group("Sentry init optionsConfiguration", () { - final fixture = Fixture(); - - test('throw is handled and logged', () async { - final sentryOptions = SentryOptions(dsn: fakeDsn) - ..automatedTestMode = false - ..debug = true - ..logger = fixture.mockLogger; - - final exception = Exception("Exception in options callback"); - await Sentry.init( - (options) async { - throw exception; - }, - options: sentryOptions, - ); - - expect(fixture.loggedException, exception); - expect(fixture.loggedLevel, SentryLevel.error); - }); - }); - - group("Sentry init optionsConfiguration", () { + group('Sentry init optionsConfiguration', () { final fixture = Fixture(); test('throw is handled and logged', () async { diff --git a/dart/test/sentry_tracer_test.dart b/dart/test/sentry_tracer_test.dart index 48ff011e82..7ba5e80fac 100644 --- a/dart/test/sentry_tracer_test.dart +++ b/dart/test/sentry_tracer_test.dart @@ -68,24 +68,7 @@ void main() { expect(sut.endTimestamp, endTimestamp); }); - test( - 'tracer finish sets given end timestamp to all children while finishing them', - () async { - final sut = fixture.getSut(); - - final childA = sut.startChild('operation-a', description: 'description'); - final childB = sut.startChild('operation-b', description: 'description'); - final endTimestamp = getUtcDateTime(); - - await sut.finish(endTimestamp: endTimestamp); - await childA.finish(); - await childB.finish(); - - expect(childA.endTimestamp, endTimestamp); - expect(childB.endTimestamp, endTimestamp); - }); - - test('tracer finishes unfinished spans', () async { + test('tracer does not finish unfinished spans', () async { final sut = fixture.getSut(); sut.startChild('child'); @@ -94,7 +77,8 @@ void main() { final tr = fixture.hub.captureTransactionCalls.first; final child = tr.transaction.spans.first; - expect(child.status.toString(), 'deadline_exceeded'); + expect(child.status, isNull); + expect(child.endTimestamp, isNull); }); test('tracer sets data to extra', () async { @@ -386,6 +370,29 @@ void main() { expect(sut.endTimestamp, endTimestamp); }); + test('end trimmed to latest child end timestamp', () async { + final sut = fixture.getSut(trimEnd: true); + final rootEndInitial = getUtcDateTime(); + + final childAEnd = rootEndInitial; + final childBEnd = rootEndInitial.add(Duration(seconds: 1)); + final childCEnd = rootEndInitial; + + final childA = sut.startChild('operation-a', description: 'description'); + final childB = sut.startChild('operation-b', description: 'description'); + final childC = sut.startChild('operation-c', description: 'description'); + + await childA.finish(endTimestamp: childAEnd); + await childB.finish(endTimestamp: childBEnd); + await childC.finish(endTimestamp: childCEnd); + + await sut.finish(endTimestamp: rootEndInitial); + + expect(sut.endTimestamp, equals(childB.endTimestamp), + reason: + 'The root end timestamp should be updated to match the latest child end timestamp.'); + }); + test('does not add more spans than configured in options', () async { fixture.hub.options.maxSpans = 2; final sut = fixture.getSut(); @@ -445,6 +452,21 @@ void main() { expect(sut.measurements.isEmpty, true); }); + + test('localMetricsAggregator is set when option is enabled', () async { + fixture.hub.options.enableMetrics = true; + fixture.hub.options.enableSpanLocalMetricAggregation = true; + final sut = fixture.getSut(); + expect(fixture.hub.options.enableSpanLocalMetricAggregation, true); + expect(sut.localMetricsAggregator, isNotNull); + }); + + test('localMetricsAggregator is null when option is disabled', () async { + fixture.hub.options.enableMetrics = false; + final sut = fixture.getSut(); + expect(fixture.hub.options.enableSpanLocalMetricAggregation, false); + expect(sut.localMetricsAggregator, null); + }); }); group('$SentryBaggageHeader', () { diff --git a/dart/test/sentry_transaction_test.dart b/dart/test/sentry_transaction_test.dart index fb784abd6d..7de0549a13 100644 --- a/dart/test/sentry_transaction_test.dart +++ b/dart/test/sentry_transaction_test.dart @@ -2,6 +2,7 @@ import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; +import 'mocks.dart'; import 'mocks/mock_hub.dart'; void main() { @@ -9,6 +10,7 @@ void main() { SentryTracer _createTracer({ bool? sampled = true, + Hub? hub, }) { final context = SentryTransactionContext( 'name', @@ -16,11 +18,16 @@ void main() { samplingDecision: SentryTracesSamplingDecision(sampled!), transactionNameSource: SentryTransactionNameSource.component, ); - return SentryTracer(context, MockHub()); + return SentryTracer(context, hub ?? MockHub()); } test('toJson serializes', () async { - final tracer = _createTracer(); + fixture.options.enableSpanLocalMetricAggregation = true; + fixture.options.enableMetrics = true; + + final tracer = _createTracer(hub: fixture.hub); + tracer.localMetricsAggregator?.add(fakeMetric, 0); + final child = tracer.startChild('child'); await child.finish(); await tracer.finish(); @@ -32,6 +39,7 @@ void main() { expect(map['start_timestamp'], isNotNull); expect(map['spans'], isNotNull); expect(map['transaction_info']['source'], 'component'); + expect(map['_metrics_summary'], isNotNull); }); test('returns finished if it is', () async { @@ -66,9 +74,43 @@ void main() { expect(sut.sampled, false); }); + + test('add a metric to localAggregator adds it to metricSummary', () async { + fixture.options.enableSpanLocalMetricAggregation = true; + fixture.options.enableMetrics = true; + + final tracer = _createTracer(hub: fixture.hub) + ..localMetricsAggregator?.add(fakeMetric, 0); + await tracer.finish(); + + final sut = fixture.getSut(tracer); + expect(sut.metricSummaries, isNotEmpty); + }); + + test('add metric after creation does not add it to metricSummary', () async { + fixture.options.enableSpanLocalMetricAggregation = true; + fixture.options.enableMetrics = true; + + final tracer = _createTracer(hub: fixture.hub); + await tracer.finish(); + final sut = fixture.getSut(tracer); + tracer.localMetricsAggregator?.add(fakeMetric, 0); + + expect(sut.metricSummaries, isEmpty); + }); + + test('metricSummary is null by default', () async { + final tracer = _createTracer(); + await tracer.finish(); + final sut = fixture.getSut(tracer); + expect(sut.metricSummaries, null); + }); } class Fixture { + final SentryOptions options = SentryOptions(dsn: fakeDsn); + late final Hub hub = Hub(options); + SentryTransaction getSut(SentryTracer tracer) { return SentryTransaction(tracer); } diff --git a/dart/test/stack_trace_test.dart b/dart/test/stack_trace_test.dart index 2bcf92c2c8..6524581794 100644 --- a/dart/test/stack_trace_test.dart +++ b/dart/test/stack_trace_test.dart @@ -254,11 +254,6 @@ isolate_instructions: 10fa27070, vm_instructions: 10fa21e20 final frames = Fixture() .getSut(considerInAppFramesByDefault: true) .getStackFrames(StackTrace.fromString(''' -#0 SentryClient._prepareEvent (package:sentry/src/sentry_client.dart:206:33) -#1 SentryClient.captureEvent (package:sentry/src/sentry_client.dart:74:34) -#2 Hub.captureEvent (package:sentry/src/hub.dart:97:38) - -#3 LoggingIntegration._onLog (package:sentry_logging/src/logging_integration.dart:58:7) ''')) .map((frame) => frame.toJson()); diff --git a/dart/test/transport/spotlight_http_transport_test.dart b/dart/test/transport/spotlight_http_transport_test.dart new file mode 100644 index 0000000000..b23f1fd87f --- /dev/null +++ b/dart/test/transport/spotlight_http_transport_test.dart @@ -0,0 +1,70 @@ +import 'package:http/http.dart' as http; +import 'package:http/testing.dart'; +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/transport/http_transport.dart'; +import 'package:sentry/src/transport/rate_limiter.dart'; +import 'package:sentry/src/transport/spotlight_http_transport.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +import '../mocks.dart'; +import '../mocks/mock_client_report_recorder.dart'; + +void main() { + group('send to Sentry', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('send event to Sentry even if Spotlight fails', () async { + List? body; + + final httpMock = MockClient((http.Request request) async { + body = request.bodyBytes; + if (request.url.toString() == fixture.options.spotlight.url) { + return http.Response('{}', 500); + } + return http.Response('{}', 200); + }); + + fixture.options.compressPayload = false; + final mockRateLimiter = MockRateLimiter(); + final sut = fixture.getSut(httpMock, mockRateLimiter); + + final sentryEvent = SentryEvent(); + final envelope = SentryEnvelope.fromEvent( + sentryEvent, + fixture.options.sdk, + dsn: fixture.options.dsn, + ); + await sut.send(envelope); + + final envelopeData = []; + await envelope + .envelopeStream(fixture.options) + .forEach(envelopeData.addAll); + + expect(body, envelopeData); + }); + }); +} + +class Fixture { + final options = SentryOptions( + dsn: 'https://public:secret@sentry.example.com/1', + ); + + late var clientReportRecorder = MockClientReportRecorder(); + + Transport getSut(http.Client client, RateLimiter rateLimiter) { + options.httpClient = client; + options.recorder = clientReportRecorder; + options.clock = () { + return DateTime.utc(2019); + }; + final httpTransport = HttpTransport(options, rateLimiter); + return SpotlightHttpTransport(options, httpTransport); + } +} diff --git a/dart/test/transport/tesk_queue_test.dart b/dart/test/transport/tesk_queue_test.dart new file mode 100644 index 0000000000..80dc97161c --- /dev/null +++ b/dart/test/transport/tesk_queue_test.dart @@ -0,0 +1,118 @@ +import 'dart:async'; + +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/transport/task_queue.dart'; +import 'package:test/test.dart'; + +import '../mocks.dart'; + +void main() { + group("called sync", () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test("enqueue only executed `maxQueueSize` times when not awaiting", + () async { + final sut = fixture.getSut(maxQueueSize: 5); + + var completedTasks = 0; + + for (int i = 0; i < 10; i++) { + unawaited(sut.enqueue(() async { + print('Task $i'); + await Future.delayed(Duration(milliseconds: 1)); + completedTasks += 1; + return 1 + 1; + }, -1)); + } + + // This will always await the other futures, even if they are running longer, as it was scheduled after them. + print('Started waiting for first 5 tasks'); + await Future.delayed(Duration(milliseconds: 1)); + print('Stopped waiting for first 5 tasks'); + + expect(completedTasks, 5); + }); + + test("enqueue picks up tasks again after await in-between", () async { + final sut = fixture.getSut(maxQueueSize: 5); + + var completedTasks = 0; + + for (int i = 1; i <= 10; i++) { + unawaited(sut.enqueue(() async { + print('Started task $i'); + await Future.delayed(Duration(milliseconds: 1)); + print('Completed task $i'); + completedTasks += 1; + return 1 + 1; + }, -1)); + } + + print('Started waiting for first 5 tasks'); + await Future.delayed(Duration(milliseconds: 1)); + print('Stopped waiting for first 5 tasks'); + + for (int i = 6; i <= 15; i++) { + unawaited(sut.enqueue(() async { + print('Started task $i'); + await Future.delayed(Duration(milliseconds: 1)); + print('Completed task $i'); + completedTasks += 1; + return 1 + 1; + }, -1)); + } + + print('Started waiting for second 5 tasks'); + await Future.delayed(Duration(milliseconds: 5)); + print('Stopped waiting for second 5 tasks'); + + expect(completedTasks, 10); // 10 were dropped + }); + + test("enqueue executes all tasks when awaiting", () async { + final sut = fixture.getSut(maxQueueSize: 5); + + var completedTasks = 0; + + for (int i = 0; i < 10; i++) { + await sut.enqueue(() async { + print('Task $i'); + await Future.delayed(Duration(milliseconds: 1)); + completedTasks += 1; + return 1 + 1; + }, -1); + } + expect(completedTasks, 10); + }); + + test("throwing tasks still execute as expected", () async { + final sut = fixture.getSut(maxQueueSize: 5); + + var completedTasks = 0; + + for (int i = 0; i < 10; i++) { + try { + await sut.enqueue(() async { + completedTasks += 1; + throw Error(); + }, -1); + } catch (_) { + // Ignore + } + } + expect(completedTasks, 10); + }); + }); +} + +class Fixture { + final options = SentryOptions(dsn: fakeDsn); + + TaskQueue getSut({required int maxQueueSize}) { + return TaskQueue(maxQueueSize, options.logger); + } +} diff --git a/dart/test/utils/http_sanitizer_test.dart b/dart/test/utils/http_sanitizer_test.dart index f9967c2778..2a4e0a58be 100644 --- a/dart/test/utils/http_sanitizer_test.dart +++ b/dart/test/utils/http_sanitizer_test.dart @@ -182,7 +182,7 @@ void main() { }); } -extension StringExtension on String { +extension _StringExtension on String { String _capitalize() { return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; } diff --git a/dart/test/version_test.dart b/dart/test/version_test.dart index f1ff8574a8..f2022bbba2 100644 --- a/dart/test/version_test.dart +++ b/dart/test/version_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. @TestOn('vm') +library dart_test; import 'dart:io'; diff --git a/dio/README.md b/dio/README.md index 72c1cbeaa8..a8cf767237 100644 --- a/dio/README.md +++ b/dio/README.md @@ -49,8 +49,9 @@ Depending on your configuration, this adds performance tracing and http breadcru #### Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) -* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) -* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) -* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) +* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) \ No newline at end of file diff --git a/dio/lib/src/dio_event_processor.dart b/dio/lib/src/dio_event_processor.dart index 3a9603abd1..afeb692be4 100644 --- a/dio/lib/src/dio_event_processor.dart +++ b/dio/lib/src/dio_event_processor.dart @@ -15,7 +15,7 @@ class DioEventProcessor implements EventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/dio/lib/src/failed_request_interceptor.dart b/dio/lib/src/failed_request_interceptor.dart index 60ea4a0133..cd36f60549 100644 --- a/dio/lib/src/failed_request_interceptor.dart +++ b/dio/lib/src/failed_request_interceptor.dart @@ -10,13 +10,16 @@ class FailedRequestInterceptor extends Interceptor { SentryHttpClient.defaultFailedRequestStatusCodes, List failedRequestTargets = SentryHttpClient.defaultFailedRequestTargets, + bool? captureFailedRequests, }) : _hub = hub ?? HubAdapter(), _failedRequestStatusCodes = failedRequestStatusCodes, - _failedRequestTargets = failedRequestTargets; + _failedRequestTargets = failedRequestTargets, + _captureFailedRequests = captureFailedRequests; final Hub _hub; final List _failedRequestStatusCodes; final List _failedRequestTargets; + final bool? _captureFailedRequests; @override Future onError( @@ -24,16 +27,16 @@ class FailedRequestInterceptor extends Interceptor { ErrorInterceptorHandler handler, ) async { // ignore: invalid_use_of_internal_member - final captureFailedRequests = _hub.options.captureFailedRequests; + final cfr = _captureFailedRequests ?? _hub.options.captureFailedRequests; final containsStatusCode = - _failedRequestStatusCodes.containsStatusCode(err.response?.statusCode); + _failedRequestStatusCodes._containsStatusCode(err.response?.statusCode); final containsRequestTarget = containsTargetOrMatchesRegExp( _failedRequestTargets, err.requestOptions.path, ); - if (captureFailedRequests && containsStatusCode && containsRequestTarget) { + if (cfr && containsStatusCode && containsRequestTarget) { final mechanism = Mechanism(type: 'SentryDioClientAdapter'); final throwableMechanism = ThrowableMechanism(mechanism, err); @@ -46,7 +49,7 @@ class FailedRequestInterceptor extends Interceptor { } extension _ListX on List { - bool containsStatusCode(int? statusCode) { + bool _containsStatusCode(int? statusCode) { if (statusCode == null) { return false; } diff --git a/dio/lib/src/sentry_dio_extension.dart b/dio/lib/src/sentry_dio_extension.dart index cf49de64d5..6c60b1f7c6 100644 --- a/dio/lib/src/sentry_dio_extension.dart +++ b/dio/lib/src/sentry_dio_extension.dart @@ -42,12 +42,15 @@ extension SentryDioExtension on Dio { /// failedRequestTargets: ['my-api.com'], /// ); /// ``` + /// + /// The captureFailedRequests argument will take precedent over options. void addSentry({ Hub? hub, List failedRequestStatusCodes = SentryHttpClient.defaultFailedRequestStatusCodes, List failedRequestTargets = SentryHttpClient.defaultFailedRequestTargets, + bool? captureFailedRequests, }) { hub = hub ?? HubAdapter(); @@ -71,7 +74,7 @@ extension SentryDioExtension on Dio { } options.sdk.addPackage(packageName, sdkVersion); - if (options.captureFailedRequests) { + if (captureFailedRequests ?? options.captureFailedRequests) { // Add FailedRequestInterceptor at index 0, so it's the first interceptor. // This ensures that it is called and not skipped by any previous interceptor. interceptors.insert( diff --git a/dio/lib/src/tracing_client_adapter.dart b/dio/lib/src/tracing_client_adapter.dart index 19a003b633..0c8def1442 100644 --- a/dio/lib/src/tracing_client_adapter.dart +++ b/dio/lib/src/tracing_client_adapter.dart @@ -51,12 +51,12 @@ class TracingClientAdapter implements HttpClientAdapter { ResponseBody? response; try { - if (span != null) { - if (containsTargetOrMatchesRegExp( - // ignore: invalid_use_of_internal_member - _hub.options.tracePropagationTargets, - options.uri.toString(), - )) { + if (containsTargetOrMatchesRegExp( + // ignore: invalid_use_of_internal_member + _hub.options.tracePropagationTargets, + options.uri.toString(), + )) { + if (span != null) { addSentryTraceHeaderFromSpan(span, options.headers); addBaggageHeaderFromSpan( span, @@ -64,6 +64,25 @@ class TracingClientAdapter implements HttpClientAdapter { // ignore: invalid_use_of_internal_member logger: _hub.options.logger, ); + } else { + // ignore: invalid_use_of_internal_member + final scope = _hub.scope; + // ignore: invalid_use_of_internal_member + final propagationContext = scope.propagationContext; + + final traceHeader = propagationContext.toSentryTrace(); + addSentryTraceHeader(traceHeader, options.headers); + + final baggage = propagationContext.baggage; + if (baggage != null) { + final baggageHeader = SentryBaggageHeader.fromBaggage(baggage); + addBaggageHeader( + baggageHeader, + options.headers, + // ignore: invalid_use_of_internal_member + logger: _hub.options.logger, + ); + } } } diff --git a/dio/lib/src/version.dart b/dio/lib/src/version.dart index 5d8e41f2aa..4b219aa09a 100644 --- a/dio/lib/src/version.dart +++ b/dio/lib/src/version.dart @@ -1,5 +1,5 @@ /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; /// The package name reported to Sentry.io in the submitted events. const String packageName = 'pub:sentry_dio'; diff --git a/dio/pubspec.yaml b/dio/pubspec.yaml index 4fd89221bb..b4865df495 100644 --- a/dio/pubspec.yaml +++ b/dio/pubspec.yaml @@ -1,6 +1,6 @@ name: sentry_dio description: An integration which adds support for performance tracing for the Dio package. -version: 7.13.1 +version: 8.3.0 homepage: https://docs.sentry.io/platforms/dart/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues @@ -9,13 +9,21 @@ documentation: https://docs.sentry.io/platforms/dart/integrations/dio/ environment: sdk: '>=2.17.0 <4.0.0' +platforms: + android: + ios: + macos: + linux: + windows: + web: + dependencies: dio: ^5.0.0 - sentry: 7.13.1 + sentry: 8.3.0 dev_dependencies: meta: ^1.3.0 - lints: ^3.0.0 + lints: ^4.0.0 test: ^1.21.1 coverage: ^1.3.0 mockito: ^5.1.0 diff --git a/dio/test/dio_event_processor_test.dart b/dio/test/dio_event_processor_test.dart index 3cd060ea8e..af4a94ab8d 100644 --- a/dio/test/dio_event_processor_test.dart +++ b/dio/test/dio_event_processor_test.dart @@ -24,7 +24,7 @@ void main() { throwable: Exception(), exceptions: [fixture.sentryError(throwable)], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(event, processedEvent); }); @@ -42,7 +42,7 @@ void main() { request: SentryRequest(), exceptions: [fixture.sentryError(dioError)], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(event.throwable, processedEvent.throwable); expect(event.request, processedEvent.request); @@ -70,7 +70,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.request?.method, 'POST'); @@ -99,7 +99,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.request?.method, 'GET'); @@ -128,7 +128,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.request?.headers, {}); }); @@ -180,7 +180,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; final capturedRequest = processedEvent.request; expect(capturedRequest, isNotNull); @@ -222,7 +222,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.contexts.response, isNotNull); @@ -263,7 +263,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.contexts.response, isNotNull); @@ -323,7 +323,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; final capturedResponse = processedEvent.contexts.response; expect(capturedResponse, isNotNull); @@ -378,7 +378,7 @@ void main() { fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; final capturedResponse = processedEvent.contexts.response; expect(capturedResponse, isNotNull); @@ -413,7 +413,7 @@ void main() { exceptions: exceptions, ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.exceptions?.length, 2); diff --git a/dio/test/failed_request_interceptor_test.dart b/dio/test/failed_request_interceptor_test.dart index e7fb5a63e1..4602180e0c 100644 --- a/dio/test/failed_request_interceptor_test.dart +++ b/dio/test/failed_request_interceptor_test.dart @@ -50,6 +50,38 @@ void main() { expect(fixture.hub.captureExceptionCalls.length, 0); }); + test('do capture if captureFailedRequests override is true', () async { + final requestOptions = RequestOptions(path: 'https://example.com'); + final error = DioError( + requestOptions: requestOptions, + response: Response(statusCode: 500, requestOptions: requestOptions), + ); + + fixture.hub.options.captureFailedRequests = false; + + final sut = fixture.getSut(captureFailedRequests: true); + await sut.onError(error, fixture.errorInterceptorHandler); + + expect(fixture.errorInterceptorHandler.nextWasCalled, true); + expect(fixture.hub.captureExceptionCalls.length, 1); + }); + + test('do not capture if captureFailedRequests override false', () async { + final requestOptions = RequestOptions(path: 'https://example.com'); + final error = DioError( + requestOptions: requestOptions, + response: Response(statusCode: 500, requestOptions: requestOptions), + ); + + fixture.hub.options.captureFailedRequests = true; + + final sut = fixture.getSut(captureFailedRequests: false); + await sut.onError(error, fixture.errorInterceptorHandler); + + expect(fixture.errorInterceptorHandler.nextWasCalled, true); + expect(fixture.hub.captureExceptionCalls.length, 0); + }); + test('capture in range failedRequestStatusCodes', () async { final requestOptions = RequestOptions(path: 'https://example.com'); final error = DioError( @@ -116,11 +148,13 @@ class Fixture { SentryStatusCode.defaultRange(), ], List failedRequestTargets = const ['.*'], + bool? captureFailedRequests, }) { return FailedRequestInterceptor( hub: hub, failedRequestStatusCodes: failedRequestStatusCodes, failedRequestTargets: failedRequestTargets, + captureFailedRequests: captureFailedRequests, ); } } diff --git a/dio/test/mocks.dart b/dio/test/mocks.dart index 5ed6dcd00a..30e53c5772 100644 --- a/dio/test/mocks.dart +++ b/dio/test/mocks.dart @@ -98,7 +98,7 @@ final fakeEvent = SentryEvent( /// Doesn't do anything with the events class NoOpEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return event; } } @@ -106,7 +106,7 @@ class NoOpEventProcessor implements EventProcessor { /// Always returns null and thus drops all events class DropAllEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return null; } } @@ -117,15 +117,15 @@ class FunctionEventProcessor implements EventProcessor { final EventProcessorFunction applyFunction; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { - return applyFunction(event, hint: hint); + SentryEvent? apply(SentryEvent event, Hint hint) { + return applyFunction(event, hint); } } typedef EventProcessorFunction = SentryEvent? Function( - SentryEvent event, { - Hint? hint, -}); + SentryEvent event, + Hint hint, +); var fakeEnvelope = SentryEnvelope.fromEvent( fakeEvent, diff --git a/dio/test/sentry_dio_extension_test.dart b/dio/test/sentry_dio_extension_test.dart index e81c3296b5..622dac5442 100644 --- a/dio/test/sentry_dio_extension_test.dart +++ b/dio/test/sentry_dio_extension_test.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:sentry_dio/sentry_dio.dart'; import 'package:sentry_dio/src/dio_error_extractor.dart'; import 'package:sentry_dio/src/dio_stacktrace_extractor.dart'; +import 'package:sentry_dio/src/failed_request_interceptor.dart'; import 'package:sentry_dio/src/sentry_dio_client_adapter.dart'; import 'package:sentry_dio/src/sentry_dio_extension.dart'; import 'package:sentry_dio/src/sentry_transformer.dart'; @@ -48,6 +49,63 @@ void main() { ); }); + test( + 'addSentry adds $FailedRequestInterceptor if captureFailedRequests true', + () { + final dio = fixture.getSut(); + + fixture.hub.options.captureFailedRequests = true; + + dio.addSentry(hub: fixture.hub); + + expect( + dio.interceptors.whereType().length, + 1, + ); + }); + + test( + 'addSentry does not add $FailedRequestInterceptor if captureFailedRequests false', + () { + final dio = fixture.getSut(); + + fixture.hub.options.captureFailedRequests = false; + + dio.addSentry(hub: fixture.hub); + + expect( + dio.interceptors.whereType().length, + 0, + ); + }); + + test('addSentry adds $FailedRequestInterceptor if override true', () { + final dio = fixture.getSut(); + + fixture.hub.options.captureFailedRequests = false; + + dio.addSentry(hub: fixture.hub, captureFailedRequests: true); + + expect( + dio.interceptors.whereType().length, + 1, + ); + }); + + test('addSentry does not add $FailedRequestInterceptor if override false', + () { + final dio = fixture.getSut(); + + fixture.hub.options.captureFailedRequests = true; + + dio.addSentry(hub: fixture.hub, captureFailedRequests: false); + + expect( + dio.interceptors.whereType().length, + 0, + ); + }); + test('addSentry only adds one $DioEventProcessor', () { final dio = fixture.getSut(); diff --git a/dio/test/tracing_client_adapter_test.dart b/dio/test/tracing_client_adapter_test.dart index b758c5a765..f67ec4c14d 100644 --- a/dio/test/tracing_client_adapter_test.dart +++ b/dio/test/tracing_client_adapter_test.dart @@ -127,25 +127,48 @@ void main() { ); }); - test('captured span do not add headers if NoOp', () async { + test('do not throw if no span bound to the scope', () async { + final sut = fixture.getSut( + client: fixture.getClient(statusCode: 200, reason: 'OK'), + ); + + await sut.get(requestOptions); + }); + + test('set headers from propagationContext when tracing is disabled', + () async { + fixture._options.enableTracing = false; final sut = fixture.getSut( client: fixture.getClient(statusCode: 200, reason: 'OK'), ); - await fixture._hub - .configureScope((scope) => scope.span = NoOpSentrySpan()); + + final propagationContext = fixture._hub.scope.propagationContext; + propagationContext.baggage = SentryBaggage({'foo': 'bar'}); final response = await sut.get(requestOptions); - expect(response.headers['baggage'], null); - expect(response.headers['sentry-trace'], null); + expect( + response.headers['sentry-trace'], + [propagationContext.toSentryTrace().value], + ); + expect(response.headers['baggage'], ['foo=bar']); }); - test('do not throw if no span bound to the scope', () async { + test('set headers from propagationContext when no transaction', () async { final sut = fixture.getSut( client: fixture.getClient(statusCode: 200, reason: 'OK'), ); - await sut.get(requestOptions); + final propagationContext = fixture._hub.scope.propagationContext; + propagationContext.baggage = SentryBaggage({'foo': 'bar'}); + + final response = await sut.get(requestOptions); + + expect( + response.headers['sentry-trace'], + [propagationContext.toSentryTrace().value], + ); + expect(response.headers['baggage'], ['foo=bar']); }); }); } diff --git a/dio/test/version_test.dart b/dio/test/version_test.dart index 551d07a4c3..2e0c6a8b14 100644 --- a/dio/test/version_test.dart +++ b/dio/test/version_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library dio_test; import 'dart:io'; diff --git a/docs/new-package-release-checklist.md b/docs/new-package-release-checklist.md new file mode 100644 index 0000000000..0a7cd19821 --- /dev/null +++ b/docs/new-package-release-checklist.md @@ -0,0 +1,57 @@ +# New Package Release Checklist + +This page serves as a checklist of what to do when releasing a new package for the first time. + +## Release Preparation + +- [ ] Make sure the project is set up + - [ ] The package only exports the public API + - [ ] The package contains an example folder + - [ ] The package contains a README.md file + - [ ] CI badges show a status + - [ ] The package contains a CHANGELOG.md file (symlink to the root changelog) + - [ ] The package contains a dartdoc_options.yaml file (symlink to the root file) + - [ ] The package contains a LICENSE (default is `MIT`) + - [ ] The package contains a pubspec.yaml file + - [ ] The package contains a analysis_options.yaml file + +- [ ] Update the [Flutter example](https://github.com/getsentry/sentry-dart/tree/main/flutter/example) to use your new package if applicable + +- [ ] Make sure your new package has a `version.dart` in the `lib/src` folder. + - This is used to set the version and package in the `Hub`. See this [example](https://github.com/getsentry/sentry-dart/blob/8609bd8dd7ea572e5d241a59643c7570e5621bda/sqflite/lib/src/sentry_database.dart#L69). + - The version will be updated to the newest version after triggering the release process. + +- [ ] Create a new workflow called `your-package-name.yml` for building and testing the package. + +- [ ] Excluding `your-package-name.yml`, add the package to the `paths-ignore` section of all package workflow files. + - For examples see `sqflite.yml`, `dio.yml` etc... + +- [ ] Add an entry to [diagram.yml](https://github.com/getsentry/sentry-dart/blob/main/.github/workflows/diagrams.yml) for your package. + +- [ ] In the root `.gitignore` file add the package coverage as ignored. + +The `analyze` workflow will fail in your PR and in the main branch because the package is not released yet and the `pubspec.yaml` is not 'valid' according to the analyzer. +This is expected - it will succeed after the release. +- [ ] Make sure the analyze workflow doesn't have other failures, only the one mentioned above. + +- [ ] **Very important**: add your package to `scripts/bump-version.sh`. + +## Doing the Release + +Do these steps in the **correct order** + +- [ ] Add your package only as a `pub-dev` target in `.craft.yml`. (**not registry**) + - The release process might fail if you add it to the registry at this point. +- [ ] Trigger the release + - [ ] Check that the release bot successfully updated the versions in `version.dart` and `pubspec.yaml` in the release branch. + +## After the first release + +- [ ] Check if package is succesfully released on `pub.dev` +- [ ] Add the package to the Sentry Release Registry + - Instructions on how to do this can be found [here](https://github.com/getsentry/sentry-release-registry#adding-new-sdks) + - [Example PR](https://github.com/getsentry/sentry-release-registry/pull/136) +- [ ] Add an entry to `.craft.yml` for the package in the `registry` section. + - Now all future releases will be added to the registry automatically. +- [ ] Update the repo's `README.md` +- [ ] Prepare and merge [Sentry documentation](https://github.com/getsentry/sentry-docs/) diff --git a/drift/README.md b/drift/README.md index e6fd9e6d11..57b335700a 100644 --- a/drift/README.md +++ b/drift/README.md @@ -10,7 +10,7 @@ Sentry integration for `drift` package | package | build | pub | likes | popularity | pub points | |-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| ------- | -| sentry_drift | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-drift/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-drift) | [![pub package](https://img.shields.io/pub/v/sentry_drift.svg)](https://pub.dev/packages/sentry_drift) | [![likes](https://img.shields.io/pub/likes/sentry_drift)](https://pub.dev/packages/sentry_drift/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_drift)](https://pub.dev/packages/sentry_drift/score) | [![pub points](https://img.shields.io/pub/points/sentry_drift)](https://pub.dev/packages/sentry_drift/score) +| sentry_drift | [![build](https://github.com/getsentry/sentry-dart/actions/workflows/drift.yml/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-drift) | [![pub package](https://img.shields.io/pub/v/sentry_drift.svg)](https://pub.dev/packages/sentry_drift) | [![likes](https://img.shields.io/pub/likes/sentry_drift)](https://pub.dev/packages/sentry_drift/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_drift)](https://pub.dev/packages/sentry_drift/score) | [![pub points](https://img.shields.io/pub/points/sentry_drift)](https://pub.dev/packages/sentry_drift/score) Integration for the [`drift`](https://pub.dev/packages/drift) package. @@ -74,8 +74,9 @@ Future runApp() async { #### Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) -* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) -* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) diff --git a/drift/lib/src/version.dart b/drift/lib/src/version.dart index 39be251dbf..f56b0af46f 100644 --- a/drift/lib/src/version.dart +++ b/drift/lib/src/version.dart @@ -1,5 +1,5 @@ /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; /// The package name reported to Sentry.io in the submitted events. const String packageName = 'pub:sentry_drift'; diff --git a/drift/pubspec.yaml b/drift/pubspec.yaml index 7f474b73e7..b3a529de9c 100644 --- a/drift/pubspec.yaml +++ b/drift/pubspec.yaml @@ -1,16 +1,23 @@ name: sentry_drift description: An integration which adds support for performance tracing for the drift package. -version: 7.13.1 +version: 8.3.0 homepage: https://docs.sentry.io/platforms/flutter/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues environment: sdk: '>=2.17.0 <4.0.0' - flutter: '>=3.3.0' + +platforms: + android: + ios: + macos: + linux: + windows: + web: dependencies: - sentry: 7.13.1 + sentry: 8.3.0 meta: ^1.3.0 drift: ^2.13.0 diff --git a/e2e_test/bin/e2e_test.dart b/e2e_test/bin/e2e_test.dart index d8d315c5e3..fff4d320ee 100644 --- a/e2e_test/bin/e2e_test.dart +++ b/e2e_test/bin/e2e_test.dart @@ -10,7 +10,7 @@ const _exampleDsn = const _org = 'sentry-sdks'; const _projectSlug = 'sentry-flutter'; -final _token = Platform.environment['SENTRY_AUTH_TOKEN'] ?? ''; +final _token = Platform.environment['SENTRY_AUTH_TOKEN_E2E'] ?? ''; void main(List arguments) async { print('Starting'); diff --git a/file/lib/src/version.dart b/file/lib/src/version.dart index da534425a9..6e9dc3050c 100644 --- a/file/lib/src/version.dart +++ b/file/lib/src/version.dart @@ -1,5 +1,5 @@ /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; /// The package name reported to Sentry.io in the submitted events. const String packageName = 'pub:sentry_file'; diff --git a/file/pubspec.yaml b/file/pubspec.yaml index d1cb6a6036..9a2027e8c7 100644 --- a/file/pubspec.yaml +++ b/file/pubspec.yaml @@ -1,6 +1,6 @@ name: sentry_file description: An integration which adds support for performance tracing for dart.io.File. -version: 7.13.1 +version: 8.3.0 homepage: https://docs.sentry.io/platforms/dart/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues @@ -9,12 +9,19 @@ documentation: https://docs.sentry.io/platforms/dart/configuration/integrations/ environment: sdk: '>=2.19.0 <4.0.0' +platforms: + android: + ios: + macos: + linux: + windows: + dependencies: - sentry: 7.13.1 + sentry: 8.3.0 meta: ^1.3.0 dev_dependencies: - lints: ^3.0.0 + lints: ^4.0.0 test: ^1.21.1 coverage: ^1.3.0 mockito: ^5.1.0 diff --git a/file/test/sentry_file_extension_test.dart b/file/test/sentry_file_extension_test.dart index 73eb94beff..d6a0bff5bc 100644 --- a/file/test/sentry_file_extension_test.dart +++ b/file/test/sentry_file_extension_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library file_test; import 'dart:io'; diff --git a/file/test/sentry_file_test.dart b/file/test/sentry_file_test.dart index 3f7135de54..48cf9b5175 100644 --- a/file/test/sentry_file_test.dart +++ b/file/test/sentry_file_test.dart @@ -1,6 +1,7 @@ // ignore_for_file: invalid_use_of_internal_member @TestOn('vm') +library file_test; import 'dart:io'; diff --git a/file/test/version_test.dart b/file/test/version_test.dart index 8bba9116b9..a21aeea800 100644 --- a/file/test/version_test.dart +++ b/file/test/version_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library file_test; import 'dart:io'; diff --git a/flutter/README.md b/flutter/README.md index ed8b2d2007..b6b7f55d8b 100644 --- a/flutter/README.md +++ b/flutter/README.md @@ -99,7 +99,7 @@ runApp( ); ``` -This adds performance tracing for all `AssetBundle` usages, where the `AssetBundle` is accessed with `DefaultAssetBunlde.of(context)`. +This adds performance tracing for all `AssetBundle` usages, where the `AssetBundle` is accessed with `DefaultAssetBundle.of(context)`. This includes all of Flutters internal access of `AssetBundle`s, like `Image.asset` for example. ##### Tracking HTTP events @@ -127,8 +127,9 @@ Or [try out the Alpha version of the Sentry Dart Plugin](https://github.com/gets #### Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/flutter/) -* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) -* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) diff --git a/flutter/android/build.gradle b/flutter/android/build.gradle index a532cb03f8..89146e73ff 100644 --- a/flutter/android/build.gradle +++ b/flutter/android/build.gradle @@ -22,7 +22,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 33 + compileSdkVersion 34 // Conditional for compatibility with AGP <4.2. if (project.android.hasProperty("namespace")) { @@ -60,7 +60,7 @@ android { } dependencies { - api 'io.sentry:sentry-android:6.33.1' + api 'io.sentry:sentry-android:7.10.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Required -- JUnit 4 framework diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index 962414c6a9..c06a8b0dc2 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -8,12 +8,14 @@ import java.util.Locale class SentryFlutter( private val androidSdk: String, - private val nativeSdk: String + private val nativeSdk: String, ) { - var autoPerformanceTracingEnabled = false - fun updateOptions(options: SentryAndroidOptions, data: Map) { + fun updateOptions( + options: SentryAndroidOptions, + data: Map, + ) { data.getIfNotNull("dsn") { options.dsn = it } @@ -122,7 +124,10 @@ class SentryFlutter( // Call the `completion` closure if cast to map value with `key` and type `T` is successful. @Suppress("UNCHECKED_CAST") -private fun Map.getIfNotNull(key: String, callback: (T) -> Unit) { +private fun Map.getIfNotNull( + key: String, + callback: (T) -> Unit, +) { (get(key) as? T)?.let { callback(it) } diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt index 2ae6a673cb..424e51c6b7 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt @@ -16,22 +16,19 @@ import io.sentry.Hint import io.sentry.HubAdapter import io.sentry.Sentry import io.sentry.SentryEvent -import io.sentry.SentryLevel import io.sentry.SentryOptions import io.sentry.android.core.ActivityFramesTracker -import io.sentry.android.core.AppStartState -import io.sentry.android.core.BuildConfig.VERSION_NAME +import io.sentry.android.core.InternalSentrySdk import io.sentry.android.core.LoadClass import io.sentry.android.core.SentryAndroid import io.sentry.android.core.SentryAndroidOptions +import io.sentry.android.core.performance.AppStartMetrics +import io.sentry.android.core.performance.TimeSpan import io.sentry.protocol.DebugImage import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryId import io.sentry.protocol.User -import java.io.File import java.lang.ref.WeakReference -import java.util.Locale -import java.util.UUID class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { private lateinit var channel: MethodChannel @@ -40,16 +37,20 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { private var activity: WeakReference? = null private var framesTracker: ActivityFramesTracker? = null + private var pluginRegistrationTime: Long? = null override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + pluginRegistrationTime = System.currentTimeMillis() + context = flutterPluginBinding.applicationContext channel = MethodChannel(flutterPluginBinding.binaryMessenger, "sentry_flutter") channel.setMethodCallHandler(this) - sentryFlutter = SentryFlutter( - androidSdk = androidSdk, - nativeSdk = nativeSdk - ) + sentryFlutter = + SentryFlutter( + androidSdk = androidSdk, + nativeSdk = nativeSdk, + ) } override fun onMethodCall(call: MethodCall, result: Result) { @@ -70,6 +71,7 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { "removeExtra" -> removeExtra(call.argument("key"), result) "setTag" -> setTag(call.argument("key"), call.argument("value"), result) "removeTag" -> removeTag(call.argument("key"), result) + "loadContexts" -> loadContexts(result) else -> result.notImplemented() } } @@ -99,18 +101,6 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { // Stub } - private fun writeEnvelope(envelope: ByteArray): Boolean { - val options = HubAdapter.getInstance().options - if (options.outboxPath.isNullOrEmpty()) { - return false - } - - val file = File(options.outboxPath, UUID.randomUUID().toString()) - file.writeBytes(envelope) - - return true - } - private fun initNativeSdk(call: MethodCall, result: Result) { if (!this::context.isInitialized) { result.error("1", "Context is null", null) @@ -140,25 +130,67 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { result.success(null) return } - val appStartTime = AppStartState.getInstance().appStartTime - val isColdStart = AppStartState.getInstance().isColdStart + + val appStartMetrics = AppStartMetrics.getInstance() + + val appStartTimeSpan = appStartMetrics.appStartTimeSpan + val appStartTime = appStartTimeSpan.startTimestamp + val isColdStart = appStartMetrics.appStartType == AppStartMetrics.AppStartType.COLD if (appStartTime == null) { Log.w("Sentry", "App start won't be sent due to missing appStartTime") result.success(null) - } else if (isColdStart == null) { - Log.w("Sentry", "App start won't be sent due to missing isColdStart") - result.success(null) } else { val appStartTimeMillis = DateUtils.nanosToMillis(appStartTime.nanoTimestamp().toDouble()) - val item = mapOf( - "appStartTime" to appStartTimeMillis, - "isColdStart" to isColdStart - ) + val item = + mutableMapOf( + "pluginRegistrationTime" to pluginRegistrationTime, + "appStartTime" to appStartTimeMillis, + "isColdStart" to isColdStart, + ) + + val androidNativeSpans = mutableMapOf() + + val processInitSpan = + TimeSpan().apply { + description = "Process Initialization" + setStartUnixTimeMs(appStartTimeSpan.startTimestampMs) + setStartedAt(appStartTimeSpan.startUptimeMs) + setStoppedAt(appStartMetrics.classLoadedUptimeMs) + } + processInitSpan.addToMap(androidNativeSpans) + + val applicationOnCreateSpan = appStartMetrics.applicationOnCreateTimeSpan + applicationOnCreateSpan.addToMap(androidNativeSpans) + + val contentProviderSpans = appStartMetrics.contentProviderOnCreateTimeSpans + contentProviderSpans.forEach { span -> + span.addToMap(androidNativeSpans) + } + + appStartMetrics.activityLifecycleTimeSpans.forEach { span -> + span.onCreate.addToMap(androidNativeSpans) + span.onStart.addToMap(androidNativeSpans) + } + + item["nativeSpanTimes"] = androidNativeSpans + result.success(item) } } + private fun TimeSpan.addToMap(map: MutableMap) { + if (startTimestamp == null) return + + description?.let { description -> + map[description] = + mapOf( + "startTimestampMsSinceEpoch" to startTimestampMs, + "stopTimestampMsSinceEpoch" to projectedStopTimestampMs, + ) + } + } + private fun beginNativeFrames(result: Result) { if (!sentryFlutter.autoPerformanceTracingEnabled) { result.success(null) @@ -194,7 +226,7 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { val frames = mapOf( "totalFrames" to total, "slowFrames" to slow, - "frozenFrames" to frozen + "frozenFrames" to frozen, ) result.success(frames) } @@ -295,20 +327,19 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { result.error("1", "The Sentry Android SDK is disabled", null) return } - - val args = call.arguments() as List? ?: listOf() + val args = call.arguments() as List? ?: listOf() if (args.isNotEmpty()) { val event = args.first() as ByteArray? - if (event != null && event.isNotEmpty()) { - if (!writeEnvelope(event)) { - result.error("2", "SentryOptions or outboxPath are null or empty", null) + val id = InternalSentrySdk.captureEnvelope(event) + if (id != null) { + result.success("") + } else { + result.error("2", "Failed to capture envelope", null) } - result.success("") return } } - result.error("3", "Envelope is null or empty", null) } @@ -346,7 +377,7 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { } private class BeforeSendCallbackImpl( - private val sdkVersion: SdkVersion? + private val sdkVersion: SdkVersion?, ) : SentryOptions.BeforeSendCallback { override fun execute(event: SentryEvent, hint: Hint): SentryEvent { setEventOriginTag(event) @@ -374,7 +405,7 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { private fun setEventEnvironmentTag( event: SentryEvent, origin: String = "android", - environment: String + environment: String, ) { event.setTag("event.origin", origin) event.setTag("event.environment", environment) @@ -393,4 +424,20 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { } } } + + private fun loadContexts(result: Result) { + val options = HubAdapter.getInstance().options + if (options !is SentryAndroidOptions) { + result.success(null) + return + } + val currentScope = InternalSentrySdk.getCurrentScope() + val serializedScope = + InternalSentrySdk.serializeScope( + context, + options, + currentScope, + ) + result.success(serializedScope) + } } diff --git a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt index 3a5c8678f8..724559bb76 100644 --- a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt +++ b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt @@ -8,7 +8,6 @@ import org.junit.Before import org.junit.Test class SentryFlutterTest { - private lateinit var fixture: Fixture @Before @@ -53,7 +52,7 @@ class SentryFlutterTest { assertEquals(BuildConfig.VERSION_NAME, fixture.options.sdkVersion?.version) assertEquals( "sentry.java.android.flutter/${BuildConfig.VERSION_NAME}", - fixture.options.sentryClientName + fixture.options.sentryClientName, ) assertEquals("fixture-nativeSdk", fixture.options.nativeSdkName) @@ -73,8 +72,8 @@ class SentryFlutterTest { sut.updateOptions( fixture.options, mapOf( - "diagnosticLevel" to "warning" - ) + "diagnosticLevel" to "warning", + ), ) // Then @@ -90,8 +89,8 @@ class SentryFlutterTest { sut.updateOptions( fixture.options, mapOf( - "enableNativeCrashHandling" to false - ) + "enableNativeCrashHandling" to false, + ), ) // Then @@ -101,39 +100,39 @@ class SentryFlutterTest { } class Fixture { - var options = SentryAndroidOptions() - val data = mapOf( - "dsn" to "fixture-dsn", - "debug" to true, - "environment" to "fixture-environment", - "release" to "fixture-release", - "dist" to "fixture-dist", - "enableAutoSessionTracking" to false, - "autoSessionTrackingIntervalMillis" to 9001L, - "anrTimeoutIntervalMillis" to 9002L, - "attachThreads" to true, - "attachStacktrace" to false, - "enableAutoNativeBreadcrumbs" to false, - "maxBreadcrumbs" to 9003, - "maxCacheItems" to 9004, - "anrEnabled" to false, - "sendDefaultPii" to true, - "enableNdkScopeSync" to false, - "proguardUuid" to "fixture-proguardUuid", - "enableNativeCrashHandling" to false, - "sendClientReports" to false, - "maxAttachmentSize" to 9005L, - "enableAutoPerformanceTracing" to true, - "connectionTimeoutMillis" to 9006, - "readTimeoutMillis" to 9007 - ) + val data = + mapOf( + "dsn" to "fixture-dsn", + "debug" to true, + "environment" to "fixture-environment", + "release" to "fixture-release", + "dist" to "fixture-dist", + "enableAutoSessionTracking" to false, + "autoSessionTrackingIntervalMillis" to 9001L, + "anrTimeoutIntervalMillis" to 9002L, + "attachThreads" to true, + "attachStacktrace" to false, + "enableAutoNativeBreadcrumbs" to false, + "maxBreadcrumbs" to 9003, + "maxCacheItems" to 9004, + "anrEnabled" to false, + "sendDefaultPii" to true, + "enableNdkScopeSync" to false, + "proguardUuid" to "fixture-proguardUuid", + "enableNativeCrashHandling" to false, + "sendClientReports" to false, + "maxAttachmentSize" to 9005L, + "enableAutoPerformanceTracing" to true, + "connectionTimeoutMillis" to 9006, + "readTimeoutMillis" to 9007, + ) fun getSut(): SentryFlutter { return SentryFlutter( androidSdk = "sentry.java.android.flutter", - nativeSdk = "fixture-nativeSdk" + nativeSdk = "fixture-nativeSdk", ) } } diff --git a/flutter/config/detekt-bl.xml b/flutter/config/detekt-bl.xml index bf2e55e08b..bfd59bc97e 100644 --- a/flutter/config/detekt-bl.xml +++ b/flutter/config/detekt-bl.xml @@ -2,9 +2,8 @@ - ComplexMethod:SentryFlutterPlugin.kt$SentryFlutterPlugin$override fun onMethodCall(call: MethodCall, result: Result) CyclomaticComplexMethod:SentryFlutterPlugin.kt$SentryFlutterPlugin$override fun onMethodCall(call: MethodCall, result: Result) - LongMethod:SentryFlutter.kt$SentryFlutter$fun updateOptions(options: SentryAndroidOptions, data: Map<String, Any>) + LongMethod:SentryFlutter.kt$SentryFlutter$fun updateOptions( options: SentryAndroidOptions, data: Map<String, Any>, ) MagicNumber:MainActivity.kt$MainActivity$6_000 TooGenericExceptionCaught:MainActivity.kt$MainActivity$e: Exception TooGenericExceptionThrown:MainActivity.kt$MainActivity$throw Exception("Catch this java exception thrown from Kotlin thread!") diff --git a/flutter/example/android/app/build.gradle b/flutter/example/android/app/build.gradle index b54cd7fdf9..e9ac4161a5 100644 --- a/flutter/example/android/app/build.gradle +++ b/flutter/example/android/app/build.gradle @@ -40,7 +40,7 @@ android { languageVersion = "1.4" } - compileSdkVersion 33 + compileSdkVersion 34 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -48,8 +48,8 @@ android { defaultConfig { applicationId "io.sentry.samples.flutter" - minSdkVersion 19 - targetSdkVersion 33 + minSdkVersion flutter.minSdkVersion + targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/flutter/example/android/build.gradle b/flutter/example/android/build.gradle index e628374358..693111bbb3 100644 --- a/flutter/example/android/build.gradle +++ b/flutter/example/android/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'io.sentry:sentry-android-gradle-plugin:3.5.0' + classpath 'io.sentry:sentry-android-gradle-plugin:4.5.0' classpath 'com.android.tools.build:gradle:7.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'io.github.howardpang:androidNativeBundle:1.1.3' @@ -32,4 +32,3 @@ subprojects { tasks.register("clean", Delete) { delete rootProject.buildDir } - diff --git a/flutter/example/integration_test/integration_test.dart b/flutter/example/integration_test/integration_test.dart index c4c71edb41..570b8c1fe2 100644 --- a/flutter/example/integration_test/integration_test.dart +++ b/flutter/example/integration_test/integration_test.dart @@ -1,4 +1,5 @@ // ignore_for_file: avoid_print +// ignore_for_file: invalid_use_of_internal_member import 'dart:async'; import 'dart:convert'; @@ -8,6 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter_example/main.dart'; import 'package:http/http.dart'; +import 'package:sentry_flutter/src/integrations/native_app_start_integration.dart'; void main() { // const org = 'sentry-sdks'; @@ -24,6 +26,8 @@ void main() { // Using fake DSN for testing purposes. Future setupSentryAndApp(WidgetTester tester, {String? dsn, BeforeSendCallback? beforeSendCallback}) async { + NativeAppStartIntegration.isIntegrationTest = true; + await setupSentry( () async { await tester.pumpWidget(SentryScreenshotWidget( @@ -199,7 +203,7 @@ void main() { class Fixture { SentryEvent? sentEvent; - FutureOr beforeSend(SentryEvent event, {Hint? hint}) async { + FutureOr beforeSend(SentryEvent event, Hint hint) async { sentEvent = event; return event; } diff --git a/flutter/example/ios/Flutter/AppFrameworkInfo.plist b/flutter/example/ios/Flutter/AppFrameworkInfo.plist index 1bdf525f9f..b7506dd05b 100644 --- a/flutter/example/ios/Flutter/AppFrameworkInfo.plist +++ b/flutter/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/flutter/example/ios/Gemfile b/flutter/example/ios/Gemfile new file mode 100644 index 0000000000..7a118b49be --- /dev/null +++ b/flutter/example/ios/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/flutter/example/ios/Podfile b/flutter/example/ios/Podfile index 8d38fc9608..8cb4ddb285 100644 --- a/flutter/example/ios/Podfile +++ b/flutter/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -32,19 +32,19 @@ target 'Runner' do use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - + # Configure test target target 'RunnerTests' do inherit! :search_paths end - + end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' end end end diff --git a/flutter/example/ios/Runner.xcodeproj/project.pbxproj b/flutter/example/ios/Runner.xcodeproj/project.pbxproj index 29c58327af..11cb23fc9d 100644 --- a/flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 15A74CDD250075770078F130 /* Buggy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Buggy.h; sourceTree = ""; }; 15A74CDE250075770078F130 /* Buggy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Buggy.m; sourceTree = ""; }; + 247E97BE2BD7CCF100751E38 /* RunnerRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerRelease.entitlements; sourceTree = ""; }; 38199AEAF0F80C193173BC10 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3CEA108DF90E0A3E0A377D59 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; @@ -146,6 +147,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 247E97BE2BD7CCF100751E38 /* RunnerRelease.entitlements */, 15A74CDD250075770078F130 /* Buggy.h */, 15A74CDE250075770078F130 /* Buggy.m */, 97C146FA1CF9000F007C117D /* Main.storyboard */, @@ -221,7 +223,7 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1430; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 92B25CE92A80EB3100884BDF = { @@ -460,7 +462,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -483,6 +485,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -491,7 +494,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.example; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.sample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -518,7 +521,7 @@ MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.example.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.sample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_EMIT_LOC_STRINGS = NO; @@ -547,7 +550,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.2; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.example.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.sample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; @@ -574,7 +577,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 16.2; MARKETING_VERSION = 1.0; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.example.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.sample.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; @@ -631,7 +634,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -681,7 +684,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -706,6 +709,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -714,7 +718,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.example; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.sample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -729,6 +733,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 97JCY7859U; ENABLE_BITCODE = NO; @@ -737,6 +742,7 @@ "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -745,7 +751,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.example; + PRODUCT_BUNDLE_IDENTIFIER = io.sentry.flutter.sample; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 0fa7c24eb1..fee8e19903 100644 --- a/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/flutter/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + ITSAppUsesNonExemptEncryption + + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -22,6 +26,8 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -41,9 +47,5 @@ UIViewControllerBasedStatusBarAppearance - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/flutter/example/ios/Runner/RunnerRelease.entitlements b/flutter/example/ios/Runner/RunnerRelease.entitlements new file mode 100644 index 0000000000..903def2af5 --- /dev/null +++ b/flutter/example/ios/Runner/RunnerRelease.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/flutter/example/ios/fastlane/Appfile b/flutter/example/ios/fastlane/Appfile new file mode 100644 index 0000000000..1f85333eac --- /dev/null +++ b/flutter/example/ios/fastlane/Appfile @@ -0,0 +1,7 @@ +app_identifier("io.sentry.flutter.sample") # The bundle identifier of your app + +itc_team_id("96157806") # App Store Connect Team ID +team_id("97JCY7859U") # Developer Portal Team ID + +# For more information about the Appfile, see: +# https://docs.fastlane.tools/advanced/#appfile diff --git a/flutter/example/ios/fastlane/Fastfile b/flutter/example/ios/fastlane/Fastfile new file mode 100644 index 0000000000..e14ca13d3c --- /dev/null +++ b/flutter/example/ios/fastlane/Fastfile @@ -0,0 +1,95 @@ +default_platform(:ios) + +platform :ios do + + desc "Bump Build Number" + lane :bump_build_number do + fetch_api_key() + + version_string = get_version_number(xcodeproj: "./Runner.xcodeproj") + version_parts = version_string.split(".") + + # Remove last digit if necessary + if version_parts.length > 3 + version_parts.pop + end + + new_version = version_parts.join(".") + + increment_version_number( + version_number: new_version, + xcodeproj: "./Runner.xcodeproj" + ) + increment_build_number( + build_number: latest_testflight_build_number + 1, + xcodeproj: "./Runner.xcodeproj" + ) + end + + desc "Build Release" + lane :build_release do + + setup_ci + + disable_automatic_code_signing + + sync_code_signing( + type: "development", + readonly: true, + app_identifier: ["io.sentry.flutter.sample"] + ) + + sync_code_signing( + type: "appstore", + readonly: true, + app_identifier: ["io.sentry.flutter.sample"] + ) + + update_project_provisioning( + xcodeproj: "Runner.xcodeproj", + target_filter: "Runner", + profile: ENV["sigh_io.sentry.flutter.sample_appstore_profile-path"], + build_configuration: "Release" + ) + + build_app( + workspace: "Runner.xcworkspace", + scheme: "Runner", + configuration: "Release", + clean: true, + include_symbols: true, + export_method: "app-store", + output_directory:"./build/", + export_options: { + method: "app-store", + provisioningProfiles: { + "io.sentry.flutter.sample" => ENV["sigh_io.sentry.flutter.sample_appstore_profile-name"] + } + }, + codesigning_identity: ENV["sigh_io.sentry.flutter.sample_appstore_certificate-name"], + output_name: "sentry_flutter_sample.ipa" + ) + + delete_keychain( + name: "fastlane_tmp_keychain" + ) unless is_ci + end + + desc "Upload to TestFlight" + lane :upload_testflight do + fetch_api_key() + testflight( + skip_waiting_for_build_processing: true, + ipa: "./build/sentry_flutter_sample.ipa" + ) + end + + desc "Fetch ASC API Key" + lane :fetch_api_key do + app_store_connect_api_key( + key_id: ENV["APP_STORE_CONNECT_KEY_ID"], + issuer_id: ENV["APP_STORE_CONNECT_ISSUER_ID"], + key_content: ENV["APP_STORE_CONNECT_KEY"] + ) + end +end diff --git a/flutter/example/ios/fastlane/Matchfile b/flutter/example/ios/fastlane/Matchfile new file mode 100644 index 0000000000..054fef1c37 --- /dev/null +++ b/flutter/example/ios/fastlane/Matchfile @@ -0,0 +1,5 @@ +git_url("git@github.com:getsentry/codesigning.git") +storage_mode("git") +username("bot@getsentry.com") # Your Apple Developer Portal username + +# The docs are available on https://docs.fastlane.tools/actions/match diff --git a/flutter/example/lib/auto_close_screen.dart b/flutter/example/lib/auto_close_screen.dart new file mode 100644 index 0000000000..6848678b4c --- /dev/null +++ b/flutter/example/lib/auto_close_screen.dart @@ -0,0 +1,54 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:sentry_dio/sentry_dio.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + +import 'main.dart'; + +/// This screen is only used to demonstrate how route navigation works. +/// Init will create a child span and pop the screen after 3 seconds. +/// Afterwards the transaction should be seen on the performance page. +class AutoCloseScreen extends StatefulWidget { + const AutoCloseScreen({super.key}); + + @override + AutoCloseScreenState createState() => AutoCloseScreenState(); +} + +class AutoCloseScreenState extends State { + static const delayInSeconds = 3; + + @override + void initState() { + super.initState(); + _doComplexOperationThenClose(); + } + + Future _doComplexOperationThenClose() async { + final dio = Dio(); + dio.addSentry(); + try { + await dio.get(exampleUrl); + } catch (exception, stackTrace) { + await Sentry.captureException(exception, stackTrace: stackTrace); + } + SentryFlutter.reportFullyDisplayed(); + // ignore: use_build_context_synchronously + Navigator.of(context).pop(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Delayed Screen'), + ), + body: const Center( + child: Text( + 'This screen will automatically close in $delayInSeconds seconds...', + textAlign: TextAlign.center, + ), + ), + ); + } +} diff --git a/flutter/example/lib/isar/user.dart b/flutter/example/lib/isar/user.dart new file mode 100644 index 0000000000..f255d2389d --- /dev/null +++ b/flutter/example/lib/isar/user.dart @@ -0,0 +1,12 @@ +import 'package:isar/isar.dart'; + +part 'user.g.dart'; + +@collection +class User { + Id id = Isar.autoIncrement; + + String? name; + + int? age; +} diff --git a/flutter/example/lib/isar/user.g.dart b/flutter/example/lib/isar/user.g.dart new file mode 100644 index 0000000000..c4d7ef985f --- /dev/null +++ b/flutter/example/lib/isar/user.g.dart @@ -0,0 +1,553 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user.dart'; + +// ************************************************************************** +// IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types + +extension GetUserCollection on Isar { + IsarCollection get users => this.collection(); +} + +final UserSchema = CollectionSchema( + name: r'User', + id: BigInt.parse("-7838171048429979076").toInt(), + properties: { + r'age': PropertySchema( + id: BigInt.parse("0").toInt(), + name: r'age', + type: IsarType.long, + ), + r'name': PropertySchema( + id: BigInt.parse("1").toInt(), + name: r'name', + type: IsarType.string, + ) + }, + estimateSize: _userEstimateSize, + serialize: _userSerialize, + deserialize: _userDeserialize, + deserializeProp: _userDeserializeProp, + idName: r'id', + indexes: {}, + links: {}, + embeddedSchemas: {}, + getId: _userGetId, + getLinks: _userGetLinks, + attach: _userAttach, + version: '3.1.0', +); + +int _userEstimateSize( + User object, + List offsets, + Map> allOffsets, +) { + var bytesCount = offsets.last; + { + final value = object.name; + if (value != null) { + bytesCount += 3 + value.length * 3; + } + } + return bytesCount; +} + +void _userSerialize( + User object, + IsarWriter writer, + List offsets, + Map> allOffsets, +) { + writer.writeLong(offsets[0], object.age); + writer.writeString(offsets[1], object.name); +} + +User _userDeserialize( + Id id, + IsarReader reader, + List offsets, + Map> allOffsets, +) { + final object = User(); + object.age = reader.readLongOrNull(offsets[0]); + object.id = id; + object.name = reader.readStringOrNull(offsets[1]); + return object; +} + +P _userDeserializeProp

( + IsarReader reader, + int propertyId, + int offset, + Map> allOffsets, +) { + switch (propertyId) { + case 0: + return (reader.readLongOrNull(offset)) as P; + case 1: + return (reader.readStringOrNull(offset)) as P; + default: + throw IsarError('Unknown property with id $propertyId'); + } +} + +Id _userGetId(User object) { + return object.id; +} + +List> _userGetLinks(User object) { + return []; +} + +void _userAttach(IsarCollection col, Id id, User object) { + object.id = id; +} + +extension UserQueryWhereSort on QueryBuilder { + QueryBuilder anyId() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(const IdWhereClause.any()); + }); + } +} + +extension UserQueryWhere on QueryBuilder { + QueryBuilder idEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: id, + upper: id, + )); + }); + } + + QueryBuilder idNotEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ) + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ); + } else { + return query + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ) + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ); + } + }); + } + + QueryBuilder idGreaterThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: include), + ); + }); + } + + QueryBuilder idLessThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: include), + ); + }); + } + + QueryBuilder idBetween( + Id lowerId, + Id upperId, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + )); + }); + } +} + +extension UserQueryFilter on QueryBuilder { + QueryBuilder ageIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'age', + )); + }); + } + + QueryBuilder ageIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'age', + )); + }); + } + + QueryBuilder ageEqualTo(int? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'age', + value: value, + )); + }); + } + + QueryBuilder ageGreaterThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'age', + value: value, + )); + }); + } + + QueryBuilder ageLessThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'age', + value: value, + )); + }); + } + + QueryBuilder ageBetween( + int? lower, + int? upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'age', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder idEqualTo(Id value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idGreaterThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idLessThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idBetween( + Id lower, + Id upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder nameIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'name', + )); + }); + } + + QueryBuilder nameIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'name', + )); + }); + } + + QueryBuilder nameEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameGreaterThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameLessThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameBetween( + String? lower, + String? upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'name', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameContains(String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameMatches(String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'name', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: '', + )); + }); + } + + QueryBuilder nameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'name', + value: '', + )); + }); + } +} + +extension UserQueryObject on QueryBuilder {} + +extension UserQueryLinks on QueryBuilder {} + +extension UserQuerySortBy on QueryBuilder { + QueryBuilder sortByAge() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.asc); + }); + } + + QueryBuilder sortByAgeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.desc); + }); + } + + QueryBuilder sortByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder sortByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension UserQuerySortThenBy on QueryBuilder { + QueryBuilder thenByAge() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.asc); + }); + } + + QueryBuilder thenByAgeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.desc); + }); + } + + QueryBuilder thenById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.asc); + }); + } + + QueryBuilder thenByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.desc); + }); + } + + QueryBuilder thenByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder thenByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension UserQueryWhereDistinct on QueryBuilder { + QueryBuilder distinctByAge() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'age'); + }); + } + + QueryBuilder distinctByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'name', caseSensitive: caseSensitive); + }); + } +} + +extension UserQueryProperty on QueryBuilder { + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'id'); + }); + } + + QueryBuilder ageProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'age'); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'name'); + }); + } +} diff --git a/flutter/example/lib/main.dart b/flutter/example/lib/main.dart index 8ff567b8cb..86da143e31 100644 --- a/flutter/example/lib/main.dart +++ b/flutter/example/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -10,6 +11,7 @@ import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sentry_drift/sentry_drift.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_isar/sentry_isar.dart'; import 'package:sentry_sqflite/sentry_sqflite.dart'; import 'package:sqflite/sqflite.dart'; @@ -18,8 +20,10 @@ import 'package:sqflite/sqflite.dart'; import 'package:universal_platform/universal_platform.dart'; import 'package:feedback/feedback.dart' as feedback; import 'package:provider/provider.dart'; +import 'auto_close_screen.dart'; import 'drift/database.dart'; import 'drift/connection/connection.dart'; +import 'isar/user.dart'; import 'user_feedback_dialog.dart'; import 'package:dio/dio.dart'; import 'package:sentry_dio/sentry_dio.dart'; @@ -30,59 +34,72 @@ import 'package:sentry_hive/sentry_hive.dart'; const String exampleDsn = 'https://e85b375ffb9f43cf8bdf9787768149e0@o447951.ingest.sentry.io/5428562'; +/// This is an exampleUrl that will be used to demonstrate how http requests are captured. +const String exampleUrl = 'https://jsonplaceholder.typicode.com/todos/'; + const _channel = MethodChannel('example.flutter.sentry.io'); var _isIntegrationTest = false; +final GlobalKey navigatorKey = GlobalKey(); + Future main() async { await setupSentry( - () => runApp( - SentryScreenshotWidget( - child: SentryUserInteractionWidget( - child: DefaultAssetBundle( - bundle: SentryAssetBundle(), - child: const MyApp(), - ), - ), - ), - ), - exampleDsn); + () => runApp( + SentryWidget( + child: DefaultAssetBundle( + bundle: SentryAssetBundle(), + child: const MyApp(), + ), + ), + ), + exampleDsn, + ); } -Future setupSentry(AppRunner appRunner, String dsn, - {bool isIntegrationTest = false, - BeforeSendCallback? beforeSendCallback}) async { - await SentryFlutter.init((options) { - options.dsn = exampleDsn; - options.tracesSampleRate = 1.0; - options.profilesSampleRate = 1.0; - options.reportPackages = false; - options.addInAppInclude('sentry_flutter_example'); - options.considerInAppFramesByDefault = false; - options.attachThreads = true; - options.enableWindowMetricBreadcrumbs = true; - options.addIntegration(LoggingIntegration(minEventLevel: Level.INFO)); - options.sendDefaultPii = true; - options.reportSilentFlutterErrors = true; - options.attachScreenshot = true; - options.screenshotQuality = SentryScreenshotQuality.low; - options.attachViewHierarchy = true; - // We can enable Sentry debug logging during development. This is likely - // going to log too much for your app, but can be useful when figuring out - // configuration issues, e.g. finding out why your events are not uploaded. - options.debug = true; - - options.maxRequestBodySize = MaxRequestBodySize.always; - options.maxResponseBodySize = MaxResponseBodySize.always; - - _isIntegrationTest = isIntegrationTest; - if (_isIntegrationTest) { - options.dist = '1'; - options.environment = 'integration'; - options.beforeSend = beforeSendCallback; - } - }, - // Init your App. - appRunner: appRunner); +Future setupSentry( + AppRunner appRunner, + String dsn, { + bool isIntegrationTest = false, + BeforeSendCallback? beforeSendCallback, +}) async { + await SentryFlutter.init( + (options) { + options.dsn = exampleDsn; + options.tracesSampleRate = 1.0; + options.profilesSampleRate = 1.0; + options.reportPackages = false; + options.addInAppInclude('sentry_flutter_example'); + options.considerInAppFramesByDefault = false; + options.attachThreads = true; + options.enableWindowMetricBreadcrumbs = true; + options.addIntegration(LoggingIntegration(minEventLevel: Level.INFO)); + options.sendDefaultPii = true; + options.reportSilentFlutterErrors = true; + options.attachScreenshot = true; + options.screenshotQuality = SentryScreenshotQuality.low; + options.attachViewHierarchy = true; + // We can enable Sentry debug logging during development. This is likely + // going to log too much for your app, but can be useful when figuring out + // configuration issues, e.g. finding out why your events are not uploaded. + options.debug = true; + options.spotlight = Spotlight(enabled: true); + options.enableTimeToFullDisplayTracing = true; + options.enableMetrics = true; + + options.maxRequestBodySize = MaxRequestBodySize.always; + options.maxResponseBodySize = MaxResponseBodySize.always; + options.navigatorKey = navigatorKey; + + _isIntegrationTest = isIntegrationTest; + if (_isIntegrationTest) { + options.dist = '1'; + options.environment = 'integration'; + options.beforeSend = beforeSendCallback; + } + }, + // Init your App. + appRunner: appRunner, + ); } class MyApp extends StatefulWidget { @@ -100,6 +117,7 @@ class _MyAppState extends State { create: (_) => ThemeProvider(), child: Builder( builder: (context) => MaterialApp( + navigatorKey: navigatorKey, navigatorObservers: [ SentryNavigatorObserver(), ], @@ -112,6 +130,31 @@ class _MyAppState extends State { } } +class TooltipButton extends StatelessWidget { + final String text; + final String buttonTitle; + final void Function()? onPressed; + + const TooltipButton({ + required this.onPressed, + required this.buttonTitle, + required this.text, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Tooltip( + message: text, + child: ElevatedButton( + onPressed: onPressed, + key: key, + child: Text(buttonTitle), + ), + ); + } +} + class MainScaffold extends StatelessWidget { const MainScaffold({ Key? key, @@ -154,97 +197,147 @@ class MainScaffold extends StatelessWidget { child: Column( children: [ if (_isIntegrationTest) const IntegrationTestWidget(), - const Center(child: Text('Trigger an action:\n')), - // For simplicity sake we skip the web set up for now. - if (!UniversalPlatform.isWeb) - ElevatedButton( - onPressed: () => driftTest(), - child: const Text('drift'), + const Center(child: Text('Trigger an action.\n')), + const Padding( + padding: EdgeInsets.all(15), //apply padding to all four sides + child: Center( + child: Text( + 'Long press a button to see more information. (hover on web)'), ), - ElevatedButton( - onPressed: () => hiveTest(), - child: const Text('hive'), ), - ElevatedButton( - onPressed: () => sqfliteTest(), - child: const Text('sqflite'), + TooltipButton( + onPressed: () => navigateToAutoCloseScreen(context), + text: + 'Pushes a screen and creates a transaction named \'AutoCloseScreen\' with a child span that finishes after 3 seconds. \nAfter the screen has popped the transaction can then be seen on the performance page.', + buttonTitle: 'Route Navigation Observer', ), - ElevatedButton( + if (!UniversalPlatform.isWeb) + TooltipButton( + onPressed: driftTest, + text: + 'Executes CRUD operations on an in-memory with Drift and sends the created transaction to Sentry.', + buttonTitle: 'drift', + ), + if (!UniversalPlatform.isWeb) + TooltipButton( + onPressed: hiveTest, + text: + 'Executes CRUD operations on an in-memory with Hive and sends the created transaction to Sentry.', + buttonTitle: 'hive', + ), + if (!UniversalPlatform.isWeb) + TooltipButton( + onPressed: isarTest, + text: + 'Executes CRUD operations on an in-memory with Isart and sends the created transaction to Sentry.', + buttonTitle: 'isar', + ), + TooltipButton( + onPressed: sqfliteTest, + text: + 'Executes CRUD operations on an in-memory with Hive and sends the created transaction to Sentry.', + buttonTitle: 'sqflite', + ), + TooltipButton( onPressed: () => SecondaryScaffold.openSecondaryScaffold(context), - child: const Text('Open another Scaffold'), + text: + 'Demonstrates how the router integration adds a navigation event to the breadcrumbs that can be seen when throwing an exception for example.', + buttonTitle: 'Open another Scaffold', ), - ElevatedButton( - onPressed: () => tryCatch(), - key: const Key('dart_try_catch'), - child: const Text('Dart: try catch'), + const TooltipButton( + onPressed: tryCatch, + key: Key('dart_try_catch'), + text: 'Creates a caught exception and sends it to Sentry.', + buttonTitle: 'Dart: try catch', ), - ElevatedButton( - onPressed: () => Scaffold.of(context).showBottomSheet( - (context) => const Text('Scaffold error'), - ), - child: const Text('Flutter error : Scaffold.of()'), + TooltipButton( + onPressed: () => Scaffold.of(context) + .showBottomSheet((context) => const Text('Scaffold error')), + text: + 'Creates an uncaught exception and sends it to Sentry. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Flutter error : Scaffold.of()', ), - ElevatedButton( + TooltipButton( // Warning : not captured if a debugger is attached // https://github.com/flutter/flutter/issues/48972 onPressed: () => throw Exception('Throws onPressed'), - child: const Text('Dart: throw onPressed'), + text: + 'Creates an uncaught exception and sends it to Sentry. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Dart: throw onPressed', ), - ElevatedButton( + TooltipButton( + // Warning : not captured if a debugger is attached + // https://github.com/flutter/flutter/issues/48972 onPressed: () { - // Only relevant in debug builds - // Warning : not captured if a debugger is attached - // https://github.com/flutter/flutter/issues/48972 assert(false, 'assert failure'); }, - child: const Text('Dart: assert'), + text: + 'Creates an uncaught exception and sends it to Sentry. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Dart: assert', ), // Calling the SDK with an appRunner will handle errors from Futures // in SDKs runZonedGuarded onError handler - ElevatedButton( + TooltipButton( onPressed: () async => asyncThrows(), - child: const Text('Dart: async throws'), + text: + 'Creates an async uncaught exception and sends it to Sentry. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Dart: async throws', ), - ElevatedButton( + TooltipButton( onPressed: () async => { await Future.microtask( () => throw StateError('Failure in a microtask'), ) }, - child: const Text('Dart: Fail in microtask.'), + text: + 'Creates an uncaught exception in a microtask and sends it to Sentry. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Dart: Fail in microtask', ), - ElevatedButton( - onPressed: () async => {await compute(loop, 10)}, - child: const Text('Dart: Fail in compute'), + TooltipButton( + onPressed: () async => { + await compute(loop, 10), + }, + text: + 'Creates an uncaught exception in a compute isolate and sends it to Sentry. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Dart: Fail in compute', ), - ElevatedButton( - onPressed: () => Future.delayed( - const Duration(milliseconds: 100), - () => throw Exception('Throws in Future.delayed'), - ), - child: const Text('Throws in Future.delayed'), + TooltipButton( + onPressed: () async => { + await Future.delayed( + const Duration(milliseconds: 100), + () => throw StateError('Failure in a Future.delayed'), + ), + }, + text: + 'Creates an uncaught exception in a Future.delayed and sends it to Sentry. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Throws in Future.delayed', ), - ElevatedButton( + TooltipButton( onPressed: () { // modeled after a real exception - FlutterError.onError?.call(FlutterErrorDetails( - exception: Exception('A really bad exception'), - silent: false, - context: DiagnosticsNode.message('while handling a gesture'), - library: 'gesture', - informationCollector: () => [ - DiagnosticsNode.message( - 'Handler: "onTap" Recognizer: TapGestureRecognizer'), - DiagnosticsNode.message( - 'Handler: "onTap" Recognizer: TapGestureRecognizer'), - DiagnosticsNode.message( - 'Handler: "onTap" Recognizer: TapGestureRecognizer'), - ], - )); + FlutterError.onError?.call( + FlutterErrorDetails( + exception: Exception('A really bad exception'), + silent: false, + context: + DiagnosticsNode.message('while handling a gesture'), + library: 'gesture', + informationCollector: () => [ + DiagnosticsNode.message( + 'Handler: "onTap" Recognizer: TapGestureRecognizer'), + DiagnosticsNode.message( + 'Handler: "onTap" Recognizer: TapGestureRecognizer'), + DiagnosticsNode.message( + 'Handler: "onTap" Recognizer: TapGestureRecognizer'), + ], + ), + ); }, - child: const Text('Capture from FlutterError.onError'), + text: + 'Creates a FlutterError and passes it to FlutterError.onError callback. This demonstrates how our flutter error integration catches unhandled exceptions.', + buttonTitle: 'Capture from FlutterError.onError', ), - ElevatedButton( + TooltipButton( onPressed: () { // Only usable on Flutter >= 3.3 // and needs the following additional setup: @@ -256,41 +349,41 @@ class MainScaffold extends StatelessWidget { StackTrace.current, ); }, - child: const Text('Capture from PlatformDispatcher.onError'), - ), - ElevatedButton( - key: const Key('view hierarchy'), - onPressed: () => {}, - child: const Visibility( - visible: true, - child: Opacity( - opacity: 0.5, - child: Text('view hierarchy'), - ), - ), + text: + 'This is only usable on Flutter >= 3.3 and requires additional setup: options.addIntegration(OnErrorIntegration());', + buttonTitle: 'Capture from PlatformDispatcher.onError', ), - ElevatedButton( + TooltipButton( onPressed: () => makeWebRequest(context), - child: const Text('Dart: Web request'), + text: + 'Attaches web request related spans to the transaction and send it to Sentry.', + buttonTitle: 'Dart: Web request', ), - ElevatedButton( - onPressed: () => showDialogWithTextAndImage(context), - child: const Text('Flutter: Load assets'), - ), - ElevatedButton( + TooltipButton( + onPressed: () => makeWebRequestWithDio(context), key: const Key('dio_web_request'), - onPressed: () async => await makeWebRequestWithDio(context), - child: const Text('Dio: Web request'), + text: + 'Attaches web request related spans to the transaction and send it to Sentry.', + buttonTitle: 'Dio: Web request', + ), + + TooltipButton( + onPressed: () => showDialogWithTextAndImage(context), + text: + 'Attaches asset bundle related spans to the transaction and send it to Sentry.', + buttonTitle: 'Flutter: Load assets', ), - ElevatedButton( + TooltipButton( onPressed: () { // ignore: avoid_print print('A print breadcrumb'); Sentry.captureMessage('A message with a print() Breadcrumb'); }, - child: const Text('Record print() as breadcrumb'), + text: + 'Sends a captureMessage to Sentry with a breadcrumb created by a print() statement.', + buttonTitle: 'Record print() as breadcrumb', ), - ElevatedButton( + TooltipButton( onPressed: () { Sentry.captureMessage( 'This event has an extra tag', @@ -299,10 +392,11 @@ class MainScaffold extends StatelessWidget { }, ); }, - child: - const Text('Capture message with scope with additional tag'), + text: + 'Sends the capture message event with additional Tag to Sentry.', + buttonTitle: 'Capture message with scope with additional tag', ), - ElevatedButton( + TooltipButton( onPressed: () async { final transaction = Sentry.getSpan() ?? Sentry.startTransaction( @@ -347,9 +441,11 @@ class MainScaffold extends StatelessWidget { // findPrimeNumber(1000000); // Uncomment to see it with profiling await transaction.finish(status: const SpanStatus.ok()); }, - child: const Text('Capture transaction'), + text: + 'Creates a custom transaction, adds child spans and send them to Sentry.', + buttonTitle: 'Capture transaction', ), - ElevatedButton( + TooltipButton( onPressed: () { Sentry.captureMessage( 'This message has an attachment', @@ -365,43 +461,42 @@ class MainScaffold extends StatelessWidget { }, ); }, - child: const Text('Capture message with attachment'), + text: 'Sends the capture message with an attachment to Sentry.', + buttonTitle: 'Capture message with attachment', ), - ElevatedButton( + TooltipButton( onPressed: () { - feedback.BetterFeedback.of(context) - .show((feedback.UserFeedback feedback) { - Sentry.captureMessage( - feedback.text, - withScope: (scope) { - final entries = feedback.extra?.entries; - if (entries != null) { - for (final extra in entries) { - scope.setExtra(extra.key, extra.value); + feedback.BetterFeedback.of(context).show( + (feedback.UserFeedback feedback) { + Sentry.captureMessage( + feedback.text, + withScope: (scope) { + final entries = feedback.extra?.entries; + if (entries != null) { + for (final extra in entries) { + scope.setExtra(extra.key, extra.value); + } } - } - scope.addAttachment( - SentryAttachment.fromUint8List( - feedback.screenshot, - 'feedback.png', - contentType: 'image/png', - ), - ); - }, - ); - }); + scope.addAttachment( + SentryAttachment.fromUint8List( + feedback.screenshot, + 'feedback.png', + contentType: 'image/png', + ), + ); + }, + ); + }, + ); }, - child: const Text('Capture message with image attachment'), + text: + 'Sends the capture message with an image attachment to Sentry.', + buttonTitle: 'Capture message with image attachment', ), - ElevatedButton( + TooltipButton( onPressed: () async { final id = await Sentry.captureMessage('UserFeedback'); - // ignore: use_build_context_synchronously - if (!context.isMounted) { - return; - } - - // ignore: use_build_context_synchronously + if (!context.mounted) return; await showDialog( context: context, builder: (context) { @@ -409,9 +504,11 @@ class MainScaffold extends StatelessWidget { }, ); }, - child: const Text('Capture User Feedback'), + text: + 'Shows a custom user feedback dialog without an ongoing event that captures and sends user feedback data to Sentry.', + buttonTitle: 'Capture User Feedback', ), - ElevatedButton( + TooltipButton( onPressed: () async { await showDialog( context: context, @@ -420,29 +517,97 @@ class MainScaffold extends StatelessWidget { }, ); }, - child: const Text('Show UserFeedback Dialog without event'), + text: '', + buttonTitle: 'Show UserFeedback Dialog without event', ), - ElevatedButton( + TooltipButton( onPressed: () { final log = Logger('Logging'); log.info('My Logging test'); }, - child: const Text('Logging'), + text: + 'Demonstrates the logging integration. log.info() will create an info event send it to Sentry.', + buttonTitle: 'Logging', + ), + TooltipButton( + onPressed: () async { + final span = Sentry.getSpan() ?? + Sentry.startTransaction( + 'testMetrics', 'span summary example', + bindToScope: true); + Sentry.metrics().increment('increment key', + unit: DurationSentryMeasurementUnit.day); + Sentry.metrics().distribution('distribution key', + value: Random().nextDouble() * 10); + Sentry.metrics().set('set int key', + value: Random().nextInt(100), + tags: {'myTag': 'myValue', 'myTag2': 'myValue2'}); + Sentry.metrics().set('set string key', + stringValue: 'Random n ${Random().nextInt(100)}'); + Sentry.metrics() + .gauge('gauge key', value: Random().nextDouble() * 10); + Sentry.metrics().timing( + 'timing key', + function: () async => await Future.delayed( + Duration(milliseconds: Random().nextInt(100)), + () => span.finish()), + unit: DurationSentryMeasurementUnit.milliSecond, + ); + }, + text: + 'Demonstrates the metrics. It creates several metrics and send them to Sentry.', + buttonTitle: 'Metrics', ), if (UniversalPlatform.isIOS || UniversalPlatform.isMacOS) const CocoaExample(), if (UniversalPlatform.isAndroid) const AndroidExample(), - ], + ].map((widget) { + if (kIsWeb) { + // Add vertical padding to web so the tooltip doesn't obstruct the clicking of the button below. + return Padding( + padding: const EdgeInsets.only(top: 18.0, bottom: 18.0), + child: widget, + ); + } + return widget; + }).toList(), ), ), ); } - Future hiveTest() async { - if (kIsWeb) { - return; - } + Future isarTest() async { + final tr = Sentry.startTransaction( + 'isarTest', + 'db', + bindToScope: true, + ); + + final dir = await getApplicationDocumentsDirectory(); + + final isar = await SentryIsar.open( + [UserSchema], + directory: dir.path, + ); + + final newUser = User() + ..name = 'Joe Dirt' + ..age = 36; + + await isar.writeTxn(() async { + await isar.users.put(newUser); // insert & update + }); + + final existingUser = await isar.users.get(newUser.id); // get + + await isar.writeTxn(() async { + await isar.users.delete(existingUser!.id); // delete + }); + + await tr.finish(status: const SpanStatus.ok()); + } + Future hiveTest() async { final tr = Sentry.startTransaction( 'hiveTest', 'db', @@ -596,6 +761,16 @@ class AndroidExample extends StatelessWidget { } } +void navigateToAutoCloseScreen(BuildContext context) { + Navigator.push( + context, + MaterialPageRoute( + settings: const RouteSettings(name: 'AutoCloseScreen'), + builder: (context) => SentryDisplayWidget(child: const AutoCloseScreen()), + ), + ); +} + Future tryCatch() async { try { throw StateError('try catch'); @@ -625,18 +800,20 @@ class _IntegrationTestWidgetState extends State { @override Widget build(BuildContext context) { - return Column(children: [ - Text( - _output, - key: const Key('output'), - ), - _isLoading - ? const CircularProgressIndicator() - : ElevatedButton( - onPressed: () async => await _captureException(), - child: const Text('captureException'), - ) - ]); + return Column( + children: [ + Text( + _output, + key: const Key('output'), + ), + _isLoading + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: () async => await _captureException(), + child: const Text('captureException'), + ) + ], + ); } Future _captureException() async { @@ -769,22 +946,13 @@ Future makeWebRequest(BuildContext context) async { ); // We don't do any exception handling here. // In case of an exception, let it get caught and reported to Sentry - final response = await client.get(Uri.parse('https://flutter.dev/')); + final response = await client.get(Uri.parse(exampleUrl)); await transaction.finish(status: const SpanStatus.ok()); - // ignore: use_build_context_synchronously - if (!context.isMounted) { - return; - } - - // ignore: use_build_context_synchronously + if (!context.mounted) return; await showDialog( context: context, - // gets tracked if using SentryNavigatorObserver - routeSettings: const RouteSettings( - name: 'flutter.dev dialog', - ), builder: (context) { return AlertDialog( title: Text('Response ${response.statusCode}'), @@ -818,7 +986,7 @@ Future makeWebRequestWithDio(BuildContext context) async { ); Response? response; try { - response = await dio.get('https://flutter.dev/'); + response = await dio.get(exampleUrl); span.status = const SpanStatus.ok(); } catch (exception, stackTrace) { span.throwable = exception; @@ -828,18 +996,9 @@ Future makeWebRequestWithDio(BuildContext context) async { await span.finish(); } - // ignore: use_build_context_synchronously - if (!context.isMounted) { - return; - } - - // ignore: use_build_context_synchronously + if (!context.mounted) return; await showDialog( context: context, - // gets tracked if using SentryNavigatorObserver - routeSettings: const RouteSettings( - name: 'flutter.dev dialog', - ), builder: (context) { return AlertDialog( title: Text('Response ${response?.statusCode}'), @@ -867,12 +1026,7 @@ Future showDialogWithTextAndImage(BuildContext context) async { final text = await DefaultAssetBundle.of(context).loadString('assets/lorem-ipsum.txt'); - // ignore: use_build_context_synchronously - if (!context.isMounted) { - return; - } - - // ignore: use_build_context_synchronously + if (!context.mounted) return; await showDialog( context: context, // gets tracked if using SentryNavigatorObserver diff --git a/flutter/example/pubspec.yaml b/flutter/example/pubspec.yaml index aa5c959aa3..1f53f5d1c3 100644 --- a/flutter/example/pubspec.yaml +++ b/flutter/example/pubspec.yaml @@ -1,6 +1,6 @@ name: sentry_flutter_example description: Demonstrates how to use the sentry_flutter plugin. -version: 7.13.1 +version: 8.3.0 publish_to: 'none' # Remove this line if you wish to publish to pub.dev @@ -19,6 +19,7 @@ dependencies: sentry_file: sentry_hive: sentry_drift: + sentry_isar: universal_platform: ^1.0.0 feedback: ^2.0.0 provider: ^6.0.0 @@ -26,6 +27,7 @@ dependencies: sqflite: any # This gets constrained by `sentry_sqflite` logging: any # This gets constrained by `sentry_logging` drift: any # This gets constrained by `sentry_drift` + isar: any # This gets constrained by `sentry_isar` package_info_plus: ^4.0.0 path_provider: ^2.0.0 #sqflite_common_ffi: ^2.0.0 @@ -42,6 +44,7 @@ dev_dependencies: flutter_test: sdk: flutter test: ^1.21.1 + build_runner: any flutter: uses-material-design: true diff --git a/flutter/example/pubspec_overrides.yaml b/flutter/example/pubspec_overrides.yaml index 4a3bb3c8cc..a392cc626d 100644 --- a/flutter/example/pubspec_overrides.yaml +++ b/flutter/example/pubspec_overrides.yaml @@ -15,3 +15,5 @@ dependency_overrides: path: ../../hive sentry_drift: path: ../../drift + sentry_isar: + path: ../../isar diff --git a/flutter/example/run.sh b/flutter/example/run.sh index d40bc89df2..025a6f31b4 100755 --- a/flutter/example/run.sh +++ b/flutter/example/run.sh @@ -6,7 +6,10 @@ set -euo pipefail # Or try out the Alpha version of the Sentry Dart Plugin that does it automatically for you, feedback is welcomed. # https://github.com/getsentry/sentry-dart-plugin -export SENTRY_RELEASE=$(date +%Y-%m-%d_%H-%M-%S) +VERSION=$(grep '^version:' pubspec.yaml | awk '{print $2}') +CURRENT_DATE=$(date +%Y-%m-%d_%H-%M-%S) + +export SENTRY_RELEASE="$CURRENT_DATE"@"$VERSION" echo -e "[\033[92mrun\033[0m] $1" @@ -23,7 +26,7 @@ elif [ "$1" == "android" ]; then launchCmd='adb shell am start -n io.sentry.samples.flutter/io.sentry.samples.flutter.MainActivity' echo -e "[\033[92mrun\033[0m] Android app installed" elif [ "$1" == "web" ]; then - flutter build web --dart-define=SENTRY_RELEASE=$SENTRY_RELEASE --source-maps + flutter build web --dart-define=SENTRY_RELEASE="$SENTRY_RELEASE" --source-maps buildDir='./build/web/' port='8132' ls -lah $buildDir diff --git a/flutter/ffi-cocoa.yaml b/flutter/ffi-cocoa.yaml index d680be1189..c27c5a882a 100644 --- a/flutter/ffi-cocoa.yaml +++ b/flutter/ffi-cocoa.yaml @@ -5,7 +5,7 @@ output: lib/src/native/cocoa/binding.dart headers: entry-points: - ./cocoa_bindings_temp/Sentry.framework/Versions/A/PrivateHeaders/PrivateSentrySDKOnly.h - - ./cocoa_bindings_temp/Sentry.framework/Versions/A/Headers/SentryId.h + - ./cocoa_bindings_temp/Sentry.framework/Versions/A/Headers/Sentry-Swift.h compiler-opts: - -DSENTRY_TARGET_PROFILING_SUPPORTED=1 - -DCOCOAPODS=1 @@ -16,3 +16,5 @@ objc-interfaces: include: - PrivateSentrySDKOnly - SentryId + module: + 'SentryId': 'Sentry' diff --git a/flutter/ios/Classes/SentryFlutter.swift b/flutter/ios/Classes/SentryFlutter.swift index f3815455fe..b26bcfc30d 100644 --- a/flutter/ios/Classes/SentryFlutter.swift +++ b/flutter/ios/Classes/SentryFlutter.swift @@ -58,6 +58,9 @@ public final class SentryFlutter { if let maxAttachmentSize = data["maxAttachmentSize"] as? NSNumber { options.maxAttachmentSize = maxAttachmentSize.uintValue } + if let recordHttpBreadcrumbs = data["recordHttpBreadcrumbs"] as? Bool { + options.enableNetworkBreadcrumbs = recordHttpBreadcrumbs + } if let captureFailedRequests = data["captureFailedRequests"] as? Bool { options.enableCaptureFailedRequests = captureFailedRequests } diff --git a/flutter/ios/Classes/SentryFlutterPluginApple.swift b/flutter/ios/Classes/SentryFlutterPluginApple.swift index be5e301791..fc8fb42f9c 100644 --- a/flutter/ios/Classes/SentryFlutterPluginApple.swift +++ b/flutter/ios/Classes/SentryFlutterPluginApple.swift @@ -26,7 +26,11 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { #endif } + private static var pluginRegistrationTime: Int64 = 0 + public static func register(with registrar: FlutterPluginRegistrar) { + pluginRegistrationTime = Int64(Date().timeIntervalSince1970 * 1000) + #if os(iOS) let channel = FlutterMethodChannel(name: "sentry_flutter", binaryMessenger: registrar.messenger()) #elseif os(macOS) @@ -375,6 +379,19 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { return } + struct TimeSpan { + var startTimestampMsSinceEpoch: NSNumber + var stopTimestampMsSinceEpoch: NSNumber + var description: String + + func addToMap(_ map: inout [String: Any]) { + map[description] = [ + "startTimestampMsSinceEpoch": startTimestampMsSinceEpoch, + "stopTimestampMsSinceEpoch": stopTimestampMsSinceEpoch + ] + } + } + private func fetchNativeAppStart(result: @escaping FlutterResult) { #if os(iOS) || os(tvOS) guard let appStartMeasurement = PrivateSentrySDKOnly.appStartMeasurement else { @@ -383,12 +400,53 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { return } + var nativeSpanTimes: [String: Any] = [:] + + let appStartTimeMs = appStartMeasurement.appStartTimestamp.timeIntervalSince1970.toMilliseconds() + let runtimeInitTimeMs = appStartMeasurement.runtimeInitTimestamp.timeIntervalSince1970.toMilliseconds() + let moduleInitializationTimeMs = + appStartMeasurement.moduleInitializationTimestamp.timeIntervalSince1970.toMilliseconds() + let sdkStartTimeMs = appStartMeasurement.sdkStartTimestamp.timeIntervalSince1970.toMilliseconds() + + if !appStartMeasurement.isPreWarmed { + let preRuntimeInitDescription = "Pre Runtime Init" + let preRuntimeInitSpan = TimeSpan( + startTimestampMsSinceEpoch: NSNumber(value: appStartTimeMs), + stopTimestampMsSinceEpoch: NSNumber(value: runtimeInitTimeMs), + description: preRuntimeInitDescription + ) + preRuntimeInitSpan.addToMap(&nativeSpanTimes) + + let moduleInitializationDescription = "Runtime init to Pre Main initializers" + let moduleInitializationSpan = TimeSpan( + startTimestampMsSinceEpoch: NSNumber(value: runtimeInitTimeMs), + stopTimestampMsSinceEpoch: NSNumber(value: moduleInitializationTimeMs), + description: moduleInitializationDescription + ) + moduleInitializationSpan.addToMap(&nativeSpanTimes) + } + + let uiKitInitDescription = "UIKit init" + let uiKitInitSpan = TimeSpan( + startTimestampMsSinceEpoch: NSNumber(value: moduleInitializationTimeMs), + stopTimestampMsSinceEpoch: NSNumber(value: sdkStartTimeMs), + description: uiKitInitDescription + ) + uiKitInitSpan.addToMap(&nativeSpanTimes) + + // Info: We don't have access to didFinishLaunchingTimestamp, + // On HybridSDKs, the Cocoa SDK misses the didFinishLaunchNotification and the + // didBecomeVisibleNotification. Therefore, we can't set the + // didFinishLaunchingTimestamp + let appStartTime = appStartMeasurement.appStartTimestamp.timeIntervalSince1970 * 1000 let isColdStart = appStartMeasurement.type == .cold let item: [String: Any] = [ + "pluginRegistrationTime": SentryFlutterPluginApple.pluginRegistrationTime, "appStartTime": appStartTime, - "isColdStart": isColdStart + "isColdStart": isColdStart, + "nativeSpanTimes": nativeSpanTimes ] result(item) @@ -430,10 +488,9 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { } let currentFrames = PrivateSentrySDKOnly.currentScreenFrames - - let total = currentFrames.total - totalFrames - let frozen = currentFrames.frozen - frozenFrames - let slow = currentFrames.slow - slowFrames + let total = max(Int(currentFrames.total) - Int(totalFrames), 0) + let frozen = max(Int(currentFrames.frozen) - Int(frozenFrames), 0) + let slow = max(Int(currentFrames.slow) - Int(slowFrames), 0) if total <= 0 && frozen <= 0 && slow <= 0 { result(nil) @@ -597,3 +654,9 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { } // swiftlint:enable function_body_length + +private extension TimeInterval { + func toMilliseconds() -> Int64 { + return Int64(self * 1000) + } +} diff --git a/flutter/ios/sentry_flutter.podspec b/flutter/ios/sentry_flutter.podspec index a309f686b6..bd76cc2f2f 100644 --- a/flutter/ios/sentry_flutter.podspec +++ b/flutter/ios/sentry_flutter.podspec @@ -1,6 +1,10 @@ +require 'yaml' +pubspec = YAML.load_file('./../pubspec.yaml') +version = pubspec['version'].to_s + Pod::Spec.new do |s| s.name = 'sentry_flutter' - s.version = '0.0.1' + s.version = version s.summary = 'Sentry SDK for Flutter.' s.description = <<-DESC Sentry SDK for Flutter with support to native through sentry-cocoa. @@ -12,10 +16,10 @@ Sentry SDK for Flutter with support to native through sentry-cocoa. :tag => s.version.to_s } s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' - s.dependency 'Sentry/HybridSDK', '8.15.2' + s.dependency 'Sentry/HybridSDK', '8.29.0' s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' - s.ios.deployment_target = '11.0' + s.ios.deployment_target = '12.0' # Flutter 3.7 requires 10.14 s.osx.deployment_target = '10.13' diff --git a/flutter/lib/sentry_flutter.dart b/flutter/lib/sentry_flutter.dart index c30ca1f5ad..d15c8b7a70 100644 --- a/flutter/lib/sentry_flutter.dart +++ b/flutter/lib/sentry_flutter.dart @@ -1,5 +1,7 @@ -// ignore: invalid_export_of_internal_element /// A Flutter client for Sentry.io crash reporting. +library sentry_flutter; + +// ignore: invalid_export_of_internal_element export 'package:sentry/sentry.dart'; export 'src/integrations/load_release_integration.dart'; @@ -13,3 +15,5 @@ export 'src/screenshot/sentry_screenshot_widget.dart'; export 'src/screenshot/sentry_screenshot_quality.dart'; export 'src/user_interaction/sentry_user_interaction_widget.dart'; export 'src/binding_wrapper.dart'; +export 'src/sentry_widget.dart'; +export 'src/navigation/sentry_display_widget.dart'; diff --git a/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart b/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart index c784f5b221..d939f4b90e 100644 --- a/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart +++ b/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart @@ -16,13 +16,13 @@ class AndroidPlatformExceptionEventProcessor implements EventProcessor { final SentryFlutterOptions _options; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { if (event is SentryTransaction) { return event; } - final plaformException = event.throwable; - if (plaformException is! PlatformException) { + final platformException = event.throwable; + if (platformException is! PlatformException) { return event; } @@ -31,18 +31,24 @@ class AndroidPlatformExceptionEventProcessor implements EventProcessor { final packageInfo = await PackageInfo.fromPlatform(); final nativeStackTrace = - _tryParse(plaformException.stacktrace, packageInfo.packageName); - final messageStackTrace = - _tryParse(plaformException.message, packageInfo.packageName); + _tryParse(platformException.stacktrace, packageInfo.packageName); - if (nativeStackTrace == null && messageStackTrace == null) { + final details = platformException.details; + String? detailsString; + if (details is String) { + detailsString = details; + } + final detailsStackTrace = + _tryParse(detailsString, packageInfo.packageName); + + if (nativeStackTrace == null && detailsStackTrace == null) { return event; } return _processPlatformException( event, nativeStackTrace, - messageStackTrace, + detailsStackTrace, ); } catch (e, stackTrace) { _options.logger( @@ -71,18 +77,18 @@ class AndroidPlatformExceptionEventProcessor implements EventProcessor { SentryEvent _processPlatformException( SentryEvent event, List>? nativeStackTrace, - List>? messageStackTrace, + List>? detailsStackTrace, ) { final threads = _markDartThreadsAsNonCrashed(event.threads); final jvmExceptions = [ ...?nativeStackTrace?.map((e) => e.key), - ...?messageStackTrace?.map((e) => e.key) + ...?detailsStackTrace?.map((e) => e.key) ]; var jvmThreads = [ ...?nativeStackTrace?.map((e) => e.value), - ...?messageStackTrace?.map((e) => e.value), + ...?detailsStackTrace?.map((e) => e.value), ]; if (jvmThreads.isNotEmpty) { @@ -153,11 +159,14 @@ extension on JvmException { String? module; final typeParts = type?.split('.'); if (typeParts != null) { - if (typeParts.length > 1) { + if (typeParts.isNotEmpty) { exceptionType = typeParts.last; } typeParts.remove(typeParts.last); - module = typeParts.join('.'); + + if (typeParts.isNotEmpty) { + module = typeParts.join('.'); + } } final stackFrames = stackTrace.asMap().entries.map((entry) { return entry.value.toSentryStackFrame(entry.key, nativePackageName); diff --git a/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart b/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart index a4d04573a6..0ea1b731d6 100644 --- a/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart +++ b/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart @@ -32,9 +32,9 @@ class FlutterEnricherEventProcessor implements EventProcessor { @override Future apply( - SentryEvent event, { - Hint? hint, - }) async { + SentryEvent event, + Hint hint, + ) async { // If there's a native integration available, it probably has better // information available than Flutter. final device = @@ -153,6 +153,7 @@ class FlutterEnricherEventProcessor implements EventProcessor { // See https://github.com/flutter/flutter/issues/83919 // 'window_is_visible': _window.viewConfiguration.visible, if (renderer != null) 'renderer': renderer, + if (_appFlavor != null) 'appFlavor': _appFlavor!, }; } @@ -266,3 +267,10 @@ class FlutterEnricherEventProcessor implements EventProcessor { return null; } } + +/// Copied from https://api.flutter.dev/flutter/services/appFlavor-constant.html +/// As soon as Flutter 3.16 is the minimal supported version of Sentry, this +/// can be replaced with the property from the link above. +const String? _appFlavor = String.fromEnvironment('FLUTTER_APP_FLAVOR') != '' + ? String.fromEnvironment('FLUTTER_APP_FLAVOR') + : null; diff --git a/flutter/lib/src/event_processor/flutter_exception_event_processor.dart b/flutter/lib/src/event_processor/flutter_exception_event_processor.dart index e0f4b6af14..05f9fd6595 100644 --- a/flutter/lib/src/event_processor/flutter_exception_event_processor.dart +++ b/flutter/lib/src/event_processor/flutter_exception_event_processor.dart @@ -3,7 +3,7 @@ import 'package:sentry/sentry.dart'; class FlutterExceptionEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/flutter/lib/src/event_processor/native_app_start_event_processor.dart b/flutter/lib/src/event_processor/native_app_start_event_processor.dart index a7abe62e05..f8ea23b265 100644 --- a/flutter/lib/src/event_processor/native_app_start_event_processor.dart +++ b/flutter/lib/src/event_processor/native_app_start_event_processor.dart @@ -1,58 +1,155 @@ -import 'dart:async'; +// ignore_for_file: invalid_use_of_internal_member -import 'package:sentry/sentry.dart'; +import 'dart:async'; +import '../../sentry_flutter.dart'; +import '../integrations/integrations.dart'; import '../native/sentry_native.dart'; +// ignore: implementation_imports +import 'package:sentry/src/sentry_tracer.dart'; + /// EventProcessor that enriches [SentryTransaction] objects with app start /// measurement. class NativeAppStartEventProcessor implements EventProcessor { - /// We filter out App starts more than 60s - static const _maxAppStartMillis = 60000; + final SentryNative _native; + final Hub _hub; NativeAppStartEventProcessor( - this._native, - ); - - final SentryNative _native; + this._native, { + Hub? hub, + }) : _hub = hub ?? HubAdapter(); @override - Future apply(SentryEvent event, {Hint? hint}) async { - final appStartEnd = _native.appStartEnd; + Future apply(SentryEvent event, Hint hint) async { + final options = _hub.options; + if (_native.didAddAppStartMeasurement || + event is! SentryTransaction || + options is! SentryFlutterOptions) { + return event; + } - if (appStartEnd != null && - event is SentryTransaction && - !_native.didFetchAppStart) { - final nativeAppStart = await _native.fetchNativeAppStart(); - if (nativeAppStart == null) { - return event; - } - final measurement = nativeAppStart.toMeasurement(appStartEnd); - // We filter out app start more than 60s. - // This could be due to many different reasons. - // If you do the manual init and init the SDK too late and it does not - // compute the app start end in the very first Screen. - // If the process starts but the App isn't in the foreground. - // If the system forked the process earlier to accelerate the app start. - // And some unknown reasons that could not be reproduced. - // We've seen app starts with hours, days and even months. - if (measurement.value >= _maxAppStartMillis) { + final appStartInfo = await NativeAppStartIntegration.getAppStartInfo(); + + final appStartEnd = _native.appStartEnd; + if (!options.autoAppStart) { + if (appStartEnd != null) { + appStartInfo?.end = appStartEnd; + } else { + // If autoAppStart is disabled and appStartEnd is not set, we can't add app starts return event; } + } + + final measurement = appStartInfo?.toMeasurement(); + if (measurement != null) { event.measurements[measurement.name] = measurement; + _native.didAddAppStartMeasurement = true; } + + if (appStartInfo != null) { + await _attachAppStartSpans(appStartInfo, event.tracer); + } + return event; } -} -extension NativeAppStartMeasurement on NativeAppStart { - SentryMeasurement toMeasurement(DateTime appStartEnd) { - final appStartDateTime = - DateTime.fromMillisecondsSinceEpoch(appStartTime.toInt()); - final duration = appStartEnd.difference(appStartDateTime); + Future _attachAppStartSpans( + AppStartInfo appStartInfo, SentryTracer transaction) async { + final transactionTraceId = transaction.context.traceId; + final appStartEnd = appStartInfo.end; + if (appStartEnd == null) { + return; + } + + final appStartSpan = await _createAndFinishSpan( + tracer: transaction, + operation: appStartInfo.appStartTypeOperation, + description: appStartInfo.appStartTypeDescription, + parentSpanId: transaction.context.spanId, + traceId: transactionTraceId, + startTimestamp: appStartInfo.start, + endTimestamp: appStartEnd); + + await _attachNativeSpans(appStartInfo, transaction, appStartSpan); + + final pluginRegistrationSpan = await _createAndFinishSpan( + tracer: transaction, + operation: appStartInfo.appStartTypeOperation, + description: appStartInfo.pluginRegistrationDescription, + parentSpanId: appStartSpan.context.spanId, + traceId: transactionTraceId, + startTimestamp: appStartInfo.start, + endTimestamp: appStartInfo.pluginRegistration); + + final sentrySetupSpan = await _createAndFinishSpan( + tracer: transaction, + operation: appStartInfo.appStartTypeOperation, + description: appStartInfo.sentrySetupDescription, + parentSpanId: appStartSpan.context.spanId, + traceId: transactionTraceId, + startTimestamp: appStartInfo.pluginRegistration, + endTimestamp: appStartInfo.sentrySetupStart); + + final firstFrameRenderSpan = await _createAndFinishSpan( + tracer: transaction, + operation: appStartInfo.appStartTypeOperation, + description: appStartInfo.firstFrameRenderDescription, + parentSpanId: appStartSpan.context.spanId, + traceId: transactionTraceId, + startTimestamp: appStartInfo.sentrySetupStart, + endTimestamp: appStartEnd); + + transaction.children.addAll([ + appStartSpan, + pluginRegistrationSpan, + sentrySetupSpan, + firstFrameRenderSpan + ]); + } + + Future _attachNativeSpans(AppStartInfo appStartInfo, + SentryTracer transaction, SentrySpan parent) async { + await Future.forEach(appStartInfo.nativeSpanTimes, + (timeSpan) async { + try { + final span = await _createAndFinishSpan( + tracer: transaction, + operation: appStartInfo.appStartTypeOperation, + description: timeSpan.description, + parentSpanId: parent.context.spanId, + traceId: transaction.context.traceId, + startTimestamp: timeSpan.start, + endTimestamp: timeSpan.end); + span.data.putIfAbsent('native', () => true); + transaction.children.add(span); + } catch (e) { + _hub.options.logger(SentryLevel.warning, + 'Failed to attach native span to app start transaction: $e'); + } + }); + } - return isColdStart - ? SentryMeasurement.coldAppStart(duration) - : SentryMeasurement.warmAppStart(duration); + Future _createAndFinishSpan({ + required SentryTracer tracer, + required String operation, + required String description, + required SpanId parentSpanId, + required SentryId traceId, + required DateTime startTimestamp, + required DateTime endTimestamp, + }) async { + final span = SentrySpan( + tracer, + SentrySpanContext( + operation: operation, + description: description, + parentSpanId: parentSpanId, + traceId: traceId, + ), + _hub, + startTimestamp: startTimestamp); + await span.finish(endTimestamp: endTimestamp); + return span; } } diff --git a/flutter/lib/src/event_processor/platform_exception_event_processor.dart b/flutter/lib/src/event_processor/platform_exception_event_processor.dart index d403509ae9..2bf33e60f9 100644 --- a/flutter/lib/src/event_processor/platform_exception_event_processor.dart +++ b/flutter/lib/src/event_processor/platform_exception_event_processor.dart @@ -4,7 +4,7 @@ import 'package:sentry/sentry.dart'; /// Add code & message from [PlatformException] to [SentryException] class PlatformExceptionEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/flutter/lib/src/event_processor/screenshot_event_processor.dart b/flutter/lib/src/event_processor/screenshot_event_processor.dart index 263722fdad..8981afe7b1 100644 --- a/flutter/lib/src/event_processor/screenshot_event_processor.dart +++ b/flutter/lib/src/event_processor/screenshot_event_processor.dart @@ -20,7 +20,7 @@ class ScreenshotEventProcessor implements EventProcessor { sentryScreenshotWidgetGlobalKey.currentContext != null; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { if (event is SentryTransaction) { return event; } @@ -30,6 +30,32 @@ class ScreenshotEventProcessor implements EventProcessor { _hasSentryScreenshotWidget) { return event; } + final beforeScreenshot = _options.beforeScreenshot; + if (beforeScreenshot != null) { + try { + final result = beforeScreenshot(event, hint: hint); + bool takeScreenshot; + if (result is Future) { + takeScreenshot = await result; + } else { + takeScreenshot = result; + } + if (!takeScreenshot) { + return event; + } + } catch (exception, stackTrace) { + _options.logger( + SentryLevel.error, + 'The beforeScreenshot callback threw an exception', + exception: exception, + stackTrace: stackTrace, + ); + // ignore: invalid_use_of_internal_member + if (_options.automatedTestMode) { + rethrow; + } + } + } final renderer = _options.rendererWrapper.getRenderer(); @@ -52,7 +78,7 @@ class ScreenshotEventProcessor implements EventProcessor { final bytes = await _createScreenshot(); if (bytes != null) { - hint?.screenshot = SentryAttachment.fromScreenshotData(bytes); + hint.screenshot = SentryAttachment.fromScreenshotData(bytes); } return event; } diff --git a/flutter/lib/src/event_processor/widget_event_processor.dart b/flutter/lib/src/event_processor/widget_event_processor.dart new file mode 100644 index 0000000000..c297585f49 --- /dev/null +++ b/flutter/lib/src/event_processor/widget_event_processor.dart @@ -0,0 +1,31 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; + +import '../../sentry_flutter.dart'; + +class WidgetEventProcessor implements EventProcessor { + @override + FutureOr apply(SentryEvent event, Hint hint) { + if (event is SentryTransaction) { + return event; + } + if (event.exceptions == null && event.throwable == null) { + return event; + } + final context = sentryWidgetGlobalKey.currentContext; + if (context == null) { + return event; + } + + // ignore: deprecated_member_use + final textScale = MediaQuery.textScaleFactorOf(context); + return event.copyWith( + contexts: event.contexts.copyWith( + app: event.contexts.app?.copyWith( + textScale: textScale, + ), + ), + ); + } +} diff --git a/flutter/lib/src/flutter_sentry_attachment.dart b/flutter/lib/src/flutter_sentry_attachment.dart index 83b75c20bd..2e8d57927a 100644 --- a/flutter/lib/src/flutter_sentry_attachment.dart +++ b/flutter/lib/src/flutter_sentry_attachment.dart @@ -16,8 +16,8 @@ class FlutterSentryAttachment extends SentryAttachment { String? filename, AssetBundle? bundle, String? type, - String? contentType, - bool? addToTransactions, + super.contentType, + super.addToTransactions, }) : super.fromLoader( loader: () async { final data = await (bundle ?? rootBundle).load(key); @@ -28,7 +28,5 @@ class FlutterSentryAttachment extends SentryAttachment { ? Uri.parse(key).pathSegments.last : 'unknown'), attachmentType: type, - contentType: contentType, - addToTransactions: addToTransactions, ); } diff --git a/flutter/lib/src/frame_callback_handler.dart b/flutter/lib/src/frame_callback_handler.dart new file mode 100644 index 0000000000..71a8f928b1 --- /dev/null +++ b/flutter/lib/src/frame_callback_handler.dart @@ -0,0 +1,15 @@ +import 'package:flutter/scheduler.dart'; + +abstract class FrameCallbackHandler { + void addPostFrameCallback(FrameCallback callback); +} + +class DefaultFrameCallbackHandler implements FrameCallbackHandler { + @override + void addPostFrameCallback(FrameCallback callback) { + try { + /// Flutter >= 2.12 throws if SchedulerBinding.instance isn't initialized. + SchedulerBinding.instance.addPostFrameCallback(callback); + } catch (_) {} + } +} diff --git a/flutter/lib/src/integrations/connectivity/connectivity_integration.dart b/flutter/lib/src/integrations/connectivity/connectivity_integration.dart new file mode 100644 index 0000000000..c8d0b80c86 --- /dev/null +++ b/flutter/lib/src/integrations/connectivity/connectivity_integration.dart @@ -0,0 +1,36 @@ +import 'package:meta/meta.dart'; +import '../../../sentry_flutter.dart'; +import 'connectivity_provider.dart'; + +class ConnectivityIntegration extends Integration { + Hub? _hub; + ConnectivityProvider? _connectivityProvider; + + @override + void call(Hub hub, SentryFlutterOptions options) { + _hub = hub; + _connectivityProvider = ConnectivityProvider(); + _connectivityProvider?.listen((connectivity) { + addBreadcrumb(connectivity); + }); + options.sdk.addIntegration('connectivityIntegration'); + } + + @override + void close() { + _hub = null; + _connectivityProvider?.cancel(); + } + + @internal + @visibleForTesting + void addBreadcrumb(String connectivity) { + _hub?.addBreadcrumb( + Breadcrumb( + category: 'device.connectivity', + level: SentryLevel.info, + type: 'connectivity', + data: {'connectivity': connectivity}), + ); + } +} diff --git a/flutter/lib/src/integrations/connectivity/connectivity_provider.dart b/flutter/lib/src/integrations/connectivity/connectivity_provider.dart new file mode 100644 index 0000000000..30095dda0d --- /dev/null +++ b/flutter/lib/src/integrations/connectivity/connectivity_provider.dart @@ -0,0 +1,9 @@ +import 'noop_connectivity_provider.dart' + if (dart.library.html) 'web_connectivity_provider.dart'; + +abstract class ConnectivityProvider { + factory ConnectivityProvider() => connectivityProvider(); + + void listen(void Function(String connectivity) onChange); + void cancel(); +} diff --git a/flutter/lib/src/integrations/connectivity/noop_connectivity_provider.dart b/flutter/lib/src/integrations/connectivity/noop_connectivity_provider.dart new file mode 100644 index 0000000000..4276448b7a --- /dev/null +++ b/flutter/lib/src/integrations/connectivity/noop_connectivity_provider.dart @@ -0,0 +1,17 @@ +import 'connectivity_provider.dart'; + +ConnectivityProvider connectivityProvider() { + return NoOpConnectivityProvider(); +} + +class NoOpConnectivityProvider implements ConnectivityProvider { + @override + void listen(void Function(String connectivity) onChange) { + // NoOp + } + + @override + void cancel() { + // NoOp + } +} diff --git a/flutter/lib/src/integrations/connectivity/web_connectivity_provider.dart b/flutter/lib/src/integrations/connectivity/web_connectivity_provider.dart new file mode 100644 index 0000000000..34d0e0ab42 --- /dev/null +++ b/flutter/lib/src/integrations/connectivity/web_connectivity_provider.dart @@ -0,0 +1,32 @@ +import 'dart:async'; +import 'dart:html' as html; + +import 'connectivity_provider.dart'; + +ConnectivityProvider connectivityProvider() { + return WebConnectivityProvider(); +} + +class WebConnectivityProvider implements ConnectivityProvider { + StreamSubscription? _onOnlineSub; + StreamSubscription? _onOfflineSub; + + @override + void listen(void Function(String connectivity) onChange) { + _onOnlineSub = html.window.onOnline.listen((_) { + onChange('wifi'); + }); + _onOfflineSub = html.window.onOffline.listen((_) { + onChange('none'); + }); + } + + @override + void cancel() { + _onOnlineSub?.cancel(); + _onOnlineSub = null; + + _onOfflineSub?.cancel(); + _onOfflineSub = null; + } +} diff --git a/flutter/lib/src/integrations/flutter_error_integration.dart b/flutter/lib/src/integrations/flutter_error_integration.dart index a9f10bcc09..c1a6d57a1d 100644 --- a/flutter/lib/src/integrations/flutter_error_integration.dart +++ b/flutter/lib/src/integrations/flutter_error_integration.dart @@ -54,16 +54,15 @@ class FlutterErrorIntegration implements Integration { stackTrace: errorDetails.stack, ); - // FlutterError doesn't crash the App. - final mechanism = Mechanism( - type: 'FlutterError', - handled: true, - ); + // FlutterError doesn't crash the app, but is not handled by the user. + final mechanism = Mechanism(type: 'FlutterError', handled: false); final throwableMechanism = ThrowableMechanism(mechanism, exception); var event = SentryEvent( throwable: throwableMechanism, - level: SentryLevel.fatal, + level: options.markAutomaticallyCollectedErrorsAsFatal + ? SentryLevel.fatal + : SentryLevel.error, contexts: flutterErrorDetails.isNotEmpty ? (Contexts()..['flutter_error_details'] = flutterErrorDetails) : null, diff --git a/flutter/lib/src/integrations/load_contexts_integration.dart b/flutter/lib/src/integrations/load_contexts_integration.dart index 710d7d0924..df8b52b97a 100644 --- a/flutter/lib/src/integrations/load_contexts_integration.dart +++ b/flutter/lib/src/integrations/load_contexts_integration.dart @@ -4,21 +4,16 @@ import 'package:flutter/services.dart'; import 'package:sentry/sentry.dart'; import '../sentry_flutter_options.dart'; -/// Load Device's Contexts from the iOS SDK. +/// Load Device's Contexts from the iOS & Android SDKs. /// -/// This integration calls the iOS SDK via Message channel to load the -/// Device's contexts before sending the event back to the iOS SDK via +/// This integration calls the iOS & Android SDKs via Message channel to load +/// the Device's contexts before sending the event back to the SDK via /// Message channel (already enriched with all the information). /// /// The Device's contexts are: /// App, Device and OS. /// -/// ps. This integration won't be run on Android because the Device's Contexts -/// is set on Android when the event is sent to the Android SDK via -/// the Message channel. -/// We intend to unify this behaviour in the future. -/// -/// This integration is only executed on iOS & MacOS Apps. +/// This integration is only executed on iOS, macOS & Android Apps. class LoadContextsIntegration extends Integration { final MethodChannel _channel; @@ -40,7 +35,7 @@ class _LoadContextsIntegrationEventProcessor implements EventProcessor { final SentryFlutterOptions _options; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { try { final loadContexts = await _channel.invokeMethod('loadContexts'); @@ -155,13 +150,23 @@ class _LoadContextsIntegrationEventProcessor implements EventProcessor { final breadcrumbsJson = List>.from(breadcrumbsList); final breadcrumbs = []; + final beforeBreadcrumb = _options.beforeBreadcrumb; for (final breadcrumbJson in breadcrumbsJson) { final breadcrumb = Breadcrumb.fromJson( Map.from(breadcrumbJson), ); - breadcrumbs.add(breadcrumb); + + if (beforeBreadcrumb != null) { + final processedBreadcrumb = beforeBreadcrumb(breadcrumb, Hint()); + if (processedBreadcrumb != null) { + breadcrumbs.add(processedBreadcrumb); + } + } else { + breadcrumbs.add(breadcrumb); + } } + event = event.copyWith(breadcrumbs: breadcrumbs); } @@ -194,8 +199,8 @@ class _LoadContextsIntegrationEventProcessor implements EventProcessor { event = event.copyWith(sdk: sdk); } - // on iOS, captureEnvelope does not call the beforeSend callback, - // hence we need to add these tags here. + // captureEnvelope does not call the beforeSend callback, hence we need to + // add these tags here. if (event.sdk?.name == 'sentry.dart.flutter') { final tags = event.tags ?? {}; tags['event.origin'] = 'flutter'; diff --git a/flutter/lib/src/integrations/load_image_list_integration.dart b/flutter/lib/src/integrations/load_image_list_integration.dart index c2a0c98848..ae08d93946 100644 --- a/flutter/lib/src/integrations/load_image_list_integration.dart +++ b/flutter/lib/src/integrations/load_image_list_integration.dart @@ -25,14 +25,25 @@ extension _NeedsSymbolication on SentryEvent { if (this is SentryTransaction) { return false; } - if (exceptions?.isNotEmpty == false) { - return false; - } - final frames = exceptions?.first.stackTrace?.frames; + final frames = _getStacktraceFrames(); if (frames == null) { return false; } - return frames.any((frame) => 'native' == frame.platform); + return frames.any((frame) => 'native' == frame?.platform); + } + + List? _getStacktraceFrames() { + if (exceptions?.isNotEmpty == true) { + return exceptions?.first.stackTrace?.frames; + } + if (threads?.isNotEmpty == true) { + var stacktraces = threads?.map((e) => e.stacktrace); + return stacktraces + ?.where((element) => element != null) + .expand((element) => element!.frames) + .toList(); + } + return null; } } @@ -43,7 +54,7 @@ class _LoadImageListIntegrationEventProcessor implements EventProcessor { final SentryFlutterOptions _options; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { if (event.needsSymbolication()) { try { // we call on every event because the loaded image list is cached diff --git a/flutter/lib/src/integrations/native_app_start_integration.dart b/flutter/lib/src/integrations/native_app_start_integration.dart index 47bf79dff4..d3be7b4a0f 100644 --- a/flutter/lib/src/integrations/native_app_start_integration.dart +++ b/flutter/lib/src/integrations/native_app_start_integration.dart @@ -1,38 +1,233 @@ -import 'package:flutter/scheduler.dart'; -import 'package:sentry/sentry.dart'; +// ignore_for_file: invalid_use_of_internal_member -import '../sentry_flutter_options.dart'; +import 'dart:async'; + +import 'package:meta/meta.dart'; + +import '../../sentry_flutter.dart'; +import '../frame_callback_handler.dart'; import '../native/sentry_native.dart'; import '../event_processor/native_app_start_event_processor.dart'; /// Integration which handles communication with native frameworks in order to /// enrich [SentryTransaction] objects with app start data for mobile vitals. class NativeAppStartIntegration extends Integration { - NativeAppStartIntegration(this._native, this._schedulerBindingProvider); + NativeAppStartIntegration(this._native, this._frameCallbackHandler, + {Hub? hub}) + : _hub = hub ?? HubAdapter(); final SentryNative _native; - final SchedulerBindingProvider _schedulerBindingProvider; + final FrameCallbackHandler _frameCallbackHandler; + final Hub _hub; + + /// Timeout duration to wait for the app start info to be fetched. + static const _timeoutDuration = Duration(seconds: 30); + + /// We filter out App starts more than 60s + static const _maxAppStartMillis = 60000; + + static Completer _appStartCompleter = + Completer(); + static AppStartInfo? _appStartInfo; + + @internal + static bool isIntegrationTest = false; + + @internal + static void setAppStartInfo(AppStartInfo? appStartInfo) { + _appStartInfo = appStartInfo; + if (_appStartCompleter.isCompleted) { + _appStartCompleter = Completer(); + } + _appStartCompleter.complete(appStartInfo); + } + + @internal + static Future getAppStartInfo() { + if (_appStartInfo != null) { + return Future.value(_appStartInfo); + } + return _appStartCompleter.future + .timeout(_timeoutDuration, onTimeout: () => null); + } + + @visibleForTesting + static void clearAppStartInfo() { + _appStartInfo = null; + _appStartCompleter = Completer(); + } @override void call(Hub hub, SentryFlutterOptions options) { - if (options.autoAppStart) { - final schedulerBinding = _schedulerBindingProvider(); - if (schedulerBinding == null) { - options.logger(SentryLevel.debug, - 'Scheduler binding is null. Can\'t auto detect app start time.'); - } else { - schedulerBinding.addPostFrameCallback((timeStamp) { - // ignore: invalid_use_of_internal_member - _native.appStartEnd = options.clock(); - }); - } + if (isIntegrationTest) { + final appStartInfo = AppStartInfo( + AppStartType.cold, + start: DateTime.now(), + end: DateTime.now().add(const Duration(milliseconds: 100)), + pluginRegistration: + DateTime.now().add(const Duration(milliseconds: 50)), + sentrySetupStart: DateTime.now().add(const Duration(milliseconds: 60)), + nativeSpanTimes: [], + ); + setAppStartInfo(appStartInfo); + return; } - options.addEventProcessor(NativeAppStartEventProcessor(_native)); + if (_native.didFetchAppStart) { + return; + } + + _frameCallbackHandler.addPostFrameCallback((timeStamp) async { + final nativeAppStart = await _native.fetchNativeAppStart(); + if (nativeAppStart == null) { + setAppStartInfo(null); + return; + } + + final sentrySetupStartDateTime = SentryFlutter.sentrySetupStartTime; + if (sentrySetupStartDateTime == null) { + setAppStartInfo(null); + return; + } + + final appStartDateTime = DateTime.fromMillisecondsSinceEpoch( + nativeAppStart.appStartTime.toInt()); + final pluginRegistrationDateTime = DateTime.fromMillisecondsSinceEpoch( + nativeAppStart.pluginRegistrationTime); + DateTime? appStartEndDateTime; + + if (options.autoAppStart) { + // We only assign the current time if it's not already set - this is useful in tests + _native.appStartEnd ??= options.clock(); + appStartEndDateTime = _native.appStartEnd; + + final duration = appStartEndDateTime?.difference(appStartDateTime); + + // We filter out app start more than 60s. + // This could be due to many different reasons. + // If you do the manual init and init the SDK too late and it does not + // compute the app start end in the very first Screen. + // If the process starts but the App isn't in the foreground. + // If the system forked the process earlier to accelerate the app start. + // And some unknown reasons that could not be reproduced. + // We've seen app starts with hours, days and even months. + if (duration != null && duration.inMilliseconds > _maxAppStartMillis) { + setAppStartInfo(null); + return; + } + } + + List nativeSpanTimes = []; + for (final entry in nativeAppStart.nativeSpanTimes.entries) { + try { + final startTimestampMs = + entry.value['startTimestampMsSinceEpoch'] as int; + final endTimestampMs = + entry.value['stopTimestampMsSinceEpoch'] as int; + nativeSpanTimes.add(TimeSpan( + start: DateTime.fromMillisecondsSinceEpoch(startTimestampMs), + end: DateTime.fromMillisecondsSinceEpoch(endTimestampMs), + description: entry.key as String, + )); + } catch (e) { + _hub.options.logger( + SentryLevel.warning, 'Failed to parse native span times: $e'); + continue; + } + } + + // We want to sort because the native spans are not guaranteed to be in order. + // Performance wise this won't affect us since the native span amount is very low. + nativeSpanTimes.sort((a, b) => a.start.compareTo(b.start)); + + final appStartInfo = AppStartInfo( + nativeAppStart.isColdStart ? AppStartType.cold : AppStartType.warm, + start: appStartDateTime, + end: appStartEndDateTime, + pluginRegistration: pluginRegistrationDateTime, + sentrySetupStart: sentrySetupStartDateTime, + nativeSpanTimes: nativeSpanTimes); + + setAppStartInfo(appStartInfo); + + // When we don't have a SentryNavigatorObserver, a TTID transaction + // is not created therefore we need to create a transaction ourselves. + // We detect this by checking if the currentRouteName is null. + // This is a workaround since there is no api that tells us if + // the navigator observer exists and has been attached. + // The navigator observer also triggers much earlier so if it was attached + // it would have already set the routeName and the isCreated flag. + // The currentRouteName is always set during a didPush triggered + // by the navigator observer. + if (!SentryNavigatorObserver.isCreated && + SentryNavigatorObserver.currentRouteName == null) { + const screenName = SentryNavigatorObserver.rootScreenName; + final transaction = hub.startTransaction( + screenName, SentrySpanOperations.uiLoad, + startTimestamp: appStartInfo.start); + final ttidSpan = transaction.startChild( + SentrySpanOperations.uiTimeToInitialDisplay, + description: '$screenName initial display', + startTimestamp: appStartInfo.start); + await ttidSpan.finish(endTimestamp: appStartInfo.end); + await transaction.finish(endTimestamp: appStartInfo.end); + } + }); + + options.addEventProcessor(NativeAppStartEventProcessor(_native, hub: hub)); options.sdk.addIntegration('nativeAppStartIntegration'); } } -/// Used to provide scheduler binding at call time. -typedef SchedulerBindingProvider = SchedulerBinding? Function(); +enum AppStartType { cold, warm } + +class AppStartInfo { + AppStartInfo( + this.type, { + required this.start, + required this.pluginRegistration, + required this.sentrySetupStart, + required this.nativeSpanTimes, + this.end, + }); + + final AppStartType type; + final DateTime start; + final List nativeSpanTimes; + + // We allow the end to be null, since it might be set at a later time + // with setAppStartEnd when autoAppStart is disabled + DateTime? end; + + final DateTime pluginRegistration; + final DateTime sentrySetupStart; + + Duration? get duration => end?.difference(start); + + SentryMeasurement? toMeasurement() { + final duration = this.duration; + if (duration == null) { + return null; + } + return type == AppStartType.cold + ? SentryMeasurement.coldAppStart(duration) + : SentryMeasurement.warmAppStart(duration); + } + + String get appStartTypeOperation => 'app.start.${type.name}'; + + String get appStartTypeDescription => + type == AppStartType.cold ? 'Cold Start' : 'Warm Start'; + final pluginRegistrationDescription = 'App start to plugin registration'; + final sentrySetupDescription = 'Before Sentry Init Setup'; + final firstFrameRenderDescription = 'First frame render'; +} + +class TimeSpan { + TimeSpan({required this.start, required this.end, required this.description}); + + final DateTime start; + final DateTime end; + final String description; +} diff --git a/flutter/lib/src/integrations/native_sdk_integration.dart b/flutter/lib/src/integrations/native_sdk_integration.dart index 9c4a98379e..35181afc1e 100644 --- a/flutter/lib/src/integrations/native_sdk_integration.dart +++ b/flutter/lib/src/integrations/native_sdk_integration.dart @@ -1,60 +1,26 @@ import 'dart:async'; -import 'package:flutter/services.dart'; import 'package:sentry/sentry.dart'; +import '../native/sentry_native.dart'; import '../sentry_flutter_options.dart'; /// Enables Sentry's native SDKs (Android and iOS) with options. class NativeSdkIntegration implements Integration { - NativeSdkIntegration(this._channel); + NativeSdkIntegration(this._native); - final MethodChannel _channel; SentryFlutterOptions? _options; + final SentryNative _native; @override Future call(Hub hub, SentryFlutterOptions options) async { _options = options; + if (!options.autoInitializeNativeSdk) { return; } - try { - await _channel.invokeMethod('initNativeSdk', { - 'dsn': options.dsn, - 'debug': options.debug, - 'environment': options.environment, - 'release': options.release, - 'enableAutoSessionTracking': options.enableAutoSessionTracking, - 'enableNativeCrashHandling': options.enableNativeCrashHandling, - 'attachStacktrace': options.attachStacktrace, - 'attachThreads': options.attachThreads, - 'autoSessionTrackingIntervalMillis': - options.autoSessionTrackingInterval.inMilliseconds, - 'dist': options.dist, - 'integrations': options.sdk.integrations, - 'packages': - options.sdk.packages.map((e) => e.toJson()).toList(growable: false), - 'diagnosticLevel': options.diagnosticLevel.name, - 'maxBreadcrumbs': options.maxBreadcrumbs, - 'anrEnabled': options.anrEnabled, - 'anrTimeoutIntervalMillis': options.anrTimeoutInterval.inMilliseconds, - 'enableAutoNativeBreadcrumbs': options.enableAutoNativeBreadcrumbs, - 'maxCacheItems': options.maxCacheItems, - 'sendDefaultPii': options.sendDefaultPii, - 'enableWatchdogTerminationTracking': - options.enableWatchdogTerminationTracking, - 'enableNdkScopeSync': options.enableNdkScopeSync, - 'enableAutoPerformanceTracing': options.enableAutoPerformanceTracing, - 'sendClientReports': options.sendClientReports, - 'proguardUuid': options.proguardUuid, - 'maxAttachmentSize': options.maxAttachmentSize, - 'captureFailedRequests': options.captureFailedRequests, - 'enableAppHangTracking': options.enableAppHangTracking, - 'connectionTimeoutMillis': options.connectionTimeout.inMilliseconds, - 'readTimeoutMillis': options.readTimeout.inMilliseconds, - 'appHangTimeoutIntervalMillis': - options.appHangTimeoutInterval.inMilliseconds, - }); + try { + await _native.init(options); options.sdk.addIntegration('nativeSdkIntegration'); } catch (exception, stackTrace) { options.logger( @@ -68,19 +34,17 @@ class NativeSdkIntegration implements Integration { @override Future close() async { - final options = _options; - if (options != null && !options.autoInitializeNativeSdk) { - return; - } - try { - await _channel.invokeMethod('closeNativeSdk'); - } catch (exception, stackTrace) { - _options?.logger( - SentryLevel.fatal, - 'nativeSdkIntegration failed to be closed', - exception: exception, - stackTrace: stackTrace, - ); + if (_options?.autoInitializeNativeSdk == true) { + try { + await _native.close(); + } catch (exception, stackTrace) { + _options?.logger( + SentryLevel.fatal, + 'nativeSdkIntegration failed to be closed', + exception: exception, + stackTrace: stackTrace, + ); + } } } } diff --git a/flutter/lib/src/integrations/screenshot_integration.dart b/flutter/lib/src/integrations/screenshot_integration.dart index d8d1adbc34..10cf60228a 100644 --- a/flutter/lib/src/integrations/screenshot_integration.dart +++ b/flutter/lib/src/integrations/screenshot_integration.dart @@ -2,7 +2,8 @@ import 'package:sentry/sentry.dart'; import '../event_processor/screenshot_event_processor.dart'; import '../sentry_flutter_options.dart'; -/// Adds [ScreenshotEventProcessor] to options event processors if [attachScreenshot] is true +/// Adds [ScreenshotEventProcessor] to options event processors if +/// [SentryFlutterOptions.attachScreenshot] is true class ScreenshotIntegration implements Integration { SentryFlutterOptions? _options; ScreenshotEventProcessor? _screenshotEventProcessor; diff --git a/flutter/lib/src/native/cocoa/binding.dart b/flutter/lib/src/native/cocoa/binding.dart index 646a6bea83..4af31cfc57 100644 --- a/flutter/lib/src/native/cocoa/binding.dart +++ b/flutter/lib/src/native/cocoa/binding.dart @@ -1012,6 +1012,10 @@ class SentryCocoa { late final _sel_URLWithString_1 = _registerName1("URLWithString:"); late final _sel_URLWithString_relativeToURL_1 = _registerName1("URLWithString:relativeToURL:"); + late final _sel_initWithString_encodingInvalidCharacters_1 = + _registerName1("initWithString:encodingInvalidCharacters:"); + late final _sel_URLWithString_encodingInvalidCharacters_1 = + _registerName1("URLWithString:encodingInvalidCharacters:"); late final _sel_initWithDataRepresentation_relativeToURL_1 = _registerName1("initWithDataRepresentation:relativeToURL:"); instancetype _objc_msgSend_37( @@ -4666,9 +4670,11 @@ class SentryCocoa { late final _sel_languageCode1 = _registerName1("languageCode"); late final _sel_localizedStringForLanguageCode_1 = _registerName1("localizedStringForLanguageCode:"); + late final _sel_languageIdentifier1 = _registerName1("languageIdentifier"); late final _sel_countryCode1 = _registerName1("countryCode"); late final _sel_localizedStringForCountryCode_1 = _registerName1("localizedStringForCountryCode:"); + late final _sel_regionCode1 = _registerName1("regionCode"); late final _sel_scriptCode1 = _registerName1("scriptCode"); late final _sel_localizedStringForScriptCode_1 = _registerName1("localizedStringForScriptCode:"); @@ -19070,36 +19076,173 @@ class SentryCocoa { instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); - late final _sel_attributedStringByInflectingString1 = - _registerName1("attributedStringByInflectingString"); - ffi.Pointer _objc_msgSend_675( + late final _sel_initWithFormat_options_locale_context_1 = + _registerName1("initWithFormat:options:locale:context:"); + instancetype _objc_msgSend_675( ffi.Pointer obj, ffi.Pointer sel, + ffi.Pointer format, + int options, + ffi.Pointer locale, + ffi.Pointer context, ) { return __objc_msgSend_675( obj, sel, + format, + options, + locale, + context, ); } late final __objc_msgSend_675Ptr = _lookup< + ffi.NativeFunction< + instancetype Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Pointer, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_675 = __objc_msgSend_675Ptr.asFunction< + instancetype Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + int, + ffi.Pointer, + ffi.Pointer)>(); + + late final _sel_initWithFormat_options_locale_context_arguments_1 = + _registerName1("initWithFormat:options:locale:context:arguments:"); + instancetype _objc_msgSend_676( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer format, + int options, + ffi.Pointer locale, + ffi.Pointer context, + ffi.Pointer<__va_list_tag> arguments, + ) { + return __objc_msgSend_676( + obj, + sel, + format, + options, + locale, + context, + arguments, + ); + } + + late final __objc_msgSend_676Ptr = _lookup< + ffi.NativeFunction< + instancetype Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer<__va_list_tag>)>>('objc_msgSend'); + late final __objc_msgSend_676 = __objc_msgSend_676Ptr.asFunction< + instancetype Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + int, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer<__va_list_tag>)>(); + + late final _sel_localizedAttributedStringWithFormat_context_1 = + _registerName1("localizedAttributedStringWithFormat:context:"); + instancetype _objc_msgSend_677( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer format, + ffi.Pointer context, + ) { + return __objc_msgSend_677( + obj, + sel, + format, + context, + ); + } + + late final __objc_msgSend_677Ptr = _lookup< + ffi.NativeFunction< + instancetype Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_677 = __objc_msgSend_677Ptr.asFunction< + instancetype Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + + late final _sel_localizedAttributedStringWithFormat_options_context_1 = + _registerName1("localizedAttributedStringWithFormat:options:context:"); + instancetype _objc_msgSend_678( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer format, + int options, + ffi.Pointer context, + ) { + return __objc_msgSend_678( + obj, + sel, + format, + options, + context, + ); + } + + late final __objc_msgSend_678Ptr = _lookup< + ffi.NativeFunction< + instancetype Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int32, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_678 = __objc_msgSend_678Ptr.asFunction< + instancetype Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer, int, ffi.Pointer)>(); + + late final _sel_attributedStringByInflectingString1 = + _registerName1("attributedStringByInflectingString"); + ffi.Pointer _objc_msgSend_679( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_679( + obj, + sel, + ); + } + + late final __objc_msgSend_679Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_675 = __objc_msgSend_675Ptr.asFunction< + late final __objc_msgSend_679 = __objc_msgSend_679Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_localizedAttributedStringForKey_value_table_1 = _registerName1("localizedAttributedStringForKey:value:table:"); - ffi.Pointer _objc_msgSend_676( + ffi.Pointer _objc_msgSend_680( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer key, ffi.Pointer value, ffi.Pointer tableName, ) { - return __objc_msgSend_676( + return __objc_msgSend_680( obj, sel, key, @@ -19108,7 +19251,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_676Ptr = _lookup< + late final __objc_msgSend_680Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -19116,7 +19259,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_676 = __objc_msgSend_676Ptr.asFunction< + late final __objc_msgSend_680 = __objc_msgSend_680Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -19141,13 +19284,13 @@ class SentryCocoa { _registerName1("preferredLocalizationsFromArray:"); late final _sel_preferredLocalizationsFromArray_forPreferences_1 = _registerName1("preferredLocalizationsFromArray:forPreferences:"); - ffi.Pointer _objc_msgSend_677( + ffi.Pointer _objc_msgSend_681( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer localizationsArray, ffi.Pointer preferencesArray, ) { - return __objc_msgSend_677( + return __objc_msgSend_681( obj, sel, localizationsArray, @@ -19155,14 +19298,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_677Ptr = _lookup< + late final __objc_msgSend_681Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_677 = __objc_msgSend_677Ptr.asFunction< + late final __objc_msgSend_681 = __objc_msgSend_681Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -19173,13 +19316,13 @@ class SentryCocoa { _registerName1("executableArchitectures"); late final _sel_setPreservationPriority_forTags_1 = _registerName1("setPreservationPriority:forTags:"); - void _objc_msgSend_678( + void _objc_msgSend_682( ffi.Pointer obj, ffi.Pointer sel, double priority, ffi.Pointer tags, ) { - return __objc_msgSend_678( + return __objc_msgSend_682( obj, sel, priority, @@ -19187,11 +19330,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_678Ptr = _lookup< + late final __objc_msgSend_682Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Double, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_678 = __objc_msgSend_678Ptr.asFunction< + late final __objc_msgSend_682 = __objc_msgSend_682Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, double, ffi.Pointer)>(); @@ -19201,13 +19344,13 @@ class SentryCocoa { _getClass1("NSMutableAttributedString"); late final _sel_setAttributes_range_1 = _registerName1("setAttributes:range:"); - void _objc_msgSend_679( + void _objc_msgSend_683( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer attrs, _NSRange range, ) { - return __objc_msgSend_679( + return __objc_msgSend_683( obj, sel, attrs, @@ -19215,43 +19358,43 @@ class SentryCocoa { ); } - late final __objc_msgSend_679Ptr = _lookup< + late final __objc_msgSend_683Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_679 = __objc_msgSend_679Ptr.asFunction< + late final __objc_msgSend_683 = __objc_msgSend_683Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, _NSRange)>(); late final _sel_mutableString1 = _registerName1("mutableString"); - ffi.Pointer _objc_msgSend_680( + ffi.Pointer _objc_msgSend_684( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_680( + return __objc_msgSend_684( obj, sel, ); } - late final __objc_msgSend_680Ptr = _lookup< + late final __objc_msgSend_684Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_680 = __objc_msgSend_680Ptr.asFunction< + late final __objc_msgSend_684 = __objc_msgSend_684Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_addAttribute_value_range_1 = _registerName1("addAttribute:value:range:"); - void _objc_msgSend_681( + void _objc_msgSend_685( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, ffi.Pointer value, _NSRange range, ) { - return __objc_msgSend_681( + return __objc_msgSend_685( obj, sel, name, @@ -19260,7 +19403,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_681Ptr = _lookup< + late final __objc_msgSend_685Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -19268,7 +19411,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_681 = __objc_msgSend_681Ptr.asFunction< + late final __objc_msgSend_685 = __objc_msgSend_685Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer, _NSRange)>(); @@ -19276,13 +19419,13 @@ class SentryCocoa { _registerName1("addAttributes:range:"); late final _sel_removeAttribute_range_1 = _registerName1("removeAttribute:range:"); - void _objc_msgSend_682( + void _objc_msgSend_686( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, _NSRange range, ) { - return __objc_msgSend_682( + return __objc_msgSend_686( obj, sel, name, @@ -19290,23 +19433,23 @@ class SentryCocoa { ); } - late final __objc_msgSend_682Ptr = _lookup< + late final __objc_msgSend_686Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_682 = __objc_msgSend_682Ptr.asFunction< + late final __objc_msgSend_686 = __objc_msgSend_686Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, _NSRange)>(); late final _sel_replaceCharactersInRange_withAttributedString_1 = _registerName1("replaceCharactersInRange:withAttributedString:"); - void _objc_msgSend_683( + void _objc_msgSend_687( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer attrString, ) { - return __objc_msgSend_683( + return __objc_msgSend_687( obj, sel, range, @@ -19314,23 +19457,23 @@ class SentryCocoa { ); } - late final __objc_msgSend_683Ptr = _lookup< + late final __objc_msgSend_687Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_683 = __objc_msgSend_683Ptr.asFunction< + late final __objc_msgSend_687 = __objc_msgSend_687Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>(); late final _sel_insertAttributedString_atIndex_1 = _registerName1("insertAttributedString:atIndex:"); - void _objc_msgSend_684( + void _objc_msgSend_688( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer attrString, int loc, ) { - return __objc_msgSend_684( + return __objc_msgSend_688( obj, sel, attrString, @@ -19338,33 +19481,33 @@ class SentryCocoa { ); } - late final __objc_msgSend_684Ptr = _lookup< + late final __objc_msgSend_688Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_684 = __objc_msgSend_684Ptr.asFunction< + late final __objc_msgSend_688 = __objc_msgSend_688Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); late final _sel_appendAttributedString_1 = _registerName1("appendAttributedString:"); - void _objc_msgSend_685( + void _objc_msgSend_689( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer attrString, ) { - return __objc_msgSend_685( + return __objc_msgSend_689( obj, sel, attrString, ); } - late final __objc_msgSend_685Ptr = _lookup< + late final __objc_msgSend_689Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_685 = __objc_msgSend_685Ptr.asFunction< + late final __objc_msgSend_689 = __objc_msgSend_689Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -19380,13 +19523,13 @@ class SentryCocoa { _registerName1("stringForObjectValue:"); late final _sel_attributedStringForObjectValue_withDefaultAttributes_1 = _registerName1("attributedStringForObjectValue:withDefaultAttributes:"); - ffi.Pointer _objc_msgSend_686( + ffi.Pointer _objc_msgSend_690( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer obj1, ffi.Pointer attrs, ) { - return __objc_msgSend_686( + return __objc_msgSend_690( obj, sel, obj1, @@ -19394,14 +19537,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_686Ptr = _lookup< + late final __objc_msgSend_690Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_686 = __objc_msgSend_686Ptr.asFunction< + late final __objc_msgSend_690 = __objc_msgSend_690Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -19412,14 +19555,14 @@ class SentryCocoa { _registerName1("editingStringForObjectValue:"); late final _sel_getObjectValue_forString_errorDescription_1 = _registerName1("getObjectValue:forString:errorDescription:"); - bool _objc_msgSend_687( + bool _objc_msgSend_691( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> obj1, ffi.Pointer string, ffi.Pointer> error, ) { - return __objc_msgSend_687( + return __objc_msgSend_691( obj, sel, obj1, @@ -19428,7 +19571,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_687Ptr = _lookup< + late final __objc_msgSend_691Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -19436,7 +19579,7 @@ class SentryCocoa { ffi.Pointer>, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_687 = __objc_msgSend_687Ptr.asFunction< + late final __objc_msgSend_691 = __objc_msgSend_691Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -19446,14 +19589,14 @@ class SentryCocoa { late final _sel_isPartialStringValid_newEditingString_errorDescription_1 = _registerName1("isPartialStringValid:newEditingString:errorDescription:"); - bool _objc_msgSend_688( + bool _objc_msgSend_692( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer partialString, ffi.Pointer> newString, ffi.Pointer> error, ) { - return __objc_msgSend_688( + return __objc_msgSend_692( obj, sel, partialString, @@ -19462,7 +19605,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_688Ptr = _lookup< + late final __objc_msgSend_692Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -19470,7 +19613,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer>, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_688 = __objc_msgSend_688Ptr.asFunction< + late final __objc_msgSend_692 = __objc_msgSend_692Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -19481,7 +19624,7 @@ class SentryCocoa { late final _sel_isPartialStringValid_proposedSelectedRange_originalString_originalSelectedRange_errorDescription_1 = _registerName1( "isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:"); - bool _objc_msgSend_689( + bool _objc_msgSend_693( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> partialStringPtr, @@ -19490,7 +19633,7 @@ class SentryCocoa { _NSRange origSelRange, ffi.Pointer> error, ) { - return __objc_msgSend_689( + return __objc_msgSend_693( obj, sel, partialStringPtr, @@ -19501,7 +19644,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_689Ptr = _lookup< + late final __objc_msgSend_693Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -19511,7 +19654,7 @@ class SentryCocoa { ffi.Pointer, _NSRange, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_689 = __objc_msgSend_689Ptr.asFunction< + late final __objc_msgSend_693 = __objc_msgSend_693Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -19522,47 +19665,47 @@ class SentryCocoa { ffi.Pointer>)>(); late final _sel_formattingContext1 = _registerName1("formattingContext"); - int _objc_msgSend_690( + int _objc_msgSend_694( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_690( + return __objc_msgSend_694( obj, sel, ); } - late final __objc_msgSend_690Ptr = _lookup< + late final __objc_msgSend_694Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_690 = __objc_msgSend_690Ptr.asFunction< + late final __objc_msgSend_694 = __objc_msgSend_694Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setFormattingContext_1 = _registerName1("setFormattingContext:"); - void _objc_msgSend_691( + void _objc_msgSend_695( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_691( + return __objc_msgSend_695( obj, sel, value, ); } - late final __objc_msgSend_691Ptr = _lookup< + late final __objc_msgSend_695Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_691 = __objc_msgSend_691Ptr.asFunction< + late final __objc_msgSend_695 = __objc_msgSend_695Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_getObjectValue_forString_range_error_1 = _registerName1("getObjectValue:forString:range:error:"); - bool _objc_msgSend_692( + bool _objc_msgSend_696( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> obj1, @@ -19570,7 +19713,7 @@ class SentryCocoa { ffi.Pointer<_NSRange> rangep, ffi.Pointer> error, ) { - return __objc_msgSend_692( + return __objc_msgSend_696( obj, sel, obj1, @@ -19580,7 +19723,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_692Ptr = _lookup< + late final __objc_msgSend_696Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -19589,7 +19732,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer<_NSRange>, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_692 = __objc_msgSend_692Ptr.asFunction< + late final __objc_msgSend_696 = __objc_msgSend_696Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -19602,14 +19745,14 @@ class SentryCocoa { late final _sel_dateFromString_1 = _registerName1("dateFromString:"); late final _sel_localizedStringFromDate_dateStyle_timeStyle_1 = _registerName1("localizedStringFromDate:dateStyle:timeStyle:"); - ffi.Pointer _objc_msgSend_693( + ffi.Pointer _objc_msgSend_697( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date, int dstyle, int tstyle, ) { - return __objc_msgSend_693( + return __objc_msgSend_697( obj, sel, date, @@ -19618,7 +19761,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_693Ptr = _lookup< + late final __objc_msgSend_697Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -19626,20 +19769,20 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_693 = __objc_msgSend_693Ptr.asFunction< + late final __objc_msgSend_697 = __objc_msgSend_697Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, int)>(); late final _sel_dateFormatFromTemplate_options_locale_1 = _registerName1("dateFormatFromTemplate:options:locale:"); - ffi.Pointer _objc_msgSend_694( + ffi.Pointer _objc_msgSend_698( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer tmplate, int opts, ffi.Pointer locale, ) { - return __objc_msgSend_694( + return __objc_msgSend_698( obj, sel, tmplate, @@ -19648,7 +19791,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_694Ptr = _lookup< + late final __objc_msgSend_698Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -19656,7 +19799,7 @@ class SentryCocoa { ffi.Pointer, ffi.UnsignedLong, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_694 = __objc_msgSend_694Ptr.asFunction< + late final __objc_msgSend_698 = __objc_msgSend_698Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -19666,42 +19809,42 @@ class SentryCocoa { late final _sel_defaultFormatterBehavior1 = _registerName1("defaultFormatterBehavior"); - int _objc_msgSend_695( + int _objc_msgSend_699( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_695( + return __objc_msgSend_699( obj, sel, ); } - late final __objc_msgSend_695Ptr = _lookup< + late final __objc_msgSend_699Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_695 = __objc_msgSend_695Ptr.asFunction< + late final __objc_msgSend_699 = __objc_msgSend_699Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setDefaultFormatterBehavior_1 = _registerName1("setDefaultFormatterBehavior:"); - void _objc_msgSend_696( + void _objc_msgSend_700( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_696( + return __objc_msgSend_700( obj, sel, value, ); } - late final __objc_msgSend_696Ptr = _lookup< + late final __objc_msgSend_700Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_696 = __objc_msgSend_696Ptr.asFunction< + late final __objc_msgSend_700 = __objc_msgSend_700Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_setLocalizedDateFormatFromTemplate_1 = @@ -19709,64 +19852,64 @@ class SentryCocoa { late final _sel_dateFormat1 = _registerName1("dateFormat"); late final _sel_setDateFormat_1 = _registerName1("setDateFormat:"); late final _sel_dateStyle1 = _registerName1("dateStyle"); - int _objc_msgSend_697( + int _objc_msgSend_701( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_697( + return __objc_msgSend_701( obj, sel, ); } - late final __objc_msgSend_697Ptr = _lookup< + late final __objc_msgSend_701Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_697 = __objc_msgSend_697Ptr.asFunction< + late final __objc_msgSend_701 = __objc_msgSend_701Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setDateStyle_1 = _registerName1("setDateStyle:"); - void _objc_msgSend_698( + void _objc_msgSend_702( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_698( + return __objc_msgSend_702( obj, sel, value, ); } - late final __objc_msgSend_698Ptr = _lookup< + late final __objc_msgSend_702Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_698 = __objc_msgSend_698Ptr.asFunction< + late final __objc_msgSend_702 = __objc_msgSend_702Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_timeStyle1 = _registerName1("timeStyle"); late final _sel_setTimeStyle_1 = _registerName1("setTimeStyle:"); late final _sel_locale1 = _registerName1("locale"); late final _sel_setLocale_1 = _registerName1("setLocale:"); - void _objc_msgSend_699( + void _objc_msgSend_703( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_699( + return __objc_msgSend_703( obj, sel, value, ); } - late final __objc_msgSend_699Ptr = _lookup< + late final __objc_msgSend_703Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_699 = __objc_msgSend_699Ptr.asFunction< + late final __objc_msgSend_703 = __objc_msgSend_703Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -19779,21 +19922,21 @@ class SentryCocoa { _registerName1("setFormatterBehavior:"); late final _class_NSCalendar1 = _getClass1("NSCalendar"); late final _sel_currentCalendar1 = _registerName1("currentCalendar"); - ffi.Pointer _objc_msgSend_700( + ffi.Pointer _objc_msgSend_704( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_700( + return __objc_msgSend_704( obj, sel, ); } - late final __objc_msgSend_700Ptr = _lookup< + late final __objc_msgSend_704Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_700 = __objc_msgSend_700Ptr.asFunction< + late final __objc_msgSend_704 = __objc_msgSend_704Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -19801,23 +19944,23 @@ class SentryCocoa { _registerName1("autoupdatingCurrentCalendar"); late final _sel_calendarWithIdentifier_1 = _registerName1("calendarWithIdentifier:"); - ffi.Pointer _objc_msgSend_701( + ffi.Pointer _objc_msgSend_705( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer calendarIdentifierConstant, ) { - return __objc_msgSend_701( + return __objc_msgSend_705( obj, sel, calendarIdentifierConstant, ); } - late final __objc_msgSend_701Ptr = _lookup< + late final __objc_msgSend_705Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_701 = __objc_msgSend_701Ptr.asFunction< + late final __objc_msgSend_705 = __objc_msgSend_705Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -19860,13 +20003,13 @@ class SentryCocoa { late final _sel_AMSymbol1 = _registerName1("AMSymbol"); late final _sel_PMSymbol1 = _registerName1("PMSymbol"); late final _sel_minimumRangeOfUnit_1 = _registerName1("minimumRangeOfUnit:"); - void _objc_msgSend_702( + void _objc_msgSend_706( ffi.Pointer<_NSRange> stret, ffi.Pointer obj, ffi.Pointer sel, int unit, ) { - return __objc_msgSend_702( + return __objc_msgSend_706( stret, obj, sel, @@ -19874,18 +20017,18 @@ class SentryCocoa { ); } - late final __objc_msgSend_702Ptr = _lookup< + late final __objc_msgSend_706Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer<_NSRange>, ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend_stret'); - late final __objc_msgSend_702 = __objc_msgSend_702Ptr.asFunction< + late final __objc_msgSend_706 = __objc_msgSend_706Ptr.asFunction< void Function(ffi.Pointer<_NSRange>, ffi.Pointer, ffi.Pointer, int)>(); late final _sel_maximumRangeOfUnit_1 = _registerName1("maximumRangeOfUnit:"); late final _sel_rangeOfUnit_inUnit_forDate_1 = _registerName1("rangeOfUnit:inUnit:forDate:"); - void _objc_msgSend_703( + void _objc_msgSend_707( ffi.Pointer<_NSRange> stret, ffi.Pointer obj, ffi.Pointer sel, @@ -19893,7 +20036,7 @@ class SentryCocoa { int larger, ffi.Pointer date, ) { - return __objc_msgSend_703( + return __objc_msgSend_707( stret, obj, sel, @@ -19903,7 +20046,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_703Ptr = _lookup< + late final __objc_msgSend_707Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer<_NSRange>, @@ -19912,20 +20055,20 @@ class SentryCocoa { ffi.Int32, ffi.Int32, ffi.Pointer)>>('objc_msgSend_stret'); - late final __objc_msgSend_703 = __objc_msgSend_703Ptr.asFunction< + late final __objc_msgSend_707 = __objc_msgSend_707Ptr.asFunction< void Function(ffi.Pointer<_NSRange>, ffi.Pointer, ffi.Pointer, int, int, ffi.Pointer)>(); late final _sel_ordinalityOfUnit_inUnit_forDate_1 = _registerName1("ordinalityOfUnit:inUnit:forDate:"); - int _objc_msgSend_704( + int _objc_msgSend_708( ffi.Pointer obj, ffi.Pointer sel, int smaller, int larger, ffi.Pointer date, ) { - return __objc_msgSend_704( + return __objc_msgSend_708( obj, sel, smaller, @@ -19934,7 +20077,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_704Ptr = _lookup< + late final __objc_msgSend_708Ptr = _lookup< ffi.NativeFunction< ffi.UnsignedLong Function( ffi.Pointer, @@ -19942,13 +20085,13 @@ class SentryCocoa { ffi.Int32, ffi.Int32, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_704 = __objc_msgSend_704Ptr.asFunction< + late final __objc_msgSend_708 = __objc_msgSend_708Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, int, int, ffi.Pointer)>(); late final _sel_rangeOfUnit_startDate_interval_forDate_1 = _registerName1("rangeOfUnit:startDate:interval:forDate:"); - bool _objc_msgSend_705( + bool _objc_msgSend_709( ffi.Pointer obj, ffi.Pointer sel, int unit, @@ -19956,7 +20099,7 @@ class SentryCocoa { ffi.Pointer tip, ffi.Pointer date, ) { - return __objc_msgSend_705( + return __objc_msgSend_709( obj, sel, unit, @@ -19966,7 +20109,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_705Ptr = _lookup< + late final __objc_msgSend_709Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -19975,7 +20118,7 @@ class SentryCocoa { ffi.Pointer>, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_705 = __objc_msgSend_705Ptr.asFunction< + late final __objc_msgSend_709 = __objc_msgSend_709Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -19987,23 +20130,23 @@ class SentryCocoa { late final _class_NSDateComponents1 = _getClass1("NSDateComponents"); late final _sel_calendar1 = _registerName1("calendar"); late final _sel_setCalendar_1 = _registerName1("setCalendar:"); - void _objc_msgSend_706( + void _objc_msgSend_710( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_706( + return __objc_msgSend_710( obj, sel, value, ); } - late final __objc_msgSend_706Ptr = _lookup< + late final __objc_msgSend_710Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_706 = __objc_msgSend_706Ptr.asFunction< + late final __objc_msgSend_710 = __objc_msgSend_710Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -20042,13 +20185,13 @@ class SentryCocoa { late final _sel_setWeek_1 = _registerName1("setWeek:"); late final _sel_setValue_forComponent_1 = _registerName1("setValue:forComponent:"); - void _objc_msgSend_707( + void _objc_msgSend_711( ffi.Pointer obj, ffi.Pointer sel, int value, int unit, ) { - return __objc_msgSend_707( + return __objc_msgSend_711( obj, sel, value, @@ -20056,86 +20199,86 @@ class SentryCocoa { ); } - late final __objc_msgSend_707Ptr = _lookup< + late final __objc_msgSend_711Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Long, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_707 = __objc_msgSend_707Ptr.asFunction< + late final __objc_msgSend_711 = __objc_msgSend_711Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int, int)>(); late final _sel_valueForComponent_1 = _registerName1("valueForComponent:"); - int _objc_msgSend_708( + int _objc_msgSend_712( ffi.Pointer obj, ffi.Pointer sel, int unit, ) { - return __objc_msgSend_708( + return __objc_msgSend_712( obj, sel, unit, ); } - late final __objc_msgSend_708Ptr = _lookup< + late final __objc_msgSend_712Ptr = _lookup< ffi.NativeFunction< ffi.Long Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_708 = __objc_msgSend_708Ptr.asFunction< + late final __objc_msgSend_712 = __objc_msgSend_712Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_isValidDate1 = _registerName1("isValidDate"); late final _sel_isValidDateInCalendar_1 = _registerName1("isValidDateInCalendar:"); - bool _objc_msgSend_709( + bool _objc_msgSend_713( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer calendar, ) { - return __objc_msgSend_709( + return __objc_msgSend_713( obj, sel, calendar, ); } - late final __objc_msgSend_709Ptr = _lookup< + late final __objc_msgSend_713Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_709 = __objc_msgSend_709Ptr.asFunction< + late final __objc_msgSend_713 = __objc_msgSend_713Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_dateFromComponents_1 = _registerName1("dateFromComponents:"); - ffi.Pointer _objc_msgSend_710( + ffi.Pointer _objc_msgSend_714( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer comps, ) { - return __objc_msgSend_710( + return __objc_msgSend_714( obj, sel, comps, ); } - late final __objc_msgSend_710Ptr = _lookup< + late final __objc_msgSend_714Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_710 = __objc_msgSend_710Ptr.asFunction< + late final __objc_msgSend_714 = __objc_msgSend_714Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_components_fromDate_1 = _registerName1("components:fromDate:"); - ffi.Pointer _objc_msgSend_711( + ffi.Pointer _objc_msgSend_715( ffi.Pointer obj, ffi.Pointer sel, int unitFlags, ffi.Pointer date, ) { - return __objc_msgSend_711( + return __objc_msgSend_715( obj, sel, unitFlags, @@ -20143,27 +20286,27 @@ class SentryCocoa { ); } - late final __objc_msgSend_711Ptr = _lookup< + late final __objc_msgSend_715Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Int32, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_711 = __objc_msgSend_711Ptr.asFunction< + late final __objc_msgSend_715 = __objc_msgSend_715Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer)>(); late final _sel_dateByAddingComponents_toDate_options_1 = _registerName1("dateByAddingComponents:toDate:options:"); - ffi.Pointer _objc_msgSend_712( + ffi.Pointer _objc_msgSend_716( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer comps, ffi.Pointer date, int opts, ) { - return __objc_msgSend_712( + return __objc_msgSend_716( obj, sel, comps, @@ -20172,7 +20315,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_712Ptr = _lookup< + late final __objc_msgSend_716Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20180,7 +20323,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_712 = __objc_msgSend_712Ptr.asFunction< + late final __objc_msgSend_716 = __objc_msgSend_716Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -20190,7 +20333,7 @@ class SentryCocoa { late final _sel_components_fromDate_toDate_options_1 = _registerName1("components:fromDate:toDate:options:"); - ffi.Pointer _objc_msgSend_713( + ffi.Pointer _objc_msgSend_717( ffi.Pointer obj, ffi.Pointer sel, int unitFlags, @@ -20198,7 +20341,7 @@ class SentryCocoa { ffi.Pointer resultDate, int opts, ) { - return __objc_msgSend_713( + return __objc_msgSend_717( obj, sel, unitFlags, @@ -20208,7 +20351,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_713Ptr = _lookup< + late final __objc_msgSend_717Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20217,7 +20360,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_713 = __objc_msgSend_713Ptr.asFunction< + late final __objc_msgSend_717 = __objc_msgSend_717Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -20228,7 +20371,7 @@ class SentryCocoa { late final _sel_getEra_year_month_day_fromDate_1 = _registerName1("getEra:year:month:day:fromDate:"); - void _objc_msgSend_714( + void _objc_msgSend_718( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer eraValuePointer, @@ -20237,7 +20380,7 @@ class SentryCocoa { ffi.Pointer dayValuePointer, ffi.Pointer date, ) { - return __objc_msgSend_714( + return __objc_msgSend_718( obj, sel, eraValuePointer, @@ -20248,7 +20391,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_714Ptr = _lookup< + late final __objc_msgSend_718Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -20258,7 +20401,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_714 = __objc_msgSend_714Ptr.asFunction< + late final __objc_msgSend_718 = __objc_msgSend_718Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -20273,13 +20416,13 @@ class SentryCocoa { late final _sel_getHour_minute_second_nanosecond_fromDate_1 = _registerName1("getHour:minute:second:nanosecond:fromDate:"); late final _sel_component_fromDate_1 = _registerName1("component:fromDate:"); - int _objc_msgSend_715( + int _objc_msgSend_719( ffi.Pointer obj, ffi.Pointer sel, int unit, ffi.Pointer date, ) { - return __objc_msgSend_715( + return __objc_msgSend_719( obj, sel, unit, @@ -20287,18 +20430,18 @@ class SentryCocoa { ); } - late final __objc_msgSend_715Ptr = _lookup< + late final __objc_msgSend_719Ptr = _lookup< ffi.NativeFunction< ffi.Long Function(ffi.Pointer, ffi.Pointer, ffi.Int32, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_715 = __objc_msgSend_715Ptr.asFunction< + late final __objc_msgSend_719 = __objc_msgSend_719Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer)>(); late final _sel_dateWithEra_year_month_day_hour_minute_second_nanosecond_1 = _registerName1( "dateWithEra:year:month:day:hour:minute:second:nanosecond:"); - ffi.Pointer _objc_msgSend_716( + ffi.Pointer _objc_msgSend_720( ffi.Pointer obj, ffi.Pointer sel, int eraValue, @@ -20310,7 +20453,7 @@ class SentryCocoa { int secondValue, int nanosecondValue, ) { - return __objc_msgSend_716( + return __objc_msgSend_720( obj, sel, eraValue, @@ -20324,7 +20467,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_716Ptr = _lookup< + late final __objc_msgSend_720Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20337,7 +20480,7 @@ class SentryCocoa { ffi.Long, ffi.Long, ffi.Long)>>('objc_msgSend'); - late final __objc_msgSend_716 = __objc_msgSend_716Ptr.asFunction< + late final __objc_msgSend_720 = __objc_msgSend_720Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, int, int, int, int, int, int, int, int)>(); @@ -20347,13 +20490,13 @@ class SentryCocoa { late final _sel_startOfDayForDate_1 = _registerName1("startOfDayForDate:"); late final _sel_componentsInTimeZone_fromDate_1 = _registerName1("componentsInTimeZone:fromDate:"); - ffi.Pointer _objc_msgSend_717( + ffi.Pointer _objc_msgSend_721( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer timezone, ffi.Pointer date, ) { - return __objc_msgSend_717( + return __objc_msgSend_721( obj, sel, timezone, @@ -20361,14 +20504,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_717Ptr = _lookup< + late final __objc_msgSend_721Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_717 = __objc_msgSend_717Ptr.asFunction< + late final __objc_msgSend_721 = __objc_msgSend_721Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -20377,14 +20520,14 @@ class SentryCocoa { late final _sel_compareDate_toDate_toUnitGranularity_1 = _registerName1("compareDate:toDate:toUnitGranularity:"); - int _objc_msgSend_718( + int _objc_msgSend_722( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date1, ffi.Pointer date2, int unit, ) { - return __objc_msgSend_718( + return __objc_msgSend_722( obj, sel, date1, @@ -20393,7 +20536,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_718Ptr = _lookup< + late final __objc_msgSend_722Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, @@ -20401,20 +20544,20 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_718 = __objc_msgSend_718Ptr.asFunction< + late final __objc_msgSend_722 = __objc_msgSend_722Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); late final _sel_isDate_equalToDate_toUnitGranularity_1 = _registerName1("isDate:equalToDate:toUnitGranularity:"); - bool _objc_msgSend_719( + bool _objc_msgSend_723( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date1, ffi.Pointer date2, int unit, ) { - return __objc_msgSend_719( + return __objc_msgSend_723( obj, sel, date1, @@ -20423,7 +20566,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_719Ptr = _lookup< + late final __objc_msgSend_723Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -20431,19 +20574,19 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_719 = __objc_msgSend_719Ptr.asFunction< + late final __objc_msgSend_723 = __objc_msgSend_723Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); late final _sel_isDate_inSameDayAsDate_1 = _registerName1("isDate:inSameDayAsDate:"); - bool _objc_msgSend_720( + bool _objc_msgSend_724( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date1, ffi.Pointer date2, ) { - return __objc_msgSend_720( + return __objc_msgSend_724( obj, sel, date1, @@ -20451,14 +20594,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_720Ptr = _lookup< + late final __objc_msgSend_724Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_720 = __objc_msgSend_720Ptr.asFunction< + late final __objc_msgSend_724 = __objc_msgSend_724Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -20468,14 +20611,14 @@ class SentryCocoa { late final _sel_isDateInWeekend_1 = _registerName1("isDateInWeekend:"); late final _sel_rangeOfWeekendStartDate_interval_containingDate_1 = _registerName1("rangeOfWeekendStartDate:interval:containingDate:"); - bool _objc_msgSend_721( + bool _objc_msgSend_725( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> datep, ffi.Pointer tip, ffi.Pointer date, ) { - return __objc_msgSend_721( + return __objc_msgSend_725( obj, sel, datep, @@ -20484,7 +20627,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_721Ptr = _lookup< + late final __objc_msgSend_725Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -20492,7 +20635,7 @@ class SentryCocoa { ffi.Pointer>, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_721 = __objc_msgSend_721Ptr.asFunction< + late final __objc_msgSend_725 = __objc_msgSend_725Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -20502,7 +20645,7 @@ class SentryCocoa { late final _sel_nextWeekendStartDate_interval_options_afterDate_1 = _registerName1("nextWeekendStartDate:interval:options:afterDate:"); - bool _objc_msgSend_722( + bool _objc_msgSend_726( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> datep, @@ -20510,7 +20653,7 @@ class SentryCocoa { int options, ffi.Pointer date, ) { - return __objc_msgSend_722( + return __objc_msgSend_726( obj, sel, datep, @@ -20520,7 +20663,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_722Ptr = _lookup< + late final __objc_msgSend_726Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -20529,7 +20672,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_722 = __objc_msgSend_722Ptr.asFunction< + late final __objc_msgSend_726 = __objc_msgSend_726Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -20540,7 +20683,7 @@ class SentryCocoa { late final _sel_components_fromDateComponents_toDateComponents_options_1 = _registerName1("components:fromDateComponents:toDateComponents:options:"); - ffi.Pointer _objc_msgSend_723( + ffi.Pointer _objc_msgSend_727( ffi.Pointer obj, ffi.Pointer sel, int unitFlags, @@ -20548,7 +20691,7 @@ class SentryCocoa { ffi.Pointer resultDateComp, int options, ) { - return __objc_msgSend_723( + return __objc_msgSend_727( obj, sel, unitFlags, @@ -20558,7 +20701,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_723Ptr = _lookup< + late final __objc_msgSend_727Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20567,7 +20710,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_723 = __objc_msgSend_723Ptr.asFunction< + late final __objc_msgSend_727 = __objc_msgSend_727Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -20578,7 +20721,7 @@ class SentryCocoa { late final _sel_dateByAddingUnit_value_toDate_options_1 = _registerName1("dateByAddingUnit:value:toDate:options:"); - ffi.Pointer _objc_msgSend_724( + ffi.Pointer _objc_msgSend_728( ffi.Pointer obj, ffi.Pointer sel, int unit, @@ -20586,7 +20729,7 @@ class SentryCocoa { ffi.Pointer date, int options, ) { - return __objc_msgSend_724( + return __objc_msgSend_728( obj, sel, unit, @@ -20596,7 +20739,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_724Ptr = _lookup< + late final __objc_msgSend_728Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20605,14 +20748,14 @@ class SentryCocoa { ffi.Long, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_724 = __objc_msgSend_724Ptr.asFunction< + late final __objc_msgSend_728 = __objc_msgSend_728Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, int, int, ffi.Pointer, int)>(); late final _sel_enumerateDatesStartingAfterDate_matchingComponents_options_usingBlock_1 = _registerName1( "enumerateDatesStartingAfterDate:matchingComponents:options:usingBlock:"); - void _objc_msgSend_725( + void _objc_msgSend_729( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer start, @@ -20620,7 +20763,7 @@ class SentryCocoa { int opts, ffi.Pointer<_ObjCBlock> block, ) { - return __objc_msgSend_725( + return __objc_msgSend_729( obj, sel, start, @@ -20630,7 +20773,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_725Ptr = _lookup< + late final __objc_msgSend_729Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -20639,7 +20782,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_725 = __objc_msgSend_725Ptr.asFunction< + late final __objc_msgSend_729 = __objc_msgSend_729Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -20650,14 +20793,14 @@ class SentryCocoa { late final _sel_nextDateAfterDate_matchingComponents_options_1 = _registerName1("nextDateAfterDate:matchingComponents:options:"); - ffi.Pointer _objc_msgSend_726( + ffi.Pointer _objc_msgSend_730( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date, ffi.Pointer comps, int options, ) { - return __objc_msgSend_726( + return __objc_msgSend_730( obj, sel, date, @@ -20666,7 +20809,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_726Ptr = _lookup< + late final __objc_msgSend_730Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20674,7 +20817,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_726 = __objc_msgSend_726Ptr.asFunction< + late final __objc_msgSend_730 = __objc_msgSend_730Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -20684,7 +20827,7 @@ class SentryCocoa { late final _sel_nextDateAfterDate_matchingUnit_value_options_1 = _registerName1("nextDateAfterDate:matchingUnit:value:options:"); - ffi.Pointer _objc_msgSend_727( + ffi.Pointer _objc_msgSend_731( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date, @@ -20692,7 +20835,7 @@ class SentryCocoa { int value, int options, ) { - return __objc_msgSend_727( + return __objc_msgSend_731( obj, sel, date, @@ -20702,7 +20845,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_727Ptr = _lookup< + late final __objc_msgSend_731Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20711,13 +20854,13 @@ class SentryCocoa { ffi.Int32, ffi.Long, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_727 = __objc_msgSend_727Ptr.asFunction< + late final __objc_msgSend_731 = __objc_msgSend_731Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, int, int)>(); late final _sel_nextDateAfterDate_matchingHour_minute_second_options_1 = _registerName1("nextDateAfterDate:matchingHour:minute:second:options:"); - ffi.Pointer _objc_msgSend_728( + ffi.Pointer _objc_msgSend_732( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date, @@ -20726,7 +20869,7 @@ class SentryCocoa { int secondValue, int options, ) { - return __objc_msgSend_728( + return __objc_msgSend_732( obj, sel, date, @@ -20737,7 +20880,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_728Ptr = _lookup< + late final __objc_msgSend_732Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20747,7 +20890,7 @@ class SentryCocoa { ffi.Long, ffi.Long, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_728 = __objc_msgSend_728Ptr.asFunction< + late final __objc_msgSend_732 = __objc_msgSend_732Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, int, int, int)>(); @@ -20755,7 +20898,7 @@ class SentryCocoa { _registerName1("dateBySettingUnit:value:ofDate:options:"); late final _sel_dateBySettingHour_minute_second_ofDate_options_1 = _registerName1("dateBySettingHour:minute:second:ofDate:options:"); - ffi.Pointer _objc_msgSend_729( + ffi.Pointer _objc_msgSend_733( ffi.Pointer obj, ffi.Pointer sel, int h, @@ -20764,7 +20907,7 @@ class SentryCocoa { ffi.Pointer date, int opts, ) { - return __objc_msgSend_729( + return __objc_msgSend_733( obj, sel, h, @@ -20775,7 +20918,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_729Ptr = _lookup< + late final __objc_msgSend_733Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -20785,19 +20928,19 @@ class SentryCocoa { ffi.Long, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_729 = __objc_msgSend_729Ptr.asFunction< + late final __objc_msgSend_733 = __objc_msgSend_733Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, int, int, int, ffi.Pointer, int)>(); late final _sel_date_matchesComponents_1 = _registerName1("date:matchesComponents:"); - bool _objc_msgSend_730( + bool _objc_msgSend_734( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer date, ffi.Pointer components, ) { - return __objc_msgSend_730( + return __objc_msgSend_734( obj, sel, date, @@ -20805,14 +20948,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_730Ptr = _lookup< + late final __objc_msgSend_734Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_730 = __objc_msgSend_730Ptr.asFunction< + late final __objc_msgSend_734 = __objc_msgSend_734Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -20824,23 +20967,23 @@ class SentryCocoa { late final _sel_defaultDate1 = _registerName1("defaultDate"); late final _sel_setDefaultDate_1 = _registerName1("setDefaultDate:"); late final _sel_setEraSymbols_1 = _registerName1("setEraSymbols:"); - void _objc_msgSend_731( + void _objc_msgSend_735( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_731( + return __objc_msgSend_735( obj, sel, value, ); } - late final __objc_msgSend_731Ptr = _lookup< + late final __objc_msgSend_735Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_731 = __objc_msgSend_731Ptr.asFunction< + late final __objc_msgSend_735 = __objc_msgSend_735Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -20889,56 +21032,56 @@ class SentryCocoa { _registerName1("allowsNaturalLanguage"); late final _class_NSNumberFormatter1 = _getClass1("NSNumberFormatter"); late final _sel_stringFromNumber_1 = _registerName1("stringFromNumber:"); - ffi.Pointer _objc_msgSend_732( + ffi.Pointer _objc_msgSend_736( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer number, ) { - return __objc_msgSend_732( + return __objc_msgSend_736( obj, sel, number, ); } - late final __objc_msgSend_732Ptr = _lookup< + late final __objc_msgSend_736Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_732 = __objc_msgSend_732Ptr.asFunction< + late final __objc_msgSend_736 = __objc_msgSend_736Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_numberFromString_1 = _registerName1("numberFromString:"); - ffi.Pointer _objc_msgSend_733( + ffi.Pointer _objc_msgSend_737( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, ) { - return __objc_msgSend_733( + return __objc_msgSend_737( obj, sel, string, ); } - late final __objc_msgSend_733Ptr = _lookup< + late final __objc_msgSend_737Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_733 = __objc_msgSend_733Ptr.asFunction< + late final __objc_msgSend_737 = __objc_msgSend_737Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_localizedStringFromNumber_numberStyle_1 = _registerName1("localizedStringFromNumber:numberStyle:"); - ffi.Pointer _objc_msgSend_734( + ffi.Pointer _objc_msgSend_738( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer num, int nstyle, ) { - return __objc_msgSend_734( + return __objc_msgSend_738( obj, sel, num, @@ -20946,112 +21089,112 @@ class SentryCocoa { ); } - late final __objc_msgSend_734Ptr = _lookup< + late final __objc_msgSend_738Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_734 = __objc_msgSend_734Ptr.asFunction< + late final __objc_msgSend_738 = __objc_msgSend_738Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); - int _objc_msgSend_735( + int _objc_msgSend_739( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_735( + return __objc_msgSend_739( obj, sel, ); } - late final __objc_msgSend_735Ptr = _lookup< + late final __objc_msgSend_739Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_735 = __objc_msgSend_735Ptr.asFunction< + late final __objc_msgSend_739 = __objc_msgSend_739Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); - void _objc_msgSend_736( + void _objc_msgSend_740( ffi.Pointer obj, ffi.Pointer sel, int behavior, ) { - return __objc_msgSend_736( + return __objc_msgSend_740( obj, sel, behavior, ); } - late final __objc_msgSend_736Ptr = _lookup< + late final __objc_msgSend_740Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_736 = __objc_msgSend_736Ptr.asFunction< + late final __objc_msgSend_740 = __objc_msgSend_740Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_numberStyle1 = _registerName1("numberStyle"); - int _objc_msgSend_737( + int _objc_msgSend_741( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_737( + return __objc_msgSend_741( obj, sel, ); } - late final __objc_msgSend_737Ptr = _lookup< + late final __objc_msgSend_741Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_737 = __objc_msgSend_737Ptr.asFunction< + late final __objc_msgSend_741 = __objc_msgSend_741Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setNumberStyle_1 = _registerName1("setNumberStyle:"); - void _objc_msgSend_738( + void _objc_msgSend_742( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_738( + return __objc_msgSend_742( obj, sel, value, ); } - late final __objc_msgSend_738Ptr = _lookup< + late final __objc_msgSend_742Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_738 = __objc_msgSend_738Ptr.asFunction< + late final __objc_msgSend_742 = __objc_msgSend_742Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_generatesDecimalNumbers1 = _registerName1("generatesDecimalNumbers"); late final _sel_setGeneratesDecimalNumbers_1 = _registerName1("setGeneratesDecimalNumbers:"); - void _objc_msgSend_739( + void _objc_msgSend_743( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_739( + return __objc_msgSend_743( obj, sel, value, ); } - late final __objc_msgSend_739Ptr = _lookup< + late final __objc_msgSend_743Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_739 = __objc_msgSend_739Ptr.asFunction< + late final __objc_msgSend_743 = __objc_msgSend_743Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_negativeFormat1 = _registerName1("negativeFormat"); @@ -21157,79 +21300,79 @@ class SentryCocoa { late final _sel_setPaddingCharacter_1 = _registerName1("setPaddingCharacter:"); late final _sel_paddingPosition1 = _registerName1("paddingPosition"); - int _objc_msgSend_740( + int _objc_msgSend_744( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_740( + return __objc_msgSend_744( obj, sel, ); } - late final __objc_msgSend_740Ptr = _lookup< + late final __objc_msgSend_744Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_740 = __objc_msgSend_740Ptr.asFunction< + late final __objc_msgSend_744 = __objc_msgSend_744Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setPaddingPosition_1 = _registerName1("setPaddingPosition:"); - void _objc_msgSend_741( + void _objc_msgSend_745( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_741( + return __objc_msgSend_745( obj, sel, value, ); } - late final __objc_msgSend_741Ptr = _lookup< + late final __objc_msgSend_745Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_741 = __objc_msgSend_741Ptr.asFunction< + late final __objc_msgSend_745 = __objc_msgSend_745Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_roundingMode1 = _registerName1("roundingMode"); - int _objc_msgSend_742( + int _objc_msgSend_746( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_742( + return __objc_msgSend_746( obj, sel, ); } - late final __objc_msgSend_742Ptr = _lookup< + late final __objc_msgSend_746Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_742 = __objc_msgSend_742Ptr.asFunction< + late final __objc_msgSend_746 = __objc_msgSend_746Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setRoundingMode_1 = _registerName1("setRoundingMode:"); - void _objc_msgSend_743( + void _objc_msgSend_747( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_743( + return __objc_msgSend_747( obj, sel, value, ); } - late final __objc_msgSend_743Ptr = _lookup< + late final __objc_msgSend_747Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_743 = __objc_msgSend_743Ptr.asFunction< + late final __objc_msgSend_747 = __objc_msgSend_747Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_roundingIncrement1 = _registerName1("roundingIncrement"); @@ -21290,23 +21433,23 @@ class SentryCocoa { _registerName1("attributedStringForZero"); late final _sel_setAttributedStringForZero_1 = _registerName1("setAttributedStringForZero:"); - void _objc_msgSend_744( + void _objc_msgSend_748( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_744( + return __objc_msgSend_748( obj, sel, value, ); } - late final __objc_msgSend_744Ptr = _lookup< + late final __objc_msgSend_748Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_744 = __objc_msgSend_744Ptr.asFunction< + late final __objc_msgSend_748 = __objc_msgSend_748Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -21322,28 +21465,28 @@ class SentryCocoa { _getClass1("NSDecimalNumberHandler"); late final _sel_defaultDecimalNumberHandler1 = _registerName1("defaultDecimalNumberHandler"); - ffi.Pointer _objc_msgSend_745( + ffi.Pointer _objc_msgSend_749( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_745( + return __objc_msgSend_749( obj, sel, ); } - late final __objc_msgSend_745Ptr = _lookup< + late final __objc_msgSend_749Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_745 = __objc_msgSend_745Ptr.asFunction< + late final __objc_msgSend_749 = __objc_msgSend_749Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_initWithRoundingMode_scale_raiseOnExactness_raiseOnOverflow_raiseOnUnderflow_raiseOnDivideByZero_1 = _registerName1( "initWithRoundingMode:scale:raiseOnExactness:raiseOnOverflow:raiseOnUnderflow:raiseOnDivideByZero:"); - instancetype _objc_msgSend_746( + instancetype _objc_msgSend_750( ffi.Pointer obj, ffi.Pointer sel, int roundingMode, @@ -21353,7 +21496,7 @@ class SentryCocoa { bool underflow, bool divideByZero, ) { - return __objc_msgSend_746( + return __objc_msgSend_750( obj, sel, roundingMode, @@ -21365,7 +21508,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_746Ptr = _lookup< + late final __objc_msgSend_750Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -21376,7 +21519,7 @@ class SentryCocoa { ffi.Bool, ffi.Bool, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_746 = __objc_msgSend_746Ptr.asFunction< + late final __objc_msgSend_750 = __objc_msgSend_750Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, int, int, bool, bool, bool, bool)>(); @@ -21386,23 +21529,23 @@ class SentryCocoa { late final _sel_roundingBehavior1 = _registerName1("roundingBehavior"); late final _sel_setRoundingBehavior_1 = _registerName1("setRoundingBehavior:"); - void _objc_msgSend_747( + void _objc_msgSend_751( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_747( + return __objc_msgSend_751( obj, sel, value, ); } - late final __objc_msgSend_747Ptr = _lookup< + late final __objc_msgSend_751Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_747 = __objc_msgSend_747Ptr.asFunction< + late final __objc_msgSend_751 = __objc_msgSend_751Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -21413,173 +21556,173 @@ class SentryCocoa { _registerName1("charactersToBeSkipped"); late final _sel_setCharactersToBeSkipped_1 = _registerName1("setCharactersToBeSkipped:"); - void _objc_msgSend_748( + void _objc_msgSend_752( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_748( + return __objc_msgSend_752( obj, sel, value, ); } - late final __objc_msgSend_748Ptr = _lookup< + late final __objc_msgSend_752Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_748 = __objc_msgSend_748Ptr.asFunction< + late final __objc_msgSend_752 = __objc_msgSend_752Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_caseSensitive1 = _registerName1("caseSensitive"); late final _sel_setCaseSensitive_1 = _registerName1("setCaseSensitive:"); late final _sel_scanInt_1 = _registerName1("scanInt:"); - bool _objc_msgSend_749( + bool _objc_msgSend_753( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, ) { - return __objc_msgSend_749( + return __objc_msgSend_753( obj, sel, result, ); } - late final __objc_msgSend_749Ptr = _lookup< + late final __objc_msgSend_753Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_749 = __objc_msgSend_749Ptr.asFunction< + late final __objc_msgSend_753 = __objc_msgSend_753Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_scanInteger_1 = _registerName1("scanInteger:"); - bool _objc_msgSend_750( + bool _objc_msgSend_754( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, ) { - return __objc_msgSend_750( + return __objc_msgSend_754( obj, sel, result, ); } - late final __objc_msgSend_750Ptr = _lookup< + late final __objc_msgSend_754Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_750 = __objc_msgSend_750Ptr.asFunction< + late final __objc_msgSend_754 = __objc_msgSend_754Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_scanLongLong_1 = _registerName1("scanLongLong:"); - bool _objc_msgSend_751( + bool _objc_msgSend_755( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, ) { - return __objc_msgSend_751( + return __objc_msgSend_755( obj, sel, result, ); } - late final __objc_msgSend_751Ptr = _lookup< + late final __objc_msgSend_755Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_751 = __objc_msgSend_751Ptr.asFunction< + late final __objc_msgSend_755 = __objc_msgSend_755Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_scanUnsignedLongLong_1 = _registerName1("scanUnsignedLongLong:"); - bool _objc_msgSend_752( + bool _objc_msgSend_756( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, ) { - return __objc_msgSend_752( + return __objc_msgSend_756( obj, sel, result, ); } - late final __objc_msgSend_752Ptr = _lookup< + late final __objc_msgSend_756Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_752 = __objc_msgSend_752Ptr.asFunction< + late final __objc_msgSend_756 = __objc_msgSend_756Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_scanFloat_1 = _registerName1("scanFloat:"); - bool _objc_msgSend_753( + bool _objc_msgSend_757( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, ) { - return __objc_msgSend_753( + return __objc_msgSend_757( obj, sel, result, ); } - late final __objc_msgSend_753Ptr = _lookup< + late final __objc_msgSend_757Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_753 = __objc_msgSend_753Ptr.asFunction< + late final __objc_msgSend_757 = __objc_msgSend_757Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_scanDouble_1 = _registerName1("scanDouble:"); - bool _objc_msgSend_754( + bool _objc_msgSend_758( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, ) { - return __objc_msgSend_754( + return __objc_msgSend_758( obj, sel, result, ); } - late final __objc_msgSend_754Ptr = _lookup< + late final __objc_msgSend_758Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_754 = __objc_msgSend_754Ptr.asFunction< + late final __objc_msgSend_758 = __objc_msgSend_758Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_scanHexInt_1 = _registerName1("scanHexInt:"); - bool _objc_msgSend_755( + bool _objc_msgSend_759( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, ) { - return __objc_msgSend_755( + return __objc_msgSend_759( obj, sel, result, ); } - late final __objc_msgSend_755Ptr = _lookup< + late final __objc_msgSend_759Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_755 = __objc_msgSend_755Ptr.asFunction< + late final __objc_msgSend_759 = __objc_msgSend_759Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -21588,13 +21731,13 @@ class SentryCocoa { late final _sel_scanHexDouble_1 = _registerName1("scanHexDouble:"); late final _sel_scanString_intoString_1 = _registerName1("scanString:intoString:"); - bool _objc_msgSend_756( + bool _objc_msgSend_760( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, ffi.Pointer> result, ) { - return __objc_msgSend_756( + return __objc_msgSend_760( obj, sel, string, @@ -21602,26 +21745,26 @@ class SentryCocoa { ); } - late final __objc_msgSend_756Ptr = _lookup< + late final __objc_msgSend_760Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_756 = __objc_msgSend_756Ptr.asFunction< + late final __objc_msgSend_760 = __objc_msgSend_760Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>(); late final _sel_scanCharactersFromSet_intoString_1 = _registerName1("scanCharactersFromSet:intoString:"); - bool _objc_msgSend_757( + bool _objc_msgSend_761( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer set1, ffi.Pointer> result, ) { - return __objc_msgSend_757( + return __objc_msgSend_761( obj, sel, set1, @@ -21629,14 +21772,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_757Ptr = _lookup< + late final __objc_msgSend_761Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_757 = __objc_msgSend_757Ptr.asFunction< + late final __objc_msgSend_761 = __objc_msgSend_761Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>(); @@ -21649,37 +21792,37 @@ class SentryCocoa { late final _sel_localizedScannerWithString_1 = _registerName1("localizedScannerWithString:"); late final _sel_scanDecimal_1 = _registerName1("scanDecimal:"); - bool _objc_msgSend_758( + bool _objc_msgSend_762( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer dcm, ) { - return __objc_msgSend_758( + return __objc_msgSend_762( obj, sel, dcm, ); } - late final __objc_msgSend_758Ptr = _lookup< + late final __objc_msgSend_762Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_758 = __objc_msgSend_758Ptr.asFunction< + late final __objc_msgSend_762 = __objc_msgSend_762Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _class_NSException1 = _getClass1("NSException"); late final _sel_exceptionWithName_reason_userInfo_1 = _registerName1("exceptionWithName:reason:userInfo:"); - ffi.Pointer _objc_msgSend_759( + ffi.Pointer _objc_msgSend_763( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, ffi.Pointer reason, ffi.Pointer userInfo, ) { - return __objc_msgSend_759( + return __objc_msgSend_763( obj, sel, name, @@ -21688,7 +21831,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_759Ptr = _lookup< + late final __objc_msgSend_763Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -21696,7 +21839,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_759 = __objc_msgSend_759Ptr.asFunction< + late final __objc_msgSend_763 = __objc_msgSend_763Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -21711,14 +21854,14 @@ class SentryCocoa { late final _sel_raise_format_1 = _registerName1("raise:format:"); late final _sel_raise_format_arguments_1 = _registerName1("raise:format:arguments:"); - void _objc_msgSend_760( + void _objc_msgSend_764( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, ffi.Pointer format, ffi.Pointer<__va_list_tag> argList, ) { - return __objc_msgSend_760( + return __objc_msgSend_764( obj, sel, name, @@ -21727,7 +21870,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_760Ptr = _lookup< + late final __objc_msgSend_764Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -21735,7 +21878,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer<__va_list_tag>)>>('objc_msgSend'); - late final __objc_msgSend_760 = __objc_msgSend_760Ptr.asFunction< + late final __objc_msgSend_764 = __objc_msgSend_764Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -21747,13 +21890,13 @@ class SentryCocoa { late final _sel_availableData1 = _registerName1("availableData"); late final _sel_initWithFileDescriptor_closeOnDealloc_1 = _registerName1("initWithFileDescriptor:closeOnDealloc:"); - instancetype _objc_msgSend_761( + instancetype _objc_msgSend_765( ffi.Pointer obj, ffi.Pointer sel, int fd, bool closeopt, ) { - return __objc_msgSend_761( + return __objc_msgSend_765( obj, sel, fd, @@ -21761,47 +21904,47 @@ class SentryCocoa { ); } - late final __objc_msgSend_761Ptr = _lookup< + late final __objc_msgSend_765Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Int, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_761 = __objc_msgSend_761Ptr.asFunction< + late final __objc_msgSend_765 = __objc_msgSend_765Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, int, bool)>(); late final _sel_readDataToEndOfFileAndReturnError_1 = _registerName1("readDataToEndOfFileAndReturnError:"); - ffi.Pointer _objc_msgSend_762( + ffi.Pointer _objc_msgSend_766( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> error, ) { - return __objc_msgSend_762( + return __objc_msgSend_766( obj, sel, error, ); } - late final __objc_msgSend_762Ptr = _lookup< + late final __objc_msgSend_766Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_762 = __objc_msgSend_762Ptr.asFunction< + late final __objc_msgSend_766 = __objc_msgSend_766Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer>)>(); late final _sel_readDataUpToLength_error_1 = _registerName1("readDataUpToLength:error:"); - ffi.Pointer _objc_msgSend_763( + ffi.Pointer _objc_msgSend_767( ffi.Pointer obj, ffi.Pointer sel, int length, ffi.Pointer> error, ) { - return __objc_msgSend_763( + return __objc_msgSend_767( obj, sel, length, @@ -21809,25 +21952,25 @@ class SentryCocoa { ); } - late final __objc_msgSend_763Ptr = _lookup< + late final __objc_msgSend_767Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.UnsignedLong, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_763 = __objc_msgSend_763Ptr.asFunction< + late final __objc_msgSend_767 = __objc_msgSend_767Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer>)>(); late final _sel_writeData_error_1 = _registerName1("writeData:error:"); - bool _objc_msgSend_764( + bool _objc_msgSend_768( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer data, ffi.Pointer> error, ) { - return __objc_msgSend_764( + return __objc_msgSend_768( obj, sel, data, @@ -21835,25 +21978,25 @@ class SentryCocoa { ); } - late final __objc_msgSend_764Ptr = _lookup< + late final __objc_msgSend_768Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_764 = __objc_msgSend_764Ptr.asFunction< + late final __objc_msgSend_768 = __objc_msgSend_768Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>(); late final _sel_getOffset_error_1 = _registerName1("getOffset:error:"); - bool _objc_msgSend_765( + bool _objc_msgSend_769( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer offsetInFile, ffi.Pointer> error, ) { - return __objc_msgSend_765( + return __objc_msgSend_769( obj, sel, offsetInFile, @@ -21861,14 +22004,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_765Ptr = _lookup< + late final __objc_msgSend_769Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_765 = __objc_msgSend_765Ptr.asFunction< + late final __objc_msgSend_769 = __objc_msgSend_769Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -21878,13 +22021,13 @@ class SentryCocoa { late final _sel_seekToEndReturningOffset_error_1 = _registerName1("seekToEndReturningOffset:error:"); late final _sel_seekToOffset_error_1 = _registerName1("seekToOffset:error:"); - bool _objc_msgSend_766( + bool _objc_msgSend_770( ffi.Pointer obj, ffi.Pointer sel, int offset, ffi.Pointer> error, ) { - return __objc_msgSend_766( + return __objc_msgSend_770( obj, sel, offset, @@ -21892,14 +22035,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_766Ptr = _lookup< + late final __objc_msgSend_770Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.UnsignedLongLong, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_766 = __objc_msgSend_766Ptr.asFunction< + late final __objc_msgSend_770 = __objc_msgSend_770Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer>)>(); @@ -21911,21 +22054,21 @@ class SentryCocoa { _registerName1("closeAndReturnError:"); late final _sel_fileHandleWithStandardInput1 = _registerName1("fileHandleWithStandardInput"); - ffi.Pointer _objc_msgSend_767( + ffi.Pointer _objc_msgSend_771( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_767( + return __objc_msgSend_771( obj, sel, ); } - late final __objc_msgSend_767Ptr = _lookup< + late final __objc_msgSend_771Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_767 = __objc_msgSend_767Ptr.asFunction< + late final __objc_msgSend_771 = __objc_msgSend_771Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -21943,13 +22086,13 @@ class SentryCocoa { _registerName1("fileHandleForUpdatingAtPath:"); late final _sel_fileHandleForReadingFromURL_error_1 = _registerName1("fileHandleForReadingFromURL:error:"); - instancetype _objc_msgSend_768( + instancetype _objc_msgSend_772( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, ffi.Pointer> error, ) { - return __objc_msgSend_768( + return __objc_msgSend_772( obj, sel, url, @@ -21957,14 +22100,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_768Ptr = _lookup< + late final __objc_msgSend_772Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_768 = __objc_msgSend_768Ptr.asFunction< + late final __objc_msgSend_772 = __objc_msgSend_772Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer>)>(); @@ -21989,43 +22132,43 @@ class SentryCocoa { late final _sel_waitForDataInBackgroundAndNotify1 = _registerName1("waitForDataInBackgroundAndNotify"); late final _sel_readabilityHandler1 = _registerName1("readabilityHandler"); - ffi.Pointer<_ObjCBlock> _objc_msgSend_769( + ffi.Pointer<_ObjCBlock> _objc_msgSend_773( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_769( + return __objc_msgSend_773( obj, sel, ); } - late final __objc_msgSend_769Ptr = _lookup< + late final __objc_msgSend_773Ptr = _lookup< ffi.NativeFunction< ffi.Pointer<_ObjCBlock> Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_769 = __objc_msgSend_769Ptr.asFunction< + late final __objc_msgSend_773 = __objc_msgSend_773Ptr.asFunction< ffi.Pointer<_ObjCBlock> Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_setReadabilityHandler_1 = _registerName1("setReadabilityHandler:"); - void _objc_msgSend_770( + void _objc_msgSend_774( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_ObjCBlock> value, ) { - return __objc_msgSend_770( + return __objc_msgSend_774( obj, sel, value, ); } - late final __objc_msgSend_770Ptr = _lookup< + late final __objc_msgSend_774Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_770 = __objc_msgSend_770Ptr.asFunction< + late final __objc_msgSend_774 = __objc_msgSend_774Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); @@ -22034,23 +22177,23 @@ class SentryCocoa { _registerName1("setWriteabilityHandler:"); late final _sel_initWithFileDescriptor_1 = _registerName1("initWithFileDescriptor:"); - instancetype _objc_msgSend_771( + instancetype _objc_msgSend_775( ffi.Pointer obj, ffi.Pointer sel, int fd, ) { - return __objc_msgSend_771( + return __objc_msgSend_775( obj, sel, fd, ); } - late final __objc_msgSend_771Ptr = _lookup< + late final __objc_msgSend_775Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Int)>>('objc_msgSend'); - late final __objc_msgSend_771 = __objc_msgSend_771Ptr.asFunction< + late final __objc_msgSend_775 = __objc_msgSend_775Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, int)>(); @@ -22060,23 +22203,23 @@ class SentryCocoa { late final _sel_offsetInFile1 = _registerName1("offsetInFile"); late final _sel_seekToEndOfFile1 = _registerName1("seekToEndOfFile"); late final _sel_seekToFileOffset_1 = _registerName1("seekToFileOffset:"); - void _objc_msgSend_772( + void _objc_msgSend_776( ffi.Pointer obj, ffi.Pointer sel, int offset, ) { - return __objc_msgSend_772( + return __objc_msgSend_776( obj, sel, offset, ); } - late final __objc_msgSend_772Ptr = _lookup< + late final __objc_msgSend_776Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.UnsignedLongLong)>>('objc_msgSend'); - late final __objc_msgSend_772 = __objc_msgSend_772Ptr.asFunction< + late final __objc_msgSend_776 = __objc_msgSend_776Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_truncateFileAtOffset_1 = @@ -22086,43 +22229,43 @@ class SentryCocoa { late final _class_NSHTTPCookieStorage1 = _getClass1("NSHTTPCookieStorage"); late final _sel_sharedHTTPCookieStorage1 = _registerName1("sharedHTTPCookieStorage"); - ffi.Pointer _objc_msgSend_773( + ffi.Pointer _objc_msgSend_777( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_773( + return __objc_msgSend_777( obj, sel, ); } - late final __objc_msgSend_773Ptr = _lookup< + late final __objc_msgSend_777Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_773 = __objc_msgSend_773Ptr.asFunction< + late final __objc_msgSend_777 = __objc_msgSend_777Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_sharedCookieStorageForGroupContainerIdentifier_1 = _registerName1("sharedCookieStorageForGroupContainerIdentifier:"); - ffi.Pointer _objc_msgSend_774( + ffi.Pointer _objc_msgSend_778( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer identifier, ) { - return __objc_msgSend_774( + return __objc_msgSend_778( obj, sel, identifier, ); } - late final __objc_msgSend_774Ptr = _lookup< + late final __objc_msgSend_778Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_774 = __objc_msgSend_774Ptr.asFunction< + late final __objc_msgSend_778 = __objc_msgSend_778Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -22131,23 +22274,23 @@ class SentryCocoa { late final _sel_initWithProperties_1 = _registerName1("initWithProperties:"); late final _sel_cookieWithProperties_1 = _registerName1("cookieWithProperties:"); - ffi.Pointer _objc_msgSend_775( + ffi.Pointer _objc_msgSend_779( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer properties, ) { - return __objc_msgSend_775( + return __objc_msgSend_779( obj, sel, properties, ); } - late final __objc_msgSend_775Ptr = _lookup< + late final __objc_msgSend_779Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_775 = __objc_msgSend_775Ptr.asFunction< + late final __objc_msgSend_779 = __objc_msgSend_779Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -22155,13 +22298,13 @@ class SentryCocoa { _registerName1("requestHeaderFieldsWithCookies:"); late final _sel_cookiesWithResponseHeaderFields_forURL_1 = _registerName1("cookiesWithResponseHeaderFields:forURL:"); - ffi.Pointer _objc_msgSend_776( + ffi.Pointer _objc_msgSend_780( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer headerFields, ffi.Pointer URL, ) { - return __objc_msgSend_776( + return __objc_msgSend_780( obj, sel, headerFields, @@ -22169,14 +22312,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_776Ptr = _lookup< + late final __objc_msgSend_780Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_776 = __objc_msgSend_776Ptr.asFunction< + late final __objc_msgSend_780 = __objc_msgSend_780Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -22194,23 +22337,23 @@ class SentryCocoa { late final _sel_portList1 = _registerName1("portList"); late final _sel_sameSitePolicy1 = _registerName1("sameSitePolicy"); late final _sel_setCookie_1 = _registerName1("setCookie:"); - void _objc_msgSend_777( + void _objc_msgSend_781( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer cookie, ) { - return __objc_msgSend_777( + return __objc_msgSend_781( obj, sel, cookie, ); } - late final __objc_msgSend_777Ptr = _lookup< + late final __objc_msgSend_781Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_777 = __objc_msgSend_777Ptr.asFunction< + late final __objc_msgSend_781 = __objc_msgSend_781Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -22220,14 +22363,14 @@ class SentryCocoa { late final _sel_cookiesForURL_1 = _registerName1("cookiesForURL:"); late final _sel_setCookies_forURL_mainDocumentURL_1 = _registerName1("setCookies:forURL:mainDocumentURL:"); - void _objc_msgSend_778( + void _objc_msgSend_782( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer cookies, ffi.Pointer URL, ffi.Pointer mainDocumentURL, ) { - return __objc_msgSend_778( + return __objc_msgSend_782( obj, sel, cookies, @@ -22236,7 +22379,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_778Ptr = _lookup< + late final __objc_msgSend_782Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -22244,7 +22387,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_778 = __objc_msgSend_778Ptr.asFunction< + late final __objc_msgSend_782 = __objc_msgSend_782Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -22253,42 +22396,42 @@ class SentryCocoa { ffi.Pointer)>(); late final _sel_cookieAcceptPolicy1 = _registerName1("cookieAcceptPolicy"); - int _objc_msgSend_779( + int _objc_msgSend_783( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_779( + return __objc_msgSend_783( obj, sel, ); } - late final __objc_msgSend_779Ptr = _lookup< + late final __objc_msgSend_783Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_779 = __objc_msgSend_779Ptr.asFunction< + late final __objc_msgSend_783 = __objc_msgSend_783Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setCookieAcceptPolicy_1 = _registerName1("setCookieAcceptPolicy:"); - void _objc_msgSend_780( + void _objc_msgSend_784( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_780( + return __objc_msgSend_784( obj, sel, value, ); } - late final __objc_msgSend_780Ptr = _lookup< + late final __objc_msgSend_784Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_780 = __objc_msgSend_780Ptr.asFunction< + late final __objc_msgSend_784 = __objc_msgSend_784Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_sortedCookiesUsingDescriptors_1 = @@ -22301,14 +22444,14 @@ class SentryCocoa { _registerName1("supportsSecureCoding"); late final _sel_requestWithURL_cachePolicy_timeoutInterval_1 = _registerName1("requestWithURL:cachePolicy:timeoutInterval:"); - instancetype _objc_msgSend_781( + instancetype _objc_msgSend_785( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer URL, int cachePolicy, double timeoutInterval, ) { - return __objc_msgSend_781( + return __objc_msgSend_785( obj, sel, URL, @@ -22317,11 +22460,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_781Ptr = _lookup< + late final __objc_msgSend_785Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Int32, ffi.Double)>>('objc_msgSend'); - late final __objc_msgSend_781 = __objc_msgSend_781Ptr.asFunction< + late final __objc_msgSend_785 = __objc_msgSend_785Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, double)>(); @@ -22329,41 +22472,41 @@ class SentryCocoa { _registerName1("initWithURL:cachePolicy:timeoutInterval:"); late final _sel_URL1 = _registerName1("URL"); late final _sel_cachePolicy1 = _registerName1("cachePolicy"); - int _objc_msgSend_782( + int _objc_msgSend_786( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_782( + return __objc_msgSend_786( obj, sel, ); } - late final __objc_msgSend_782Ptr = _lookup< + late final __objc_msgSend_786Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_782 = __objc_msgSend_782Ptr.asFunction< + late final __objc_msgSend_786 = __objc_msgSend_786Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_timeoutInterval1 = _registerName1("timeoutInterval"); late final _sel_mainDocumentURL1 = _registerName1("mainDocumentURL"); late final _sel_networkServiceType1 = _registerName1("networkServiceType"); - int _objc_msgSend_783( + int _objc_msgSend_787( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_783( + return __objc_msgSend_787( obj, sel, ); } - late final __objc_msgSend_783Ptr = _lookup< + late final __objc_msgSend_787Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_783 = __objc_msgSend_783Ptr.asFunction< + late final __objc_msgSend_787 = __objc_msgSend_787Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_allowsCellularAccess1 = @@ -22374,21 +22517,21 @@ class SentryCocoa { _registerName1("allowsConstrainedNetworkAccess"); late final _sel_assumesHTTP3Capable1 = _registerName1("assumesHTTP3Capable"); late final _sel_attribution1 = _registerName1("attribution"); - int _objc_msgSend_784( + int _objc_msgSend_788( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_784( + return __objc_msgSend_788( obj, sel, ); } - late final __objc_msgSend_784Ptr = _lookup< + late final __objc_msgSend_788Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_784 = __objc_msgSend_784Ptr.asFunction< + late final __objc_msgSend_788 = __objc_msgSend_788Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_requiresDNSSECValidation1 = @@ -22403,33 +22546,33 @@ class SentryCocoa { late final _sel_open1 = _registerName1("open"); late final _sel_close1 = _registerName1("close"); late final _sel_streamStatus1 = _registerName1("streamStatus"); - int _objc_msgSend_785( + int _objc_msgSend_789( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_785( + return __objc_msgSend_789( obj, sel, ); } - late final __objc_msgSend_785Ptr = _lookup< + late final __objc_msgSend_789Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_785 = __objc_msgSend_785Ptr.asFunction< + late final __objc_msgSend_789 = __objc_msgSend_789Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_streamError1 = _registerName1("streamError"); late final _class_NSOutputStream1 = _getClass1("NSOutputStream"); late final _sel_write_maxLength_1 = _registerName1("write:maxLength:"); - int _objc_msgSend_786( + int _objc_msgSend_790( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer buffer, int len, ) { - return __objc_msgSend_786( + return __objc_msgSend_790( obj, sel, buffer, @@ -22437,11 +22580,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_786Ptr = _lookup< + late final __objc_msgSend_790Ptr = _lookup< ffi.NativeFunction< ffi.Long Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_786 = __objc_msgSend_786Ptr.asFunction< + late final __objc_msgSend_790 = __objc_msgSend_790Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); @@ -22449,13 +22592,13 @@ class SentryCocoa { late final _sel_initToMemory1 = _registerName1("initToMemory"); late final _sel_initToBuffer_capacity_1 = _registerName1("initToBuffer:capacity:"); - instancetype _objc_msgSend_787( + instancetype _objc_msgSend_791( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer buffer, int capacity, ) { - return __objc_msgSend_787( + return __objc_msgSend_791( obj, sel, buffer, @@ -22463,11 +22606,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_787Ptr = _lookup< + late final __objc_msgSend_791Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_787 = __objc_msgSend_787Ptr.asFunction< + late final __objc_msgSend_791 = __objc_msgSend_791Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); @@ -22484,7 +22627,7 @@ class SentryCocoa { _registerName1("outputStreamWithURL:append:"); late final _sel_getStreamsToHostWithName_port_inputStream_outputStream_1 = _registerName1("getStreamsToHostWithName:port:inputStream:outputStream:"); - void _objc_msgSend_788( + void _objc_msgSend_792( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer hostname, @@ -22492,7 +22635,7 @@ class SentryCocoa { ffi.Pointer> inputStream, ffi.Pointer> outputStream, ) { - return __objc_msgSend_788( + return __objc_msgSend_792( obj, sel, hostname, @@ -22502,7 +22645,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_788Ptr = _lookup< + late final __objc_msgSend_792Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -22511,7 +22654,7 @@ class SentryCocoa { ffi.Long, ffi.Pointer>, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_788 = __objc_msgSend_788Ptr.asFunction< + late final __objc_msgSend_792 = __objc_msgSend_792Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -22525,23 +22668,23 @@ class SentryCocoa { late final _sel_hostWithName_1 = _registerName1("hostWithName:"); late final _sel_hostWithAddress_1 = _registerName1("hostWithAddress:"); late final _sel_isEqualToHost_1 = _registerName1("isEqualToHost:"); - bool _objc_msgSend_789( + bool _objc_msgSend_793( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer aHost, ) { - return __objc_msgSend_789( + return __objc_msgSend_793( obj, sel, aHost, ); } - late final __objc_msgSend_789Ptr = _lookup< + late final __objc_msgSend_793Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_789 = __objc_msgSend_789Ptr.asFunction< + late final __objc_msgSend_793 = __objc_msgSend_793Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -22551,30 +22694,30 @@ class SentryCocoa { late final _sel_localizedName1 = _registerName1("localizedName"); late final _sel_setHostCacheEnabled_1 = _registerName1("setHostCacheEnabled:"); - void _objc_msgSend_790( + void _objc_msgSend_794( ffi.Pointer obj, ffi.Pointer sel, bool flag, ) { - return __objc_msgSend_790( + return __objc_msgSend_794( obj, sel, flag, ); } - late final __objc_msgSend_790Ptr = _lookup< + late final __objc_msgSend_794Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_790 = __objc_msgSend_790Ptr.asFunction< + late final __objc_msgSend_794 = __objc_msgSend_794Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, bool)>(); late final _sel_isHostCacheEnabled1 = _registerName1("isHostCacheEnabled"); late final _sel_flushHostCache1 = _registerName1("flushHostCache"); late final _sel_getStreamsToHost_port_inputStream_outputStream_1 = _registerName1("getStreamsToHost:port:inputStream:outputStream:"); - void _objc_msgSend_791( + void _objc_msgSend_795( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer host, @@ -22582,7 +22725,7 @@ class SentryCocoa { ffi.Pointer> inputStream, ffi.Pointer> outputStream, ) { - return __objc_msgSend_791( + return __objc_msgSend_795( obj, sel, host, @@ -22592,7 +22735,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_791Ptr = _lookup< + late final __objc_msgSend_795Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -22601,7 +22744,7 @@ class SentryCocoa { ffi.Long, ffi.Pointer>, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_791 = __objc_msgSend_791Ptr.asFunction< + late final __objc_msgSend_795 = __objc_msgSend_795Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -22612,14 +22755,14 @@ class SentryCocoa { late final _sel_getBoundStreamsWithBufferSize_inputStream_outputStream_1 = _registerName1("getBoundStreamsWithBufferSize:inputStream:outputStream:"); - void _objc_msgSend_792( + void _objc_msgSend_796( ffi.Pointer obj, ffi.Pointer sel, int bufferSize, ffi.Pointer> inputStream, ffi.Pointer> outputStream, ) { - return __objc_msgSend_792( + return __objc_msgSend_796( obj, sel, bufferSize, @@ -22628,7 +22771,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_792Ptr = _lookup< + late final __objc_msgSend_796Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -22636,7 +22779,7 @@ class SentryCocoa { ffi.UnsignedLong, ffi.Pointer>, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_792 = __objc_msgSend_792Ptr.asFunction< + late final __objc_msgSend_796 = __objc_msgSend_796Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -22646,13 +22789,13 @@ class SentryCocoa { late final _sel_read_maxLength_1 = _registerName1("read:maxLength:"); late final _sel_getBuffer_length_1 = _registerName1("getBuffer:length:"); - bool _objc_msgSend_793( + bool _objc_msgSend_797( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> buffer, ffi.Pointer len, ) { - return __objc_msgSend_793( + return __objc_msgSend_797( obj, sel, buffer, @@ -22660,14 +22803,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_793Ptr = _lookup< + late final __objc_msgSend_797Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer>, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_793 = __objc_msgSend_793Ptr.asFunction< + late final __objc_msgSend_797 = __objc_msgSend_797Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -22682,21 +22825,21 @@ class SentryCocoa { _registerName1("inputStreamWithFileAtPath:"); late final _sel_inputStreamWithURL_1 = _registerName1("inputStreamWithURL:"); late final _sel_HTTPBodyStream1 = _registerName1("HTTPBodyStream"); - ffi.Pointer _objc_msgSend_794( + ffi.Pointer _objc_msgSend_798( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_794( + return __objc_msgSend_798( obj, sel, ); } - late final __objc_msgSend_794Ptr = _lookup< + late final __objc_msgSend_798Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_794 = __objc_msgSend_794Ptr.asFunction< + late final __objc_msgSend_798 = __objc_msgSend_798Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -22705,21 +22848,21 @@ class SentryCocoa { late final _sel_HTTPShouldUsePipelining1 = _registerName1("HTTPShouldUsePipelining"); late final _sel_originalRequest1 = _registerName1("originalRequest"); - ffi.Pointer _objc_msgSend_795( + ffi.Pointer _objc_msgSend_799( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_795( + return __objc_msgSend_799( obj, sel, ); } - late final __objc_msgSend_795Ptr = _lookup< + late final __objc_msgSend_799Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_795 = __objc_msgSend_795Ptr.asFunction< + late final __objc_msgSend_799 = __objc_msgSend_799Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -22728,7 +22871,7 @@ class SentryCocoa { late final _sel_initWithURL_MIMEType_expectedContentLength_textEncodingName_1 = _registerName1( "initWithURL:MIMEType:expectedContentLength:textEncodingName:"); - instancetype _objc_msgSend_796( + instancetype _objc_msgSend_800( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer URL, @@ -22736,7 +22879,7 @@ class SentryCocoa { int length, ffi.Pointer name, ) { - return __objc_msgSend_796( + return __objc_msgSend_800( obj, sel, URL, @@ -22746,7 +22889,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_796Ptr = _lookup< + late final __objc_msgSend_800Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -22755,7 +22898,7 @@ class SentryCocoa { ffi.Pointer, ffi.Long, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_796 = __objc_msgSend_796Ptr.asFunction< + late final __objc_msgSend_800 = __objc_msgSend_800Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -22770,21 +22913,21 @@ class SentryCocoa { late final _sel_textEncodingName1 = _registerName1("textEncodingName"); late final _sel_suggestedFilename1 = _registerName1("suggestedFilename"); late final _sel_response1 = _registerName1("response"); - ffi.Pointer _objc_msgSend_797( + ffi.Pointer _objc_msgSend_801( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_797( + return __objc_msgSend_801( obj, sel, ); } - late final __objc_msgSend_797Ptr = _lookup< + late final __objc_msgSend_801Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_797 = __objc_msgSend_797Ptr.asFunction< + late final __objc_msgSend_801 = __objc_msgSend_801Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -22810,43 +22953,43 @@ class SentryCocoa { late final _sel_taskDescription1 = _registerName1("taskDescription"); late final _sel_setTaskDescription_1 = _registerName1("setTaskDescription:"); late final _sel_state1 = _registerName1("state"); - int _objc_msgSend_798( + int _objc_msgSend_802( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_798( + return __objc_msgSend_802( obj, sel, ); } - late final __objc_msgSend_798Ptr = _lookup< + late final __objc_msgSend_802Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_798 = __objc_msgSend_798Ptr.asFunction< + late final __objc_msgSend_802 = __objc_msgSend_802Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_suspend1 = _registerName1("suspend"); late final _sel_priority1 = _registerName1("priority"); late final _sel_setPriority_1 = _registerName1("setPriority:"); - void _objc_msgSend_799( + void _objc_msgSend_803( ffi.Pointer obj, ffi.Pointer sel, double value, ) { - return __objc_msgSend_799( + return __objc_msgSend_803( obj, sel, value, ); } - late final __objc_msgSend_799Ptr = _lookup< + late final __objc_msgSend_803Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Float)>>('objc_msgSend'); - late final __objc_msgSend_799 = __objc_msgSend_799Ptr.asFunction< + late final __objc_msgSend_803 = __objc_msgSend_803Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, double)>(); late final _sel_prefersIncrementalDelivery1 = @@ -22855,13 +22998,13 @@ class SentryCocoa { _registerName1("setPrefersIncrementalDelivery:"); late final _sel_storeCookies_forTask_1 = _registerName1("storeCookies:forTask:"); - void _objc_msgSend_800( + void _objc_msgSend_804( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer cookies, ffi.Pointer task, ) { - return __objc_msgSend_800( + return __objc_msgSend_804( obj, sel, cookies, @@ -22869,26 +23012,26 @@ class SentryCocoa { ); } - late final __objc_msgSend_800Ptr = _lookup< + late final __objc_msgSend_804Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_800 = __objc_msgSend_800Ptr.asFunction< + late final __objc_msgSend_804 = __objc_msgSend_804Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_getCookiesForTask_completionHandler_1 = _registerName1("getCookiesForTask:completionHandler:"); - void _objc_msgSend_801( + void _objc_msgSend_805( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer task, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_801( + return __objc_msgSend_805( obj, sel, task, @@ -22896,14 +23039,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_801Ptr = _lookup< + late final __objc_msgSend_805Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_801 = __objc_msgSend_801Ptr.asFunction< + late final __objc_msgSend_805 = __objc_msgSend_805Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); @@ -22911,13 +23054,13 @@ class SentryCocoa { late final _sel_indexPathWithIndex_1 = _registerName1("indexPathWithIndex:"); late final _sel_indexPathWithIndexes_length_1 = _registerName1("indexPathWithIndexes:length:"); - instancetype _objc_msgSend_802( + instancetype _objc_msgSend_806( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer indexes, int length, ) { - return __objc_msgSend_802( + return __objc_msgSend_806( obj, sel, indexes, @@ -22925,14 +23068,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_802Ptr = _lookup< + late final __objc_msgSend_806Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_802 = __objc_msgSend_802Ptr.asFunction< + late final __objc_msgSend_806 = __objc_msgSend_806Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); @@ -22940,55 +23083,55 @@ class SentryCocoa { _registerName1("initWithIndexes:length:"); late final _sel_indexPathByAddingIndex_1 = _registerName1("indexPathByAddingIndex:"); - ffi.Pointer _objc_msgSend_803( + ffi.Pointer _objc_msgSend_807( ffi.Pointer obj, ffi.Pointer sel, int index, ) { - return __objc_msgSend_803( + return __objc_msgSend_807( obj, sel, index, ); } - late final __objc_msgSend_803Ptr = _lookup< + late final __objc_msgSend_807Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_803 = __objc_msgSend_803Ptr.asFunction< + late final __objc_msgSend_807 = __objc_msgSend_807Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); late final _sel_indexPathByRemovingLastIndex1 = _registerName1("indexPathByRemovingLastIndex"); - ffi.Pointer _objc_msgSend_804( + ffi.Pointer _objc_msgSend_808( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_804( + return __objc_msgSend_808( obj, sel, ); } - late final __objc_msgSend_804Ptr = _lookup< + late final __objc_msgSend_808Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_804 = __objc_msgSend_804Ptr.asFunction< + late final __objc_msgSend_808 = __objc_msgSend_808Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_indexAtPosition_1 = _registerName1("indexAtPosition:"); late final _sel_getIndexes_range_1 = _registerName1("getIndexes:range:"); - void _objc_msgSend_805( + void _objc_msgSend_809( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer indexes, _NSRange positionRange, ) { - return __objc_msgSend_805( + return __objc_msgSend_809( obj, sel, indexes, @@ -22996,72 +23139,72 @@ class SentryCocoa { ); } - late final __objc_msgSend_805Ptr = _lookup< + late final __objc_msgSend_809Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_805 = __objc_msgSend_805Ptr.asFunction< + late final __objc_msgSend_809 = __objc_msgSend_809Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, _NSRange)>(); - int _objc_msgSend_806( + int _objc_msgSend_810( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer otherObject, ) { - return __objc_msgSend_806( + return __objc_msgSend_810( obj, sel, otherObject, ); } - late final __objc_msgSend_806Ptr = _lookup< + late final __objc_msgSend_810Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_806 = __objc_msgSend_806Ptr.asFunction< + late final __objc_msgSend_810 = __objc_msgSend_810Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_getIndexes_1 = _registerName1("getIndexes:"); - void _objc_msgSend_807( + void _objc_msgSend_811( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer indexes, ) { - return __objc_msgSend_807( + return __objc_msgSend_811( obj, sel, indexes, ); } - late final __objc_msgSend_807Ptr = _lookup< + late final __objc_msgSend_811Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_807 = __objc_msgSend_807Ptr.asFunction< + late final __objc_msgSend_811 = __objc_msgSend_811Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _class_NSInflectionRule1 = _getClass1("NSInflectionRule"); late final _sel_automaticRule1 = _registerName1("automaticRule"); - ffi.Pointer _objc_msgSend_808( + ffi.Pointer _objc_msgSend_812( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_808( + return __objc_msgSend_812( obj, sel, ); } - late final __objc_msgSend_808Ptr = _lookup< + late final __objc_msgSend_812Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_808 = __objc_msgSend_808Ptr.asFunction< + late final __objc_msgSend_812 = __objc_msgSend_812Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -23070,118 +23213,309 @@ class SentryCocoa { _registerName1("canInflectPreferredLocalization"); late final _class_NSMorphology1 = _getClass1("NSMorphology"); late final _sel_grammaticalGender1 = _registerName1("grammaticalGender"); - int _objc_msgSend_809( + int _objc_msgSend_813( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_809( + return __objc_msgSend_813( obj, sel, ); } - late final __objc_msgSend_809Ptr = _lookup< + late final __objc_msgSend_813Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_809 = __objc_msgSend_809Ptr.asFunction< + late final __objc_msgSend_813 = __objc_msgSend_813Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setGrammaticalGender_1 = _registerName1("setGrammaticalGender:"); - void _objc_msgSend_810( + void _objc_msgSend_814( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_810( + return __objc_msgSend_814( obj, sel, value, ); } - late final __objc_msgSend_810Ptr = _lookup< + late final __objc_msgSend_814Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_810 = __objc_msgSend_810Ptr.asFunction< + late final __objc_msgSend_814 = __objc_msgSend_814Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_partOfSpeech1 = _registerName1("partOfSpeech"); - int _objc_msgSend_811( + int _objc_msgSend_815( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_811( + return __objc_msgSend_815( obj, sel, ); } - late final __objc_msgSend_811Ptr = _lookup< + late final __objc_msgSend_815Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_811 = __objc_msgSend_811Ptr.asFunction< + late final __objc_msgSend_815 = __objc_msgSend_815Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setPartOfSpeech_1 = _registerName1("setPartOfSpeech:"); - void _objc_msgSend_812( + void _objc_msgSend_816( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_812( + return __objc_msgSend_816( obj, sel, value, ); } - late final __objc_msgSend_812Ptr = _lookup< + late final __objc_msgSend_816Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_812 = __objc_msgSend_812Ptr.asFunction< + late final __objc_msgSend_816 = __objc_msgSend_816Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_number1 = _registerName1("number"); - int _objc_msgSend_813( + int _objc_msgSend_817( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_813( + return __objc_msgSend_817( obj, sel, ); } - late final __objc_msgSend_813Ptr = _lookup< + late final __objc_msgSend_817Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_813 = __objc_msgSend_813Ptr.asFunction< + late final __objc_msgSend_817 = __objc_msgSend_817Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setNumber_1 = _registerName1("setNumber:"); - void _objc_msgSend_814( + void _objc_msgSend_818( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_814( + return __objc_msgSend_818( obj, sel, value, ); } - late final __objc_msgSend_814Ptr = _lookup< + late final __objc_msgSend_818Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_814 = __objc_msgSend_814Ptr.asFunction< + late final __objc_msgSend_818 = __objc_msgSend_818Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, int)>(); + + late final _sel_grammaticalCase1 = _registerName1("grammaticalCase"); + int _objc_msgSend_819( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_819( + obj, + sel, + ); + } + + late final __objc_msgSend_819Ptr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_819 = __objc_msgSend_819Ptr.asFunction< + int Function(ffi.Pointer, ffi.Pointer)>(); + + late final _sel_setGrammaticalCase_1 = _registerName1("setGrammaticalCase:"); + void _objc_msgSend_820( + ffi.Pointer obj, + ffi.Pointer sel, + int value, + ) { + return __objc_msgSend_820( + obj, + sel, + value, + ); + } + + late final __objc_msgSend_820Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Int32)>>('objc_msgSend'); + late final __objc_msgSend_820 = __objc_msgSend_820Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, int)>(); + + late final _sel_determination1 = _registerName1("determination"); + int _objc_msgSend_821( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_821( + obj, + sel, + ); + } + + late final __objc_msgSend_821Ptr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_821 = __objc_msgSend_821Ptr.asFunction< + int Function(ffi.Pointer, ffi.Pointer)>(); + + late final _sel_setDetermination_1 = _registerName1("setDetermination:"); + void _objc_msgSend_822( + ffi.Pointer obj, + ffi.Pointer sel, + int value, + ) { + return __objc_msgSend_822( + obj, + sel, + value, + ); + } + + late final __objc_msgSend_822Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Int32)>>('objc_msgSend'); + late final __objc_msgSend_822 = __objc_msgSend_822Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, int)>(); + + late final _sel_grammaticalPerson1 = _registerName1("grammaticalPerson"); + int _objc_msgSend_823( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_823( + obj, + sel, + ); + } + + late final __objc_msgSend_823Ptr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_823 = __objc_msgSend_823Ptr.asFunction< + int Function(ffi.Pointer, ffi.Pointer)>(); + + late final _sel_setGrammaticalPerson_1 = + _registerName1("setGrammaticalPerson:"); + void _objc_msgSend_824( + ffi.Pointer obj, + ffi.Pointer sel, + int value, + ) { + return __objc_msgSend_824( + obj, + sel, + value, + ); + } + + late final __objc_msgSend_824Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Int32)>>('objc_msgSend'); + late final __objc_msgSend_824 = __objc_msgSend_824Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, int)>(); + + late final _sel_pronounType1 = _registerName1("pronounType"); + int _objc_msgSend_825( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_825( + obj, + sel, + ); + } + + late final __objc_msgSend_825Ptr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_825 = __objc_msgSend_825Ptr.asFunction< + int Function(ffi.Pointer, ffi.Pointer)>(); + + late final _sel_setPronounType_1 = _registerName1("setPronounType:"); + void _objc_msgSend_826( + ffi.Pointer obj, + ffi.Pointer sel, + int value, + ) { + return __objc_msgSend_826( + obj, + sel, + value, + ); + } + + late final __objc_msgSend_826Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Int32)>>('objc_msgSend'); + late final __objc_msgSend_826 = __objc_msgSend_826Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, int)>(); + + late final _sel_definiteness1 = _registerName1("definiteness"); + int _objc_msgSend_827( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_827( + obj, + sel, + ); + } + + late final __objc_msgSend_827Ptr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function( + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_827 = __objc_msgSend_827Ptr.asFunction< + int Function(ffi.Pointer, ffi.Pointer)>(); + + late final _sel_setDefiniteness_1 = _registerName1("setDefiniteness:"); + void _objc_msgSend_828( + ffi.Pointer obj, + ffi.Pointer sel, + int value, + ) { + return __objc_msgSend_828( + obj, + sel, + value, + ); + } + + late final __objc_msgSend_828Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Int32)>>('objc_msgSend'); + late final __objc_msgSend_828 = __objc_msgSend_828Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _class_NSMorphologyCustomPronoun1 = @@ -23204,36 +23538,36 @@ class SentryCocoa { late final _sel_setReflexiveForm_1 = _registerName1("setReflexiveForm:"); late final _sel_customPronounForLanguage_1 = _registerName1("customPronounForLanguage:"); - ffi.Pointer _objc_msgSend_815( + ffi.Pointer _objc_msgSend_829( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer language, ) { - return __objc_msgSend_815( + return __objc_msgSend_829( obj, sel, language, ); } - late final __objc_msgSend_815Ptr = _lookup< + late final __objc_msgSend_829Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_815 = __objc_msgSend_815Ptr.asFunction< + late final __objc_msgSend_829 = __objc_msgSend_829Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_setCustomPronoun_forLanguage_error_1 = _registerName1("setCustomPronoun:forLanguage:error:"); - bool _objc_msgSend_816( + bool _objc_msgSend_830( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer features, ffi.Pointer language, ffi.Pointer> error, ) { - return __objc_msgSend_816( + return __objc_msgSend_830( obj, sel, features, @@ -23242,7 +23576,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_816Ptr = _lookup< + late final __objc_msgSend_830Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -23250,7 +23584,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_816 = __objc_msgSend_816Ptr.asFunction< + late final __objc_msgSend_830 = __objc_msgSend_830Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -23260,21 +23594,21 @@ class SentryCocoa { late final _sel_isUnspecified1 = _registerName1("isUnspecified"); late final _sel_userMorphology1 = _registerName1("userMorphology"); - ffi.Pointer _objc_msgSend_817( + ffi.Pointer _objc_msgSend_831( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_817( + return __objc_msgSend_831( obj, sel, ); } - late final __objc_msgSend_817Ptr = _lookup< + late final __objc_msgSend_831Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_817 = __objc_msgSend_817Ptr.asFunction< + late final __objc_msgSend_831 = __objc_msgSend_831Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -23284,64 +23618,64 @@ class SentryCocoa { late final _sel_isAsynchronous1 = _registerName1("isAsynchronous"); late final _sel_isReady1 = _registerName1("isReady"); late final _sel_addDependency_1 = _registerName1("addDependency:"); - void _objc_msgSend_818( + void _objc_msgSend_832( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer op, ) { - return __objc_msgSend_818( + return __objc_msgSend_832( obj, sel, op, ); } - late final __objc_msgSend_818Ptr = _lookup< + late final __objc_msgSend_832Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_818 = __objc_msgSend_818Ptr.asFunction< + late final __objc_msgSend_832 = __objc_msgSend_832Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_removeDependency_1 = _registerName1("removeDependency:"); late final _sel_dependencies1 = _registerName1("dependencies"); late final _sel_queuePriority1 = _registerName1("queuePriority"); - int _objc_msgSend_819( + int _objc_msgSend_833( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_819( + return __objc_msgSend_833( obj, sel, ); } - late final __objc_msgSend_819Ptr = _lookup< + late final __objc_msgSend_833Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_819 = __objc_msgSend_819Ptr.asFunction< + late final __objc_msgSend_833 = __objc_msgSend_833Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setQueuePriority_1 = _registerName1("setQueuePriority:"); - void _objc_msgSend_820( + void _objc_msgSend_834( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_820( + return __objc_msgSend_834( obj, sel, value, ); } - late final __objc_msgSend_820Ptr = _lookup< + late final __objc_msgSend_834Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_820 = __objc_msgSend_820Ptr.asFunction< + late final __objc_msgSend_834 = __objc_msgSend_834Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_completionBlock1 = _registerName1("completionBlock"); @@ -23350,13 +23684,13 @@ class SentryCocoa { late final _sel_addOperation_1 = _registerName1("addOperation:"); late final _sel_addOperations_waitUntilFinished_1 = _registerName1("addOperations:waitUntilFinished:"); - void _objc_msgSend_821( + void _objc_msgSend_835( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer ops, bool wait, ) { - return __objc_msgSend_821( + return __objc_msgSend_835( obj, sel, ops, @@ -23364,11 +23698,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_821Ptr = _lookup< + late final __objc_msgSend_835Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_821 = __objc_msgSend_821Ptr.asFunction< + late final __objc_msgSend_835 = __objc_msgSend_835Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, bool)>(); @@ -23382,42 +23716,42 @@ class SentryCocoa { late final _sel_isSuspended1 = _registerName1("isSuspended"); late final _sel_setSuspended_1 = _registerName1("setSuspended:"); late final _sel_underlyingQueue1 = _registerName1("underlyingQueue"); - ffi.Pointer _objc_msgSend_822( + ffi.Pointer _objc_msgSend_836( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_822( + return __objc_msgSend_836( obj, sel, ); } - late final __objc_msgSend_822Ptr = _lookup< + late final __objc_msgSend_836Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_822 = __objc_msgSend_822Ptr.asFunction< + late final __objc_msgSend_836 = __objc_msgSend_836Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_setUnderlyingQueue_1 = _registerName1("setUnderlyingQueue:"); - void _objc_msgSend_823( + void _objc_msgSend_837( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_823( + return __objc_msgSend_837( obj, sel, value, ); } - late final __objc_msgSend_823Ptr = _lookup< + late final __objc_msgSend_837Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_823 = __objc_msgSend_823Ptr.asFunction< + late final __objc_msgSend_837 = __objc_msgSend_837Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -23425,21 +23759,21 @@ class SentryCocoa { late final _sel_waitUntilAllOperationsAreFinished1 = _registerName1("waitUntilAllOperationsAreFinished"); late final _sel_currentQueue1 = _registerName1("currentQueue"); - ffi.Pointer _objc_msgSend_824( + ffi.Pointer _objc_msgSend_838( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_824( + return __objc_msgSend_838( obj, sel, ); } - late final __objc_msgSend_824Ptr = _lookup< + late final __objc_msgSend_838Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_824 = __objc_msgSend_824Ptr.asFunction< + late final __objc_msgSend_838 = __objc_msgSend_838Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -23448,46 +23782,46 @@ class SentryCocoa { late final _sel_operationCount1 = _registerName1("operationCount"); late final _class_NSPointerArray1 = _getClass1("NSPointerArray"); late final _sel_initWithOptions_1 = _registerName1("initWithOptions:"); - instancetype _objc_msgSend_825( + instancetype _objc_msgSend_839( ffi.Pointer obj, ffi.Pointer sel, int options, ) { - return __objc_msgSend_825( + return __objc_msgSend_839( obj, sel, options, ); } - late final __objc_msgSend_825Ptr = _lookup< + late final __objc_msgSend_839Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_825 = __objc_msgSend_825Ptr.asFunction< + late final __objc_msgSend_839 = __objc_msgSend_839Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, int)>(); late final _class_NSPointerFunctions1 = _getClass1("NSPointerFunctions"); late final _sel_pointerFunctionsWithOptions_1 = _registerName1("pointerFunctionsWithOptions:"); - ffi.Pointer _objc_msgSend_826( + ffi.Pointer _objc_msgSend_840( ffi.Pointer obj, ffi.Pointer sel, int options, ) { - return __objc_msgSend_826( + return __objc_msgSend_840( obj, sel, options, ); } - late final __objc_msgSend_826Ptr = _lookup< + late final __objc_msgSend_840Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_826 = __objc_msgSend_826Ptr.asFunction< + late final __objc_msgSend_840 = __objc_msgSend_840Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); @@ -23499,17 +23833,17 @@ class SentryCocoa { ffi.Pointer< ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>)>> - _objc_msgSend_827( + _objc_msgSend_841( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_827( + return __objc_msgSend_841( obj, sel, ); } - late final __objc_msgSend_827Ptr = _lookup< + late final __objc_msgSend_841Ptr = _lookup< ffi.NativeFunction< ffi.Pointer< ffi.NativeFunction< @@ -23521,7 +23855,7 @@ class SentryCocoa { ffi.Pointer)>>)>> Function(ffi.Pointer, ffi.Pointer)>>( 'objc_msgSend'); - late final __objc_msgSend_827 = __objc_msgSend_827Ptr.asFunction< + late final __objc_msgSend_841 = __objc_msgSend_841Ptr.asFunction< ffi.Pointer< ffi.NativeFunction< ffi.UnsignedLong Function( @@ -23533,7 +23867,7 @@ class SentryCocoa { Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setHashFunction_1 = _registerName1("setHashFunction:"); - void _objc_msgSend_828( + void _objc_msgSend_842( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer< @@ -23546,14 +23880,14 @@ class SentryCocoa { ffi.Pointer)>>)>> value, ) { - return __objc_msgSend_828( + return __objc_msgSend_842( obj, sel, value, ); } - late final __objc_msgSend_828Ptr = _lookup< + late final __objc_msgSend_842Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -23567,7 +23901,7 @@ class SentryCocoa { ffi.UnsignedLong Function( ffi.Pointer)>>)>>)>>( 'objc_msgSend'); - late final __objc_msgSend_828 = __objc_msgSend_828Ptr.asFunction< + late final __objc_msgSend_842 = __objc_msgSend_842Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -23589,17 +23923,17 @@ class SentryCocoa { ffi.Pointer< ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>)>> - _objc_msgSend_829( + _objc_msgSend_843( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_829( + return __objc_msgSend_843( obj, sel, ); } - late final __objc_msgSend_829Ptr = _lookup< + late final __objc_msgSend_843Ptr = _lookup< ffi.NativeFunction< ffi.Pointer< ffi.NativeFunction< @@ -23612,7 +23946,7 @@ class SentryCocoa { ffi.Pointer)>>)>> Function(ffi.Pointer, ffi.Pointer)>>( 'objc_msgSend'); - late final __objc_msgSend_829 = __objc_msgSend_829Ptr.asFunction< + late final __objc_msgSend_843 = __objc_msgSend_843Ptr.asFunction< ffi.Pointer< ffi.NativeFunction< ffi.Bool Function( @@ -23625,7 +23959,7 @@ class SentryCocoa { Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setIsEqualFunction_1 = _registerName1("setIsEqualFunction:"); - void _objc_msgSend_830( + void _objc_msgSend_844( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer< @@ -23639,14 +23973,14 @@ class SentryCocoa { ffi.Pointer)>>)>> value, ) { - return __objc_msgSend_830( + return __objc_msgSend_844( obj, sel, value, ); } - late final __objc_msgSend_830Ptr = _lookup< + late final __objc_msgSend_844Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -23661,7 +23995,7 @@ class SentryCocoa { ffi.UnsignedLong Function( ffi.Pointer)>>)>>)>>( 'objc_msgSend'); - late final __objc_msgSend_830 = __objc_msgSend_830Ptr.asFunction< + late final __objc_msgSend_844 = __objc_msgSend_844Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -23678,31 +24012,31 @@ class SentryCocoa { late final _sel_sizeFunction1 = _registerName1("sizeFunction"); ffi.Pointer< ffi.NativeFunction)>> - _objc_msgSend_831( + _objc_msgSend_845( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_831( + return __objc_msgSend_845( obj, sel, ); } - late final __objc_msgSend_831Ptr = _lookup< + late final __objc_msgSend_845Ptr = _lookup< ffi.NativeFunction< ffi.Pointer< ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>> Function(ffi.Pointer, ffi.Pointer)>>( 'objc_msgSend'); - late final __objc_msgSend_831 = __objc_msgSend_831Ptr.asFunction< + late final __objc_msgSend_845 = __objc_msgSend_845Ptr.asFunction< ffi.Pointer< ffi .NativeFunction)>> Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setSizeFunction_1 = _registerName1("setSizeFunction:"); - void _objc_msgSend_832( + void _objc_msgSend_846( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer< @@ -23710,14 +24044,14 @@ class SentryCocoa { .NativeFunction)>> value, ) { - return __objc_msgSend_832( + return __objc_msgSend_846( obj, sel, value, ); } - late final __objc_msgSend_832Ptr = _lookup< + late final __objc_msgSend_846Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -23726,7 +24060,7 @@ class SentryCocoa { ffi.NativeFunction< ffi.UnsignedLong Function( ffi.Pointer)>>)>>('objc_msgSend'); - late final __objc_msgSend_832 = __objc_msgSend_832Ptr.asFunction< + late final __objc_msgSend_846 = __objc_msgSend_846Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -23738,17 +24072,17 @@ class SentryCocoa { ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer)>> - _objc_msgSend_833( + _objc_msgSend_847( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_833( + return __objc_msgSend_847( obj, sel, ); } - late final __objc_msgSend_833Ptr = + late final __objc_msgSend_847Ptr = _lookup< ffi.NativeFunction< ffi.Pointer< @@ -23757,7 +24091,7 @@ class SentryCocoa { ffi.Pointer)>> Function(ffi.Pointer, ffi.Pointer)>>( 'objc_msgSend'); - late final __objc_msgSend_833 = __objc_msgSend_833Ptr.asFunction< + late final __objc_msgSend_847 = __objc_msgSend_847Ptr.asFunction< ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer)>> @@ -23765,7 +24099,7 @@ class SentryCocoa { late final _sel_setDescriptionFunction_1 = _registerName1("setDescriptionFunction:"); - void _objc_msgSend_834( + void _objc_msgSend_848( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer< @@ -23773,14 +24107,14 @@ class SentryCocoa { ffi.Pointer Function(ffi.Pointer)>> value, ) { - return __objc_msgSend_834( + return __objc_msgSend_848( obj, sel, value, ); } - late final __objc_msgSend_834Ptr = _lookup< + late final __objc_msgSend_848Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -23789,7 +24123,7 @@ class SentryCocoa { ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer)>>)>>('objc_msgSend'); - late final __objc_msgSend_834 = __objc_msgSend_834Ptr.asFunction< + late final __objc_msgSend_848 = __objc_msgSend_848Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -23805,17 +24139,17 @@ class SentryCocoa { ffi.Pointer< ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>)>> - _objc_msgSend_835( + _objc_msgSend_849( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_835( + return __objc_msgSend_849( obj, sel, ); } - late final __objc_msgSend_835Ptr = _lookup< + late final __objc_msgSend_849Ptr = _lookup< ffi.NativeFunction< ffi.Pointer< ffi.NativeFunction< @@ -23827,7 +24161,7 @@ class SentryCocoa { ffi.Pointer)>>)>> Function(ffi.Pointer, ffi.Pointer)>>( 'objc_msgSend'); - late final __objc_msgSend_835 = __objc_msgSend_835Ptr.asFunction< + late final __objc_msgSend_849 = __objc_msgSend_849Ptr.asFunction< ffi.Pointer< ffi.NativeFunction< ffi.Void Function( @@ -23840,7 +24174,7 @@ class SentryCocoa { late final _sel_setRelinquishFunction_1 = _registerName1("setRelinquishFunction:"); - void _objc_msgSend_836( + void _objc_msgSend_850( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer< @@ -23853,14 +24187,14 @@ class SentryCocoa { ffi.Pointer)>>)>> value, ) { - return __objc_msgSend_836( + return __objc_msgSend_850( obj, sel, value, ); } - late final __objc_msgSend_836Ptr = _lookup< + late final __objc_msgSend_850Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -23874,7 +24208,7 @@ class SentryCocoa { ffi.UnsignedLong Function( ffi.Pointer)>>)>>)>>( 'objc_msgSend'); - late final __objc_msgSend_836 = __objc_msgSend_836Ptr.asFunction< + late final __objc_msgSend_850 = __objc_msgSend_850Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -23895,17 +24229,17 @@ class SentryCocoa { ffi.Pointer< ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>, - ffi.Bool)>> _objc_msgSend_837( + ffi.Bool)>> _objc_msgSend_851( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_837( + return __objc_msgSend_851( obj, sel, ); } - late final __objc_msgSend_837Ptr = _lookup< + late final __objc_msgSend_851Ptr = _lookup< ffi.NativeFunction< ffi.Pointer< ffi.NativeFunction< @@ -23918,7 +24252,7 @@ class SentryCocoa { ffi.Bool)>> Function(ffi.Pointer, ffi.Pointer)>>( 'objc_msgSend'); - late final __objc_msgSend_837 = __objc_msgSend_837Ptr.asFunction< + late final __objc_msgSend_851 = __objc_msgSend_851Ptr.asFunction< ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function( @@ -23931,7 +24265,7 @@ class SentryCocoa { Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setAcquireFunction_1 = _registerName1("setAcquireFunction:"); - void _objc_msgSend_838( + void _objc_msgSend_852( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer< @@ -23944,14 +24278,14 @@ class SentryCocoa { ffi.Bool)>> value, ) { - return __objc_msgSend_838( + return __objc_msgSend_852( obj, sel, value, ); } - late final __objc_msgSend_838Ptr = _lookup< + late final __objc_msgSend_852Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -23965,7 +24299,7 @@ class SentryCocoa { ffi.UnsignedLong Function( ffi.Pointer)>>, ffi.Bool)>>)>>('objc_msgSend'); - late final __objc_msgSend_838 = __objc_msgSend_838Ptr.asFunction< + late final __objc_msgSend_852 = __objc_msgSend_852Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -23989,107 +24323,107 @@ class SentryCocoa { _registerName1("setUsesWeakReadAndWriteBarriers:"); late final _sel_initWithPointerFunctions_1 = _registerName1("initWithPointerFunctions:"); - instancetype _objc_msgSend_839( + instancetype _objc_msgSend_853( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer functions, ) { - return __objc_msgSend_839( + return __objc_msgSend_853( obj, sel, functions, ); } - late final __objc_msgSend_839Ptr = _lookup< + late final __objc_msgSend_853Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_839 = __objc_msgSend_839Ptr.asFunction< + late final __objc_msgSend_853 = __objc_msgSend_853Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_pointerArrayWithOptions_1 = _registerName1("pointerArrayWithOptions:"); - ffi.Pointer _objc_msgSend_840( + ffi.Pointer _objc_msgSend_854( ffi.Pointer obj, ffi.Pointer sel, int options, ) { - return __objc_msgSend_840( + return __objc_msgSend_854( obj, sel, options, ); } - late final __objc_msgSend_840Ptr = _lookup< + late final __objc_msgSend_854Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_840 = __objc_msgSend_840Ptr.asFunction< + late final __objc_msgSend_854 = __objc_msgSend_854Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); late final _sel_pointerArrayWithPointerFunctions_1 = _registerName1("pointerArrayWithPointerFunctions:"); - ffi.Pointer _objc_msgSend_841( + ffi.Pointer _objc_msgSend_855( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer functions, ) { - return __objc_msgSend_841( + return __objc_msgSend_855( obj, sel, functions, ); } - late final __objc_msgSend_841Ptr = _lookup< + late final __objc_msgSend_855Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_841 = __objc_msgSend_841Ptr.asFunction< + late final __objc_msgSend_855 = __objc_msgSend_855Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_pointerFunctions1 = _registerName1("pointerFunctions"); - ffi.Pointer _objc_msgSend_842( + ffi.Pointer _objc_msgSend_856( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_842( + return __objc_msgSend_856( obj, sel, ); } - late final __objc_msgSend_842Ptr = _lookup< + late final __objc_msgSend_856Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_842 = __objc_msgSend_842Ptr.asFunction< + late final __objc_msgSend_856 = __objc_msgSend_856Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_pointerAtIndex_1 = _registerName1("pointerAtIndex:"); - ffi.Pointer _objc_msgSend_843( + ffi.Pointer _objc_msgSend_857( ffi.Pointer obj, ffi.Pointer sel, int index, ) { - return __objc_msgSend_843( + return __objc_msgSend_857( obj, sel, index, ); } - late final __objc_msgSend_843Ptr = _lookup< + late final __objc_msgSend_857Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_843 = __objc_msgSend_843Ptr.asFunction< + late final __objc_msgSend_857 = __objc_msgSend_857Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); @@ -24100,13 +24434,13 @@ class SentryCocoa { _registerName1("insertPointer:atIndex:"); late final _sel_replacePointerAtIndex_withPointer_1 = _registerName1("replacePointerAtIndex:withPointer:"); - void _objc_msgSend_844( + void _objc_msgSend_858( ffi.Pointer obj, ffi.Pointer sel, int index, ffi.Pointer item, ) { - return __objc_msgSend_844( + return __objc_msgSend_858( obj, sel, index, @@ -24114,11 +24448,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_844Ptr = _lookup< + late final __objc_msgSend_858Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.UnsignedLong, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_844 = __objc_msgSend_844Ptr.asFunction< + late final __objc_msgSend_858 = __objc_msgSend_858Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer)>(); @@ -24130,21 +24464,21 @@ class SentryCocoa { _registerName1("pointerArrayWithWeakObjects"); late final _sel_strongObjectsPointerArray1 = _registerName1("strongObjectsPointerArray"); - ffi.Pointer _objc_msgSend_845( + ffi.Pointer _objc_msgSend_859( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_845( + return __objc_msgSend_859( obj, sel, ); } - late final __objc_msgSend_845Ptr = _lookup< + late final __objc_msgSend_859Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_845 = __objc_msgSend_845Ptr.asFunction< + late final __objc_msgSend_859 = __objc_msgSend_859Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -24152,21 +24486,21 @@ class SentryCocoa { _registerName1("weakObjectsPointerArray"); late final _class_NSProcessInfo1 = _getClass1("NSProcessInfo"); late final _sel_processInfo1 = _registerName1("processInfo"); - ffi.Pointer _objc_msgSend_846( + ffi.Pointer _objc_msgSend_860( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_846( + return __objc_msgSend_860( obj, sel, ); } - late final __objc_msgSend_846Ptr = _lookup< + late final __objc_msgSend_860Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_846 = __objc_msgSend_846Ptr.asFunction< + late final __objc_msgSend_860 = __objc_msgSend_860Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -24183,25 +24517,25 @@ class SentryCocoa { _registerName1("operatingSystemVersionString"); late final _sel_operatingSystemVersion1 = _registerName1("operatingSystemVersion"); - void _objc_msgSend_847( + void _objc_msgSend_861( ffi.Pointer stret, ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_847( + return __objc_msgSend_861( stret, obj, sel, ); } - late final __objc_msgSend_847Ptr = _lookup< + late final __objc_msgSend_861Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend_stret'); - late final __objc_msgSend_847 = __objc_msgSend_847Ptr.asFunction< + late final __objc_msgSend_861 = __objc_msgSend_861Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -24211,23 +24545,23 @@ class SentryCocoa { late final _sel_physicalMemory1 = _registerName1("physicalMemory"); late final _sel_isOperatingSystemAtLeastVersion_1 = _registerName1("isOperatingSystemAtLeastVersion:"); - bool _objc_msgSend_848( + bool _objc_msgSend_862( ffi.Pointer obj, ffi.Pointer sel, NSOperatingSystemVersion version, ) { - return __objc_msgSend_848( + return __objc_msgSend_862( obj, sel, version, ); } - late final __objc_msgSend_848Ptr = _lookup< + late final __objc_msgSend_862Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, NSOperatingSystemVersion)>>('objc_msgSend'); - late final __objc_msgSend_848 = __objc_msgSend_848Ptr.asFunction< + late final __objc_msgSend_862 = __objc_msgSend_862Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, NSOperatingSystemVersion)>(); @@ -24246,13 +24580,13 @@ class SentryCocoa { _registerName1("setAutomaticTerminationSupportEnabled:"); late final _sel_beginActivityWithOptions_reason_1 = _registerName1("beginActivityWithOptions:reason:"); - ffi.Pointer _objc_msgSend_849( + ffi.Pointer _objc_msgSend_863( ffi.Pointer obj, ffi.Pointer sel, int options, ffi.Pointer reason, ) { - return __objc_msgSend_849( + return __objc_msgSend_863( obj, sel, options, @@ -24260,28 +24594,28 @@ class SentryCocoa { ); } - late final __objc_msgSend_849Ptr = _lookup< + late final __objc_msgSend_863Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Int32, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_849 = __objc_msgSend_849Ptr.asFunction< + late final __objc_msgSend_863 = __objc_msgSend_863Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer)>(); late final _sel_endActivity_1 = _registerName1("endActivity:"); late final _sel_performActivityWithOptions_reason_usingBlock_1 = _registerName1("performActivityWithOptions:reason:usingBlock:"); - void _objc_msgSend_850( + void _objc_msgSend_864( ffi.Pointer obj, ffi.Pointer sel, int options, ffi.Pointer reason, ffi.Pointer<_ObjCBlock> block, ) { - return __objc_msgSend_850( + return __objc_msgSend_864( obj, sel, options, @@ -24290,7 +24624,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_850Ptr = _lookup< + late final __objc_msgSend_864Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -24298,19 +24632,19 @@ class SentryCocoa { ffi.Int32, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_850 = __objc_msgSend_850Ptr.asFunction< + late final __objc_msgSend_864 = __objc_msgSend_864Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_performExpiringActivityWithReason_usingBlock_1 = _registerName1("performExpiringActivityWithReason:usingBlock:"); - void _objc_msgSend_851( + void _objc_msgSend_865( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer reason, ffi.Pointer<_ObjCBlock> block, ) { - return __objc_msgSend_851( + return __objc_msgSend_865( obj, sel, reason, @@ -24318,35 +24652,35 @@ class SentryCocoa { ); } - late final __objc_msgSend_851Ptr = _lookup< + late final __objc_msgSend_865Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_851 = __objc_msgSend_851Ptr.asFunction< + late final __objc_msgSend_865 = __objc_msgSend_865Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_userName1 = _registerName1("userName"); late final _sel_fullUserName1 = _registerName1("fullUserName"); late final _sel_thermalState1 = _registerName1("thermalState"); - int _objc_msgSend_852( + int _objc_msgSend_866( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_852( + return __objc_msgSend_866( obj, sel, ); } - late final __objc_msgSend_852Ptr = _lookup< + late final __objc_msgSend_866Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_852 = __objc_msgSend_852Ptr.asFunction< + late final __objc_msgSend_866 = __objc_msgSend_866Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_isLowPowerModeEnabled1 = @@ -24355,40 +24689,40 @@ class SentryCocoa { late final _sel_isiOSAppOnMac1 = _registerName1("isiOSAppOnMac"); late final _class_NSTextCheckingResult1 = _getClass1("NSTextCheckingResult"); late final _sel_resultType1 = _registerName1("resultType"); - int _objc_msgSend_853( + int _objc_msgSend_867( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_853( + return __objc_msgSend_867( obj, sel, ); } - late final __objc_msgSend_853Ptr = _lookup< + late final __objc_msgSend_867Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_853 = __objc_msgSend_853Ptr.asFunction< + late final __objc_msgSend_867 = __objc_msgSend_867Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_range1 = _registerName1("range"); late final _sel_orthography1 = _registerName1("orthography"); - ffi.Pointer _objc_msgSend_854( + ffi.Pointer _objc_msgSend_868( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_854( + return __objc_msgSend_868( obj, sel, ); } - late final __objc_msgSend_854Ptr = _lookup< + late final __objc_msgSend_868Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_854 = __objc_msgSend_854Ptr.asFunction< + late final __objc_msgSend_868 = __objc_msgSend_868Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -24400,14 +24734,14 @@ class SentryCocoa { late final _class_NSRegularExpression1 = _getClass1("NSRegularExpression"); late final _sel_regularExpressionWithPattern_options_error_1 = _registerName1("regularExpressionWithPattern:options:error:"); - ffi.Pointer _objc_msgSend_855( + ffi.Pointer _objc_msgSend_869( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer pattern, int options, ffi.Pointer> error, ) { - return __objc_msgSend_855( + return __objc_msgSend_869( obj, sel, pattern, @@ -24416,7 +24750,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_855Ptr = _lookup< + late final __objc_msgSend_869Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -24424,7 +24758,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_855 = __objc_msgSend_855Ptr.asFunction< + late final __objc_msgSend_869 = __objc_msgSend_869Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -24434,14 +24768,14 @@ class SentryCocoa { late final _sel_initWithPattern_options_error_1 = _registerName1("initWithPattern:options:error:"); - instancetype _objc_msgSend_856( + instancetype _objc_msgSend_870( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer pattern, int options, ffi.Pointer> error, ) { - return __objc_msgSend_856( + return __objc_msgSend_870( obj, sel, pattern, @@ -24450,7 +24784,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_856Ptr = _lookup< + late final __objc_msgSend_870Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -24458,7 +24792,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_856 = __objc_msgSend_856Ptr.asFunction< + late final __objc_msgSend_870 = __objc_msgSend_870Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -24468,21 +24802,21 @@ class SentryCocoa { late final _sel_pattern1 = _registerName1("pattern"); late final _sel_options1 = _registerName1("options"); - int _objc_msgSend_857( + int _objc_msgSend_871( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_857( + return __objc_msgSend_871( obj, sel, ); } - late final __objc_msgSend_857Ptr = _lookup< + late final __objc_msgSend_871Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_857 = __objc_msgSend_857Ptr.asFunction< + late final __objc_msgSend_871 = __objc_msgSend_871Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_numberOfCaptureGroups1 = @@ -24491,7 +24825,7 @@ class SentryCocoa { _registerName1("escapedPatternForString:"); late final _sel_enumerateMatchesInString_options_range_usingBlock_1 = _registerName1("enumerateMatchesInString:options:range:usingBlock:"); - void _objc_msgSend_858( + void _objc_msgSend_872( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, @@ -24499,7 +24833,7 @@ class SentryCocoa { _NSRange range, ffi.Pointer<_ObjCBlock> block, ) { - return __objc_msgSend_858( + return __objc_msgSend_872( obj, sel, string, @@ -24509,7 +24843,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_858Ptr = _lookup< + late final __objc_msgSend_872Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -24518,20 +24852,20 @@ class SentryCocoa { ffi.Int32, _NSRange, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_858 = __objc_msgSend_858Ptr.asFunction< + late final __objc_msgSend_872 = __objc_msgSend_872Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, _NSRange, ffi.Pointer<_ObjCBlock>)>(); late final _sel_matchesInString_options_range_1 = _registerName1("matchesInString:options:range:"); - ffi.Pointer _objc_msgSend_859( + ffi.Pointer _objc_msgSend_873( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, int options, _NSRange range, ) { - return __objc_msgSend_859( + return __objc_msgSend_873( obj, sel, string, @@ -24540,7 +24874,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_859Ptr = _lookup< + late final __objc_msgSend_873Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -24548,20 +24882,20 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_859 = __objc_msgSend_859Ptr.asFunction< + late final __objc_msgSend_873 = __objc_msgSend_873Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, _NSRange)>(); late final _sel_numberOfMatchesInString_options_range_1 = _registerName1("numberOfMatchesInString:options:range:"); - int _objc_msgSend_860( + int _objc_msgSend_874( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, int options, _NSRange range, ) { - return __objc_msgSend_860( + return __objc_msgSend_874( obj, sel, string, @@ -24570,7 +24904,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_860Ptr = _lookup< + late final __objc_msgSend_874Ptr = _lookup< ffi.NativeFunction< ffi.UnsignedLong Function( ffi.Pointer, @@ -24578,20 +24912,20 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_860 = __objc_msgSend_860Ptr.asFunction< + late final __objc_msgSend_874 = __objc_msgSend_874Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, _NSRange)>(); late final _sel_firstMatchInString_options_range_1 = _registerName1("firstMatchInString:options:range:"); - ffi.Pointer _objc_msgSend_861( + ffi.Pointer _objc_msgSend_875( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, int options, _NSRange range, ) { - return __objc_msgSend_861( + return __objc_msgSend_875( obj, sel, string, @@ -24600,7 +24934,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_861Ptr = _lookup< + late final __objc_msgSend_875Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -24608,13 +24942,13 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_861 = __objc_msgSend_861Ptr.asFunction< + late final __objc_msgSend_875 = __objc_msgSend_875Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, _NSRange)>(); late final _sel_rangeOfFirstMatchInString_options_range_1 = _registerName1("rangeOfFirstMatchInString:options:range:"); - void _objc_msgSend_862( + void _objc_msgSend_876( ffi.Pointer<_NSRange> stret, ffi.Pointer obj, ffi.Pointer sel, @@ -24622,7 +24956,7 @@ class SentryCocoa { int options, _NSRange range, ) { - return __objc_msgSend_862( + return __objc_msgSend_876( stret, obj, sel, @@ -24632,7 +24966,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_862Ptr = _lookup< + late final __objc_msgSend_876Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer<_NSRange>, @@ -24641,14 +24975,14 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, _NSRange)>>('objc_msgSend_stret'); - late final __objc_msgSend_862 = __objc_msgSend_862Ptr.asFunction< + late final __objc_msgSend_876 = __objc_msgSend_876Ptr.asFunction< void Function(ffi.Pointer<_NSRange>, ffi.Pointer, ffi.Pointer, ffi.Pointer, int, _NSRange)>(); late final _sel_stringByReplacingMatchesInString_options_range_withTemplate_1 = _registerName1( "stringByReplacingMatchesInString:options:range:withTemplate:"); - ffi.Pointer _objc_msgSend_863( + ffi.Pointer _objc_msgSend_877( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, @@ -24656,7 +24990,7 @@ class SentryCocoa { _NSRange range, ffi.Pointer templ, ) { - return __objc_msgSend_863( + return __objc_msgSend_877( obj, sel, string, @@ -24666,7 +25000,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_863Ptr = _lookup< + late final __objc_msgSend_877Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -24675,7 +25009,7 @@ class SentryCocoa { ffi.Int32, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_863 = __objc_msgSend_863Ptr.asFunction< + late final __objc_msgSend_877 = __objc_msgSend_877Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -24686,7 +25020,7 @@ class SentryCocoa { late final _sel_replaceMatchesInString_options_range_withTemplate_1 = _registerName1("replaceMatchesInString:options:range:withTemplate:"); - int _objc_msgSend_864( + int _objc_msgSend_878( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, @@ -24694,7 +25028,7 @@ class SentryCocoa { _NSRange range, ffi.Pointer templ, ) { - return __objc_msgSend_864( + return __objc_msgSend_878( obj, sel, string, @@ -24704,7 +25038,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_864Ptr = _lookup< + late final __objc_msgSend_878Ptr = _lookup< ffi.NativeFunction< ffi.UnsignedLong Function( ffi.Pointer, @@ -24713,13 +25047,13 @@ class SentryCocoa { ffi.Int32, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_864 = __objc_msgSend_864Ptr.asFunction< + late final __objc_msgSend_878 = __objc_msgSend_878Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int, _NSRange, ffi.Pointer)>(); late final _sel_replacementStringForResult_inString_offset_template_1 = _registerName1("replacementStringForResult:inString:offset:template:"); - ffi.Pointer _objc_msgSend_865( + ffi.Pointer _objc_msgSend_879( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer result, @@ -24727,7 +25061,7 @@ class SentryCocoa { int offset, ffi.Pointer templ, ) { - return __objc_msgSend_865( + return __objc_msgSend_879( obj, sel, result, @@ -24737,7 +25071,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_865Ptr = _lookup< + late final __objc_msgSend_879Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -24746,7 +25080,7 @@ class SentryCocoa { ffi.Pointer, ffi.Long, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_865 = __objc_msgSend_865Ptr.asFunction< + late final __objc_msgSend_879 = __objc_msgSend_879Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -24758,21 +25092,21 @@ class SentryCocoa { late final _sel_escapedTemplateForString_1 = _registerName1("escapedTemplateForString:"); late final _sel_regularExpression1 = _registerName1("regularExpression"); - ffi.Pointer _objc_msgSend_866( + ffi.Pointer _objc_msgSend_880( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_866( + return __objc_msgSend_880( obj, sel, ); } - late final __objc_msgSend_866Ptr = _lookup< + late final __objc_msgSend_880Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_866 = __objc_msgSend_866Ptr.asFunction< + late final __objc_msgSend_880 = __objc_msgSend_880Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -24782,36 +25116,36 @@ class SentryCocoa { late final _sel_rangeWithName_1 = _registerName1("rangeWithName:"); late final _sel_resultByAdjustingRangesWithOffset_1 = _registerName1("resultByAdjustingRangesWithOffset:"); - ffi.Pointer _objc_msgSend_867( + ffi.Pointer _objc_msgSend_881( ffi.Pointer obj, ffi.Pointer sel, int offset, ) { - return __objc_msgSend_867( + return __objc_msgSend_881( obj, sel, offset, ); } - late final __objc_msgSend_867Ptr = _lookup< + late final __objc_msgSend_881Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Long)>>('objc_msgSend'); - late final __objc_msgSend_867 = __objc_msgSend_867Ptr.asFunction< + late final __objc_msgSend_881 = __objc_msgSend_881Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); late final _sel_addressComponents1 = _registerName1("addressComponents"); late final _sel_orthographyCheckingResultWithRange_orthography_1 = _registerName1("orthographyCheckingResultWithRange:orthography:"); - ffi.Pointer _objc_msgSend_868( + ffi.Pointer _objc_msgSend_882( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer orthography, ) { - return __objc_msgSend_868( + return __objc_msgSend_882( obj, sel, range, @@ -24819,48 +25153,48 @@ class SentryCocoa { ); } - late final __objc_msgSend_868Ptr = _lookup< + late final __objc_msgSend_882Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_868 = __objc_msgSend_868Ptr.asFunction< + late final __objc_msgSend_882 = __objc_msgSend_882Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>(); late final _sel_spellCheckingResultWithRange_1 = _registerName1("spellCheckingResultWithRange:"); - ffi.Pointer _objc_msgSend_869( + ffi.Pointer _objc_msgSend_883( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ) { - return __objc_msgSend_869( + return __objc_msgSend_883( obj, sel, range, ); } - late final __objc_msgSend_869Ptr = _lookup< + late final __objc_msgSend_883Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, _NSRange)>>('objc_msgSend'); - late final __objc_msgSend_869 = __objc_msgSend_869Ptr.asFunction< + late final __objc_msgSend_883 = __objc_msgSend_883Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, _NSRange)>(); late final _sel_grammarCheckingResultWithRange_details_1 = _registerName1("grammarCheckingResultWithRange:details:"); - ffi.Pointer _objc_msgSend_870( + ffi.Pointer _objc_msgSend_884( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer details, ) { - return __objc_msgSend_870( + return __objc_msgSend_884( obj, sel, range, @@ -24868,26 +25202,26 @@ class SentryCocoa { ); } - late final __objc_msgSend_870Ptr = _lookup< + late final __objc_msgSend_884Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_870 = __objc_msgSend_870Ptr.asFunction< + late final __objc_msgSend_884 = __objc_msgSend_884Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>(); late final _sel_dateCheckingResultWithRange_date_1 = _registerName1("dateCheckingResultWithRange:date:"); - ffi.Pointer _objc_msgSend_871( + ffi.Pointer _objc_msgSend_885( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer date, ) { - return __objc_msgSend_871( + return __objc_msgSend_885( obj, sel, range, @@ -24895,20 +25229,20 @@ class SentryCocoa { ); } - late final __objc_msgSend_871Ptr = _lookup< + late final __objc_msgSend_885Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_871 = __objc_msgSend_871Ptr.asFunction< + late final __objc_msgSend_885 = __objc_msgSend_885Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>(); late final _sel_dateCheckingResultWithRange_date_timeZone_duration_1 = _registerName1("dateCheckingResultWithRange:date:timeZone:duration:"); - ffi.Pointer _objc_msgSend_872( + ffi.Pointer _objc_msgSend_886( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, @@ -24916,7 +25250,7 @@ class SentryCocoa { ffi.Pointer timeZone, double duration, ) { - return __objc_msgSend_872( + return __objc_msgSend_886( obj, sel, range, @@ -24926,7 +25260,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_872Ptr = _lookup< + late final __objc_msgSend_886Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -24935,7 +25269,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Double)>>('objc_msgSend'); - late final __objc_msgSend_872 = __objc_msgSend_872Ptr.asFunction< + late final __objc_msgSend_886 = __objc_msgSend_886Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -24946,13 +25280,13 @@ class SentryCocoa { late final _sel_addressCheckingResultWithRange_components_1 = _registerName1("addressCheckingResultWithRange:components:"); - ffi.Pointer _objc_msgSend_873( + ffi.Pointer _objc_msgSend_887( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer components, ) { - return __objc_msgSend_873( + return __objc_msgSend_887( obj, sel, range, @@ -24960,26 +25294,26 @@ class SentryCocoa { ); } - late final __objc_msgSend_873Ptr = _lookup< + late final __objc_msgSend_887Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_873 = __objc_msgSend_873Ptr.asFunction< + late final __objc_msgSend_887 = __objc_msgSend_887Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>(); late final _sel_linkCheckingResultWithRange_URL_1 = _registerName1("linkCheckingResultWithRange:URL:"); - ffi.Pointer _objc_msgSend_874( + ffi.Pointer _objc_msgSend_888( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer url, ) { - return __objc_msgSend_874( + return __objc_msgSend_888( obj, sel, range, @@ -24987,26 +25321,26 @@ class SentryCocoa { ); } - late final __objc_msgSend_874Ptr = _lookup< + late final __objc_msgSend_888Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_874 = __objc_msgSend_874Ptr.asFunction< + late final __objc_msgSend_888 = __objc_msgSend_888Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>(); late final _sel_quoteCheckingResultWithRange_replacementString_1 = _registerName1("quoteCheckingResultWithRange:replacementString:"); - ffi.Pointer _objc_msgSend_875( + ffi.Pointer _objc_msgSend_889( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer replacementString, ) { - return __objc_msgSend_875( + return __objc_msgSend_889( obj, sel, range, @@ -25014,14 +25348,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_875Ptr = _lookup< + late final __objc_msgSend_889Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_875 = __objc_msgSend_875Ptr.asFunction< + late final __objc_msgSend_889 = __objc_msgSend_889Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, _NSRange, ffi.Pointer)>(); @@ -25034,14 +25368,14 @@ class SentryCocoa { late final _sel_correctionCheckingResultWithRange_replacementString_alternativeStrings_1 = _registerName1( "correctionCheckingResultWithRange:replacementString:alternativeStrings:"); - ffi.Pointer _objc_msgSend_876( + ffi.Pointer _objc_msgSend_890( ffi.Pointer obj, ffi.Pointer sel, _NSRange range, ffi.Pointer replacementString, ffi.Pointer alternativeStrings, ) { - return __objc_msgSend_876( + return __objc_msgSend_890( obj, sel, range, @@ -25050,7 +25384,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_876Ptr = _lookup< + late final __objc_msgSend_890Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -25058,7 +25392,7 @@ class SentryCocoa { _NSRange, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_876 = __objc_msgSend_876Ptr.asFunction< + late final __objc_msgSend_890 = __objc_msgSend_890Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -25069,14 +25403,14 @@ class SentryCocoa { late final _sel_regularExpressionCheckingResultWithRanges_count_regularExpression_1 = _registerName1( "regularExpressionCheckingResultWithRanges:count:regularExpression:"); - ffi.Pointer _objc_msgSend_877( + ffi.Pointer _objc_msgSend_891( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_NSRange> ranges, int count, ffi.Pointer regularExpression, ) { - return __objc_msgSend_877( + return __objc_msgSend_891( obj, sel, ranges, @@ -25085,7 +25419,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_877Ptr = _lookup< + late final __objc_msgSend_891Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -25093,7 +25427,7 @@ class SentryCocoa { ffi.Pointer<_NSRange>, ffi.UnsignedLong, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_877 = __objc_msgSend_877Ptr.asFunction< + late final __objc_msgSend_891 = __objc_msgSend_891Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -25107,55 +25441,55 @@ class SentryCocoa { _registerName1("transitInformationCheckingResultWithRange:components:"); late final _class_NSURLCache1 = _getClass1("NSURLCache"); late final _sel_sharedURLCache1 = _registerName1("sharedURLCache"); - ffi.Pointer _objc_msgSend_878( + ffi.Pointer _objc_msgSend_892( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_878( + return __objc_msgSend_892( obj, sel, ); } - late final __objc_msgSend_878Ptr = _lookup< + late final __objc_msgSend_892Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_878 = __objc_msgSend_878Ptr.asFunction< + late final __objc_msgSend_892 = __objc_msgSend_892Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_setSharedURLCache_1 = _registerName1("setSharedURLCache:"); - void _objc_msgSend_879( + void _objc_msgSend_893( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_879( + return __objc_msgSend_893( obj, sel, value, ); } - late final __objc_msgSend_879Ptr = _lookup< + late final __objc_msgSend_893Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_879 = __objc_msgSend_879Ptr.asFunction< + late final __objc_msgSend_893 = __objc_msgSend_893Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_initWithMemoryCapacity_diskCapacity_diskPath_1 = _registerName1("initWithMemoryCapacity:diskCapacity:diskPath:"); - instancetype _objc_msgSend_880( + instancetype _objc_msgSend_894( ffi.Pointer obj, ffi.Pointer sel, int memoryCapacity, int diskCapacity, ffi.Pointer path, ) { - return __objc_msgSend_880( + return __objc_msgSend_894( obj, sel, memoryCapacity, @@ -25164,7 +25498,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_880Ptr = _lookup< + late final __objc_msgSend_894Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -25172,20 +25506,20 @@ class SentryCocoa { ffi.UnsignedLong, ffi.UnsignedLong, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_880 = __objc_msgSend_880Ptr.asFunction< + late final __objc_msgSend_894 = __objc_msgSend_894Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, int, int, ffi.Pointer)>(); late final _sel_initWithMemoryCapacity_diskCapacity_directoryURL_1 = _registerName1("initWithMemoryCapacity:diskCapacity:directoryURL:"); - instancetype _objc_msgSend_881( + instancetype _objc_msgSend_895( ffi.Pointer obj, ffi.Pointer sel, int memoryCapacity, int diskCapacity, ffi.Pointer directoryURL, ) { - return __objc_msgSend_881( + return __objc_msgSend_895( obj, sel, memoryCapacity, @@ -25194,7 +25528,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_881Ptr = _lookup< + late final __objc_msgSend_895Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -25202,20 +25536,20 @@ class SentryCocoa { ffi.UnsignedLong, ffi.UnsignedLong, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_881 = __objc_msgSend_881Ptr.asFunction< + late final __objc_msgSend_895 = __objc_msgSend_895Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, int, int, ffi.Pointer)>(); late final _class_NSCachedURLResponse1 = _getClass1("NSCachedURLResponse"); late final _sel_initWithResponse_data_1 = _registerName1("initWithResponse:data:"); - instancetype _objc_msgSend_882( + instancetype _objc_msgSend_896( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer response, ffi.Pointer data, ) { - return __objc_msgSend_882( + return __objc_msgSend_896( obj, sel, response, @@ -25223,20 +25557,20 @@ class SentryCocoa { ); } - late final __objc_msgSend_882Ptr = _lookup< + late final __objc_msgSend_896Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_882 = __objc_msgSend_882Ptr.asFunction< + late final __objc_msgSend_896 = __objc_msgSend_896Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_initWithResponse_data_userInfo_storagePolicy_1 = _registerName1("initWithResponse:data:userInfo:storagePolicy:"); - instancetype _objc_msgSend_883( + instancetype _objc_msgSend_897( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer response, @@ -25244,7 +25578,7 @@ class SentryCocoa { ffi.Pointer userInfo, int storagePolicy, ) { - return __objc_msgSend_883( + return __objc_msgSend_897( obj, sel, response, @@ -25254,7 +25588,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_883Ptr = _lookup< + late final __objc_msgSend_897Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -25263,7 +25597,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_883 = __objc_msgSend_883Ptr.asFunction< + late final __objc_msgSend_897 = __objc_msgSend_897Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -25273,54 +25607,54 @@ class SentryCocoa { int)>(); late final _sel_storagePolicy1 = _registerName1("storagePolicy"); - int _objc_msgSend_884( + int _objc_msgSend_898( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_884( + return __objc_msgSend_898( obj, sel, ); } - late final __objc_msgSend_884Ptr = _lookup< + late final __objc_msgSend_898Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_884 = __objc_msgSend_884Ptr.asFunction< + late final __objc_msgSend_898 = __objc_msgSend_898Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_cachedResponseForRequest_1 = _registerName1("cachedResponseForRequest:"); - ffi.Pointer _objc_msgSend_885( + ffi.Pointer _objc_msgSend_899( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ) { - return __objc_msgSend_885( + return __objc_msgSend_899( obj, sel, request, ); } - late final __objc_msgSend_885Ptr = _lookup< + late final __objc_msgSend_899Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_885 = __objc_msgSend_885Ptr.asFunction< + late final __objc_msgSend_899 = __objc_msgSend_899Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_storeCachedResponse_forRequest_1 = _registerName1("storeCachedResponse:forRequest:"); - void _objc_msgSend_886( + void _objc_msgSend_900( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer cachedResponse, ffi.Pointer request, ) { - return __objc_msgSend_886( + return __objc_msgSend_900( obj, sel, cachedResponse, @@ -25328,36 +25662,36 @@ class SentryCocoa { ); } - late final __objc_msgSend_886Ptr = _lookup< + late final __objc_msgSend_900Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_886 = __objc_msgSend_886Ptr.asFunction< + late final __objc_msgSend_900 = __objc_msgSend_900Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_removeCachedResponseForRequest_1 = _registerName1("removeCachedResponseForRequest:"); - void _objc_msgSend_887( + void _objc_msgSend_901( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ) { - return __objc_msgSend_887( + return __objc_msgSend_901( obj, sel, request, ); } - late final __objc_msgSend_887Ptr = _lookup< + late final __objc_msgSend_901Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_887 = __objc_msgSend_887Ptr.asFunction< + late final __objc_msgSend_901 = __objc_msgSend_901Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -25374,13 +25708,13 @@ class SentryCocoa { late final _class_NSURLSessionDataTask1 = _getClass1("NSURLSessionDataTask"); late final _sel_storeCachedResponse_forDataTask_1 = _registerName1("storeCachedResponse:forDataTask:"); - void _objc_msgSend_888( + void _objc_msgSend_902( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer cachedResponse, ffi.Pointer dataTask, ) { - return __objc_msgSend_888( + return __objc_msgSend_902( obj, sel, cachedResponse, @@ -25388,26 +25722,26 @@ class SentryCocoa { ); } - late final __objc_msgSend_888Ptr = _lookup< + late final __objc_msgSend_902Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_888 = __objc_msgSend_888Ptr.asFunction< + late final __objc_msgSend_902 = __objc_msgSend_902Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_getCachedResponseForDataTask_completionHandler_1 = _registerName1("getCachedResponseForDataTask:completionHandler:"); - void _objc_msgSend_889( + void _objc_msgSend_903( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer dataTask, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_889( + return __objc_msgSend_903( obj, sel, dataTask, @@ -25415,50 +25749,50 @@ class SentryCocoa { ); } - late final __objc_msgSend_889Ptr = _lookup< + late final __objc_msgSend_903Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_889 = __objc_msgSend_889Ptr.asFunction< + late final __objc_msgSend_903 = __objc_msgSend_903Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_removeCachedResponseForDataTask_1 = _registerName1("removeCachedResponseForDataTask:"); - void _objc_msgSend_890( + void _objc_msgSend_904( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer dataTask, ) { - return __objc_msgSend_890( + return __objc_msgSend_904( obj, sel, dataTask, ); } - late final __objc_msgSend_890Ptr = _lookup< + late final __objc_msgSend_904Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_890 = __objc_msgSend_890Ptr.asFunction< + late final __objc_msgSend_904 = __objc_msgSend_904Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _class_NSURLConnection1 = _getClass1("NSURLConnection"); late final _sel_initWithRequest_delegate_startImmediately_1 = _registerName1("initWithRequest:delegate:startImmediately:"); - instancetype _objc_msgSend_891( + instancetype _objc_msgSend_905( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer delegate, bool startImmediately, ) { - return __objc_msgSend_891( + return __objc_msgSend_905( obj, sel, request, @@ -25467,7 +25801,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_891Ptr = _lookup< + late final __objc_msgSend_905Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -25475,19 +25809,19 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_891 = __objc_msgSend_891Ptr.asFunction< + late final __objc_msgSend_905 = __objc_msgSend_905Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer, bool)>(); late final _sel_initWithRequest_delegate_1 = _registerName1("initWithRequest:delegate:"); - instancetype _objc_msgSend_892( + instancetype _objc_msgSend_906( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer delegate, ) { - return __objc_msgSend_892( + return __objc_msgSend_906( obj, sel, request, @@ -25495,26 +25829,26 @@ class SentryCocoa { ); } - late final __objc_msgSend_892Ptr = _lookup< + late final __objc_msgSend_906Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_892 = __objc_msgSend_892Ptr.asFunction< + late final __objc_msgSend_906 = __objc_msgSend_906Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_connectionWithRequest_delegate_1 = _registerName1("connectionWithRequest:delegate:"); - ffi.Pointer _objc_msgSend_893( + ffi.Pointer _objc_msgSend_907( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer delegate, ) { - return __objc_msgSend_893( + return __objc_msgSend_907( obj, sel, request, @@ -25522,14 +25856,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_893Ptr = _lookup< + late final __objc_msgSend_907Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_893 = __objc_msgSend_893Ptr.asFunction< + late final __objc_msgSend_907 = __objc_msgSend_907Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -25539,57 +25873,57 @@ class SentryCocoa { late final _sel_unscheduleFromRunLoop_forMode_1 = _registerName1("unscheduleFromRunLoop:forMode:"); late final _sel_setDelegateQueue_1 = _registerName1("setDelegateQueue:"); - void _objc_msgSend_894( + void _objc_msgSend_908( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer queue, ) { - return __objc_msgSend_894( + return __objc_msgSend_908( obj, sel, queue, ); } - late final __objc_msgSend_894Ptr = _lookup< + late final __objc_msgSend_908Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_894 = __objc_msgSend_894Ptr.asFunction< + late final __objc_msgSend_908 = __objc_msgSend_908Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_canHandleRequest_1 = _registerName1("canHandleRequest:"); - bool _objc_msgSend_895( + bool _objc_msgSend_909( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ) { - return __objc_msgSend_895( + return __objc_msgSend_909( obj, sel, request, ); } - late final __objc_msgSend_895Ptr = _lookup< + late final __objc_msgSend_909Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_895 = __objc_msgSend_895Ptr.asFunction< + late final __objc_msgSend_909 = __objc_msgSend_909Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_sendSynchronousRequest_returningResponse_error_1 = _registerName1("sendSynchronousRequest:returningResponse:error:"); - ffi.Pointer _objc_msgSend_896( + ffi.Pointer _objc_msgSend_910( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer> response, ffi.Pointer> error, ) { - return __objc_msgSend_896( + return __objc_msgSend_910( obj, sel, request, @@ -25598,7 +25932,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_896Ptr = _lookup< + late final __objc_msgSend_910Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -25606,7 +25940,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer>, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_896 = __objc_msgSend_896Ptr.asFunction< + late final __objc_msgSend_910 = __objc_msgSend_910Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -25616,14 +25950,14 @@ class SentryCocoa { late final _sel_sendAsynchronousRequest_queue_completionHandler_1 = _registerName1("sendAsynchronousRequest:queue:completionHandler:"); - void _objc_msgSend_897( + void _objc_msgSend_911( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer queue, ffi.Pointer<_ObjCBlock> handler, ) { - return __objc_msgSend_897( + return __objc_msgSend_911( obj, sel, request, @@ -25632,7 +25966,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_897Ptr = _lookup< + late final __objc_msgSend_911Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -25640,7 +25974,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_897 = __objc_msgSend_897Ptr.asFunction< + late final __objc_msgSend_911 = __objc_msgSend_911Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -25650,33 +25984,33 @@ class SentryCocoa { late final _class_NSURLCredential1 = _getClass1("NSURLCredential"); late final _sel_persistence1 = _registerName1("persistence"); - int _objc_msgSend_898( + int _objc_msgSend_912( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_898( + return __objc_msgSend_912( obj, sel, ); } - late final __objc_msgSend_898Ptr = _lookup< + late final __objc_msgSend_912Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_898 = __objc_msgSend_898Ptr.asFunction< + late final __objc_msgSend_912 = __objc_msgSend_912Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_initWithUser_password_persistence_1 = _registerName1("initWithUser:password:persistence:"); - instancetype _objc_msgSend_899( + instancetype _objc_msgSend_913( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer user, ffi.Pointer password, int persistence, ) { - return __objc_msgSend_899( + return __objc_msgSend_913( obj, sel, user, @@ -25685,7 +26019,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_899Ptr = _lookup< + late final __objc_msgSend_913Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -25693,20 +26027,20 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_899 = __objc_msgSend_899Ptr.asFunction< + late final __objc_msgSend_913 = __objc_msgSend_913Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); late final _sel_credentialWithUser_password_persistence_1 = _registerName1("credentialWithUser:password:persistence:"); - ffi.Pointer _objc_msgSend_900( + ffi.Pointer _objc_msgSend_914( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer user, ffi.Pointer password, int persistence, ) { - return __objc_msgSend_900( + return __objc_msgSend_914( obj, sel, user, @@ -25715,7 +26049,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_900Ptr = _lookup< + late final __objc_msgSend_914Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -25723,7 +26057,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_900 = __objc_msgSend_900Ptr.asFunction< + late final __objc_msgSend_914 = __objc_msgSend_914Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -25734,14 +26068,14 @@ class SentryCocoa { late final _sel_hasPassword1 = _registerName1("hasPassword"); late final _sel_initWithIdentity_certificates_persistence_1 = _registerName1("initWithIdentity:certificates:persistence:"); - instancetype _objc_msgSend_901( + instancetype _objc_msgSend_915( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<__SecIdentity> identity, ffi.Pointer certArray, int persistence, ) { - return __objc_msgSend_901( + return __objc_msgSend_915( obj, sel, identity, @@ -25750,7 +26084,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_901Ptr = _lookup< + late final __objc_msgSend_915Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -25758,20 +26092,20 @@ class SentryCocoa { ffi.Pointer<__SecIdentity>, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_901 = __objc_msgSend_901Ptr.asFunction< + late final __objc_msgSend_915 = __objc_msgSend_915Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<__SecIdentity>, ffi.Pointer, int)>(); late final _sel_credentialWithIdentity_certificates_persistence_1 = _registerName1("credentialWithIdentity:certificates:persistence:"); - ffi.Pointer _objc_msgSend_902( + ffi.Pointer _objc_msgSend_916( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<__SecIdentity> identity, ffi.Pointer certArray, int persistence, ) { - return __objc_msgSend_902( + return __objc_msgSend_916( obj, sel, identity, @@ -25780,7 +26114,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_902Ptr = _lookup< + late final __objc_msgSend_916Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -25788,7 +26122,7 @@ class SentryCocoa { ffi.Pointer<__SecIdentity>, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_902 = __objc_msgSend_902Ptr.asFunction< + late final __objc_msgSend_916 = __objc_msgSend_916Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -25797,71 +26131,71 @@ class SentryCocoa { int)>(); late final _sel_identity1 = _registerName1("identity"); - ffi.Pointer<__SecIdentity> _objc_msgSend_903( + ffi.Pointer<__SecIdentity> _objc_msgSend_917( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_903( + return __objc_msgSend_917( obj, sel, ); } - late final __objc_msgSend_903Ptr = _lookup< + late final __objc_msgSend_917Ptr = _lookup< ffi.NativeFunction< ffi.Pointer<__SecIdentity> Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_903 = __objc_msgSend_903Ptr.asFunction< + late final __objc_msgSend_917 = __objc_msgSend_917Ptr.asFunction< ffi.Pointer<__SecIdentity> Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_certificates1 = _registerName1("certificates"); late final _sel_initWithTrust_1 = _registerName1("initWithTrust:"); - instancetype _objc_msgSend_904( + instancetype _objc_msgSend_918( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<__SecTrust> trust, ) { - return __objc_msgSend_904( + return __objc_msgSend_918( obj, sel, trust, ); } - late final __objc_msgSend_904Ptr = _lookup< + late final __objc_msgSend_918Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<__SecTrust>)>>('objc_msgSend'); - late final __objc_msgSend_904 = __objc_msgSend_904Ptr.asFunction< + late final __objc_msgSend_918 = __objc_msgSend_918Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<__SecTrust>)>(); late final _sel_credentialForTrust_1 = _registerName1("credentialForTrust:"); - ffi.Pointer _objc_msgSend_905( + ffi.Pointer _objc_msgSend_919( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<__SecTrust> trust, ) { - return __objc_msgSend_905( + return __objc_msgSend_919( obj, sel, trust, ); } - late final __objc_msgSend_905Ptr = _lookup< + late final __objc_msgSend_919Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<__SecTrust>)>>('objc_msgSend'); - late final __objc_msgSend_905 = __objc_msgSend_905Ptr.asFunction< + late final __objc_msgSend_919 = __objc_msgSend_919Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<__SecTrust>)>(); late final _class_NSURLProtectionSpace1 = _getClass1("NSURLProtectionSpace"); late final _sel_initWithHost_port_protocol_realm_authenticationMethod_1 = _registerName1("initWithHost:port:protocol:realm:authenticationMethod:"); - instancetype _objc_msgSend_906( + instancetype _objc_msgSend_920( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer host, @@ -25870,7 +26204,7 @@ class SentryCocoa { ffi.Pointer realm, ffi.Pointer authenticationMethod, ) { - return __objc_msgSend_906( + return __objc_msgSend_920( obj, sel, host, @@ -25881,7 +26215,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_906Ptr = _lookup< + late final __objc_msgSend_920Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -25891,7 +26225,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_906 = __objc_msgSend_906Ptr.asFunction< + late final __objc_msgSend_920 = __objc_msgSend_920Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -25913,21 +26247,21 @@ class SentryCocoa { _registerName1("authenticationMethod"); late final _sel_distinguishedNames1 = _registerName1("distinguishedNames"); late final _sel_serverTrust1 = _registerName1("serverTrust"); - ffi.Pointer<__SecTrust> _objc_msgSend_907( + ffi.Pointer<__SecTrust> _objc_msgSend_921( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_907( + return __objc_msgSend_921( obj, sel, ); } - late final __objc_msgSend_907Ptr = _lookup< + late final __objc_msgSend_921Ptr = _lookup< ffi.NativeFunction< ffi.Pointer<__SecTrust> Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_907 = __objc_msgSend_907Ptr.asFunction< + late final __objc_msgSend_921 = __objc_msgSend_921Ptr.asFunction< ffi.Pointer<__SecTrust> Function( ffi.Pointer, ffi.Pointer)>(); @@ -25935,56 +26269,56 @@ class SentryCocoa { _getClass1("NSURLCredentialStorage"); late final _sel_sharedCredentialStorage1 = _registerName1("sharedCredentialStorage"); - ffi.Pointer _objc_msgSend_908( + ffi.Pointer _objc_msgSend_922( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_908( + return __objc_msgSend_922( obj, sel, ); } - late final __objc_msgSend_908Ptr = _lookup< + late final __objc_msgSend_922Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_908 = __objc_msgSend_908Ptr.asFunction< + late final __objc_msgSend_922 = __objc_msgSend_922Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_credentialsForProtectionSpace_1 = _registerName1("credentialsForProtectionSpace:"); - ffi.Pointer _objc_msgSend_909( + ffi.Pointer _objc_msgSend_923( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer space, ) { - return __objc_msgSend_909( + return __objc_msgSend_923( obj, sel, space, ); } - late final __objc_msgSend_909Ptr = _lookup< + late final __objc_msgSend_923Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_909 = __objc_msgSend_909Ptr.asFunction< + late final __objc_msgSend_923 = __objc_msgSend_923Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_allCredentials1 = _registerName1("allCredentials"); late final _sel_setCredential_forProtectionSpace_1 = _registerName1("setCredential:forProtectionSpace:"); - void _objc_msgSend_910( + void _objc_msgSend_924( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer credential, ffi.Pointer space, ) { - return __objc_msgSend_910( + return __objc_msgSend_924( obj, sel, credential, @@ -25992,14 +26326,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_910Ptr = _lookup< + late final __objc_msgSend_924Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_910 = __objc_msgSend_910Ptr.asFunction< + late final __objc_msgSend_924 = __objc_msgSend_924Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -26007,14 +26341,14 @@ class SentryCocoa { _registerName1("removeCredential:forProtectionSpace:"); late final _sel_removeCredential_forProtectionSpace_options_1 = _registerName1("removeCredential:forProtectionSpace:options:"); - void _objc_msgSend_911( + void _objc_msgSend_925( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer credential, ffi.Pointer space, ffi.Pointer options, ) { - return __objc_msgSend_911( + return __objc_msgSend_925( obj, sel, credential, @@ -26023,7 +26357,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_911Ptr = _lookup< + late final __objc_msgSend_925Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -26031,7 +26365,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_911 = __objc_msgSend_911Ptr.asFunction< + late final __objc_msgSend_925 = __objc_msgSend_925Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -26041,23 +26375,23 @@ class SentryCocoa { late final _sel_defaultCredentialForProtectionSpace_1 = _registerName1("defaultCredentialForProtectionSpace:"); - ffi.Pointer _objc_msgSend_912( + ffi.Pointer _objc_msgSend_926( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer space, ) { - return __objc_msgSend_912( + return __objc_msgSend_926( obj, sel, space, ); } - late final __objc_msgSend_912Ptr = _lookup< + late final __objc_msgSend_926Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_912 = __objc_msgSend_912Ptr.asFunction< + late final __objc_msgSend_926 = __objc_msgSend_926Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -26066,14 +26400,14 @@ class SentryCocoa { late final _sel_getCredentialsForProtectionSpace_task_completionHandler_1 = _registerName1( "getCredentialsForProtectionSpace:task:completionHandler:"); - void _objc_msgSend_913( + void _objc_msgSend_927( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer protectionSpace, ffi.Pointer task, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_913( + return __objc_msgSend_927( obj, sel, protectionSpace, @@ -26082,7 +26416,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_913Ptr = _lookup< + late final __objc_msgSend_927Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -26090,7 +26424,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_913 = __objc_msgSend_913Ptr.asFunction< + late final __objc_msgSend_927 = __objc_msgSend_927Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -26100,14 +26434,14 @@ class SentryCocoa { late final _sel_setCredential_forProtectionSpace_task_1 = _registerName1("setCredential:forProtectionSpace:task:"); - void _objc_msgSend_914( + void _objc_msgSend_928( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer credential, ffi.Pointer protectionSpace, ffi.Pointer task, ) { - return __objc_msgSend_914( + return __objc_msgSend_928( obj, sel, credential, @@ -26116,7 +26450,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_914Ptr = _lookup< + late final __objc_msgSend_928Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -26124,7 +26458,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_914 = __objc_msgSend_914Ptr.asFunction< + late final __objc_msgSend_928 = __objc_msgSend_928Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -26134,7 +26468,7 @@ class SentryCocoa { late final _sel_removeCredential_forProtectionSpace_options_task_1 = _registerName1("removeCredential:forProtectionSpace:options:task:"); - void _objc_msgSend_915( + void _objc_msgSend_929( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer credential, @@ -26142,7 +26476,7 @@ class SentryCocoa { ffi.Pointer options, ffi.Pointer task, ) { - return __objc_msgSend_915( + return __objc_msgSend_929( obj, sel, credential, @@ -26152,7 +26486,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_915Ptr = _lookup< + late final __objc_msgSend_929Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -26161,7 +26495,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_915 = __objc_msgSend_915Ptr.asFunction< + late final __objc_msgSend_929 = __objc_msgSend_929Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -26173,14 +26507,14 @@ class SentryCocoa { late final _sel_getDefaultCredentialForProtectionSpace_task_completionHandler_1 = _registerName1( "getDefaultCredentialForProtectionSpace:task:completionHandler:"); - void _objc_msgSend_916( + void _objc_msgSend_930( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer space, ffi.Pointer task, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_916( + return __objc_msgSend_930( obj, sel, space, @@ -26189,7 +26523,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_916Ptr = _lookup< + late final __objc_msgSend_930Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -26197,7 +26531,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_916 = __objc_msgSend_916Ptr.asFunction< + late final __objc_msgSend_930 = __objc_msgSend_930Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -26210,14 +26544,14 @@ class SentryCocoa { late final _class_NSURLProtocol1 = _getClass1("NSURLProtocol"); late final _sel_initWithRequest_cachedResponse_client_1 = _registerName1("initWithRequest:cachedResponse:client:"); - instancetype _objc_msgSend_917( + instancetype _objc_msgSend_931( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer cachedResponse, ffi.Pointer client, ) { - return __objc_msgSend_917( + return __objc_msgSend_931( obj, sel, request, @@ -26226,7 +26560,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_917Ptr = _lookup< + late final __objc_msgSend_931Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -26234,7 +26568,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_917 = __objc_msgSend_917Ptr.asFunction< + late final __objc_msgSend_931 = __objc_msgSend_931Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -26245,56 +26579,56 @@ class SentryCocoa { late final _sel_client1 = _registerName1("client"); late final _sel_request1 = _registerName1("request"); late final _sel_cachedResponse1 = _registerName1("cachedResponse"); - ffi.Pointer _objc_msgSend_918( + ffi.Pointer _objc_msgSend_932( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_918( + return __objc_msgSend_932( obj, sel, ); } - late final __objc_msgSend_918Ptr = _lookup< + late final __objc_msgSend_932Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_918 = __objc_msgSend_918Ptr.asFunction< + late final __objc_msgSend_932 = __objc_msgSend_932Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_canInitWithRequest_1 = _registerName1("canInitWithRequest:"); late final _sel_canonicalRequestForRequest_1 = _registerName1("canonicalRequestForRequest:"); - ffi.Pointer _objc_msgSend_919( + ffi.Pointer _objc_msgSend_933( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ) { - return __objc_msgSend_919( + return __objc_msgSend_933( obj, sel, request, ); } - late final __objc_msgSend_919Ptr = _lookup< + late final __objc_msgSend_933Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_919 = __objc_msgSend_919Ptr.asFunction< + late final __objc_msgSend_933 = __objc_msgSend_933Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_requestIsCacheEquivalent_toRequest_1 = _registerName1("requestIsCacheEquivalent:toRequest:"); - bool _objc_msgSend_920( + bool _objc_msgSend_934( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer a, ffi.Pointer b, ) { - return __objc_msgSend_920( + return __objc_msgSend_934( obj, sel, a, @@ -26302,14 +26636,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_920Ptr = _lookup< + late final __objc_msgSend_934Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_920 = __objc_msgSend_920Ptr.asFunction< + late final __objc_msgSend_934 = __objc_msgSend_934Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -26317,13 +26651,13 @@ class SentryCocoa { late final _sel_stopLoading1 = _registerName1("stopLoading"); late final _sel_propertyForKey_inRequest_1 = _registerName1("propertyForKey:inRequest:"); - ffi.Pointer _objc_msgSend_921( + ffi.Pointer _objc_msgSend_935( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer key, ffi.Pointer request, ) { - return __objc_msgSend_921( + return __objc_msgSend_935( obj, sel, key, @@ -26331,14 +26665,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_921Ptr = _lookup< + late final __objc_msgSend_935Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_921 = __objc_msgSend_921Ptr.asFunction< + late final __objc_msgSend_935 = __objc_msgSend_935Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -26348,46 +26682,46 @@ class SentryCocoa { late final _class_NSMutableURLRequest1 = _getClass1("NSMutableURLRequest"); late final _sel_setURL_1 = _registerName1("setURL:"); late final _sel_setCachePolicy_1 = _registerName1("setCachePolicy:"); - void _objc_msgSend_922( + void _objc_msgSend_936( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_922( + return __objc_msgSend_936( obj, sel, value, ); } - late final __objc_msgSend_922Ptr = _lookup< + late final __objc_msgSend_936Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_922 = __objc_msgSend_922Ptr.asFunction< + late final __objc_msgSend_936 = __objc_msgSend_936Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_setTimeoutInterval_1 = _registerName1("setTimeoutInterval:"); late final _sel_setMainDocumentURL_1 = _registerName1("setMainDocumentURL:"); late final _sel_setNetworkServiceType_1 = _registerName1("setNetworkServiceType:"); - void _objc_msgSend_923( + void _objc_msgSend_937( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_923( + return __objc_msgSend_937( obj, sel, value, ); } - late final __objc_msgSend_923Ptr = _lookup< + late final __objc_msgSend_937Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_923 = __objc_msgSend_923Ptr.asFunction< + late final __objc_msgSend_937 = __objc_msgSend_937Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_setAllowsCellularAccess_1 = @@ -26399,23 +26733,23 @@ class SentryCocoa { late final _sel_setAssumesHTTP3Capable_1 = _registerName1("setAssumesHTTP3Capable:"); late final _sel_setAttribution_1 = _registerName1("setAttribution:"); - void _objc_msgSend_924( + void _objc_msgSend_938( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_924( + return __objc_msgSend_938( obj, sel, value, ); } - late final __objc_msgSend_924Ptr = _lookup< + late final __objc_msgSend_938Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_924 = __objc_msgSend_924Ptr.asFunction< + late final __objc_msgSend_938 = __objc_msgSend_938Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_setRequiresDNSSECValidation_1 = @@ -26428,44 +26762,44 @@ class SentryCocoa { late final _sel_addValue_forHTTPHeaderField_1 = _registerName1("addValue:forHTTPHeaderField:"); late final _sel_setHTTPBody_1 = _registerName1("setHTTPBody:"); - void _objc_msgSend_925( + void _objc_msgSend_939( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_925( + return __objc_msgSend_939( obj, sel, value, ); } - late final __objc_msgSend_925Ptr = _lookup< + late final __objc_msgSend_939Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_925 = __objc_msgSend_925Ptr.asFunction< + late final __objc_msgSend_939 = __objc_msgSend_939Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_setHTTPBodyStream_1 = _registerName1("setHTTPBodyStream:"); - void _objc_msgSend_926( + void _objc_msgSend_940( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_926( + return __objc_msgSend_940( obj, sel, value, ); } - late final __objc_msgSend_926Ptr = _lookup< + late final __objc_msgSend_940Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_926 = __objc_msgSend_926Ptr.asFunction< + late final __objc_msgSend_940 = __objc_msgSend_940Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -26475,14 +26809,14 @@ class SentryCocoa { _registerName1("setHTTPShouldUsePipelining:"); late final _sel_setProperty_forKey_inRequest_1 = _registerName1("setProperty:forKey:inRequest:"); - void _objc_msgSend_927( + void _objc_msgSend_941( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ffi.Pointer key, ffi.Pointer request, ) { - return __objc_msgSend_927( + return __objc_msgSend_941( obj, sel, value, @@ -26491,7 +26825,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_927Ptr = _lookup< + late final __objc_msgSend_941Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -26499,7 +26833,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_927 = __objc_msgSend_927Ptr.asFunction< + late final __objc_msgSend_941 = __objc_msgSend_941Ptr.asFunction< void Function( ffi.Pointer, ffi.Pointer, @@ -26509,13 +26843,13 @@ class SentryCocoa { late final _sel_removePropertyForKey_inRequest_1 = _registerName1("removePropertyForKey:inRequest:"); - void _objc_msgSend_928( + void _objc_msgSend_942( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer key, ffi.Pointer request, ) { - return __objc_msgSend_928( + return __objc_msgSend_942( obj, sel, key, @@ -26523,50 +26857,50 @@ class SentryCocoa { ); } - late final __objc_msgSend_928Ptr = _lookup< + late final __objc_msgSend_942Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_928 = __objc_msgSend_928Ptr.asFunction< + late final __objc_msgSend_942 = __objc_msgSend_942Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_registerClass_1 = _registerName1("registerClass:"); late final _sel_unregisterClass_1 = _registerName1("unregisterClass:"); late final _sel_canInitWithTask_1 = _registerName1("canInitWithTask:"); - bool _objc_msgSend_929( + bool _objc_msgSend_943( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer task, ) { - return __objc_msgSend_929( + return __objc_msgSend_943( obj, sel, task, ); } - late final __objc_msgSend_929Ptr = _lookup< + late final __objc_msgSend_943Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_929 = __objc_msgSend_929Ptr.asFunction< + late final __objc_msgSend_943 = __objc_msgSend_943Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_initWithTask_cachedResponse_client_1 = _registerName1("initWithTask:cachedResponse:client:"); - instancetype _objc_msgSend_930( + instancetype _objc_msgSend_944( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer task, ffi.Pointer cachedResponse, ffi.Pointer client, ) { - return __objc_msgSend_930( + return __objc_msgSend_944( obj, sel, task, @@ -26575,7 +26909,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_930Ptr = _lookup< + late final __objc_msgSend_944Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -26583,7 +26917,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_930 = __objc_msgSend_930Ptr.asFunction< + late final __objc_msgSend_944 = __objc_msgSend_944Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -26592,43 +26926,43 @@ class SentryCocoa { ffi.Pointer)>(); late final _sel_task1 = _registerName1("task"); - ffi.Pointer _objc_msgSend_931( + ffi.Pointer _objc_msgSend_945( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_931( + return __objc_msgSend_945( obj, sel, ); } - late final __objc_msgSend_931Ptr = _lookup< + late final __objc_msgSend_945Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_931 = __objc_msgSend_931Ptr.asFunction< + late final __objc_msgSend_945 = __objc_msgSend_945Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _class_NSXMLParser1 = _getClass1("NSXMLParser"); late final _sel_initWithStream_1 = _registerName1("initWithStream:"); - instancetype _objc_msgSend_932( + instancetype _objc_msgSend_946( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer stream, ) { - return __objc_msgSend_932( + return __objc_msgSend_946( obj, sel, stream, ); } - late final __objc_msgSend_932Ptr = _lookup< + late final __objc_msgSend_946Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_932 = __objc_msgSend_932Ptr.asFunction< + late final __objc_msgSend_946 = __objc_msgSend_946Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -26642,65 +26976,65 @@ class SentryCocoa { _registerName1("setShouldReportNamespacePrefixes:"); late final _sel_externalEntityResolvingPolicy1 = _registerName1("externalEntityResolvingPolicy"); - int _objc_msgSend_933( + int _objc_msgSend_947( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_933( + return __objc_msgSend_947( obj, sel, ); } - late final __objc_msgSend_933Ptr = _lookup< + late final __objc_msgSend_947Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_933 = __objc_msgSend_933Ptr.asFunction< + late final __objc_msgSend_947 = __objc_msgSend_947Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setExternalEntityResolvingPolicy_1 = _registerName1("setExternalEntityResolvingPolicy:"); - void _objc_msgSend_934( + void _objc_msgSend_948( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_934( + return __objc_msgSend_948( obj, sel, value, ); } - late final __objc_msgSend_934Ptr = _lookup< + late final __objc_msgSend_948Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_934 = __objc_msgSend_934Ptr.asFunction< + late final __objc_msgSend_948 = __objc_msgSend_948Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_allowedExternalEntityURLs1 = _registerName1("allowedExternalEntityURLs"); late final _sel_setAllowedExternalEntityURLs_1 = _registerName1("setAllowedExternalEntityURLs:"); - void _objc_msgSend_935( + void _objc_msgSend_949( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_935( + return __objc_msgSend_949( obj, sel, value, ); } - late final __objc_msgSend_935Ptr = _lookup< + late final __objc_msgSend_949Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_935 = __objc_msgSend_935Ptr.asFunction< + late final __objc_msgSend_949 = __objc_msgSend_949Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -26718,14 +27052,14 @@ class SentryCocoa { late final _class_NSFileWrapper1 = _getClass1("NSFileWrapper"); late final _sel_initWithURL_options_error_1 = _registerName1("initWithURL:options:error:"); - instancetype _objc_msgSend_936( + instancetype _objc_msgSend_950( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, int options, ffi.Pointer> outError, ) { - return __objc_msgSend_936( + return __objc_msgSend_950( obj, sel, url, @@ -26734,7 +27068,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_936Ptr = _lookup< + late final __objc_msgSend_950Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -26742,7 +27076,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_936 = __objc_msgSend_936Ptr.asFunction< + late final __objc_msgSend_950 = __objc_msgSend_950Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -26772,14 +27106,14 @@ class SentryCocoa { _registerName1("matchesContentsOfURL:"); late final _sel_readFromURL_options_error_1 = _registerName1("readFromURL:options:error:"); - bool _objc_msgSend_937( + bool _objc_msgSend_951( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, int options, ffi.Pointer> outError, ) { - return __objc_msgSend_937( + return __objc_msgSend_951( obj, sel, url, @@ -26788,7 +27122,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_937Ptr = _lookup< + late final __objc_msgSend_951Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -26796,7 +27130,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_937 = __objc_msgSend_937Ptr.asFunction< + late final __objc_msgSend_951 = __objc_msgSend_951Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -26806,7 +27140,7 @@ class SentryCocoa { late final _sel_writeToURL_options_originalContentsURL_error_1 = _registerName1("writeToURL:options:originalContentsURL:error:"); - bool _objc_msgSend_938( + bool _objc_msgSend_952( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, @@ -26814,7 +27148,7 @@ class SentryCocoa { ffi.Pointer originalContentsURL, ffi.Pointer> outError, ) { - return __objc_msgSend_938( + return __objc_msgSend_952( obj, sel, url, @@ -26824,7 +27158,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_938Ptr = _lookup< + late final __objc_msgSend_952Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, @@ -26833,7 +27167,7 @@ class SentryCocoa { ffi.Int32, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_938 = __objc_msgSend_938Ptr.asFunction< + late final __objc_msgSend_952 = __objc_msgSend_952Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -26845,35 +27179,35 @@ class SentryCocoa { late final _sel_serializedRepresentation1 = _registerName1("serializedRepresentation"); late final _sel_addFileWrapper_1 = _registerName1("addFileWrapper:"); - ffi.Pointer _objc_msgSend_939( + ffi.Pointer _objc_msgSend_953( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer child, ) { - return __objc_msgSend_939( + return __objc_msgSend_953( obj, sel, child, ); } - late final __objc_msgSend_939Ptr = _lookup< + late final __objc_msgSend_953Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_939 = __objc_msgSend_939Ptr.asFunction< + late final __objc_msgSend_953 = __objc_msgSend_953Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_addRegularFileWithContents_preferredFilename_1 = _registerName1("addRegularFileWithContents:preferredFilename:"); - ffi.Pointer _objc_msgSend_940( + ffi.Pointer _objc_msgSend_954( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer data, ffi.Pointer fileName, ) { - return __objc_msgSend_940( + return __objc_msgSend_954( obj, sel, data, @@ -26881,14 +27215,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_940Ptr = _lookup< + late final __objc_msgSend_954Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_940 = __objc_msgSend_940Ptr.asFunction< + late final __objc_msgSend_954 = __objc_msgSend_954Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -26896,23 +27230,23 @@ class SentryCocoa { ffi.Pointer)>(); late final _sel_removeFileWrapper_1 = _registerName1("removeFileWrapper:"); - void _objc_msgSend_941( + void _objc_msgSend_955( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer child, ) { - return __objc_msgSend_941( + return __objc_msgSend_955( obj, sel, child, ); } - late final __objc_msgSend_941Ptr = _lookup< + late final __objc_msgSend_955Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_941 = __objc_msgSend_941Ptr.asFunction< + late final __objc_msgSend_955 = __objc_msgSend_955Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -26928,14 +27262,14 @@ class SentryCocoa { late final _sel_updateFromPath_1 = _registerName1("updateFromPath:"); late final _sel_writeToFile_atomically_updateFilenames_1 = _registerName1("writeToFile:atomically:updateFilenames:"); - bool _objc_msgSend_942( + bool _objc_msgSend_956( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer path, bool atomicFlag, bool updateFilenamesFlag, ) { - return __objc_msgSend_942( + return __objc_msgSend_956( obj, sel, path, @@ -26944,11 +27278,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_942Ptr = _lookup< + late final __objc_msgSend_956Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Bool, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_942 = __objc_msgSend_942Ptr.asFunction< + late final __objc_msgSend_956 = __objc_msgSend_956Ptr.asFunction< bool Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, bool, bool)>(); @@ -26959,21 +27293,21 @@ class SentryCocoa { _registerName1("symbolicLinkDestination"); late final _class_NSURLSession1 = _getClass1("NSURLSession"); late final _sel_sharedSession1 = _registerName1("sharedSession"); - ffi.Pointer _objc_msgSend_943( + ffi.Pointer _objc_msgSend_957( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_943( + return __objc_msgSend_957( obj, sel, ); } - late final __objc_msgSend_943Ptr = _lookup< + late final __objc_msgSend_957Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_943 = __objc_msgSend_943Ptr.asFunction< + late final __objc_msgSend_957 = __objc_msgSend_957Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -26981,21 +27315,21 @@ class SentryCocoa { _getClass1("NSURLSessionConfiguration"); late final _sel_defaultSessionConfiguration1 = _registerName1("defaultSessionConfiguration"); - ffi.Pointer _objc_msgSend_944( + ffi.Pointer _objc_msgSend_958( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_944( + return __objc_msgSend_958( obj, sel, ); } - late final __objc_msgSend_944Ptr = _lookup< + late final __objc_msgSend_958Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_944 = __objc_msgSend_944Ptr.asFunction< + late final __objc_msgSend_958 = __objc_msgSend_958Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -27003,23 +27337,23 @@ class SentryCocoa { _registerName1("ephemeralSessionConfiguration"); late final _sel_backgroundSessionConfigurationWithIdentifier_1 = _registerName1("backgroundSessionConfigurationWithIdentifier:"); - ffi.Pointer _objc_msgSend_945( + ffi.Pointer _objc_msgSend_959( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer identifier, ) { - return __objc_msgSend_945( + return __objc_msgSend_959( obj, sel, identifier, ); } - late final __objc_msgSend_945Ptr = _lookup< + late final __objc_msgSend_959Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_945 = __objc_msgSend_945Ptr.asFunction< + late final __objc_msgSend_959 = __objc_msgSend_959Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -27055,42 +27389,42 @@ class SentryCocoa { _registerName1("setConnectionProxyDictionary:"); late final _sel_TLSMinimumSupportedProtocol1 = _registerName1("TLSMinimumSupportedProtocol"); - int _objc_msgSend_946( + int _objc_msgSend_960( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_946( + return __objc_msgSend_960( obj, sel, ); } - late final __objc_msgSend_946Ptr = _lookup< + late final __objc_msgSend_960Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_946 = __objc_msgSend_946Ptr.asFunction< + late final __objc_msgSend_960 = __objc_msgSend_960Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setTLSMinimumSupportedProtocol_1 = _registerName1("setTLSMinimumSupportedProtocol:"); - void _objc_msgSend_947( + void _objc_msgSend_961( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_947( + return __objc_msgSend_961( obj, sel, value, ); } - late final __objc_msgSend_947Ptr = _lookup< + late final __objc_msgSend_961Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_947 = __objc_msgSend_947Ptr.asFunction< + late final __objc_msgSend_961 = __objc_msgSend_961Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_TLSMaximumSupportedProtocol1 = @@ -27099,42 +27433,42 @@ class SentryCocoa { _registerName1("setTLSMaximumSupportedProtocol:"); late final _sel_TLSMinimumSupportedProtocolVersion1 = _registerName1("TLSMinimumSupportedProtocolVersion"); - int _objc_msgSend_948( + int _objc_msgSend_962( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_948( + return __objc_msgSend_962( obj, sel, ); } - late final __objc_msgSend_948Ptr = _lookup< + late final __objc_msgSend_962Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_948 = __objc_msgSend_948Ptr.asFunction< + late final __objc_msgSend_962 = __objc_msgSend_962Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setTLSMinimumSupportedProtocolVersion_1 = _registerName1("setTLSMinimumSupportedProtocolVersion:"); - void _objc_msgSend_949( + void _objc_msgSend_963( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_949( + return __objc_msgSend_963( obj, sel, value, ); } - late final __objc_msgSend_949Ptr = _lookup< + late final __objc_msgSend_963Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_949 = __objc_msgSend_949Ptr.asFunction< + late final __objc_msgSend_963 = __objc_msgSend_963Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_TLSMaximumSupportedProtocolVersion1 = @@ -27160,23 +27494,23 @@ class SentryCocoa { late final _sel_HTTPCookieStorage1 = _registerName1("HTTPCookieStorage"); late final _sel_setHTTPCookieStorage_1 = _registerName1("setHTTPCookieStorage:"); - void _objc_msgSend_950( + void _objc_msgSend_964( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_950( + return __objc_msgSend_964( obj, sel, value, ); } - late final __objc_msgSend_950Ptr = _lookup< + late final __objc_msgSend_964Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_950 = __objc_msgSend_950Ptr.asFunction< + late final __objc_msgSend_964 = __objc_msgSend_964Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -27184,23 +27518,23 @@ class SentryCocoa { _registerName1("URLCredentialStorage"); late final _sel_setURLCredentialStorage_1 = _registerName1("setURLCredentialStorage:"); - void _objc_msgSend_951( + void _objc_msgSend_965( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_951( + return __objc_msgSend_965( obj, sel, value, ); } - late final __objc_msgSend_951Ptr = _lookup< + late final __objc_msgSend_965Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_951 = __objc_msgSend_951Ptr.asFunction< + late final __objc_msgSend_965 = __objc_msgSend_965Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -27214,78 +27548,78 @@ class SentryCocoa { late final _sel_setProtocolClasses_1 = _registerName1("setProtocolClasses:"); late final _sel_multipathServiceType1 = _registerName1("multipathServiceType"); - int _objc_msgSend_952( + int _objc_msgSend_966( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_952( + return __objc_msgSend_966( obj, sel, ); } - late final __objc_msgSend_952Ptr = _lookup< + late final __objc_msgSend_966Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_952 = __objc_msgSend_952Ptr.asFunction< + late final __objc_msgSend_966 = __objc_msgSend_966Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setMultipathServiceType_1 = _registerName1("setMultipathServiceType:"); - void _objc_msgSend_953( + void _objc_msgSend_967( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_953( + return __objc_msgSend_967( obj, sel, value, ); } - late final __objc_msgSend_953Ptr = _lookup< + late final __objc_msgSend_967Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_953 = __objc_msgSend_953Ptr.asFunction< + late final __objc_msgSend_967 = __objc_msgSend_967Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_backgroundSessionConfiguration_1 = _registerName1("backgroundSessionConfiguration:"); late final _sel_sessionWithConfiguration_1 = _registerName1("sessionWithConfiguration:"); - ffi.Pointer _objc_msgSend_954( + ffi.Pointer _objc_msgSend_968( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer configuration, ) { - return __objc_msgSend_954( + return __objc_msgSend_968( obj, sel, configuration, ); } - late final __objc_msgSend_954Ptr = _lookup< + late final __objc_msgSend_968Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_954 = __objc_msgSend_954Ptr.asFunction< + late final __objc_msgSend_968 = __objc_msgSend_968Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_sessionWithConfiguration_delegate_delegateQueue_1 = _registerName1("sessionWithConfiguration:delegate:delegateQueue:"); - ffi.Pointer _objc_msgSend_955( + ffi.Pointer _objc_msgSend_969( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer configuration, ffi.Pointer delegate, ffi.Pointer queue, ) { - return __objc_msgSend_955( + return __objc_msgSend_969( obj, sel, configuration, @@ -27294,7 +27628,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_955Ptr = _lookup< + late final __objc_msgSend_969Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -27302,7 +27636,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_955 = __objc_msgSend_955Ptr.asFunction< + late final __objc_msgSend_969 = __objc_msgSend_969Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -27324,102 +27658,124 @@ class SentryCocoa { _registerName1("flushWithCompletionHandler:"); late final _sel_getTasksWithCompletionHandler_1 = _registerName1("getTasksWithCompletionHandler:"); - void _objc_msgSend_956( + void _objc_msgSend_970( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_956( + return __objc_msgSend_970( obj, sel, completionHandler, ); } - late final __objc_msgSend_956Ptr = _lookup< + late final __objc_msgSend_970Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_956 = __objc_msgSend_956Ptr.asFunction< + late final __objc_msgSend_970 = __objc_msgSend_970Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_getAllTasksWithCompletionHandler_1 = _registerName1("getAllTasksWithCompletionHandler:"); - void _objc_msgSend_957( + void _objc_msgSend_971( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_957( + return __objc_msgSend_971( obj, sel, completionHandler, ); } - late final __objc_msgSend_957Ptr = _lookup< + late final __objc_msgSend_971Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_957 = __objc_msgSend_957Ptr.asFunction< + late final __objc_msgSend_971 = __objc_msgSend_971Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_dataTaskWithRequest_1 = _registerName1("dataTaskWithRequest:"); - ffi.Pointer _objc_msgSend_958( + ffi.Pointer _objc_msgSend_972( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ) { - return __objc_msgSend_958( + return __objc_msgSend_972( obj, sel, request, ); } - late final __objc_msgSend_958Ptr = _lookup< + late final __objc_msgSend_972Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_958 = __objc_msgSend_958Ptr.asFunction< + late final __objc_msgSend_972 = __objc_msgSend_972Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_dataTaskWithURL_1 = _registerName1("dataTaskWithURL:"); - ffi.Pointer _objc_msgSend_959( + ffi.Pointer _objc_msgSend_973( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, ) { - return __objc_msgSend_959( + return __objc_msgSend_973( obj, sel, url, ); } - late final __objc_msgSend_959Ptr = _lookup< + late final __objc_msgSend_973Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_959 = __objc_msgSend_959Ptr.asFunction< + late final __objc_msgSend_973 = __objc_msgSend_973Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _class_NSURLSessionUploadTask1 = _getClass1("NSURLSessionUploadTask"); + late final _sel_cancelByProducingResumeData_1 = + _registerName1("cancelByProducingResumeData:"); + void _objc_msgSend_974( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer<_ObjCBlock> completionHandler, + ) { + return __objc_msgSend_974( + obj, + sel, + completionHandler, + ); + } + + late final __objc_msgSend_974Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); + late final __objc_msgSend_974 = __objc_msgSend_974Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer<_ObjCBlock>)>(); + late final _sel_uploadTaskWithRequest_fromFile_1 = _registerName1("uploadTaskWithRequest:fromFile:"); - ffi.Pointer _objc_msgSend_960( + ffi.Pointer _objc_msgSend_975( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer fileURL, ) { - return __objc_msgSend_960( + return __objc_msgSend_975( obj, sel, request, @@ -27427,14 +27783,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_960Ptr = _lookup< + late final __objc_msgSend_975Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_960 = __objc_msgSend_960Ptr.asFunction< + late final __objc_msgSend_975 = __objc_msgSend_975Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -27443,13 +27799,13 @@ class SentryCocoa { late final _sel_uploadTaskWithRequest_fromData_1 = _registerName1("uploadTaskWithRequest:fromData:"); - ffi.Pointer _objc_msgSend_961( + ffi.Pointer _objc_msgSend_976( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer bodyData, ) { - return __objc_msgSend_961( + return __objc_msgSend_976( obj, sel, request, @@ -27457,129 +27813,129 @@ class SentryCocoa { ); } - late final __objc_msgSend_961Ptr = _lookup< + late final __objc_msgSend_976Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_961 = __objc_msgSend_961Ptr.asFunction< + late final __objc_msgSend_976 = __objc_msgSend_976Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); - late final _sel_uploadTaskWithStreamedRequest_1 = - _registerName1("uploadTaskWithStreamedRequest:"); - ffi.Pointer _objc_msgSend_962( + late final _sel_uploadTaskWithResumeData_1 = + _registerName1("uploadTaskWithResumeData:"); + ffi.Pointer _objc_msgSend_977( ffi.Pointer obj, ffi.Pointer sel, - ffi.Pointer request, + ffi.Pointer resumeData, ) { - return __objc_msgSend_962( + return __objc_msgSend_977( obj, sel, - request, + resumeData, ); } - late final __objc_msgSend_962Ptr = _lookup< + late final __objc_msgSend_977Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_962 = __objc_msgSend_962Ptr.asFunction< + late final __objc_msgSend_977 = __objc_msgSend_977Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); - late final _class_NSURLSessionDownloadTask1 = - _getClass1("NSURLSessionDownloadTask"); - late final _sel_cancelByProducingResumeData_1 = - _registerName1("cancelByProducingResumeData:"); - void _objc_msgSend_963( + late final _sel_uploadTaskWithStreamedRequest_1 = + _registerName1("uploadTaskWithStreamedRequest:"); + ffi.Pointer _objc_msgSend_978( ffi.Pointer obj, ffi.Pointer sel, - ffi.Pointer<_ObjCBlock> completionHandler, + ffi.Pointer request, ) { - return __objc_msgSend_963( + return __objc_msgSend_978( obj, sel, - completionHandler, + request, ); } - late final __objc_msgSend_963Ptr = _lookup< + late final __objc_msgSend_978Ptr = _lookup< ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_963 = __objc_msgSend_963Ptr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer<_ObjCBlock>)>(); + ffi.Pointer Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_978 = __objc_msgSend_978Ptr.asFunction< + ffi.Pointer Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>(); + late final _class_NSURLSessionDownloadTask1 = + _getClass1("NSURLSessionDownloadTask"); late final _sel_downloadTaskWithRequest_1 = _registerName1("downloadTaskWithRequest:"); - ffi.Pointer _objc_msgSend_964( + ffi.Pointer _objc_msgSend_979( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ) { - return __objc_msgSend_964( + return __objc_msgSend_979( obj, sel, request, ); } - late final __objc_msgSend_964Ptr = _lookup< + late final __objc_msgSend_979Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_964 = __objc_msgSend_964Ptr.asFunction< + late final __objc_msgSend_979 = __objc_msgSend_979Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_downloadTaskWithURL_1 = _registerName1("downloadTaskWithURL:"); - ffi.Pointer _objc_msgSend_965( + ffi.Pointer _objc_msgSend_980( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, ) { - return __objc_msgSend_965( + return __objc_msgSend_980( obj, sel, url, ); } - late final __objc_msgSend_965Ptr = _lookup< + late final __objc_msgSend_980Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_965 = __objc_msgSend_965Ptr.asFunction< + late final __objc_msgSend_980 = __objc_msgSend_980Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_downloadTaskWithResumeData_1 = _registerName1("downloadTaskWithResumeData:"); - ffi.Pointer _objc_msgSend_966( + ffi.Pointer _objc_msgSend_981( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer resumeData, ) { - return __objc_msgSend_966( + return __objc_msgSend_981( obj, sel, resumeData, ); } - late final __objc_msgSend_966Ptr = _lookup< + late final __objc_msgSend_981Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_966 = __objc_msgSend_966Ptr.asFunction< + late final __objc_msgSend_981 = __objc_msgSend_981Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -27588,7 +27944,7 @@ class SentryCocoa { late final _sel_readDataOfMinLength_maxLength_timeout_completionHandler_1 = _registerName1( "readDataOfMinLength:maxLength:timeout:completionHandler:"); - void _objc_msgSend_967( + void _objc_msgSend_982( ffi.Pointer obj, ffi.Pointer sel, int minBytes, @@ -27596,7 +27952,7 @@ class SentryCocoa { double timeout, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_967( + return __objc_msgSend_982( obj, sel, minBytes, @@ -27606,7 +27962,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_967Ptr = _lookup< + late final __objc_msgSend_982Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -27615,20 +27971,20 @@ class SentryCocoa { ffi.UnsignedLong, ffi.Double, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_967 = __objc_msgSend_967Ptr.asFunction< + late final __objc_msgSend_982 = __objc_msgSend_982Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int, int, double, ffi.Pointer<_ObjCBlock>)>(); late final _sel_writeData_timeout_completionHandler_1 = _registerName1("writeData:timeout:completionHandler:"); - void _objc_msgSend_968( + void _objc_msgSend_983( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer data, double timeout, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_968( + return __objc_msgSend_983( obj, sel, data, @@ -27637,7 +27993,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_968Ptr = _lookup< + late final __objc_msgSend_983Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, @@ -27645,7 +28001,7 @@ class SentryCocoa { ffi.Pointer, ffi.Double, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_968 = __objc_msgSend_968Ptr.asFunction< + late final __objc_msgSend_983 = __objc_msgSend_983Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, double, ffi.Pointer<_ObjCBlock>)>(); @@ -27658,13 +28014,13 @@ class SentryCocoa { _registerName1("stopSecureConnection"); late final _sel_streamTaskWithHostName_port_1 = _registerName1("streamTaskWithHostName:port:"); - ffi.Pointer _objc_msgSend_969( + ffi.Pointer _objc_msgSend_984( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer hostname, int port, ) { - return __objc_msgSend_969( + return __objc_msgSend_984( obj, sel, hostname, @@ -27672,21 +28028,21 @@ class SentryCocoa { ); } - late final __objc_msgSend_969Ptr = _lookup< + late final __objc_msgSend_984Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Long)>>('objc_msgSend'); - late final __objc_msgSend_969 = __objc_msgSend_969Ptr.asFunction< + late final __objc_msgSend_984 = __objc_msgSend_984Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); late final _class_NSNetService1 = _getClass1("NSNetService"); late final _sel_initWithDomain_type_name_port_1 = _registerName1("initWithDomain:type:name:port:"); - instancetype _objc_msgSend_970( + instancetype _objc_msgSend_985( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer domain, @@ -27694,7 +28050,7 @@ class SentryCocoa { ffi.Pointer name, int port, ) { - return __objc_msgSend_970( + return __objc_msgSend_985( obj, sel, domain, @@ -27704,7 +28060,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_970Ptr = _lookup< + late final __objc_msgSend_985Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -27713,7 +28069,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Int)>>('objc_msgSend'); - late final __objc_msgSend_970 = __objc_msgSend_970Ptr.asFunction< + late final __objc_msgSend_985 = __objc_msgSend_985Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -27729,81 +28085,81 @@ class SentryCocoa { _registerName1("setIncludesPeerToPeer:"); late final _sel_type1 = _registerName1("type"); late final _sel_publishWithOptions_1 = _registerName1("publishWithOptions:"); - void _objc_msgSend_971( + void _objc_msgSend_986( ffi.Pointer obj, ffi.Pointer sel, int options, ) { - return __objc_msgSend_971( + return __objc_msgSend_986( obj, sel, options, ); } - late final __objc_msgSend_971Ptr = _lookup< + late final __objc_msgSend_986Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_971 = __objc_msgSend_971Ptr.asFunction< + late final __objc_msgSend_986 = __objc_msgSend_986Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_resolve1 = _registerName1("resolve"); late final _sel_stop1 = _registerName1("stop"); late final _sel_dictionaryFromTXTRecordData_1 = _registerName1("dictionaryFromTXTRecordData:"); - ffi.Pointer _objc_msgSend_972( + ffi.Pointer _objc_msgSend_987( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer txtData, ) { - return __objc_msgSend_972( + return __objc_msgSend_987( obj, sel, txtData, ); } - late final __objc_msgSend_972Ptr = _lookup< + late final __objc_msgSend_987Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_972 = __objc_msgSend_972Ptr.asFunction< + late final __objc_msgSend_987 = __objc_msgSend_987Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_dataFromTXTRecordDictionary_1 = _registerName1("dataFromTXTRecordDictionary:"); - ffi.Pointer _objc_msgSend_973( + ffi.Pointer _objc_msgSend_988( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer txtDictionary, ) { - return __objc_msgSend_973( + return __objc_msgSend_988( obj, sel, txtDictionary, ); } - late final __objc_msgSend_973Ptr = _lookup< + late final __objc_msgSend_988Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_973 = __objc_msgSend_973Ptr.asFunction< + late final __objc_msgSend_988 = __objc_msgSend_988Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_resolveWithTimeout_1 = _registerName1("resolveWithTimeout:"); late final _sel_getInputStream_outputStream_1 = _registerName1("getInputStream:outputStream:"); - bool _objc_msgSend_974( + bool _objc_msgSend_989( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer> inputStream, ffi.Pointer> outputStream, ) { - return __objc_msgSend_974( + return __objc_msgSend_989( obj, sel, inputStream, @@ -27811,14 +28167,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_974Ptr = _lookup< + late final __objc_msgSend_989Ptr = _lookup< ffi.NativeFunction< ffi.Bool Function( ffi.Pointer, ffi.Pointer, ffi.Pointer>, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_974 = __objc_msgSend_974Ptr.asFunction< + late final __objc_msgSend_989 = __objc_msgSend_989Ptr.asFunction< bool Function( ffi.Pointer, ffi.Pointer, @@ -27831,23 +28187,23 @@ class SentryCocoa { late final _sel_stopMonitoring1 = _registerName1("stopMonitoring"); late final _sel_streamTaskWithNetService_1 = _registerName1("streamTaskWithNetService:"); - ffi.Pointer _objc_msgSend_975( + ffi.Pointer _objc_msgSend_990( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer service, ) { - return __objc_msgSend_975( + return __objc_msgSend_990( obj, sel, service, ); } - late final __objc_msgSend_975Ptr = _lookup< + late final __objc_msgSend_990Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_975 = __objc_msgSend_975Ptr.asFunction< + late final __objc_msgSend_990 = __objc_msgSend_990Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -27855,32 +28211,32 @@ class SentryCocoa { _getClass1("NSURLSessionWebSocketTask"); late final _class_NSURLSessionWebSocketMessage1 = _getClass1("NSURLSessionWebSocketMessage"); - int _objc_msgSend_976( + int _objc_msgSend_991( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_976( + return __objc_msgSend_991( obj, sel, ); } - late final __objc_msgSend_976Ptr = _lookup< + late final __objc_msgSend_991Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_976 = __objc_msgSend_976Ptr.asFunction< + late final __objc_msgSend_991 = __objc_msgSend_991Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_sendMessage_completionHandler_1 = _registerName1("sendMessage:completionHandler:"); - void _objc_msgSend_977( + void _objc_msgSend_992( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer message, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_977( + return __objc_msgSend_992( obj, sel, message, @@ -27888,70 +28244,70 @@ class SentryCocoa { ); } - late final __objc_msgSend_977Ptr = _lookup< + late final __objc_msgSend_992Ptr = _lookup< ffi.NativeFunction< ffi.Void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_977 = __objc_msgSend_977Ptr.asFunction< + late final __objc_msgSend_992 = __objc_msgSend_992Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_receiveMessageWithCompletionHandler_1 = _registerName1("receiveMessageWithCompletionHandler:"); - void _objc_msgSend_978( + void _objc_msgSend_993( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_978( + return __objc_msgSend_993( obj, sel, completionHandler, ); } - late final __objc_msgSend_978Ptr = _lookup< + late final __objc_msgSend_993Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_978 = __objc_msgSend_978Ptr.asFunction< + late final __objc_msgSend_993 = __objc_msgSend_993Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_sendPingWithPongReceiveHandler_1 = _registerName1("sendPingWithPongReceiveHandler:"); - void _objc_msgSend_979( + void _objc_msgSend_994( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_ObjCBlock> pongReceiveHandler, ) { - return __objc_msgSend_979( + return __objc_msgSend_994( obj, sel, pongReceiveHandler, ); } - late final __objc_msgSend_979Ptr = _lookup< + late final __objc_msgSend_994Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_979 = __objc_msgSend_979Ptr.asFunction< + late final __objc_msgSend_994 = __objc_msgSend_994Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_cancelWithCloseCode_reason_1 = _registerName1("cancelWithCloseCode:reason:"); - void _objc_msgSend_980( + void _objc_msgSend_995( ffi.Pointer obj, ffi.Pointer sel, int closeCode, ffi.Pointer reason, ) { - return __objc_msgSend_980( + return __objc_msgSend_995( obj, sel, closeCode, @@ -27959,11 +28315,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_980Ptr = _lookup< + late final __objc_msgSend_995Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_980 = __objc_msgSend_980Ptr.asFunction< + late final __objc_msgSend_995 = __objc_msgSend_995Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer)>(); @@ -27971,55 +28327,55 @@ class SentryCocoa { late final _sel_setMaximumMessageSize_1 = _registerName1("setMaximumMessageSize:"); late final _sel_closeCode1 = _registerName1("closeCode"); - int _objc_msgSend_981( + int _objc_msgSend_996( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_981( + return __objc_msgSend_996( obj, sel, ); } - late final __objc_msgSend_981Ptr = _lookup< + late final __objc_msgSend_996Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_981 = __objc_msgSend_981Ptr.asFunction< + late final __objc_msgSend_996 = __objc_msgSend_996Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_closeReason1 = _registerName1("closeReason"); late final _sel_webSocketTaskWithURL_1 = _registerName1("webSocketTaskWithURL:"); - ffi.Pointer _objc_msgSend_982( + ffi.Pointer _objc_msgSend_997( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, ) { - return __objc_msgSend_982( + return __objc_msgSend_997( obj, sel, url, ); } - late final __objc_msgSend_982Ptr = _lookup< + late final __objc_msgSend_997Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_982 = __objc_msgSend_982Ptr.asFunction< + late final __objc_msgSend_997 = __objc_msgSend_997Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_webSocketTaskWithURL_protocols_1 = _registerName1("webSocketTaskWithURL:protocols:"); - ffi.Pointer _objc_msgSend_983( + ffi.Pointer _objc_msgSend_998( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, ffi.Pointer protocols, ) { - return __objc_msgSend_983( + return __objc_msgSend_998( obj, sel, url, @@ -28027,14 +28383,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_983Ptr = _lookup< + late final __objc_msgSend_998Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_983 = __objc_msgSend_983Ptr.asFunction< + late final __objc_msgSend_998 = __objc_msgSend_998Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28043,35 +28399,35 @@ class SentryCocoa { late final _sel_webSocketTaskWithRequest_1 = _registerName1("webSocketTaskWithRequest:"); - ffi.Pointer _objc_msgSend_984( + ffi.Pointer _objc_msgSend_999( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ) { - return __objc_msgSend_984( + return __objc_msgSend_999( obj, sel, request, ); } - late final __objc_msgSend_984Ptr = _lookup< + late final __objc_msgSend_999Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_984 = __objc_msgSend_984Ptr.asFunction< + late final __objc_msgSend_999 = __objc_msgSend_999Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_dataTaskWithRequest_completionHandler_1 = _registerName1("dataTaskWithRequest:completionHandler:"); - ffi.Pointer _objc_msgSend_985( + ffi.Pointer _objc_msgSend_1000( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_985( + return __objc_msgSend_1000( obj, sel, request, @@ -28079,14 +28435,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_985Ptr = _lookup< + late final __objc_msgSend_1000Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_985 = __objc_msgSend_985Ptr.asFunction< + late final __objc_msgSend_1000 = __objc_msgSend_1000Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28095,13 +28451,13 @@ class SentryCocoa { late final _sel_dataTaskWithURL_completionHandler_1 = _registerName1("dataTaskWithURL:completionHandler:"); - ffi.Pointer _objc_msgSend_986( + ffi.Pointer _objc_msgSend_1001( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_986( + return __objc_msgSend_1001( obj, sel, url, @@ -28109,14 +28465,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_986Ptr = _lookup< + late final __objc_msgSend_1001Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_986 = __objc_msgSend_986Ptr.asFunction< + late final __objc_msgSend_1001 = __objc_msgSend_1001Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28125,14 +28481,14 @@ class SentryCocoa { late final _sel_uploadTaskWithRequest_fromFile_completionHandler_1 = _registerName1("uploadTaskWithRequest:fromFile:completionHandler:"); - ffi.Pointer _objc_msgSend_987( + ffi.Pointer _objc_msgSend_1002( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer fileURL, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_987( + return __objc_msgSend_1002( obj, sel, request, @@ -28141,7 +28497,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_987Ptr = _lookup< + late final __objc_msgSend_1002Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -28149,7 +28505,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_987 = __objc_msgSend_987Ptr.asFunction< + late final __objc_msgSend_1002 = __objc_msgSend_1002Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28159,14 +28515,14 @@ class SentryCocoa { late final _sel_uploadTaskWithRequest_fromData_completionHandler_1 = _registerName1("uploadTaskWithRequest:fromData:completionHandler:"); - ffi.Pointer _objc_msgSend_988( + ffi.Pointer _objc_msgSend_1003( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer bodyData, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_988( + return __objc_msgSend_1003( obj, sel, request, @@ -28175,7 +28531,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_988Ptr = _lookup< + late final __objc_msgSend_1003Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -28183,7 +28539,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_988 = __objc_msgSend_988Ptr.asFunction< + late final __objc_msgSend_1003 = __objc_msgSend_1003Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28191,15 +28547,45 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); + late final _sel_uploadTaskWithResumeData_completionHandler_1 = + _registerName1("uploadTaskWithResumeData:completionHandler:"); + ffi.Pointer _objc_msgSend_1004( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer resumeData, + ffi.Pointer<_ObjCBlock> completionHandler, + ) { + return __objc_msgSend_1004( + obj, + sel, + resumeData, + completionHandler, + ); + } + + late final __objc_msgSend_1004Ptr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); + late final __objc_msgSend_1004 = __objc_msgSend_1004Ptr.asFunction< + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer<_ObjCBlock>)>(); + late final _sel_downloadTaskWithRequest_completionHandler_1 = _registerName1("downloadTaskWithRequest:completionHandler:"); - ffi.Pointer _objc_msgSend_989( + ffi.Pointer _objc_msgSend_1005( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer request, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_989( + return __objc_msgSend_1005( obj, sel, request, @@ -28207,14 +28593,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_989Ptr = _lookup< + late final __objc_msgSend_1005Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_989 = __objc_msgSend_989Ptr.asFunction< + late final __objc_msgSend_1005 = __objc_msgSend_1005Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28223,13 +28609,13 @@ class SentryCocoa { late final _sel_downloadTaskWithURL_completionHandler_1 = _registerName1("downloadTaskWithURL:completionHandler:"); - ffi.Pointer _objc_msgSend_990( + ffi.Pointer _objc_msgSend_1006( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_990( + return __objc_msgSend_1006( obj, sel, url, @@ -28237,14 +28623,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_990Ptr = _lookup< + late final __objc_msgSend_1006Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_990 = __objc_msgSend_990Ptr.asFunction< + late final __objc_msgSend_1006 = __objc_msgSend_1006Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28253,13 +28639,13 @@ class SentryCocoa { late final _sel_downloadTaskWithResumeData_completionHandler_1 = _registerName1("downloadTaskWithResumeData:completionHandler:"); - ffi.Pointer _objc_msgSend_991( + ffi.Pointer _objc_msgSend_1007( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer resumeData, ffi.Pointer<_ObjCBlock> completionHandler, ) { - return __objc_msgSend_991( + return __objc_msgSend_1007( obj, sel, resumeData, @@ -28267,14 +28653,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_991Ptr = _lookup< + late final __objc_msgSend_1007Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_991 = __objc_msgSend_991Ptr.asFunction< + late final __objc_msgSend_1007 = __objc_msgSend_1007Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28282,33 +28668,33 @@ class SentryCocoa { ffi.Pointer<_ObjCBlock>)>(); late final _class_NSProtocolChecker1 = _getClass1("NSProtocolChecker"); - ffi.Pointer _objc_msgSend_992( + ffi.Pointer _objc_msgSend_1008( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_992( + return __objc_msgSend_1008( obj, sel, ); } - late final __objc_msgSend_992Ptr = _lookup< + late final __objc_msgSend_1008Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_992 = __objc_msgSend_992Ptr.asFunction< + late final __objc_msgSend_1008 = __objc_msgSend_1008Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_protocolCheckerWithTarget_protocol_1 = _registerName1("protocolCheckerWithTarget:protocol:"); - instancetype _objc_msgSend_993( + instancetype _objc_msgSend_1009( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer anObject, ffi.Pointer aProtocol, ) { - return __objc_msgSend_993( + return __objc_msgSend_1009( obj, sel, anObject, @@ -28316,14 +28702,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_993Ptr = _lookup< + late final __objc_msgSend_1009Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_993 = __objc_msgSend_993Ptr.asFunction< + late final __objc_msgSend_1009 = __objc_msgSend_1009Ptr.asFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -28348,68 +28734,68 @@ class SentryCocoa { late final _sel_isRunning1 = _registerName1("isRunning"); late final _sel_terminationStatus1 = _registerName1("terminationStatus"); late final _sel_terminationReason1 = _registerName1("terminationReason"); - int _objc_msgSend_994( + int _objc_msgSend_1010( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_994( + return __objc_msgSend_1010( obj, sel, ); } - late final __objc_msgSend_994Ptr = _lookup< + late final __objc_msgSend_1010Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_994 = __objc_msgSend_994Ptr.asFunction< + late final __objc_msgSend_1010 = __objc_msgSend_1010Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_terminationHandler1 = _registerName1("terminationHandler"); - ffi.Pointer<_ObjCBlock> _objc_msgSend_995( + ffi.Pointer<_ObjCBlock> _objc_msgSend_1011( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_995( + return __objc_msgSend_1011( obj, sel, ); } - late final __objc_msgSend_995Ptr = _lookup< + late final __objc_msgSend_1011Ptr = _lookup< ffi.NativeFunction< ffi.Pointer<_ObjCBlock> Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_995 = __objc_msgSend_995Ptr.asFunction< + late final __objc_msgSend_1011 = __objc_msgSend_1011Ptr.asFunction< ffi.Pointer<_ObjCBlock> Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_setTerminationHandler_1 = _registerName1("setTerminationHandler:"); - void _objc_msgSend_996( + void _objc_msgSend_1012( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_ObjCBlock> value, ) { - return __objc_msgSend_996( + return __objc_msgSend_1012( obj, sel, value, ); } - late final __objc_msgSend_996Ptr = _lookup< + late final __objc_msgSend_1012Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_996 = __objc_msgSend_996Ptr.asFunction< + late final __objc_msgSend_1012 = __objc_msgSend_1012Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_launchedTaskWithExecutableURL_arguments_error_terminationHandler_1 = _registerName1( "launchedTaskWithExecutableURL:arguments:error:terminationHandler:"); - ffi.Pointer _objc_msgSend_997( + ffi.Pointer _objc_msgSend_1013( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, @@ -28417,7 +28803,7 @@ class SentryCocoa { ffi.Pointer> error, ffi.Pointer<_ObjCBlock> terminationHandler, ) { - return __objc_msgSend_997( + return __objc_msgSend_1013( obj, sel, url, @@ -28427,7 +28813,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_997Ptr = _lookup< + late final __objc_msgSend_1013Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -28436,7 +28822,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer>, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_997 = __objc_msgSend_997Ptr.asFunction< + late final __objc_msgSend_1013 = __objc_msgSend_1013Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28453,13 +28839,13 @@ class SentryCocoa { late final _sel_launch1 = _registerName1("launch"); late final _sel_launchedTaskWithLaunchPath_arguments_1 = _registerName1("launchedTaskWithLaunchPath:arguments:"); - ffi.Pointer _objc_msgSend_998( + ffi.Pointer _objc_msgSend_1014( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer path, ffi.Pointer arguments, ) { - return __objc_msgSend_998( + return __objc_msgSend_1014( obj, sel, path, @@ -28467,14 +28853,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_998Ptr = _lookup< + late final __objc_msgSend_1014Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_998 = __objc_msgSend_998Ptr.asFunction< + late final __objc_msgSend_1014 = __objc_msgSend_1014Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28484,35 +28870,35 @@ class SentryCocoa { late final _class_NSXMLElement1 = _getClass1("NSXMLElement"); late final _class_NSXMLNode1 = _getClass1("NSXMLNode"); late final _sel_initWithKind_1 = _registerName1("initWithKind:"); - instancetype _objc_msgSend_999( + instancetype _objc_msgSend_1015( ffi.Pointer obj, ffi.Pointer sel, int kind, ) { - return __objc_msgSend_999( + return __objc_msgSend_1015( obj, sel, kind, ); } - late final __objc_msgSend_999Ptr = _lookup< + late final __objc_msgSend_1015Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_999 = __objc_msgSend_999Ptr.asFunction< + late final __objc_msgSend_1015 = __objc_msgSend_1015Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, int)>(); late final _sel_initWithKind_options_1 = _registerName1("initWithKind:options:"); - instancetype _objc_msgSend_1000( + instancetype _objc_msgSend_1016( ffi.Pointer obj, ffi.Pointer sel, int kind, int options, ) { - return __objc_msgSend_1000( + return __objc_msgSend_1016( obj, sel, kind, @@ -28520,34 +28906,34 @@ class SentryCocoa { ); } - late final __objc_msgSend_1000Ptr = _lookup< + late final __objc_msgSend_1016Ptr = _lookup< ffi.NativeFunction< instancetype Function(ffi.Pointer, ffi.Pointer, ffi.Int32, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_1000 = __objc_msgSend_1000Ptr.asFunction< + late final __objc_msgSend_1016 = __objc_msgSend_1016Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, int, int)>(); late final _sel_document1 = _registerName1("document"); late final _sel_documentWithRootElement_1 = _registerName1("documentWithRootElement:"); - ffi.Pointer _objc_msgSend_1001( + ffi.Pointer _objc_msgSend_1017( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer element, ) { - return __objc_msgSend_1001( + return __objc_msgSend_1017( obj, sel, element, ); } - late final __objc_msgSend_1001Ptr = _lookup< + late final __objc_msgSend_1017Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1001 = __objc_msgSend_1001Ptr.asFunction< + late final __objc_msgSend_1017 = __objc_msgSend_1017Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -28558,14 +28944,14 @@ class SentryCocoa { _registerName1("elementWithName:stringValue:"); late final _sel_elementWithName_children_attributes_1 = _registerName1("elementWithName:children:attributes:"); - ffi.Pointer _objc_msgSend_1002( + ffi.Pointer _objc_msgSend_1018( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, ffi.Pointer children, ffi.Pointer attributes, ) { - return __objc_msgSend_1002( + return __objc_msgSend_1018( obj, sel, name, @@ -28574,7 +28960,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1002Ptr = _lookup< + late final __objc_msgSend_1018Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -28582,7 +28968,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1002 = __objc_msgSend_1002Ptr.asFunction< + late final __objc_msgSend_1018 = __objc_msgSend_1018Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -28604,21 +28990,21 @@ class SentryCocoa { _registerName1("textWithStringValue:"); late final _sel_DTDNodeWithXMLString_1 = _registerName1("DTDNodeWithXMLString:"); - int _objc_msgSend_1003( + int _objc_msgSend_1019( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1003( + return __objc_msgSend_1019( obj, sel, ); } - late final __objc_msgSend_1003Ptr = _lookup< + late final __objc_msgSend_1019Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1003 = __objc_msgSend_1003Ptr.asFunction< + late final __objc_msgSend_1019 = __objc_msgSend_1019Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_objectValue1 = _registerName1("objectValue"); @@ -28626,13 +29012,13 @@ class SentryCocoa { late final _sel_setStringValue_1 = _registerName1("setStringValue:"); late final _sel_setStringValue_resolvingEntities_1 = _registerName1("setStringValue:resolvingEntities:"); - void _objc_msgSend_1004( + void _objc_msgSend_1020( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, bool resolve, ) { - return __objc_msgSend_1004( + return __objc_msgSend_1020( obj, sel, string, @@ -28640,11 +29026,11 @@ class SentryCocoa { ); } - late final __objc_msgSend_1004Ptr = _lookup< + late final __objc_msgSend_1020Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_1004 = __objc_msgSend_1004Ptr.asFunction< + late final __objc_msgSend_1020 = __objc_msgSend_1020Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, bool)>(); @@ -28653,14 +29039,14 @@ class SentryCocoa { late final _class_NSXMLDocument1 = _getClass1("NSXMLDocument"); late final _sel_initWithXMLString_options_error_1 = _registerName1("initWithXMLString:options:error:"); - instancetype _objc_msgSend_1005( + instancetype _objc_msgSend_1021( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer string, int mask, ffi.Pointer> error, ) { - return __objc_msgSend_1005( + return __objc_msgSend_1021( obj, sel, string, @@ -28669,7 +29055,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1005Ptr = _lookup< + late final __objc_msgSend_1021Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -28677,7 +29063,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_1005 = __objc_msgSend_1005Ptr.asFunction< + late final __objc_msgSend_1021 = __objc_msgSend_1021Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -28685,14 +29071,14 @@ class SentryCocoa { int, ffi.Pointer>)>(); - instancetype _objc_msgSend_1006( + instancetype _objc_msgSend_1022( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer url, int mask, ffi.Pointer> error, ) { - return __objc_msgSend_1006( + return __objc_msgSend_1022( obj, sel, url, @@ -28701,7 +29087,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1006Ptr = _lookup< + late final __objc_msgSend_1022Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -28709,7 +29095,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_1006 = __objc_msgSend_1006Ptr.asFunction< + late final __objc_msgSend_1022 = __objc_msgSend_1022Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -28719,14 +29105,14 @@ class SentryCocoa { late final _sel_initWithData_options_error_1 = _registerName1("initWithData:options:error:"); - instancetype _objc_msgSend_1007( + instancetype _objc_msgSend_1023( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer data, int mask, ffi.Pointer> error, ) { - return __objc_msgSend_1007( + return __objc_msgSend_1023( obj, sel, data, @@ -28735,7 +29121,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1007Ptr = _lookup< + late final __objc_msgSend_1023Ptr = _lookup< ffi.NativeFunction< instancetype Function( ffi.Pointer, @@ -28743,7 +29129,7 @@ class SentryCocoa { ffi.Pointer, ffi.Int32, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_1007 = __objc_msgSend_1007Ptr.asFunction< + late final __objc_msgSend_1023 = __objc_msgSend_1023Ptr.asFunction< instancetype Function( ffi.Pointer, ffi.Pointer, @@ -28761,42 +29147,42 @@ class SentryCocoa { late final _sel_isStandalone1 = _registerName1("isStandalone"); late final _sel_setStandalone_1 = _registerName1("setStandalone:"); late final _sel_documentContentKind1 = _registerName1("documentContentKind"); - int _objc_msgSend_1008( + int _objc_msgSend_1024( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1008( + return __objc_msgSend_1024( obj, sel, ); } - late final __objc_msgSend_1008Ptr = _lookup< + late final __objc_msgSend_1024Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1008 = __objc_msgSend_1008Ptr.asFunction< + late final __objc_msgSend_1024 = __objc_msgSend_1024Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setDocumentContentKind_1 = _registerName1("setDocumentContentKind:"); - void _objc_msgSend_1009( + void _objc_msgSend_1025( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_1009( + return __objc_msgSend_1025( obj, sel, value, ); } - late final __objc_msgSend_1009Ptr = _lookup< + late final __objc_msgSend_1025Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_1009 = __objc_msgSend_1009Ptr.asFunction< + late final __objc_msgSend_1025 = __objc_msgSend_1025Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_setMIMEType_1 = _registerName1("setMIMEType:"); @@ -28805,13 +29191,13 @@ class SentryCocoa { late final _sel_setSystemID_1 = _registerName1("setSystemID:"); late final _sel_insertChild_atIndex_1 = _registerName1("insertChild:atIndex:"); - void _objc_msgSend_1010( + void _objc_msgSend_1026( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer child, int index, ) { - return __objc_msgSend_1010( + return __objc_msgSend_1026( obj, sel, child, @@ -28819,23 +29205,23 @@ class SentryCocoa { ); } - late final __objc_msgSend_1010Ptr = _lookup< + late final __objc_msgSend_1026Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_1010 = __objc_msgSend_1010Ptr.asFunction< + late final __objc_msgSend_1026 = __objc_msgSend_1026Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); late final _sel_insertChildren_atIndex_1 = _registerName1("insertChildren:atIndex:"); - void _objc_msgSend_1011( + void _objc_msgSend_1027( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer children, int index, ) { - return __objc_msgSend_1011( + return __objc_msgSend_1027( obj, sel, children, @@ -28843,46 +29229,46 @@ class SentryCocoa { ); } - late final __objc_msgSend_1011Ptr = _lookup< + late final __objc_msgSend_1027Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_1011 = __objc_msgSend_1011Ptr.asFunction< + late final __objc_msgSend_1027 = __objc_msgSend_1027Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); late final _sel_removeChildAtIndex_1 = _registerName1("removeChildAtIndex:"); late final _sel_setChildren_1 = _registerName1("setChildren:"); late final _sel_addChild_1 = _registerName1("addChild:"); - void _objc_msgSend_1012( + void _objc_msgSend_1028( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer child, ) { - return __objc_msgSend_1012( + return __objc_msgSend_1028( obj, sel, child, ); } - late final __objc_msgSend_1012Ptr = _lookup< + late final __objc_msgSend_1028Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1012 = __objc_msgSend_1012Ptr.asFunction< + late final __objc_msgSend_1028 = __objc_msgSend_1028Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_replaceChildAtIndex_withNode_1 = _registerName1("replaceChildAtIndex:withNode:"); - void _objc_msgSend_1013( + void _objc_msgSend_1029( ffi.Pointer obj, ffi.Pointer sel, int index, ffi.Pointer node, ) { - return __objc_msgSend_1013( + return __objc_msgSend_1029( obj, sel, index, @@ -28890,52 +29276,52 @@ class SentryCocoa { ); } - late final __objc_msgSend_1013Ptr = _lookup< + late final __objc_msgSend_1029Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.UnsignedLong, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1013 = __objc_msgSend_1013Ptr.asFunction< + late final __objc_msgSend_1029 = __objc_msgSend_1029Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int, ffi.Pointer)>(); late final _class_NSXMLDTDNode1 = _getClass1("NSXMLDTDNode"); late final _sel_initWithXMLString_1 = _registerName1("initWithXMLString:"); late final _sel_DTDKind1 = _registerName1("DTDKind"); - int _objc_msgSend_1014( + int _objc_msgSend_1030( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1014( + return __objc_msgSend_1030( obj, sel, ); } - late final __objc_msgSend_1014Ptr = _lookup< + late final __objc_msgSend_1030Ptr = _lookup< ffi.NativeFunction< ffi.Int32 Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1014 = __objc_msgSend_1014Ptr.asFunction< + late final __objc_msgSend_1030 = __objc_msgSend_1030Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer)>(); late final _sel_setDTDKind_1 = _registerName1("setDTDKind:"); - void _objc_msgSend_1015( + void _objc_msgSend_1031( ffi.Pointer obj, ffi.Pointer sel, int value, ) { - return __objc_msgSend_1015( + return __objc_msgSend_1031( obj, sel, value, ); } - late final __objc_msgSend_1015Ptr = _lookup< + late final __objc_msgSend_1031Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_1015 = __objc_msgSend_1015Ptr.asFunction< + late final __objc_msgSend_1031 = __objc_msgSend_1031Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, int)>(); late final _sel_isExternal1 = _registerName1("isExternal"); @@ -28945,45 +29331,45 @@ class SentryCocoa { late final _sel_prefixForName_1 = _registerName1("prefixForName:"); late final _sel_predefinedNamespaceForPrefix_1 = _registerName1("predefinedNamespaceForPrefix:"); - ffi.Pointer _objc_msgSend_1016( + ffi.Pointer _objc_msgSend_1032( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, ) { - return __objc_msgSend_1016( + return __objc_msgSend_1032( obj, sel, name, ); } - late final __objc_msgSend_1016Ptr = _lookup< + late final __objc_msgSend_1032Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1016 = __objc_msgSend_1016Ptr.asFunction< + late final __objc_msgSend_1032 = __objc_msgSend_1032Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_entityDeclarationForName_1 = _registerName1("entityDeclarationForName:"); - ffi.Pointer _objc_msgSend_1017( + ffi.Pointer _objc_msgSend_1033( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, ) { - return __objc_msgSend_1017( + return __objc_msgSend_1033( obj, sel, name, ); } - late final __objc_msgSend_1017Ptr = _lookup< + late final __objc_msgSend_1033Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1017 = __objc_msgSend_1017Ptr.asFunction< + late final __objc_msgSend_1033 = __objc_msgSend_1033Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -28993,13 +29379,13 @@ class SentryCocoa { _registerName1("elementDeclarationForName:"); late final _sel_attributeDeclarationForName_elementName_1 = _registerName1("attributeDeclarationForName:elementName:"); - ffi.Pointer _objc_msgSend_1018( + ffi.Pointer _objc_msgSend_1034( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer name, ffi.Pointer elementName, ) { - return __objc_msgSend_1018( + return __objc_msgSend_1034( obj, sel, name, @@ -29007,14 +29393,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_1018Ptr = _lookup< + late final __objc_msgSend_1034Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1018 = __objc_msgSend_1018Ptr.asFunction< + late final __objc_msgSend_1034 = __objc_msgSend_1034Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -29024,117 +29410,117 @@ class SentryCocoa { late final _sel_predefinedEntityDeclarationForName_1 = _registerName1("predefinedEntityDeclarationForName:"); late final _sel_DTD1 = _registerName1("DTD"); - ffi.Pointer _objc_msgSend_1019( + ffi.Pointer _objc_msgSend_1035( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1019( + return __objc_msgSend_1035( obj, sel, ); } - late final __objc_msgSend_1019Ptr = _lookup< + late final __objc_msgSend_1035Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1019 = __objc_msgSend_1019Ptr.asFunction< + late final __objc_msgSend_1035 = __objc_msgSend_1035Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_setDTD_1 = _registerName1("setDTD:"); - void _objc_msgSend_1020( + void _objc_msgSend_1036( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer value, ) { - return __objc_msgSend_1020( + return __objc_msgSend_1036( obj, sel, value, ); } - late final __objc_msgSend_1020Ptr = _lookup< + late final __objc_msgSend_1036Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1020 = __objc_msgSend_1020Ptr.asFunction< + late final __objc_msgSend_1036 = __objc_msgSend_1036Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_setRootElement_1 = _registerName1("setRootElement:"); - void _objc_msgSend_1021( + void _objc_msgSend_1037( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer root, ) { - return __objc_msgSend_1021( + return __objc_msgSend_1037( obj, sel, root, ); } - late final __objc_msgSend_1021Ptr = _lookup< + late final __objc_msgSend_1037Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1021 = __objc_msgSend_1021Ptr.asFunction< + late final __objc_msgSend_1037 = __objc_msgSend_1037Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_rootElement1 = _registerName1("rootElement"); - ffi.Pointer _objc_msgSend_1022( + ffi.Pointer _objc_msgSend_1038( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1022( + return __objc_msgSend_1038( obj, sel, ); } - late final __objc_msgSend_1022Ptr = _lookup< + late final __objc_msgSend_1038Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1022 = __objc_msgSend_1022Ptr.asFunction< + late final __objc_msgSend_1038 = __objc_msgSend_1038Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_XMLData1 = _registerName1("XMLData"); late final _sel_XMLDataWithOptions_1 = _registerName1("XMLDataWithOptions:"); - ffi.Pointer _objc_msgSend_1023( + ffi.Pointer _objc_msgSend_1039( ffi.Pointer obj, ffi.Pointer sel, int options, ) { - return __objc_msgSend_1023( + return __objc_msgSend_1039( obj, sel, options, ); } - late final __objc_msgSend_1023Ptr = _lookup< + late final __objc_msgSend_1039Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_1023 = __objc_msgSend_1023Ptr.asFunction< + late final __objc_msgSend_1039 = __objc_msgSend_1039Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); late final _sel_objectByApplyingXSLT_arguments_error_1 = _registerName1("objectByApplyingXSLT:arguments:error:"); - ffi.Pointer _objc_msgSend_1024( + ffi.Pointer _objc_msgSend_1040( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer xslt, ffi.Pointer arguments, ffi.Pointer> error, ) { - return __objc_msgSend_1024( + return __objc_msgSend_1040( obj, sel, xslt, @@ -29143,7 +29529,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1024Ptr = _lookup< + late final __objc_msgSend_1040Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -29151,7 +29537,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_1024 = __objc_msgSend_1024Ptr.asFunction< + late final __objc_msgSend_1040 = __objc_msgSend_1040Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -29161,14 +29547,14 @@ class SentryCocoa { late final _sel_objectByApplyingXSLTString_arguments_error_1 = _registerName1("objectByApplyingXSLTString:arguments:error:"); - ffi.Pointer _objc_msgSend_1025( + ffi.Pointer _objc_msgSend_1041( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer xslt, ffi.Pointer arguments, ffi.Pointer> error, ) { - return __objc_msgSend_1025( + return __objc_msgSend_1041( obj, sel, xslt, @@ -29177,7 +29563,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1025Ptr = _lookup< + late final __objc_msgSend_1041Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -29185,7 +29571,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_1025 = __objc_msgSend_1025Ptr.asFunction< + late final __objc_msgSend_1041 = __objc_msgSend_1041Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -29195,14 +29581,14 @@ class SentryCocoa { late final _sel_objectByApplyingXSLTAtURL_arguments_error_1 = _registerName1("objectByApplyingXSLTAtURL:arguments:error:"); - ffi.Pointer _objc_msgSend_1026( + ffi.Pointer _objc_msgSend_1042( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer xsltURL, ffi.Pointer argument, ffi.Pointer> error, ) { - return __objc_msgSend_1026( + return __objc_msgSend_1042( obj, sel, xsltURL, @@ -29211,7 +29597,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1026Ptr = _lookup< + late final __objc_msgSend_1042Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -29219,7 +29605,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_1026 = __objc_msgSend_1026Ptr.asFunction< + late final __objc_msgSend_1042 = __objc_msgSend_1042Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -29230,63 +29616,63 @@ class SentryCocoa { late final _sel_validateAndReturnError_1 = _registerName1("validateAndReturnError:"); late final _sel_rootDocument1 = _registerName1("rootDocument"); - ffi.Pointer _objc_msgSend_1027( + ffi.Pointer _objc_msgSend_1043( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1027( + return __objc_msgSend_1043( obj, sel, ); } - late final __objc_msgSend_1027Ptr = _lookup< + late final __objc_msgSend_1043Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1027 = __objc_msgSend_1027Ptr.asFunction< + late final __objc_msgSend_1043 = __objc_msgSend_1043Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_parent1 = _registerName1("parent"); - ffi.Pointer _objc_msgSend_1028( + ffi.Pointer _objc_msgSend_1044( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1028( + return __objc_msgSend_1044( obj, sel, ); } - late final __objc_msgSend_1028Ptr = _lookup< + late final __objc_msgSend_1044Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1028 = __objc_msgSend_1028Ptr.asFunction< + late final __objc_msgSend_1044 = __objc_msgSend_1044Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_childCount1 = _registerName1("childCount"); late final _sel_children1 = _registerName1("children"); late final _sel_childAtIndex_1 = _registerName1("childAtIndex:"); - ffi.Pointer _objc_msgSend_1029( + ffi.Pointer _objc_msgSend_1045( ffi.Pointer obj, ffi.Pointer sel, int index, ) { - return __objc_msgSend_1029( + return __objc_msgSend_1045( obj, sel, index, ); } - late final __objc_msgSend_1029Ptr = _lookup< + late final __objc_msgSend_1045Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_1029 = __objc_msgSend_1029Ptr.asFunction< + late final __objc_msgSend_1045 = __objc_msgSend_1045Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); @@ -29303,45 +29689,45 @@ class SentryCocoa { late final _sel_XMLString1 = _registerName1("XMLString"); late final _sel_XMLStringWithOptions_1 = _registerName1("XMLStringWithOptions:"); - ffi.Pointer _objc_msgSend_1030( + ffi.Pointer _objc_msgSend_1046( ffi.Pointer obj, ffi.Pointer sel, int options, ) { - return __objc_msgSend_1030( + return __objc_msgSend_1046( obj, sel, options, ); } - late final __objc_msgSend_1030Ptr = _lookup< + late final __objc_msgSend_1046Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Int32)>>('objc_msgSend'); - late final __objc_msgSend_1030 = __objc_msgSend_1030Ptr.asFunction< + late final __objc_msgSend_1046 = __objc_msgSend_1046Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, int)>(); late final _sel_canonicalXMLStringPreservingComments_1 = _registerName1("canonicalXMLStringPreservingComments:"); - ffi.Pointer _objc_msgSend_1031( + ffi.Pointer _objc_msgSend_1047( ffi.Pointer obj, ffi.Pointer sel, bool comments, ) { - return __objc_msgSend_1031( + return __objc_msgSend_1047( obj, sel, comments, ); } - late final __objc_msgSend_1031Ptr = _lookup< + late final __objc_msgSend_1047Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_1031 = __objc_msgSend_1031Ptr.asFunction< + late final __objc_msgSend_1047 = __objc_msgSend_1047Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, bool)>(); @@ -29349,14 +29735,14 @@ class SentryCocoa { _registerName1("nodesForXPath:error:"); late final _sel_objectsForXQuery_constants_error_1 = _registerName1("objectsForXQuery:constants:error:"); - ffi.Pointer _objc_msgSend_1032( + ffi.Pointer _objc_msgSend_1048( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer xquery, ffi.Pointer constants, ffi.Pointer> error, ) { - return __objc_msgSend_1032( + return __objc_msgSend_1048( obj, sel, xquery, @@ -29365,7 +29751,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1032Ptr = _lookup< + late final __objc_msgSend_1048Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -29373,7 +29759,7 @@ class SentryCocoa { ffi.Pointer, ffi.Pointer, ffi.Pointer>)>>('objc_msgSend'); - late final __objc_msgSend_1032 = __objc_msgSend_1032Ptr.asFunction< + late final __objc_msgSend_1048 = __objc_msgSend_1048Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -29401,13 +29787,13 @@ class SentryCocoa { late final _sel_attributeForName_1 = _registerName1("attributeForName:"); late final _sel_attributeForLocalName_URI_1 = _registerName1("attributeForLocalName:URI:"); - ffi.Pointer _objc_msgSend_1033( + ffi.Pointer _objc_msgSend_1049( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer localName, ffi.Pointer URI, ) { - return __objc_msgSend_1033( + return __objc_msgSend_1049( obj, sel, localName, @@ -29415,14 +29801,14 @@ class SentryCocoa { ); } - late final __objc_msgSend_1033Ptr = _lookup< + late final __objc_msgSend_1049Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1033 = __objc_msgSend_1033Ptr.asFunction< + late final __objc_msgSend_1049 = __objc_msgSend_1049Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, @@ -29445,571 +29831,69 @@ class SentryCocoa { _registerName1("setAttributesAsDictionary:"); late final _class_PrivateSentrySDKOnly1 = _getClass1("PrivateSentrySDKOnly"); late final _class_SentryEnvelope1 = _getClass1("SentryEnvelope"); - late final _class_SentryId1 = _getClass1("SentryId"); - late final _class_NSUUID1 = _getClass1("NSUUID"); - late final _sel_UUID1 = _registerName1("UUID"); - late final _sel_initWithUUIDString_1 = _registerName1("initWithUUIDString:"); - late final _sel_initWithUUIDBytes_1 = _registerName1("initWithUUIDBytes:"); - instancetype _objc_msgSend_1034( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer bytes, - ) { - return __objc_msgSend_1034( - obj, - sel, - bytes, - ); - } - - late final __objc_msgSend_1034Ptr = _lookup< - ffi.NativeFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1034 = __objc_msgSend_1034Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final _sel_getUUIDBytes_1 = _registerName1("getUUIDBytes:"); - void _objc_msgSend_1035( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer uuid, - ) { - return __objc_msgSend_1035( - obj, - sel, - uuid, - ); - } - - late final __objc_msgSend_1035Ptr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1035 = __objc_msgSend_1035Ptr.asFunction< - void Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - int _objc_msgSend_1036( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer otherUUID, - ) { - return __objc_msgSend_1036( - obj, - sel, - otherUUID, - ); - } - - late final __objc_msgSend_1036Ptr = _lookup< - ffi.NativeFunction< - ffi.Int32 Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1036 = __objc_msgSend_1036Ptr.asFunction< - int Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final _sel_UUIDString1 = _registerName1("UUIDString"); - late final _sel_initWithUUID_1 = _registerName1("initWithUUID:"); - instancetype _objc_msgSend_1037( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer uuid, - ) { - return __objc_msgSend_1037( - obj, - sel, - uuid, - ); - } - - late final __objc_msgSend_1037Ptr = _lookup< - ffi.NativeFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1037 = __objc_msgSend_1037Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final _sel_sentryIdString1 = _registerName1("sentryIdString"); - late final _sel_empty1 = _registerName1("empty"); - ffi.Pointer _objc_msgSend_1038( - ffi.Pointer obj, - ffi.Pointer sel, - ) { - return __objc_msgSend_1038( - obj, - sel, - ); - } - - late final __objc_msgSend_1038Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1038 = __objc_msgSend_1038Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final _class_SentryEnvelopeItem1 = _getClass1("SentryEnvelopeItem"); - late final _class_SentryEvent1 = _getClass1("SentryEvent"); - late final _sel_initWithEvent_1 = _registerName1("initWithEvent:"); - instancetype _objc_msgSend_1039( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer event, - ) { - return __objc_msgSend_1039( - obj, - sel, - event, - ); - } - - late final __objc_msgSend_1039Ptr = _lookup< - ffi.NativeFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1039 = __objc_msgSend_1039Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final _class_SentrySession1 = _getClass1("SentrySession"); - late final _sel_initWithSession_1 = _registerName1("initWithSession:"); - instancetype _objc_msgSend_1040( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer session, - ) { - return __objc_msgSend_1040( - obj, - sel, - session, - ); - } - - late final __objc_msgSend_1040Ptr = _lookup< - ffi.NativeFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1040 = __objc_msgSend_1040Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final _class_SentryUserFeedback1 = _getClass1("SentryUserFeedback"); - late final _sel_initWithUserFeedback_1 = - _registerName1("initWithUserFeedback:"); - instancetype _objc_msgSend_1041( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer userFeedback, - ) { - return __objc_msgSend_1041( - obj, - sel, - userFeedback, - ); - } - - late final __objc_msgSend_1041Ptr = _lookup< - ffi.NativeFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1041 = __objc_msgSend_1041Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final _class_SentryAttachment1 = _getClass1("SentryAttachment"); - late final _sel_initWithAttachment_maxAttachmentSize_1 = - _registerName1("initWithAttachment:maxAttachmentSize:"); - instancetype _objc_msgSend_1042( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer attachment, - int maxAttachmentSize, - ) { - return __objc_msgSend_1042( - obj, - sel, - attachment, - maxAttachmentSize, - ); - } - - late final __objc_msgSend_1042Ptr = _lookup< - ffi.NativeFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.UnsignedLong)>>('objc_msgSend'); - late final __objc_msgSend_1042 = __objc_msgSend_1042Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, int)>(); - - late final _class_SentryEnvelopeItemHeader1 = - _getClass1("SentryEnvelopeItemHeader"); - late final _sel_initWithHeader_data_1 = - _registerName1("initWithHeader:data:"); - instancetype _objc_msgSend_1043( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer header, - ffi.Pointer data, - ) { - return __objc_msgSend_1043( - obj, - sel, - header, - data, - ); - } - - late final __objc_msgSend_1043Ptr = _lookup< - ffi.NativeFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1043 = __objc_msgSend_1043Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final _sel_header1 = _registerName1("header"); - ffi.Pointer _objc_msgSend_1044( - ffi.Pointer obj, - ffi.Pointer sel, - ) { - return __objc_msgSend_1044( - obj, - sel, - ); - } - - late final __objc_msgSend_1044Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1044 = __objc_msgSend_1044Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final _sel_initWithId_singleItem_1 = - _registerName1("initWithId:singleItem:"); - instancetype _objc_msgSend_1045( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer id, - ffi.Pointer item, - ) { - return __objc_msgSend_1045( - obj, - sel, - id, - item, - ); - } - - late final __objc_msgSend_1045Ptr = _lookup< - ffi.NativeFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1045 = __objc_msgSend_1045Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final _class_SentryEnvelopeHeader1 = _getClass1("SentryEnvelopeHeader"); - late final _sel_initWithId_1 = _registerName1("initWithId:"); - instancetype _objc_msgSend_1046( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer eventId, - ) { - return __objc_msgSend_1046( - obj, - sel, - eventId, - ); - } - - late final __objc_msgSend_1046Ptr = _lookup< - ffi.NativeFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1046 = __objc_msgSend_1046Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); - - late final _class_SentryTraceContext1 = _getClass1("SentryTraceContext"); - late final _sel_initWithId_traceContext_1 = - _registerName1("initWithId:traceContext:"); - instancetype _objc_msgSend_1047( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer eventId, - ffi.Pointer traceContext, - ) { - return __objc_msgSend_1047( - obj, - sel, - eventId, - traceContext, - ); - } - - late final __objc_msgSend_1047Ptr = _lookup< - ffi.NativeFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1047 = __objc_msgSend_1047Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final _class_SentrySdkInfo1 = _getClass1("SentrySdkInfo"); - late final _sel_initWithId_sdkInfo_traceContext_1 = - _registerName1("initWithId:sdkInfo:traceContext:"); - instancetype _objc_msgSend_1048( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer eventId, - ffi.Pointer sdkInfo, - ffi.Pointer traceContext, - ) { - return __objc_msgSend_1048( - obj, - sel, - eventId, - sdkInfo, - traceContext, - ); - } - - late final __objc_msgSend_1048Ptr = _lookup< - ffi.NativeFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1048 = __objc_msgSend_1048Ptr.asFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>(); - - late final _sel_eventId1 = _registerName1("eventId"); - late final _sel_sdkInfo1 = _registerName1("sdkInfo"); - ffi.Pointer _objc_msgSend_1049( - ffi.Pointer obj, - ffi.Pointer sel, - ) { - return __objc_msgSend_1049( - obj, - sel, - ); - } - - late final __objc_msgSend_1049Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1049 = __objc_msgSend_1049Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final _sel_traceContext1 = _registerName1("traceContext"); - ffi.Pointer _objc_msgSend_1050( - ffi.Pointer obj, - ffi.Pointer sel, - ) { - return __objc_msgSend_1050( - obj, - sel, - ); - } - - late final __objc_msgSend_1050Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1050 = __objc_msgSend_1050Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final _sel_sentAt1 = _registerName1("sentAt"); - late final _sel_setSentAt_1 = _registerName1("setSentAt:"); - late final _sel_initWithHeader_singleItem_1 = - _registerName1("initWithHeader:singleItem:"); - instancetype _objc_msgSend_1051( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer header, - ffi.Pointer item, - ) { - return __objc_msgSend_1051( - obj, - sel, - header, - item, - ); - } - - late final __objc_msgSend_1051Ptr = _lookup< - ffi.NativeFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1051 = __objc_msgSend_1051Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final _sel_initWithId_items_1 = _registerName1("initWithId:items:"); - instancetype _objc_msgSend_1052( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer id, - ffi.Pointer items, - ) { - return __objc_msgSend_1052( - obj, - sel, - id, - items, - ); - } - - late final __objc_msgSend_1052Ptr = _lookup< - ffi.NativeFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1052 = __objc_msgSend_1052Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - late final _sel_initWithSessions_1 = _registerName1("initWithSessions:"); - late final _sel_initWithHeader_items_1 = - _registerName1("initWithHeader:items:"); - instancetype _objc_msgSend_1053( - ffi.Pointer obj, - ffi.Pointer sel, - ffi.Pointer header, - ffi.Pointer items, - ) { - return __objc_msgSend_1053( - obj, - sel, - header, - items, - ); - } - - late final __objc_msgSend_1053Ptr = _lookup< - ffi.NativeFunction< - instancetype Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1053 = __objc_msgSend_1053Ptr.asFunction< - instancetype Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer, ffi.Pointer)>(); - - ffi.Pointer _objc_msgSend_1054( - ffi.Pointer obj, - ffi.Pointer sel, - ) { - return __objc_msgSend_1054( - obj, - sel, - ); - } - - late final __objc_msgSend_1054Ptr = _lookup< - ffi.NativeFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1054 = __objc_msgSend_1054Ptr.asFunction< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); - - late final _sel_items1 = _registerName1("items"); late final _sel_storeEnvelope_1 = _registerName1("storeEnvelope:"); - void _objc_msgSend_1055( + void _objc_msgSend_1050( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer envelope, ) { - return __objc_msgSend_1055( + return __objc_msgSend_1050( obj, sel, envelope, ); } - late final __objc_msgSend_1055Ptr = _lookup< + late final __objc_msgSend_1050Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1055 = __objc_msgSend_1055Ptr.asFunction< + late final __objc_msgSend_1050 = __objc_msgSend_1050Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_captureEnvelope_1 = _registerName1("captureEnvelope:"); late final _sel_envelopeWithData_1 = _registerName1("envelopeWithData:"); - ffi.Pointer _objc_msgSend_1056( + ffi.Pointer _objc_msgSend_1051( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer data, ) { - return __objc_msgSend_1056( + return __objc_msgSend_1051( obj, sel, data, ); } - late final __objc_msgSend_1056Ptr = _lookup< + late final __objc_msgSend_1051Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1056 = __objc_msgSend_1056Ptr.asFunction< + late final __objc_msgSend_1051 = __objc_msgSend_1051Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_getDebugImages1 = _registerName1("getDebugImages"); late final _sel_getDebugImagesCrashed_1 = _registerName1("getDebugImagesCrashed:"); - ffi.Pointer _objc_msgSend_1057( + ffi.Pointer _objc_msgSend_1052( ffi.Pointer obj, ffi.Pointer sel, bool isCrash, ) { - return __objc_msgSend_1057( + return __objc_msgSend_1052( obj, sel, isCrash, ); } - late final __objc_msgSend_1057Ptr = _lookup< + late final __objc_msgSend_1052Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Bool)>>('objc_msgSend'); - late final __objc_msgSend_1057 = __objc_msgSend_1057Ptr.asFunction< + late final __objc_msgSend_1052 = __objc_msgSend_1052Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer, bool)>(); @@ -30019,38 +29903,39 @@ class SentryCocoa { late final _sel_getSdkName1 = _registerName1("getSdkName"); late final _sel_getSdkVersionString1 = _registerName1("getSdkVersionString"); late final _sel_getExtraContext1 = _registerName1("getExtraContext"); + late final _class_SentryId2 = _getClass1("Sentry.SentryId"); late final _sel_startProfilerForTrace_1 = _registerName1("startProfilerForTrace:"); - int _objc_msgSend_1058( + int _objc_msgSend_1053( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer traceId, ) { - return __objc_msgSend_1058( + return __objc_msgSend_1053( obj, sel, traceId, ); } - late final __objc_msgSend_1058Ptr = _lookup< + late final __objc_msgSend_1053Ptr = _lookup< ffi.NativeFunction< ffi.Uint64 Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1058 = __objc_msgSend_1058Ptr.asFunction< + late final __objc_msgSend_1053 = __objc_msgSend_1053Ptr.asFunction< int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _sel_collectProfileBetween_and_forTrace_1 = _registerName1("collectProfileBetween:and:forTrace:"); - ffi.Pointer _objc_msgSend_1059( + ffi.Pointer _objc_msgSend_1054( ffi.Pointer obj, ffi.Pointer sel, int startSystemTime, int endSystemTime, ffi.Pointer traceId, ) { - return __objc_msgSend_1059( + return __objc_msgSend_1054( obj, sel, startSystemTime, @@ -30059,7 +29944,7 @@ class SentryCocoa { ); } - late final __objc_msgSend_1059Ptr = _lookup< + late final __objc_msgSend_1054Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, @@ -30067,29 +29952,29 @@ class SentryCocoa { ffi.Uint64, ffi.Uint64, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1059 = __objc_msgSend_1059Ptr.asFunction< + late final __objc_msgSend_1054 = __objc_msgSend_1054Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, int, int, ffi.Pointer)>(); late final _sel_discardProfilerForTrace_1 = _registerName1("discardProfilerForTrace:"); - void _objc_msgSend_1060( + void _objc_msgSend_1055( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer traceId, ) { - return __objc_msgSend_1060( + return __objc_msgSend_1055( obj, sel, traceId, ); } - late final __objc_msgSend_1060Ptr = _lookup< + late final __objc_msgSend_1055Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1060 = __objc_msgSend_1060Ptr.asFunction< + late final __objc_msgSend_1055 = __objc_msgSend_1055Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); @@ -30097,82 +29982,82 @@ class SentryCocoa { _getClass1("SentryAppStartMeasurement"); late final _sel_onAppStartMeasurementAvailable1 = _registerName1("onAppStartMeasurementAvailable"); - ffi.Pointer<_ObjCBlock> _objc_msgSend_1061( + ffi.Pointer<_ObjCBlock> _objc_msgSend_1056( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1061( + return __objc_msgSend_1056( obj, sel, ); } - late final __objc_msgSend_1061Ptr = _lookup< + late final __objc_msgSend_1056Ptr = _lookup< ffi.NativeFunction< ffi.Pointer<_ObjCBlock> Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1061 = __objc_msgSend_1061Ptr.asFunction< + late final __objc_msgSend_1056 = __objc_msgSend_1056Ptr.asFunction< ffi.Pointer<_ObjCBlock> Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_setOnAppStartMeasurementAvailable_1 = _registerName1("setOnAppStartMeasurementAvailable:"); - void _objc_msgSend_1062( + void _objc_msgSend_1057( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer<_ObjCBlock> value, ) { - return __objc_msgSend_1062( + return __objc_msgSend_1057( obj, sel, value, ); } - late final __objc_msgSend_1062Ptr = _lookup< + late final __objc_msgSend_1057Ptr = _lookup< ffi.NativeFunction< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>>('objc_msgSend'); - late final __objc_msgSend_1062 = __objc_msgSend_1062Ptr.asFunction< + late final __objc_msgSend_1057 = __objc_msgSend_1057Ptr.asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer<_ObjCBlock>)>(); late final _sel_appStartMeasurement1 = _registerName1("appStartMeasurement"); - ffi.Pointer _objc_msgSend_1063( + ffi.Pointer _objc_msgSend_1058( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1063( + return __objc_msgSend_1058( obj, sel, ); } - late final __objc_msgSend_1063Ptr = _lookup< + late final __objc_msgSend_1058Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1063 = __objc_msgSend_1063Ptr.asFunction< + late final __objc_msgSend_1058 = __objc_msgSend_1058Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); late final _sel_installationID1 = _registerName1("installationID"); late final _class_SentryOptions1 = _getClass1("SentryOptions"); - ffi.Pointer _objc_msgSend_1064( + ffi.Pointer _objc_msgSend_1059( ffi.Pointer obj, ffi.Pointer sel, ) { - return __objc_msgSend_1064( + return __objc_msgSend_1059( obj, sel, ); } - late final __objc_msgSend_1064Ptr = _lookup< + late final __objc_msgSend_1059Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1064 = __objc_msgSend_1064Ptr.asFunction< + late final __objc_msgSend_1059 = __objc_msgSend_1059Ptr.asFunction< ffi.Pointer Function( ffi.Pointer, ffi.Pointer)>(); @@ -30180,73 +30065,234 @@ class SentryCocoa { _registerName1("appStartMeasurementHybridSDKMode"); late final _sel_setAppStartMeasurementHybridSDKMode_1 = _registerName1("setAppStartMeasurementHybridSDKMode:"); + late final _sel_appStartMeasurementWithSpans1 = + _registerName1("appStartMeasurementWithSpans"); late final _class_SentryUser1 = _getClass1("SentryUser"); late final _sel_userWithDictionary_1 = _registerName1("userWithDictionary:"); - ffi.Pointer _objc_msgSend_1065( + ffi.Pointer _objc_msgSend_1060( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer dictionary, ) { - return __objc_msgSend_1065( + return __objc_msgSend_1060( obj, sel, dictionary, ); } - late final __objc_msgSend_1065Ptr = _lookup< + late final __objc_msgSend_1060Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1065 = __objc_msgSend_1065Ptr.asFunction< + late final __objc_msgSend_1060 = __objc_msgSend_1060Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); late final _class_SentryBreadcrumb1 = _getClass1("SentryBreadcrumb"); late final _sel_breadcrumbWithDictionary_1 = _registerName1("breadcrumbWithDictionary:"); - ffi.Pointer _objc_msgSend_1066( + ffi.Pointer _objc_msgSend_1061( ffi.Pointer obj, ffi.Pointer sel, ffi.Pointer dictionary, ) { - return __objc_msgSend_1066( + return __objc_msgSend_1061( obj, sel, dictionary, ); } - late final __objc_msgSend_1066Ptr = _lookup< + late final __objc_msgSend_1061Ptr = _lookup< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); - late final __objc_msgSend_1066 = __objc_msgSend_1066Ptr.asFunction< + late final __objc_msgSend_1061 = __objc_msgSend_1061Ptr.asFunction< ffi.Pointer Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>(); -} - -class _ObjCWrapper implements ffi.Finalizable { - final ffi.Pointer _id; - final SentryCocoa _lib; - bool _pendingRelease; - _ObjCWrapper._(this._id, this._lib, - {bool retain = false, bool release = false}) - : _pendingRelease = release { - if (retain) { - _lib._objc_retain(_id.cast()); - } - if (release) { - _lib._objc_releaseFinalizer2.attach(this, _id.cast(), detach: this); - } + late final _sel_captureReplay1 = _registerName1("captureReplay"); + late final _sel_getReplayId1 = _registerName1("getReplayId"); + late final _sel_addReplayIgnoreClasses_1 = + _registerName1("addReplayIgnoreClasses:"); + late final _sel_addReplayRedactClasses_1 = + _registerName1("addReplayRedactClasses:"); + late final _class_SentryCurrentDateProvider1 = + _getClass1("SentryCurrentDateProvider"); + late final _sel_timezoneOffset1 = _registerName1("timezoneOffset"); + late final _sel_systemTime1 = _registerName1("systemTime"); + int _objc_msgSend_1062( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_1062( + obj, + sel, + ); } - /// Releases the reference to the underlying ObjC object held by this wrapper. - /// Throws a StateError if this wrapper doesn't currently hold a reference. - void release() { - if (_pendingRelease) { - _pendingRelease = false; + late final __objc_msgSend_1062Ptr = _lookup< + ffi.NativeFunction< + ffi.Uint64 Function( + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_1062 = __objc_msgSend_1062Ptr.asFunction< + int Function(ffi.Pointer, ffi.Pointer)>(); + + late final _sel_bucketTimestamp1 = _registerName1("bucketTimestamp"); + late final _class_SentryId11 = _getClass1("Sentry.SentryId"); + late final _sel_empty1 = _registerName1("empty"); + ffi.Pointer _objc_msgSend_1063( + ffi.Pointer obj, + ffi.Pointer sel, + ) { + return __objc_msgSend_1063( + obj, + sel, + ); + } + + late final __objc_msgSend_1063Ptr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer, ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_1063 = __objc_msgSend_1063Ptr.asFunction< + ffi.Pointer Function( + ffi.Pointer, ffi.Pointer)>(); + + late final _sel_setEmpty_1 = _registerName1("setEmpty:"); + void _objc_msgSend_1064( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer value, + ) { + return __objc_msgSend_1064( + obj, + sel, + value, + ); + } + + late final __objc_msgSend_1064Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_1064 = __objc_msgSend_1064Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + late final _sel_sentryIdString1 = _registerName1("sentryIdString"); + late final _class_NSUUID1 = _getClass1("NSUUID"); + late final _sel_UUID1 = _registerName1("UUID"); + late final _sel_initWithUUIDString_1 = _registerName1("initWithUUIDString:"); + late final _sel_initWithUUIDBytes_1 = _registerName1("initWithUUIDBytes:"); + instancetype _objc_msgSend_1065( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer bytes, + ) { + return __objc_msgSend_1065( + obj, + sel, + bytes, + ); + } + + late final __objc_msgSend_1065Ptr = _lookup< + ffi.NativeFunction< + instancetype Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_1065 = __objc_msgSend_1065Ptr.asFunction< + instancetype Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + late final _sel_getUUIDBytes_1 = _registerName1("getUUIDBytes:"); + void _objc_msgSend_1066( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer uuid, + ) { + return __objc_msgSend_1066( + obj, + sel, + uuid, + ); + } + + late final __objc_msgSend_1066Ptr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_1066 = __objc_msgSend_1066Ptr.asFunction< + void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + int _objc_msgSend_1067( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer otherUUID, + ) { + return __objc_msgSend_1067( + obj, + sel, + otherUUID, + ); + } + + late final __objc_msgSend_1067Ptr = _lookup< + ffi.NativeFunction< + ffi.Int32 Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_1067 = __objc_msgSend_1067Ptr.asFunction< + int Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + late final _sel_UUIDString1 = _registerName1("UUIDString"); + late final _sel_initWithUuid_1 = _registerName1("initWithUuid:"); + instancetype _objc_msgSend_1068( + ffi.Pointer obj, + ffi.Pointer sel, + ffi.Pointer uuid, + ) { + return __objc_msgSend_1068( + obj, + sel, + uuid, + ); + } + + late final __objc_msgSend_1068Ptr = _lookup< + ffi.NativeFunction< + instancetype Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>>('objc_msgSend'); + late final __objc_msgSend_1068 = __objc_msgSend_1068Ptr.asFunction< + instancetype Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); + + late final _sel_isEqual_1 = _registerName1("isEqual:"); +} + +class _ObjCWrapper implements ffi.Finalizable { + final ffi.Pointer _id; + final SentryCocoa _lib; + bool _pendingRelease; + + _ObjCWrapper._(this._id, this._lib, + {bool retain = false, bool release = false}) + : _pendingRelease = release { + if (retain) { + _lib._objc_retain(_id.cast()); + } + if (release) { + _lib._objc_releaseFinalizer2.attach(this, _id.cast(), detach: this); + } + } + + /// Releases the reference to the underlying ObjC object held by this wrapper. + /// Throws a StateError if this wrapper doesn't currently hold a reference. + void release() { + if (_pendingRelease) { + _pendingRelease = false; _lib._objc_release(_id.cast()); _lib._objc_releaseFinalizer2.detach(this); } else { @@ -34563,6 +34609,26 @@ class NSURL extends NSObject { return NSURL._(_ret, _lib, retain: true, release: true); } + NSURL initWithString_encodingInvalidCharacters_( + NSString? URLString, bool encodingInvalidCharacters) { + final _ret = _lib._objc_msgSend_29( + _id, + _lib._sel_initWithString_encodingInvalidCharacters_1, + URLString?._id ?? ffi.nullptr, + encodingInvalidCharacters); + return NSURL._(_ret, _lib, retain: true, release: true); + } + + static NSURL URLWithString_encodingInvalidCharacters_( + SentryCocoa _lib, NSString? URLString, bool encodingInvalidCharacters) { + final _ret = _lib._objc_msgSend_29( + _lib._class_NSURL1, + _lib._sel_URLWithString_encodingInvalidCharacters_1, + URLString?._id ?? ffi.nullptr, + encodingInvalidCharacters); + return NSURL._(_ret, _lib, retain: true, release: true); + } + NSURL initWithDataRepresentation_relativeToURL_( NSData? data, NSURL? baseURL) { final _ret = _lib._objc_msgSend_37( @@ -40105,6 +40171,13 @@ class NSLocale extends NSObject { return NSString._(_ret, _lib, retain: true, release: true); } + NSString? get languageIdentifier { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_languageIdentifier1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); + } + NSString? get countryCode { final _ret = _lib._objc_msgSend_20(_id, _lib._sel_countryCode1); return _ret.address == 0 @@ -40120,6 +40193,13 @@ class NSLocale extends NSObject { return NSString._(_ret, _lib, retain: true, release: true); } + NSString? get regionCode { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_regionCode1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); + } + NSString? get scriptCode { final _ret = _lib._objc_msgSend_20(_id, _lib._sel_scriptCode1); return _ret.address == 0 @@ -41133,6 +41213,8 @@ abstract class NSDataWritingOptions { static const int NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication = 1073741824; + static const int NSDataWritingFileProtectionCompleteWhenUserInactive = + 1342177280; static const int NSDataWritingFileProtectionMask = 4026531840; static const int NSAtomicWrite = 1; } @@ -52367,7 +52449,7 @@ class NSBundle extends NSObject { NSAttributedString localizedAttributedStringForKey_value_table_( NSString? key, NSString? value, NSString? tableName) { - final _ret = _lib._objc_msgSend_676( + final _ret = _lib._objc_msgSend_680( _id, _lib._sel_localizedAttributedStringForKey_value_table_1, key?._id ?? ffi.nullptr, @@ -52449,7 +52531,7 @@ class NSBundle extends NSObject { SentryCocoa _lib, NSArray? localizationsArray, NSArray? preferencesArray) { - final _ret = _lib._objc_msgSend_677( + final _ret = _lib._objc_msgSend_681( _lib._class_NSBundle1, _lib._sel_preferredLocalizationsFromArray_forPreferences_1, localizationsArray?._id ?? ffi.nullptr, @@ -52465,7 +52547,7 @@ class NSBundle extends NSObject { } void setPreservationPriority_forTags_(double priority, NSSet? tags) { - _lib._objc_msgSend_678(_id, _lib._sel_setPreservationPriority_forTags_1, + _lib._objc_msgSend_682(_id, _lib._sel_setPreservationPriority_forTags_1, priority, tags?._id ?? ffi.nullptr); } @@ -52787,8 +52869,62 @@ class NSAttributedString extends NSObject { return NSAttributedString._(_ret, _lib, retain: true, release: true); } - NSAttributedString attributedStringByInflectingString() { + NSAttributedString initWithFormat_options_locale_context_( + NSAttributedString? format, + int options, + NSLocale? locale, + NSDictionary? context) { final _ret = _lib._objc_msgSend_675( + _id, + _lib._sel_initWithFormat_options_locale_context_1, + format?._id ?? ffi.nullptr, + options, + locale?._id ?? ffi.nullptr, + context?._id ?? ffi.nullptr); + return NSAttributedString._(_ret, _lib, retain: true, release: true); + } + + NSAttributedString initWithFormat_options_locale_context_arguments_( + NSAttributedString? format, + int options, + NSLocale? locale, + NSDictionary? context, + ffi.Pointer<__va_list_tag> arguments) { + final _ret = _lib._objc_msgSend_676( + _id, + _lib._sel_initWithFormat_options_locale_context_arguments_1, + format?._id ?? ffi.nullptr, + options, + locale?._id ?? ffi.nullptr, + context?._id ?? ffi.nullptr, + arguments); + return NSAttributedString._(_ret, _lib, retain: true, release: true); + } + + static NSAttributedString localizedAttributedStringWithFormat_context_( + SentryCocoa _lib, NSAttributedString? format, NSDictionary? context) { + final _ret = _lib._objc_msgSend_677( + _lib._class_NSAttributedString1, + _lib._sel_localizedAttributedStringWithFormat_context_1, + format?._id ?? ffi.nullptr, + context?._id ?? ffi.nullptr); + return NSAttributedString._(_ret, _lib, retain: true, release: true); + } + + static NSAttributedString + localizedAttributedStringWithFormat_options_context_(SentryCocoa _lib, + NSAttributedString? format, int options, NSDictionary? context) { + final _ret = _lib._objc_msgSend_678( + _lib._class_NSAttributedString1, + _lib._sel_localizedAttributedStringWithFormat_options_context_1, + format?._id ?? ffi.nullptr, + options, + context?._id ?? ffi.nullptr); + return NSAttributedString._(_ret, _lib, retain: true, release: true); + } + + NSAttributedString attributedStringByInflectingString() { + final _ret = _lib._objc_msgSend_679( _id, _lib._sel_attributedStringByInflectingString1); return NSAttributedString._(_ret, _lib, retain: true, release: true); } @@ -53327,12 +53463,12 @@ class NSMutableAttributedString extends NSAttributedString { } void setAttributes_range_(NSDictionary? attrs, _NSRange range) { - _lib._objc_msgSend_679( + _lib._objc_msgSend_683( _id, _lib._sel_setAttributes_range_1, attrs?._id ?? ffi.nullptr, range); } NSMutableString? get mutableString { - final _ret = _lib._objc_msgSend_680(_id, _lib._sel_mutableString1); + final _ret = _lib._objc_msgSend_684(_id, _lib._sel_mutableString1); return _ret.address == 0 ? null : NSMutableString._(_ret, _lib, retain: true, release: true); @@ -53340,23 +53476,23 @@ class NSMutableAttributedString extends NSAttributedString { void addAttribute_value_range_( NSString name, NSObject value, _NSRange range) { - _lib._objc_msgSend_681( + _lib._objc_msgSend_685( _id, _lib._sel_addAttribute_value_range_1, name._id, value._id, range); } void addAttributes_range_(NSDictionary? attrs, _NSRange range) { - _lib._objc_msgSend_679( + _lib._objc_msgSend_683( _id, _lib._sel_addAttributes_range_1, attrs?._id ?? ffi.nullptr, range); } void removeAttribute_range_(NSString name, _NSRange range) { - _lib._objc_msgSend_682( + _lib._objc_msgSend_686( _id, _lib._sel_removeAttribute_range_1, name._id, range); } void replaceCharactersInRange_withAttributedString_( _NSRange range, NSAttributedString? attrString) { - _lib._objc_msgSend_683( + _lib._objc_msgSend_687( _id, _lib._sel_replaceCharactersInRange_withAttributedString_1, range, @@ -53365,12 +53501,12 @@ class NSMutableAttributedString extends NSAttributedString { void insertAttributedString_atIndex_( NSAttributedString? attrString, int loc) { - _lib._objc_msgSend_684(_id, _lib._sel_insertAttributedString_atIndex_1, + _lib._objc_msgSend_688(_id, _lib._sel_insertAttributedString_atIndex_1, attrString?._id ?? ffi.nullptr, loc); } void appendAttributedString_(NSAttributedString? attrString) { - _lib._objc_msgSend_685(_id, _lib._sel_appendAttributedString_1, + _lib._objc_msgSend_689(_id, _lib._sel_appendAttributedString_1, attrString?._id ?? ffi.nullptr); } @@ -53379,7 +53515,7 @@ class NSMutableAttributedString extends NSAttributedString { } void setAttributedString_(NSAttributedString? attrString) { - _lib._objc_msgSend_685( + _lib._objc_msgSend_689( _id, _lib._sel_setAttributedString_1, attrString?._id ?? ffi.nullptr); } @@ -53392,7 +53528,7 @@ class NSMutableAttributedString extends NSAttributedString { } void appendLocalizedFormat_(NSAttributedString? format) { - _lib._objc_msgSend_685( + _lib._objc_msgSend_689( _id, _lib._sel_appendLocalizedFormat_1, format?._id ?? ffi.nullptr); } @@ -53518,6 +53654,62 @@ class NSMutableAttributedString extends NSAttributedString { return NSMutableAttributedString._(_ret, _lib, retain: true, release: true); } + @override + NSMutableAttributedString initWithFormat_options_locale_context_( + NSAttributedString? format, + int options, + NSLocale? locale, + NSDictionary? context) { + final _ret = _lib._objc_msgSend_675( + _id, + _lib._sel_initWithFormat_options_locale_context_1, + format?._id ?? ffi.nullptr, + options, + locale?._id ?? ffi.nullptr, + context?._id ?? ffi.nullptr); + return NSMutableAttributedString._(_ret, _lib, retain: true, release: true); + } + + @override + NSMutableAttributedString initWithFormat_options_locale_context_arguments_( + NSAttributedString? format, + int options, + NSLocale? locale, + NSDictionary? context, + ffi.Pointer<__va_list_tag> arguments) { + final _ret = _lib._objc_msgSend_676( + _id, + _lib._sel_initWithFormat_options_locale_context_arguments_1, + format?._id ?? ffi.nullptr, + options, + locale?._id ?? ffi.nullptr, + context?._id ?? ffi.nullptr, + arguments); + return NSMutableAttributedString._(_ret, _lib, retain: true, release: true); + } + + static NSMutableAttributedString localizedAttributedStringWithFormat_context_( + SentryCocoa _lib, NSAttributedString? format, NSDictionary? context) { + final _ret = _lib._objc_msgSend_677( + _lib._class_NSMutableAttributedString1, + _lib._sel_localizedAttributedStringWithFormat_context_1, + format?._id ?? ffi.nullptr, + context?._id ?? ffi.nullptr); + return NSMutableAttributedString._(_ret, _lib, retain: true, release: true); + } + + static NSMutableAttributedString + localizedAttributedStringWithFormat_options_context_(SentryCocoa _lib, + NSAttributedString? format, int options, NSDictionary? context) { + final _ret = _lib._objc_msgSend_678( + _lib._class_NSMutableAttributedString1, + _lib._sel_localizedAttributedStringWithFormat_options_context_1, + format?._id ?? ffi.nullptr, + options, + context?._id ?? ffi.nullptr); + return NSMutableAttributedString._(_ret, _lib, retain: true, release: true); + } + @override NSMutableAttributedString init() { final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); @@ -53639,11 +53831,11 @@ class NSDateFormatter extends NSFormatter { } int get formattingContext { - return _lib._objc_msgSend_690(_id, _lib._sel_formattingContext1); + return _lib._objc_msgSend_694(_id, _lib._sel_formattingContext1); } set formattingContext(int value) { - return _lib._objc_msgSend_691(_id, _lib._sel_setFormattingContext_1, value); + return _lib._objc_msgSend_695(_id, _lib._sel_setFormattingContext_1, value); } bool getObjectValue_forString_range_error_( @@ -53651,7 +53843,7 @@ class NSDateFormatter extends NSFormatter { NSString? string, ffi.Pointer<_NSRange> rangep, ffi.Pointer> error) { - return _lib._objc_msgSend_692( + return _lib._objc_msgSend_696( _id, _lib._sel_getObjectValue_forString_range_error_1, obj, @@ -53674,7 +53866,7 @@ class NSDateFormatter extends NSFormatter { static NSString localizedStringFromDate_dateStyle_timeStyle_( SentryCocoa _lib, NSDate? date, int dstyle, int tstyle) { - final _ret = _lib._objc_msgSend_693( + final _ret = _lib._objc_msgSend_697( _lib._class_NSDateFormatter1, _lib._sel_localizedStringFromDate_dateStyle_timeStyle_1, date?._id ?? ffi.nullptr, @@ -53685,7 +53877,7 @@ class NSDateFormatter extends NSFormatter { static NSString dateFormatFromTemplate_options_locale_( SentryCocoa _lib, NSString? tmplate, int opts, NSLocale? locale) { - final _ret = _lib._objc_msgSend_694( + final _ret = _lib._objc_msgSend_698( _lib._class_NSDateFormatter1, _lib._sel_dateFormatFromTemplate_options_locale_1, tmplate?._id ?? ffi.nullptr, @@ -53695,12 +53887,12 @@ class NSDateFormatter extends NSFormatter { } static int getDefaultFormatterBehavior(SentryCocoa _lib) { - return _lib._objc_msgSend_695( + return _lib._objc_msgSend_699( _lib._class_NSDateFormatter1, _lib._sel_defaultFormatterBehavior1); } static void setDefaultFormatterBehavior(SentryCocoa _lib, int value) { - return _lib._objc_msgSend_696(_lib._class_NSDateFormatter1, + return _lib._objc_msgSend_700(_lib._class_NSDateFormatter1, _lib._sel_setDefaultFormatterBehavior_1, value); } @@ -53722,19 +53914,19 @@ class NSDateFormatter extends NSFormatter { } int get dateStyle { - return _lib._objc_msgSend_697(_id, _lib._sel_dateStyle1); + return _lib._objc_msgSend_701(_id, _lib._sel_dateStyle1); } set dateStyle(int value) { - return _lib._objc_msgSend_698(_id, _lib._sel_setDateStyle_1, value); + return _lib._objc_msgSend_702(_id, _lib._sel_setDateStyle_1, value); } int get timeStyle { - return _lib._objc_msgSend_697(_id, _lib._sel_timeStyle1); + return _lib._objc_msgSend_701(_id, _lib._sel_timeStyle1); } set timeStyle(int value) { - return _lib._objc_msgSend_698(_id, _lib._sel_setTimeStyle_1, value); + return _lib._objc_msgSend_702(_id, _lib._sel_setTimeStyle_1, value); } NSLocale? get locale { @@ -53745,7 +53937,7 @@ class NSDateFormatter extends NSFormatter { } set locale(NSLocale? value) { - return _lib._objc_msgSend_699( + return _lib._objc_msgSend_703( _id, _lib._sel_setLocale_1, value?._id ?? ffi.nullptr); } @@ -53759,11 +53951,11 @@ class NSDateFormatter extends NSFormatter { } int get formatterBehavior { - return _lib._objc_msgSend_695(_id, _lib._sel_formatterBehavior1); + return _lib._objc_msgSend_699(_id, _lib._sel_formatterBehavior1); } set formatterBehavior(int value) { - return _lib._objc_msgSend_696(_id, _lib._sel_setFormatterBehavior_1, value); + return _lib._objc_msgSend_700(_id, _lib._sel_setFormatterBehavior_1, value); } NSTimeZone? get timeZone { @@ -53779,14 +53971,14 @@ class NSDateFormatter extends NSFormatter { } NSCalendar? get calendar { - final _ret = _lib._objc_msgSend_700(_id, _lib._sel_calendar1); + final _ret = _lib._objc_msgSend_704(_id, _lib._sel_calendar1); return _ret.address == 0 ? null : NSCalendar._(_ret, _lib, retain: true, release: true); } set calendar(NSCalendar? value) { - return _lib._objc_msgSend_706( + return _lib._objc_msgSend_710( _id, _lib._sel_setCalendar_1, value?._id ?? ffi.nullptr); } @@ -53830,7 +54022,7 @@ class NSDateFormatter extends NSFormatter { } set eraSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setEraSymbols_1, value?._id ?? ffi.nullptr); } @@ -53842,7 +54034,7 @@ class NSDateFormatter extends NSFormatter { } set monthSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setMonthSymbols_1, value?._id ?? ffi.nullptr); } @@ -53854,7 +54046,7 @@ class NSDateFormatter extends NSFormatter { } set shortMonthSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setShortMonthSymbols_1, value?._id ?? ffi.nullptr); } @@ -53866,7 +54058,7 @@ class NSDateFormatter extends NSFormatter { } set weekdaySymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setWeekdaySymbols_1, value?._id ?? ffi.nullptr); } @@ -53878,7 +54070,7 @@ class NSDateFormatter extends NSFormatter { } set shortWeekdaySymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setShortWeekdaySymbols_1, value?._id ?? ffi.nullptr); } @@ -53914,7 +54106,7 @@ class NSDateFormatter extends NSFormatter { } set longEraSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setLongEraSymbols_1, value?._id ?? ffi.nullptr); } @@ -53926,7 +54118,7 @@ class NSDateFormatter extends NSFormatter { } set veryShortMonthSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setVeryShortMonthSymbols_1, value?._id ?? ffi.nullptr); } @@ -53938,7 +54130,7 @@ class NSDateFormatter extends NSFormatter { } set standaloneMonthSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setStandaloneMonthSymbols_1, value?._id ?? ffi.nullptr); } @@ -53951,7 +54143,7 @@ class NSDateFormatter extends NSFormatter { } set shortStandaloneMonthSymbols(NSArray? value) { - return _lib._objc_msgSend_731(_id, + return _lib._objc_msgSend_735(_id, _lib._sel_setShortStandaloneMonthSymbols_1, value?._id ?? ffi.nullptr); } @@ -53964,7 +54156,7 @@ class NSDateFormatter extends NSFormatter { } set veryShortStandaloneMonthSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setVeryShortStandaloneMonthSymbols_1, value?._id ?? ffi.nullptr); @@ -53978,7 +54170,7 @@ class NSDateFormatter extends NSFormatter { } set veryShortWeekdaySymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setVeryShortWeekdaySymbols_1, value?._id ?? ffi.nullptr); } @@ -53991,7 +54183,7 @@ class NSDateFormatter extends NSFormatter { } set standaloneWeekdaySymbols(NSArray? value) { - return _lib._objc_msgSend_731(_id, _lib._sel_setStandaloneWeekdaySymbols_1, + return _lib._objc_msgSend_735(_id, _lib._sel_setStandaloneWeekdaySymbols_1, value?._id ?? ffi.nullptr); } @@ -54004,7 +54196,7 @@ class NSDateFormatter extends NSFormatter { } set shortStandaloneWeekdaySymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setShortStandaloneWeekdaySymbols_1, value?._id ?? ffi.nullptr); @@ -54019,7 +54211,7 @@ class NSDateFormatter extends NSFormatter { } set veryShortStandaloneWeekdaySymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setVeryShortStandaloneWeekdaySymbols_1, value?._id ?? ffi.nullptr); @@ -54033,7 +54225,7 @@ class NSDateFormatter extends NSFormatter { } set quarterSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setQuarterSymbols_1, value?._id ?? ffi.nullptr); } @@ -54045,7 +54237,7 @@ class NSDateFormatter extends NSFormatter { } set shortQuarterSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setShortQuarterSymbols_1, value?._id ?? ffi.nullptr); } @@ -54058,7 +54250,7 @@ class NSDateFormatter extends NSFormatter { } set standaloneQuarterSymbols(NSArray? value) { - return _lib._objc_msgSend_731(_id, _lib._sel_setStandaloneQuarterSymbols_1, + return _lib._objc_msgSend_735(_id, _lib._sel_setStandaloneQuarterSymbols_1, value?._id ?? ffi.nullptr); } @@ -54071,7 +54263,7 @@ class NSDateFormatter extends NSFormatter { } set shortStandaloneQuarterSymbols(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setShortStandaloneQuarterSymbols_1, value?._id ?? ffi.nullptr); @@ -54236,7 +54428,7 @@ class NSFormatter extends NSObject { NSAttributedString attributedStringForObjectValue_withDefaultAttributes_( NSObject obj, NSDictionary? attrs) { - final _ret = _lib._objc_msgSend_686( + final _ret = _lib._objc_msgSend_690( _id, _lib._sel_attributedStringForObjectValue_withDefaultAttributes_1, obj._id, @@ -54254,7 +54446,7 @@ class NSFormatter extends NSObject { ffi.Pointer> obj, NSString? string, ffi.Pointer> error) { - return _lib._objc_msgSend_687( + return _lib._objc_msgSend_691( _id, _lib._sel_getObjectValue_forString_errorDescription_1, obj, @@ -54266,7 +54458,7 @@ class NSFormatter extends NSObject { NSString? partialString, ffi.Pointer> newString, ffi.Pointer> error) { - return _lib._objc_msgSend_688( + return _lib._objc_msgSend_692( _id, _lib._sel_isPartialStringValid_newEditingString_errorDescription_1, partialString?._id ?? ffi.nullptr, @@ -54281,7 +54473,7 @@ class NSFormatter extends NSObject { NSString? origString, _NSRange origSelRange, ffi.Pointer> error) { - return _lib._objc_msgSend_689( + return _lib._objc_msgSend_693( _id, _lib._sel_isPartialStringValid_proposedSelectedRange_originalString_originalSelectedRange_errorDescription_1, partialStringPtr, @@ -54430,7 +54622,7 @@ class NSCalendar extends NSObject { } static NSCalendar? getCurrentCalendar(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_700( + final _ret = _lib._objc_msgSend_704( _lib._class_NSCalendar1, _lib._sel_currentCalendar1); return _ret.address == 0 ? null @@ -54438,7 +54630,7 @@ class NSCalendar extends NSObject { } static NSCalendar? getAutoupdatingCurrentCalendar(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_700( + final _ret = _lib._objc_msgSend_704( _lib._class_NSCalendar1, _lib._sel_autoupdatingCurrentCalendar1); return _ret.address == 0 ? null @@ -54447,7 +54639,7 @@ class NSCalendar extends NSObject { static NSCalendar calendarWithIdentifier_( SentryCocoa _lib, NSString calendarIdentifierConstant) { - final _ret = _lib._objc_msgSend_701(_lib._class_NSCalendar1, + final _ret = _lib._objc_msgSend_705(_lib._class_NSCalendar1, _lib._sel_calendarWithIdentifier_1, calendarIdentifierConstant._id); return NSCalendar._(_ret, _lib, retain: true, release: true); } @@ -54477,7 +54669,7 @@ class NSCalendar extends NSObject { } set locale(NSLocale? value) { - return _lib._objc_msgSend_699( + return _lib._objc_msgSend_703( _id, _lib._sel_setLocale_1, value?._id ?? ffi.nullptr); } @@ -54658,21 +54850,21 @@ class NSCalendar extends NSObject { } void minimumRangeOfUnit_(ffi.Pointer<_NSRange> stret, int unit) { - _lib._objc_msgSend_702(stret, _id, _lib._sel_minimumRangeOfUnit_1, unit); + _lib._objc_msgSend_706(stret, _id, _lib._sel_minimumRangeOfUnit_1, unit); } void maximumRangeOfUnit_(ffi.Pointer<_NSRange> stret, int unit) { - _lib._objc_msgSend_702(stret, _id, _lib._sel_maximumRangeOfUnit_1, unit); + _lib._objc_msgSend_706(stret, _id, _lib._sel_maximumRangeOfUnit_1, unit); } void rangeOfUnit_inUnit_forDate_( ffi.Pointer<_NSRange> stret, int smaller, int larger, NSDate? date) { - _lib._objc_msgSend_703(stret, _id, _lib._sel_rangeOfUnit_inUnit_forDate_1, + _lib._objc_msgSend_707(stret, _id, _lib._sel_rangeOfUnit_inUnit_forDate_1, smaller, larger, date?._id ?? ffi.nullptr); } int ordinalityOfUnit_inUnit_forDate_(int smaller, int larger, NSDate? date) { - return _lib._objc_msgSend_704( + return _lib._objc_msgSend_708( _id, _lib._sel_ordinalityOfUnit_inUnit_forDate_1, smaller, @@ -54685,7 +54877,7 @@ class NSCalendar extends NSObject { ffi.Pointer> datep, ffi.Pointer tip, NSDate? date) { - return _lib._objc_msgSend_705( + return _lib._objc_msgSend_709( _id, _lib._sel_rangeOfUnit_startDate_interval_forDate_1, unit, @@ -54695,20 +54887,20 @@ class NSCalendar extends NSObject { } NSDate dateFromComponents_(NSDateComponents? comps) { - final _ret = _lib._objc_msgSend_710( + final _ret = _lib._objc_msgSend_714( _id, _lib._sel_dateFromComponents_1, comps?._id ?? ffi.nullptr); return NSDate._(_ret, _lib, retain: true, release: true); } NSDateComponents components_fromDate_(int unitFlags, NSDate? date) { - final _ret = _lib._objc_msgSend_711(_id, _lib._sel_components_fromDate_1, + final _ret = _lib._objc_msgSend_715(_id, _lib._sel_components_fromDate_1, unitFlags, date?._id ?? ffi.nullptr); return NSDateComponents._(_ret, _lib, retain: true, release: true); } NSDate dateByAddingComponents_toDate_options_( NSDateComponents? comps, NSDate? date, int opts) { - final _ret = _lib._objc_msgSend_712( + final _ret = _lib._objc_msgSend_716( _id, _lib._sel_dateByAddingComponents_toDate_options_1, comps?._id ?? ffi.nullptr, @@ -54719,7 +54911,7 @@ class NSCalendar extends NSObject { NSDateComponents components_fromDate_toDate_options_( int unitFlags, NSDate? startingDate, NSDate? resultDate, int opts) { - final _ret = _lib._objc_msgSend_713( + final _ret = _lib._objc_msgSend_717( _id, _lib._sel_components_fromDate_toDate_options_1, unitFlags, @@ -54735,7 +54927,7 @@ class NSCalendar extends NSObject { ffi.Pointer monthValuePointer, ffi.Pointer dayValuePointer, NSDate? date) { - _lib._objc_msgSend_714( + _lib._objc_msgSend_718( _id, _lib._sel_getEra_year_month_day_fromDate_1, eraValuePointer, @@ -54751,7 +54943,7 @@ class NSCalendar extends NSObject { ffi.Pointer weekValuePointer, ffi.Pointer weekdayValuePointer, NSDate? date) { - _lib._objc_msgSend_714( + _lib._objc_msgSend_718( _id, _lib._sel_getEra_yearForWeekOfYear_weekOfYear_weekday_fromDate_1, eraValuePointer, @@ -54767,7 +54959,7 @@ class NSCalendar extends NSObject { ffi.Pointer secondValuePointer, ffi.Pointer nanosecondValuePointer, NSDate? date) { - _lib._objc_msgSend_714( + _lib._objc_msgSend_718( _id, _lib._sel_getHour_minute_second_nanosecond_fromDate_1, hourValuePointer, @@ -54778,7 +54970,7 @@ class NSCalendar extends NSObject { } int component_fromDate_(int unit, NSDate? date) { - return _lib._objc_msgSend_715( + return _lib._objc_msgSend_719( _id, _lib._sel_component_fromDate_1, unit, date?._id ?? ffi.nullptr); } @@ -54791,7 +54983,7 @@ class NSCalendar extends NSObject { int minuteValue, int secondValue, int nanosecondValue) { - final _ret = _lib._objc_msgSend_716( + final _ret = _lib._objc_msgSend_720( _id, _lib._sel_dateWithEra_year_month_day_hour_minute_second_nanosecond_1, eraValue, @@ -54815,7 +55007,7 @@ class NSCalendar extends NSObject { int minuteValue, int secondValue, int nanosecondValue) { - final _ret = _lib._objc_msgSend_716( + final _ret = _lib._objc_msgSend_720( _id, _lib._sel_dateWithEra_yearForWeekOfYear_weekOfYear_weekday_hour_minute_second_nanosecond_1, eraValue, @@ -54837,7 +55029,7 @@ class NSCalendar extends NSObject { NSDateComponents componentsInTimeZone_fromDate_( NSTimeZone? timezone, NSDate? date) { - final _ret = _lib._objc_msgSend_717( + final _ret = _lib._objc_msgSend_721( _id, _lib._sel_componentsInTimeZone_fromDate_1, timezone?._id ?? ffi.nullptr, @@ -54847,7 +55039,7 @@ class NSCalendar extends NSObject { int compareDate_toDate_toUnitGranularity_( NSDate? date1, NSDate? date2, int unit) { - return _lib._objc_msgSend_718( + return _lib._objc_msgSend_722( _id, _lib._sel_compareDate_toDate_toUnitGranularity_1, date1?._id ?? ffi.nullptr, @@ -54857,7 +55049,7 @@ class NSCalendar extends NSObject { bool isDate_equalToDate_toUnitGranularity_( NSDate? date1, NSDate? date2, int unit) { - return _lib._objc_msgSend_719( + return _lib._objc_msgSend_723( _id, _lib._sel_isDate_equalToDate_toUnitGranularity_1, date1?._id ?? ffi.nullptr, @@ -54866,7 +55058,7 @@ class NSCalendar extends NSObject { } bool isDate_inSameDayAsDate_(NSDate? date1, NSDate? date2) { - return _lib._objc_msgSend_720(_id, _lib._sel_isDate_inSameDayAsDate_1, + return _lib._objc_msgSend_724(_id, _lib._sel_isDate_inSameDayAsDate_1, date1?._id ?? ffi.nullptr, date2?._id ?? ffi.nullptr); } @@ -54894,7 +55086,7 @@ class NSCalendar extends NSObject { ffi.Pointer> datep, ffi.Pointer tip, NSDate? date) { - return _lib._objc_msgSend_721( + return _lib._objc_msgSend_725( _id, _lib._sel_rangeOfWeekendStartDate_interval_containingDate_1, datep, @@ -54907,7 +55099,7 @@ class NSCalendar extends NSObject { ffi.Pointer tip, int options, NSDate? date) { - return _lib._objc_msgSend_722( + return _lib._objc_msgSend_726( _id, _lib._sel_nextWeekendStartDate_interval_options_afterDate_1, datep, @@ -54921,7 +55113,7 @@ class NSCalendar extends NSObject { NSDateComponents? startingDateComp, NSDateComponents? resultDateComp, int options) { - final _ret = _lib._objc_msgSend_723( + final _ret = _lib._objc_msgSend_727( _id, _lib._sel_components_fromDateComponents_toDateComponents_options_1, unitFlags, @@ -54933,7 +55125,7 @@ class NSCalendar extends NSObject { NSDate dateByAddingUnit_value_toDate_options_( int unit, int value, NSDate? date, int options) { - final _ret = _lib._objc_msgSend_724( + final _ret = _lib._objc_msgSend_728( _id, _lib._sel_dateByAddingUnit_value_toDate_options_1, unit, @@ -54948,7 +55140,7 @@ class NSCalendar extends NSObject { NSDateComponents? comps, int opts, ObjCBlock_ffiVoid_NSDate_bool_bool block) { - _lib._objc_msgSend_725( + _lib._objc_msgSend_729( _id, _lib._sel_enumerateDatesStartingAfterDate_matchingComponents_options_usingBlock_1, start?._id ?? ffi.nullptr, @@ -54959,7 +55151,7 @@ class NSCalendar extends NSObject { NSDate nextDateAfterDate_matchingComponents_options_( NSDate? date, NSDateComponents? comps, int options) { - final _ret = _lib._objc_msgSend_726( + final _ret = _lib._objc_msgSend_730( _id, _lib._sel_nextDateAfterDate_matchingComponents_options_1, date?._id ?? ffi.nullptr, @@ -54970,7 +55162,7 @@ class NSCalendar extends NSObject { NSDate nextDateAfterDate_matchingUnit_value_options_( NSDate? date, int unit, int value, int options) { - final _ret = _lib._objc_msgSend_727( + final _ret = _lib._objc_msgSend_731( _id, _lib._sel_nextDateAfterDate_matchingUnit_value_options_1, date?._id ?? ffi.nullptr, @@ -54982,7 +55174,7 @@ class NSCalendar extends NSObject { NSDate nextDateAfterDate_matchingHour_minute_second_options_(NSDate? date, int hourValue, int minuteValue, int secondValue, int options) { - final _ret = _lib._objc_msgSend_728( + final _ret = _lib._objc_msgSend_732( _id, _lib._sel_nextDateAfterDate_matchingHour_minute_second_options_1, date?._id ?? ffi.nullptr, @@ -54995,7 +55187,7 @@ class NSCalendar extends NSObject { NSDate dateBySettingUnit_value_ofDate_options_( int unit, int v, NSDate? date, int opts) { - final _ret = _lib._objc_msgSend_724( + final _ret = _lib._objc_msgSend_728( _id, _lib._sel_dateBySettingUnit_value_ofDate_options_1, unit, @@ -55007,7 +55199,7 @@ class NSCalendar extends NSObject { NSDate dateBySettingHour_minute_second_ofDate_options_( int h, int m, int s, NSDate? date, int opts) { - final _ret = _lib._objc_msgSend_729( + final _ret = _lib._objc_msgSend_733( _id, _lib._sel_dateBySettingHour_minute_second_ofDate_options_1, h, @@ -55019,7 +55211,7 @@ class NSCalendar extends NSObject { } bool date_matchesComponents_(NSDate? date, NSDateComponents? components) { - return _lib._objc_msgSend_730(_id, _lib._sel_date_matchesComponents_1, + return _lib._objc_msgSend_734(_id, _lib._sel_date_matchesComponents_1, date?._id ?? ffi.nullptr, components?._id ?? ffi.nullptr); } @@ -55169,14 +55361,14 @@ class NSDateComponents extends NSObject { } NSCalendar? get calendar { - final _ret = _lib._objc_msgSend_700(_id, _lib._sel_calendar1); + final _ret = _lib._objc_msgSend_704(_id, _lib._sel_calendar1); return _ret.address == 0 ? null : NSCalendar._(_ret, _lib, retain: true, release: true); } set calendar(NSCalendar? value) { - return _lib._objc_msgSend_706( + return _lib._objc_msgSend_710( _id, _lib._sel_setCalendar_1, value?._id ?? ffi.nullptr); } @@ -55328,11 +55520,11 @@ class NSDateComponents extends NSObject { } void setValue_forComponent_(int value, int unit) { - _lib._objc_msgSend_707(_id, _lib._sel_setValue_forComponent_1, value, unit); + _lib._objc_msgSend_711(_id, _lib._sel_setValue_forComponent_1, value, unit); } int valueForComponent_(int unit) { - return _lib._objc_msgSend_708(_id, _lib._sel_valueForComponent_1, unit); + return _lib._objc_msgSend_712(_id, _lib._sel_valueForComponent_1, unit); } bool get validDate { @@ -55340,7 +55532,7 @@ class NSDateComponents extends NSObject { } bool isValidDateInCalendar_(NSCalendar? calendar) { - return _lib._objc_msgSend_709( + return _lib._objc_msgSend_713( _id, _lib._sel_isValidDateInCalendar_1, calendar?._id ?? ffi.nullptr); } @@ -55573,11 +55765,11 @@ class NSNumberFormatter extends NSFormatter { } int get formattingContext { - return _lib._objc_msgSend_690(_id, _lib._sel_formattingContext1); + return _lib._objc_msgSend_694(_id, _lib._sel_formattingContext1); } set formattingContext(int value) { - return _lib._objc_msgSend_691(_id, _lib._sel_setFormattingContext_1, value); + return _lib._objc_msgSend_695(_id, _lib._sel_setFormattingContext_1, value); } bool getObjectValue_forString_range_error_( @@ -55585,7 +55777,7 @@ class NSNumberFormatter extends NSFormatter { NSString? string, ffi.Pointer<_NSRange> rangep, ffi.Pointer> error) { - return _lib._objc_msgSend_692( + return _lib._objc_msgSend_696( _id, _lib._sel_getObjectValue_forString_range_error_1, obj, @@ -55595,20 +55787,20 @@ class NSNumberFormatter extends NSFormatter { } NSString stringFromNumber_(NSNumber? number) { - final _ret = _lib._objc_msgSend_732( + final _ret = _lib._objc_msgSend_736( _id, _lib._sel_stringFromNumber_1, number?._id ?? ffi.nullptr); return NSString._(_ret, _lib, retain: true, release: true); } NSNumber numberFromString_(NSString? string) { - final _ret = _lib._objc_msgSend_733( + final _ret = _lib._objc_msgSend_737( _id, _lib._sel_numberFromString_1, string?._id ?? ffi.nullptr); return NSNumber._(_ret, _lib, retain: true, release: true); } static NSString localizedStringFromNumber_numberStyle_( SentryCocoa _lib, NSNumber? num, int nstyle) { - final _ret = _lib._objc_msgSend_734( + final _ret = _lib._objc_msgSend_738( _lib._class_NSNumberFormatter1, _lib._sel_localizedStringFromNumber_numberStyle_1, num?._id ?? ffi.nullptr, @@ -55617,21 +55809,21 @@ class NSNumberFormatter extends NSFormatter { } static int defaultFormatterBehavior(SentryCocoa _lib) { - return _lib._objc_msgSend_735( + return _lib._objc_msgSend_739( _lib._class_NSNumberFormatter1, _lib._sel_defaultFormatterBehavior1); } static void setDefaultFormatterBehavior_(SentryCocoa _lib, int behavior) { - _lib._objc_msgSend_736(_lib._class_NSNumberFormatter1, + _lib._objc_msgSend_740(_lib._class_NSNumberFormatter1, _lib._sel_setDefaultFormatterBehavior_1, behavior); } int get numberStyle { - return _lib._objc_msgSend_737(_id, _lib._sel_numberStyle1); + return _lib._objc_msgSend_741(_id, _lib._sel_numberStyle1); } set numberStyle(int value) { - return _lib._objc_msgSend_738(_id, _lib._sel_setNumberStyle_1, value); + return _lib._objc_msgSend_742(_id, _lib._sel_setNumberStyle_1, value); } NSLocale? get locale { @@ -55642,7 +55834,7 @@ class NSNumberFormatter extends NSFormatter { } set locale(NSLocale? value) { - return _lib._objc_msgSend_699( + return _lib._objc_msgSend_703( _id, _lib._sel_setLocale_1, value?._id ?? ffi.nullptr); } @@ -55656,11 +55848,11 @@ class NSNumberFormatter extends NSFormatter { } int get formatterBehavior { - return _lib._objc_msgSend_735(_id, _lib._sel_formatterBehavior1); + return _lib._objc_msgSend_739(_id, _lib._sel_formatterBehavior1); } set formatterBehavior(int value) { - return _lib._objc_msgSend_739(_id, _lib._sel_setFormatterBehavior_1, value); + return _lib._objc_msgSend_743(_id, _lib._sel_setFormatterBehavior_1, value); } NSString? get negativeFormat { @@ -56102,19 +56294,19 @@ class NSNumberFormatter extends NSFormatter { } int get paddingPosition { - return _lib._objc_msgSend_740(_id, _lib._sel_paddingPosition1); + return _lib._objc_msgSend_744(_id, _lib._sel_paddingPosition1); } set paddingPosition(int value) { - return _lib._objc_msgSend_741(_id, _lib._sel_setPaddingPosition_1, value); + return _lib._objc_msgSend_745(_id, _lib._sel_setPaddingPosition_1, value); } int get roundingMode { - return _lib._objc_msgSend_742(_id, _lib._sel_roundingMode1); + return _lib._objc_msgSend_746(_id, _lib._sel_roundingMode1); } set roundingMode(int value) { - return _lib._objc_msgSend_743(_id, _lib._sel_setRoundingMode_1, value); + return _lib._objc_msgSend_747(_id, _lib._sel_setRoundingMode_1, value); } NSNumber? get roundingIncrement { @@ -56290,53 +56482,53 @@ class NSNumberFormatter extends NSFormatter { NSAttributedString? get attributedStringForZero { final _ret = - _lib._objc_msgSend_675(_id, _lib._sel_attributedStringForZero1); + _lib._objc_msgSend_679(_id, _lib._sel_attributedStringForZero1); return _ret.address == 0 ? null : NSAttributedString._(_ret, _lib, retain: true, release: true); } set attributedStringForZero(NSAttributedString? value) { - return _lib._objc_msgSend_744( + return _lib._objc_msgSend_748( _id, _lib._sel_setAttributedStringForZero_1, value?._id ?? ffi.nullptr); } NSAttributedString? get attributedStringForNil { - final _ret = _lib._objc_msgSend_675(_id, _lib._sel_attributedStringForNil1); + final _ret = _lib._objc_msgSend_679(_id, _lib._sel_attributedStringForNil1); return _ret.address == 0 ? null : NSAttributedString._(_ret, _lib, retain: true, release: true); } set attributedStringForNil(NSAttributedString? value) { - return _lib._objc_msgSend_744( + return _lib._objc_msgSend_748( _id, _lib._sel_setAttributedStringForNil_1, value?._id ?? ffi.nullptr); } NSAttributedString? get attributedStringForNotANumber { final _ret = - _lib._objc_msgSend_675(_id, _lib._sel_attributedStringForNotANumber1); + _lib._objc_msgSend_679(_id, _lib._sel_attributedStringForNotANumber1); return _ret.address == 0 ? null : NSAttributedString._(_ret, _lib, retain: true, release: true); } set attributedStringForNotANumber(NSAttributedString? value) { - return _lib._objc_msgSend_744( + return _lib._objc_msgSend_748( _id, _lib._sel_setAttributedStringForNotANumber_1, value?._id ?? ffi.nullptr); } NSDecimalNumberHandler? get roundingBehavior { - final _ret = _lib._objc_msgSend_745(_id, _lib._sel_roundingBehavior1); + final _ret = _lib._objc_msgSend_749(_id, _lib._sel_roundingBehavior1); return _ret.address == 0 ? null : NSDecimalNumberHandler._(_ret, _lib, retain: true, release: true); } set roundingBehavior(NSDecimalNumberHandler? value) { - return _lib._objc_msgSend_747( + return _lib._objc_msgSend_751( _id, _lib._sel_setRoundingBehavior_1, value?._id ?? ffi.nullptr); } @@ -56496,7 +56688,7 @@ class NSDecimalNumberHandler extends NSObject { static NSDecimalNumberHandler? getDefaultDecimalNumberHandler( SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_745(_lib._class_NSDecimalNumberHandler1, + final _ret = _lib._objc_msgSend_749(_lib._class_NSDecimalNumberHandler1, _lib._sel_defaultDecimalNumberHandler1); return _ret.address == 0 ? null @@ -56511,7 +56703,7 @@ class NSDecimalNumberHandler extends NSObject { bool overflow, bool underflow, bool divideByZero) { - final _ret = _lib._objc_msgSend_746( + final _ret = _lib._objc_msgSend_750( _id, _lib._sel_initWithRoundingMode_scale_raiseOnExactness_raiseOnOverflow_raiseOnUnderflow_raiseOnDivideByZero_1, roundingMode, @@ -56532,7 +56724,7 @@ class NSDecimalNumberHandler extends NSObject { bool overflow, bool underflow, bool divideByZero) { - final _ret = _lib._objc_msgSend_746( + final _ret = _lib._objc_msgSend_750( _lib._class_NSDecimalNumberHandler1, _lib._sel_decimalNumberHandlerWithRoundingMode_scale_raiseOnExactness_raiseOnOverflow_raiseOnUnderflow_raiseOnDivideByZero_1, roundingMode, @@ -56690,7 +56882,7 @@ class NSScanner extends NSObject { } set charactersToBeSkipped(NSCharacterSet? value) { - return _lib._objc_msgSend_748( + return _lib._objc_msgSend_752( _id, _lib._sel_setCharactersToBeSkipped_1, value?._id ?? ffi.nullptr); } @@ -56718,55 +56910,55 @@ class NSScanner extends NSObject { } bool scanInt_(ffi.Pointer result) { - return _lib._objc_msgSend_749(_id, _lib._sel_scanInt_1, result); + return _lib._objc_msgSend_753(_id, _lib._sel_scanInt_1, result); } bool scanInteger_(ffi.Pointer result) { - return _lib._objc_msgSend_750(_id, _lib._sel_scanInteger_1, result); + return _lib._objc_msgSend_754(_id, _lib._sel_scanInteger_1, result); } bool scanLongLong_(ffi.Pointer result) { - return _lib._objc_msgSend_751(_id, _lib._sel_scanLongLong_1, result); + return _lib._objc_msgSend_755(_id, _lib._sel_scanLongLong_1, result); } bool scanUnsignedLongLong_(ffi.Pointer result) { - return _lib._objc_msgSend_752( + return _lib._objc_msgSend_756( _id, _lib._sel_scanUnsignedLongLong_1, result); } bool scanFloat_(ffi.Pointer result) { - return _lib._objc_msgSend_753(_id, _lib._sel_scanFloat_1, result); + return _lib._objc_msgSend_757(_id, _lib._sel_scanFloat_1, result); } bool scanDouble_(ffi.Pointer result) { - return _lib._objc_msgSend_754(_id, _lib._sel_scanDouble_1, result); + return _lib._objc_msgSend_758(_id, _lib._sel_scanDouble_1, result); } bool scanHexInt_(ffi.Pointer result) { - return _lib._objc_msgSend_755(_id, _lib._sel_scanHexInt_1, result); + return _lib._objc_msgSend_759(_id, _lib._sel_scanHexInt_1, result); } bool scanHexLongLong_(ffi.Pointer result) { - return _lib._objc_msgSend_752(_id, _lib._sel_scanHexLongLong_1, result); + return _lib._objc_msgSend_756(_id, _lib._sel_scanHexLongLong_1, result); } bool scanHexFloat_(ffi.Pointer result) { - return _lib._objc_msgSend_753(_id, _lib._sel_scanHexFloat_1, result); + return _lib._objc_msgSend_757(_id, _lib._sel_scanHexFloat_1, result); } bool scanHexDouble_(ffi.Pointer result) { - return _lib._objc_msgSend_754(_id, _lib._sel_scanHexDouble_1, result); + return _lib._objc_msgSend_758(_id, _lib._sel_scanHexDouble_1, result); } bool scanString_intoString_( NSString? string, ffi.Pointer> result) { - return _lib._objc_msgSend_756(_id, _lib._sel_scanString_intoString_1, + return _lib._objc_msgSend_760(_id, _lib._sel_scanString_intoString_1, string?._id ?? ffi.nullptr, result); } bool scanCharactersFromSet_intoString_( NSCharacterSet? set, ffi.Pointer> result) { - return _lib._objc_msgSend_757( + return _lib._objc_msgSend_761( _id, _lib._sel_scanCharactersFromSet_intoString_1, set?._id ?? ffi.nullptr, @@ -56775,13 +56967,13 @@ class NSScanner extends NSObject { bool scanUpToString_intoString_( NSString? string, ffi.Pointer> result) { - return _lib._objc_msgSend_756(_id, _lib._sel_scanUpToString_intoString_1, + return _lib._objc_msgSend_760(_id, _lib._sel_scanUpToString_intoString_1, string?._id ?? ffi.nullptr, result); } bool scanUpToCharactersFromSet_intoString_( NSCharacterSet? set, ffi.Pointer> result) { - return _lib._objc_msgSend_757( + return _lib._objc_msgSend_761( _id, _lib._sel_scanUpToCharactersFromSet_intoString_1, set?._id ?? ffi.nullptr, @@ -56806,7 +56998,7 @@ class NSScanner extends NSObject { } bool scanDecimal_(ffi.Pointer dcm) { - return _lib._objc_msgSend_758(_id, _lib._sel_scanDecimal_1, dcm); + return _lib._objc_msgSend_762(_id, _lib._sel_scanDecimal_1, dcm); } @override @@ -56926,7 +57118,7 @@ class NSException extends NSObject { static NSException exceptionWithName_reason_userInfo_(SentryCocoa _lib, NSString name, NSString? reason, NSDictionary? userInfo) { - final _ret = _lib._objc_msgSend_759( + final _ret = _lib._objc_msgSend_763( _lib._class_NSException1, _lib._sel_exceptionWithName_reason_userInfo_1, name._id, @@ -56991,7 +57183,7 @@ class NSException extends NSObject { static void raise_format_arguments_(SentryCocoa _lib, NSString name, NSString? format, ffi.Pointer<__va_list_tag> argList) { - _lib._objc_msgSend_760( + _lib._objc_msgSend_764( _lib._class_NSException1, _lib._sel_raise_format_arguments_1, name._id, @@ -57122,7 +57314,7 @@ class NSFileHandle extends NSObject { } NSFileHandle initWithFileDescriptor_closeOnDealloc_(int fd, bool closeopt) { - final _ret = _lib._objc_msgSend_761( + final _ret = _lib._objc_msgSend_765( _id, _lib._sel_initWithFileDescriptor_closeOnDealloc_1, fd, closeopt); return NSFileHandle._(_ret, _lib, retain: true, release: true); } @@ -57135,46 +57327,46 @@ class NSFileHandle extends NSObject { NSData readDataToEndOfFileAndReturnError_( ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_762( + final _ret = _lib._objc_msgSend_766( _id, _lib._sel_readDataToEndOfFileAndReturnError_1, error); return NSData._(_ret, _lib, retain: true, release: true); } NSData readDataUpToLength_error_( int length, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_763( + final _ret = _lib._objc_msgSend_767( _id, _lib._sel_readDataUpToLength_error_1, length, error); return NSData._(_ret, _lib, retain: true, release: true); } bool writeData_error_( NSData? data, ffi.Pointer> error) { - return _lib._objc_msgSend_764( + return _lib._objc_msgSend_768( _id, _lib._sel_writeData_error_1, data?._id ?? ffi.nullptr, error); } bool getOffset_error_(ffi.Pointer offsetInFile, ffi.Pointer> error) { - return _lib._objc_msgSend_765( + return _lib._objc_msgSend_769( _id, _lib._sel_getOffset_error_1, offsetInFile, error); } bool seekToEndReturningOffset_error_( ffi.Pointer offsetInFile, ffi.Pointer> error) { - return _lib._objc_msgSend_765( + return _lib._objc_msgSend_769( _id, _lib._sel_seekToEndReturningOffset_error_1, offsetInFile, error); } bool seekToOffset_error_( int offset, ffi.Pointer> error) { - return _lib._objc_msgSend_766( + return _lib._objc_msgSend_770( _id, _lib._sel_seekToOffset_error_1, offset, error); } bool truncateAtOffset_error_( int offset, ffi.Pointer> error) { - return _lib._objc_msgSend_766( + return _lib._objc_msgSend_770( _id, _lib._sel_truncateAtOffset_error_1, offset, error); } @@ -57188,7 +57380,7 @@ class NSFileHandle extends NSObject { } static NSFileHandle? getFileHandleWithStandardInput(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_767( + final _ret = _lib._objc_msgSend_771( _lib._class_NSFileHandle1, _lib._sel_fileHandleWithStandardInput1); return _ret.address == 0 ? null @@ -57196,7 +57388,7 @@ class NSFileHandle extends NSObject { } static NSFileHandle? getFileHandleWithStandardOutput(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_767( + final _ret = _lib._objc_msgSend_771( _lib._class_NSFileHandle1, _lib._sel_fileHandleWithStandardOutput1); return _ret.address == 0 ? null @@ -57204,7 +57396,7 @@ class NSFileHandle extends NSObject { } static NSFileHandle? getFileHandleWithStandardError(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_767( + final _ret = _lib._objc_msgSend_771( _lib._class_NSFileHandle1, _lib._sel_fileHandleWithStandardError1); return _ret.address == 0 ? null @@ -57212,7 +57404,7 @@ class NSFileHandle extends NSObject { } static NSFileHandle? getFileHandleWithNullDevice(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_767( + final _ret = _lib._objc_msgSend_771( _lib._class_NSFileHandle1, _lib._sel_fileHandleWithNullDevice1); return _ret.address == 0 ? null @@ -57242,7 +57434,7 @@ class NSFileHandle extends NSObject { static NSFileHandle fileHandleForReadingFromURL_error_(SentryCocoa _lib, NSURL? url, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_768( + final _ret = _lib._objc_msgSend_772( _lib._class_NSFileHandle1, _lib._sel_fileHandleForReadingFromURL_error_1, url?._id ?? ffi.nullptr, @@ -57252,7 +57444,7 @@ class NSFileHandle extends NSObject { static NSFileHandle fileHandleForWritingToURL_error_(SentryCocoa _lib, NSURL? url, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_768( + final _ret = _lib._objc_msgSend_772( _lib._class_NSFileHandle1, _lib._sel_fileHandleForWritingToURL_error_1, url?._id ?? ffi.nullptr, @@ -57262,7 +57454,7 @@ class NSFileHandle extends NSObject { static NSFileHandle fileHandleForUpdatingURL_error_(SentryCocoa _lib, NSURL? url, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_768( + final _ret = _lib._objc_msgSend_772( _lib._class_NSFileHandle1, _lib._sel_fileHandleForUpdatingURL_error_1, url?._id ?? ffi.nullptr, @@ -57313,28 +57505,28 @@ class NSFileHandle extends NSObject { } ObjCBlock_ffiVoid_NSFileHandle get readabilityHandler { - final _ret = _lib._objc_msgSend_769(_id, _lib._sel_readabilityHandler1); + final _ret = _lib._objc_msgSend_773(_id, _lib._sel_readabilityHandler1); return ObjCBlock_ffiVoid_NSFileHandle._(_ret, _lib); } set readabilityHandler(ObjCBlock_ffiVoid_NSFileHandle value) { - return _lib._objc_msgSend_770( + return _lib._objc_msgSend_774( _id, _lib._sel_setReadabilityHandler_1, value._id); } ObjCBlock_ffiVoid_NSFileHandle get writeabilityHandler { - final _ret = _lib._objc_msgSend_769(_id, _lib._sel_writeabilityHandler1); + final _ret = _lib._objc_msgSend_773(_id, _lib._sel_writeabilityHandler1); return ObjCBlock_ffiVoid_NSFileHandle._(_ret, _lib); } set writeabilityHandler(ObjCBlock_ffiVoid_NSFileHandle value) { - return _lib._objc_msgSend_770( + return _lib._objc_msgSend_774( _id, _lib._sel_setWriteabilityHandler_1, value._id); } NSFileHandle initWithFileDescriptor_(int fd) { final _ret = - _lib._objc_msgSend_771(_id, _lib._sel_initWithFileDescriptor_1, fd); + _lib._objc_msgSend_775(_id, _lib._sel_initWithFileDescriptor_1, fd); return NSFileHandle._(_ret, _lib, retain: true, release: true); } @@ -57367,11 +57559,11 @@ class NSFileHandle extends NSObject { } void seekToFileOffset_(int offset) { - _lib._objc_msgSend_772(_id, _lib._sel_seekToFileOffset_1, offset); + _lib._objc_msgSend_776(_id, _lib._sel_seekToFileOffset_1, offset); } void truncateFileAtOffset_(int offset) { - _lib._objc_msgSend_772(_id, _lib._sel_truncateFileAtOffset_1, offset); + _lib._objc_msgSend_776(_id, _lib._sel_truncateFileAtOffset_1, offset); } void synchronizeFile() { @@ -57570,7 +57762,7 @@ class NSHTTPCookieStorage extends NSObject { } static NSHTTPCookieStorage? getSharedHTTPCookieStorage(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_773( + final _ret = _lib._objc_msgSend_777( _lib._class_NSHTTPCookieStorage1, _lib._sel_sharedHTTPCookieStorage1); return _ret.address == 0 ? null @@ -57579,7 +57771,7 @@ class NSHTTPCookieStorage extends NSObject { static NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier_( SentryCocoa _lib, NSString? identifier) { - final _ret = _lib._objc_msgSend_774( + final _ret = _lib._objc_msgSend_778( _lib._class_NSHTTPCookieStorage1, _lib._sel_sharedCookieStorageForGroupContainerIdentifier_1, identifier?._id ?? ffi.nullptr); @@ -57594,12 +57786,12 @@ class NSHTTPCookieStorage extends NSObject { } void setCookie_(NSHTTPCookie? cookie) { - _lib._objc_msgSend_777( + _lib._objc_msgSend_781( _id, _lib._sel_setCookie_1, cookie?._id ?? ffi.nullptr); } void deleteCookie_(NSHTTPCookie? cookie) { - _lib._objc_msgSend_777( + _lib._objc_msgSend_781( _id, _lib._sel_deleteCookie_1, cookie?._id ?? ffi.nullptr); } @@ -57616,7 +57808,7 @@ class NSHTTPCookieStorage extends NSObject { void setCookies_forURL_mainDocumentURL_( NSArray? cookies, NSURL? URL, NSURL? mainDocumentURL) { - _lib._objc_msgSend_778( + _lib._objc_msgSend_782( _id, _lib._sel_setCookies_forURL_mainDocumentURL_1, cookies?._id ?? ffi.nullptr, @@ -57625,11 +57817,11 @@ class NSHTTPCookieStorage extends NSObject { } int get cookieAcceptPolicy { - return _lib._objc_msgSend_779(_id, _lib._sel_cookieAcceptPolicy1); + return _lib._objc_msgSend_783(_id, _lib._sel_cookieAcceptPolicy1); } set cookieAcceptPolicy(int value) { - return _lib._objc_msgSend_780( + return _lib._objc_msgSend_784( _id, _lib._sel_setCookieAcceptPolicy_1, value); } @@ -57642,13 +57834,13 @@ class NSHTTPCookieStorage extends NSObject { } void storeCookies_forTask_(NSArray? cookies, NSURLSessionTask? task) { - _lib._objc_msgSend_800(_id, _lib._sel_storeCookies_forTask_1, + _lib._objc_msgSend_804(_id, _lib._sel_storeCookies_forTask_1, cookies?._id ?? ffi.nullptr, task?._id ?? ffi.nullptr); } void getCookiesForTask_completionHandler_( NSURLSessionTask? task, ObjCBlock_ffiVoid_NSArray completionHandler) { - _lib._objc_msgSend_801(_id, _lib._sel_getCookiesForTask_completionHandler_1, + _lib._objc_msgSend_805(_id, _lib._sel_getCookiesForTask_completionHandler_1, task?._id ?? ffi.nullptr, completionHandler._id); } @@ -57776,7 +57968,7 @@ class NSHTTPCookie extends NSObject { static NSHTTPCookie cookieWithProperties_( SentryCocoa _lib, NSDictionary? properties) { - final _ret = _lib._objc_msgSend_775(_lib._class_NSHTTPCookie1, + final _ret = _lib._objc_msgSend_779(_lib._class_NSHTTPCookie1, _lib._sel_cookieWithProperties_1, properties?._id ?? ffi.nullptr); return NSHTTPCookie._(_ret, _lib, retain: true, release: true); } @@ -57792,7 +57984,7 @@ class NSHTTPCookie extends NSObject { static NSArray cookiesWithResponseHeaderFields_forURL_( SentryCocoa _lib, NSDictionary? headerFields, NSURL? URL) { - final _ret = _lib._objc_msgSend_776( + final _ret = _lib._objc_msgSend_780( _lib._class_NSHTTPCookie1, _lib._sel_cookiesWithResponseHeaderFields_forURL_1, headerFields?._id ?? ffi.nullptr, @@ -58012,21 +58204,21 @@ class NSURLSessionTask extends NSObject { } NSURLRequest? get originalRequest { - final _ret = _lib._objc_msgSend_795(_id, _lib._sel_originalRequest1); + final _ret = _lib._objc_msgSend_799(_id, _lib._sel_originalRequest1); return _ret.address == 0 ? null : NSURLRequest._(_ret, _lib, retain: true, release: true); } NSURLRequest? get currentRequest { - final _ret = _lib._objc_msgSend_795(_id, _lib._sel_currentRequest1); + final _ret = _lib._objc_msgSend_799(_id, _lib._sel_currentRequest1); return _ret.address == 0 ? null : NSURLRequest._(_ret, _lib, retain: true, release: true); } NSURLResponse? get response { - final _ret = _lib._objc_msgSend_797(_id, _lib._sel_response1); + final _ret = _lib._objc_msgSend_801(_id, _lib._sel_response1); return _ret.address == 0 ? null : NSURLResponse._(_ret, _lib, retain: true, release: true); @@ -58117,7 +58309,7 @@ class NSURLSessionTask extends NSObject { } int get state { - return _lib._objc_msgSend_798(_id, _lib._sel_state1); + return _lib._objc_msgSend_802(_id, _lib._sel_state1); } NSError? get error { @@ -58140,7 +58332,7 @@ class NSURLSessionTask extends NSObject { } set priority(double value) { - return _lib._objc_msgSend_799(_id, _lib._sel_setPriority_1, value); + return _lib._objc_msgSend_803(_id, _lib._sel_setPriority_1, value); } bool get prefersIncrementalDelivery { @@ -58281,7 +58473,7 @@ class NSURLRequest extends NSObject { static NSURLRequest requestWithURL_cachePolicy_timeoutInterval_( SentryCocoa _lib, NSURL? URL, int cachePolicy, double timeoutInterval) { - final _ret = _lib._objc_msgSend_781( + final _ret = _lib._objc_msgSend_785( _lib._class_NSURLRequest1, _lib._sel_requestWithURL_cachePolicy_timeoutInterval_1, URL?._id ?? ffi.nullptr, @@ -58298,7 +58490,7 @@ class NSURLRequest extends NSObject { NSURLRequest initWithURL_cachePolicy_timeoutInterval_( NSURL? URL, int cachePolicy, double timeoutInterval) { - final _ret = _lib._objc_msgSend_781( + final _ret = _lib._objc_msgSend_785( _id, _lib._sel_initWithURL_cachePolicy_timeoutInterval_1, URL?._id ?? ffi.nullptr, @@ -58315,7 +58507,7 @@ class NSURLRequest extends NSObject { } int get cachePolicy { - return _lib._objc_msgSend_782(_id, _lib._sel_cachePolicy1); + return _lib._objc_msgSend_786(_id, _lib._sel_cachePolicy1); } double get timeoutInterval { @@ -58330,7 +58522,7 @@ class NSURLRequest extends NSObject { } int get networkServiceType { - return _lib._objc_msgSend_783(_id, _lib._sel_networkServiceType1); + return _lib._objc_msgSend_787(_id, _lib._sel_networkServiceType1); } bool get allowsCellularAccess { @@ -58351,7 +58543,7 @@ class NSURLRequest extends NSObject { } int get attribution { - return _lib._objc_msgSend_784(_id, _lib._sel_attribution1); + return _lib._objc_msgSend_788(_id, _lib._sel_attribution1); } bool get requiresDNSSECValidation { @@ -58386,7 +58578,7 @@ class NSURLRequest extends NSObject { } NSInputStream? get HTTPBodyStream { - final _ret = _lib._objc_msgSend_794(_id, _lib._sel_HTTPBodyStream1); + final _ret = _lib._objc_msgSend_798(_id, _lib._sel_HTTPBodyStream1); return _ret.address == 0 ? null : NSInputStream._(_ret, _lib, retain: true, release: true); @@ -58544,12 +58736,12 @@ class NSInputStream extends NSStream { } int read_maxLength_(ffi.Pointer buffer, int len) { - return _lib._objc_msgSend_786(_id, _lib._sel_read_maxLength_1, buffer, len); + return _lib._objc_msgSend_790(_id, _lib._sel_read_maxLength_1, buffer, len); } bool getBuffer_length_(ffi.Pointer> buffer, ffi.Pointer len) { - return _lib._objc_msgSend_793( + return _lib._objc_msgSend_797( _id, _lib._sel_getBuffer_length_1, buffer, len); } @@ -58600,7 +58792,7 @@ class NSInputStream extends NSStream { int port, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_788( + _lib._objc_msgSend_792( _lib._class_NSInputStream1, _lib._sel_getStreamsToHostWithName_port_inputStream_outputStream_1, hostname?._id ?? ffi.nullptr, @@ -58615,7 +58807,7 @@ class NSInputStream extends NSStream { int port, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_791( + _lib._objc_msgSend_795( _lib._class_NSInputStream1, _lib._sel_getStreamsToHost_port_inputStream_outputStream_1, host?._id ?? ffi.nullptr, @@ -58629,7 +58821,7 @@ class NSInputStream extends NSStream { int bufferSize, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_792( + _lib._objc_msgSend_796( _lib._class_NSInputStream1, _lib._sel_getBoundStreamsWithBufferSize_inputStream_outputStream_1, bufferSize, @@ -58795,7 +58987,7 @@ class NSStream extends NSObject { } int get streamStatus { - return _lib._objc_msgSend_785(_id, _lib._sel_streamStatus1); + return _lib._objc_msgSend_789(_id, _lib._sel_streamStatus1); } NSError? get streamError { @@ -58811,7 +59003,7 @@ class NSStream extends NSObject { int port, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_788( + _lib._objc_msgSend_792( _lib._class_NSStream1, _lib._sel_getStreamsToHostWithName_port_inputStream_outputStream_1, hostname?._id ?? ffi.nullptr, @@ -58826,7 +59018,7 @@ class NSStream extends NSObject { int port, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_791( + _lib._objc_msgSend_795( _lib._class_NSStream1, _lib._sel_getStreamsToHost_port_inputStream_outputStream_1, host?._id ?? ffi.nullptr, @@ -58840,7 +59032,7 @@ class NSStream extends NSObject { int bufferSize, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_792( + _lib._objc_msgSend_796( _lib._class_NSStream1, _lib._sel_getBoundStreamsWithBufferSize_inputStream_outputStream_1, bufferSize, @@ -58973,7 +59165,7 @@ class NSOutputStream extends NSStream { } int write_maxLength_(ffi.Pointer buffer, int len) { - return _lib._objc_msgSend_786( + return _lib._objc_msgSend_790( _id, _lib._sel_write_maxLength_1, buffer, len); } @@ -58988,7 +59180,7 @@ class NSOutputStream extends NSStream { NSOutputStream initToBuffer_capacity_( ffi.Pointer buffer, int capacity) { - final _ret = _lib._objc_msgSend_787( + final _ret = _lib._objc_msgSend_791( _id, _lib._sel_initToBuffer_capacity_1, buffer, capacity); return NSOutputStream._(_ret, _lib, retain: true, release: true); } @@ -59013,7 +59205,7 @@ class NSOutputStream extends NSStream { static NSOutputStream outputStreamToBuffer_capacity_( SentryCocoa _lib, ffi.Pointer buffer, int capacity) { - final _ret = _lib._objc_msgSend_787(_lib._class_NSOutputStream1, + final _ret = _lib._objc_msgSend_791(_lib._class_NSOutputStream1, _lib._sel_outputStreamToBuffer_capacity_1, buffer, capacity); return NSOutputStream._(_ret, _lib, retain: true, release: true); } @@ -59044,7 +59236,7 @@ class NSOutputStream extends NSStream { int port, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_788( + _lib._objc_msgSend_792( _lib._class_NSOutputStream1, _lib._sel_getStreamsToHostWithName_port_inputStream_outputStream_1, hostname?._id ?? ffi.nullptr, @@ -59059,7 +59251,7 @@ class NSOutputStream extends NSStream { int port, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_791( + _lib._objc_msgSend_795( _lib._class_NSOutputStream1, _lib._sel_getStreamsToHost_port_inputStream_outputStream_1, host?._id ?? ffi.nullptr, @@ -59073,7 +59265,7 @@ class NSOutputStream extends NSStream { int bufferSize, ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - _lib._objc_msgSend_792( + _lib._objc_msgSend_796( _lib._class_NSOutputStream1, _lib._sel_getBoundStreamsWithBufferSize_inputStream_outputStream_1, bufferSize, @@ -59215,7 +59407,7 @@ class NSHost extends NSObject { } bool isEqualToHost_(NSHost? aHost) { - return _lib._objc_msgSend_789( + return _lib._objc_msgSend_793( _id, _lib._sel_isEqualToHost_1, aHost?._id ?? ffi.nullptr); } @@ -59255,7 +59447,7 @@ class NSHost extends NSObject { } static void setHostCacheEnabled_(SentryCocoa _lib, bool flag) { - _lib._objc_msgSend_790( + _lib._objc_msgSend_794( _lib._class_NSHost1, _lib._sel_setHostCacheEnabled_1, flag); } @@ -59383,7 +59575,7 @@ class NSURLResponse extends NSObject { NSURLResponse initWithURL_MIMEType_expectedContentLength_textEncodingName_( NSURL? URL, NSString? MIMEType, int length, NSString? name) { - final _ret = _lib._objc_msgSend_796( + final _ret = _lib._objc_msgSend_800( _id, _lib._sel_initWithURL_MIMEType_expectedContentLength_textEncodingName_1, URL?._id ?? ffi.nullptr, @@ -59625,14 +59817,14 @@ class NSIndexPath extends NSObject { static NSIndexPath indexPathWithIndexes_length_( SentryCocoa _lib, ffi.Pointer indexes, int length) { - final _ret = _lib._objc_msgSend_802(_lib._class_NSIndexPath1, + final _ret = _lib._objc_msgSend_806(_lib._class_NSIndexPath1, _lib._sel_indexPathWithIndexes_length_1, indexes, length); return NSIndexPath._(_ret, _lib, retain: true, release: true); } NSIndexPath initWithIndexes_length_( ffi.Pointer indexes, int length) { - final _ret = _lib._objc_msgSend_802( + final _ret = _lib._objc_msgSend_806( _id, _lib._sel_initWithIndexes_length_1, indexes, length); return NSIndexPath._(_ret, _lib, retain: true, release: true); } @@ -59644,13 +59836,13 @@ class NSIndexPath extends NSObject { NSIndexPath indexPathByAddingIndex_(int index) { final _ret = - _lib._objc_msgSend_803(_id, _lib._sel_indexPathByAddingIndex_1, index); + _lib._objc_msgSend_807(_id, _lib._sel_indexPathByAddingIndex_1, index); return NSIndexPath._(_ret, _lib, retain: true, release: true); } NSIndexPath indexPathByRemovingLastIndex() { final _ret = - _lib._objc_msgSend_804(_id, _lib._sel_indexPathByRemovingLastIndex1); + _lib._objc_msgSend_808(_id, _lib._sel_indexPathByRemovingLastIndex1); return NSIndexPath._(_ret, _lib, retain: true, release: true); } @@ -59664,17 +59856,17 @@ class NSIndexPath extends NSObject { void getIndexes_range_( ffi.Pointer indexes, _NSRange positionRange) { - _lib._objc_msgSend_805( + _lib._objc_msgSend_809( _id, _lib._sel_getIndexes_range_1, indexes, positionRange); } int compare_(NSIndexPath? otherObject) { - return _lib._objc_msgSend_806( + return _lib._objc_msgSend_810( _id, _lib._sel_compare_1, otherObject?._id ?? ffi.nullptr); } void getIndexes_(ffi.Pointer indexes) { - _lib._objc_msgSend_807(_id, _lib._sel_getIndexes_1, indexes); + _lib._objc_msgSend_811(_id, _lib._sel_getIndexes_1, indexes); } @override @@ -59800,7 +59992,7 @@ class NSInflectionRule extends NSObject { } static NSInflectionRule? getAutomaticRule(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_808( + final _ret = _lib._objc_msgSend_812( _lib._class_NSInflectionRule1, _lib._sel_automaticRule1); return _ret.address == 0 ? null @@ -59928,38 +60120,78 @@ class NSMorphology extends NSObject { } int get grammaticalGender { - return _lib._objc_msgSend_809(_id, _lib._sel_grammaticalGender1); + return _lib._objc_msgSend_813(_id, _lib._sel_grammaticalGender1); } set grammaticalGender(int value) { - return _lib._objc_msgSend_810(_id, _lib._sel_setGrammaticalGender_1, value); + return _lib._objc_msgSend_814(_id, _lib._sel_setGrammaticalGender_1, value); } int get partOfSpeech { - return _lib._objc_msgSend_811(_id, _lib._sel_partOfSpeech1); + return _lib._objc_msgSend_815(_id, _lib._sel_partOfSpeech1); } set partOfSpeech(int value) { - return _lib._objc_msgSend_812(_id, _lib._sel_setPartOfSpeech_1, value); + return _lib._objc_msgSend_816(_id, _lib._sel_setPartOfSpeech_1, value); } int get number { - return _lib._objc_msgSend_813(_id, _lib._sel_number1); + return _lib._objc_msgSend_817(_id, _lib._sel_number1); } set number(int value) { - return _lib._objc_msgSend_814(_id, _lib._sel_setNumber_1, value); + return _lib._objc_msgSend_818(_id, _lib._sel_setNumber_1, value); + } + + int get grammaticalCase { + return _lib._objc_msgSend_819(_id, _lib._sel_grammaticalCase1); + } + + set grammaticalCase(int value) { + return _lib._objc_msgSend_820(_id, _lib._sel_setGrammaticalCase_1, value); + } + + int get determination { + return _lib._objc_msgSend_821(_id, _lib._sel_determination1); + } + + set determination(int value) { + return _lib._objc_msgSend_822(_id, _lib._sel_setDetermination_1, value); + } + + int get grammaticalPerson { + return _lib._objc_msgSend_823(_id, _lib._sel_grammaticalPerson1); + } + + set grammaticalPerson(int value) { + return _lib._objc_msgSend_824(_id, _lib._sel_setGrammaticalPerson_1, value); + } + + int get pronounType { + return _lib._objc_msgSend_825(_id, _lib._sel_pronounType1); + } + + set pronounType(int value) { + return _lib._objc_msgSend_826(_id, _lib._sel_setPronounType_1, value); + } + + int get definiteness { + return _lib._objc_msgSend_827(_id, _lib._sel_definiteness1); + } + + set definiteness(int value) { + return _lib._objc_msgSend_828(_id, _lib._sel_setDefiniteness_1, value); } NSMorphologyCustomPronoun customPronounForLanguage_(NSString? language) { - final _ret = _lib._objc_msgSend_815(_id, + final _ret = _lib._objc_msgSend_829(_id, _lib._sel_customPronounForLanguage_1, language?._id ?? ffi.nullptr); return NSMorphologyCustomPronoun._(_ret, _lib, retain: true, release: true); } bool setCustomPronoun_forLanguage_error_(NSMorphologyCustomPronoun? features, NSString? language, ffi.Pointer> error) { - return _lib._objc_msgSend_816( + return _lib._objc_msgSend_830( _id, _lib._sel_setCustomPronoun_forLanguage_error_1, features?._id ?? ffi.nullptr, @@ -59972,7 +60204,7 @@ class NSMorphology extends NSObject { } static NSMorphology? getUserMorphology(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_817( + final _ret = _lib._objc_msgSend_831( _lib._class_NSMorphology1, _lib._sel_userMorphology1); return _ret.address == 0 ? null @@ -60107,6 +60339,50 @@ abstract class NSGrammaticalNumber { static const int NSGrammaticalNumberPluralMany = 6; } +abstract class NSGrammaticalCase { + static const int NSGrammaticalCaseNotSet = 0; + static const int NSGrammaticalCaseNominative = 1; + static const int NSGrammaticalCaseAccusative = 2; + static const int NSGrammaticalCaseDative = 3; + static const int NSGrammaticalCaseGenitive = 4; + static const int NSGrammaticalCasePrepositional = 5; + static const int NSGrammaticalCaseAblative = 6; + static const int NSGrammaticalCaseAdessive = 7; + static const int NSGrammaticalCaseAllative = 8; + static const int NSGrammaticalCaseElative = 9; + static const int NSGrammaticalCaseIllative = 10; + static const int NSGrammaticalCaseEssive = 11; + static const int NSGrammaticalCaseInessive = 12; + static const int NSGrammaticalCaseLocative = 13; + static const int NSGrammaticalCaseTranslative = 14; +} + +abstract class NSGrammaticalDetermination { + static const int NSGrammaticalDeterminationNotSet = 0; + static const int NSGrammaticalDeterminationIndependent = 1; + static const int NSGrammaticalDeterminationDependent = 2; +} + +abstract class NSGrammaticalPerson { + static const int NSGrammaticalPersonNotSet = 0; + static const int NSGrammaticalPersonFirst = 1; + static const int NSGrammaticalPersonSecond = 2; + static const int NSGrammaticalPersonThird = 3; +} + +abstract class NSGrammaticalPronounType { + static const int NSGrammaticalPronounTypeNotSet = 0; + static const int NSGrammaticalPronounTypePersonal = 1; + static const int NSGrammaticalPronounTypeReflexive = 2; + static const int NSGrammaticalPronounTypePossessive = 3; +} + +abstract class NSGrammaticalDefiniteness { + static const int NSGrammaticalDefinitenessNotSet = 0; + static const int NSGrammaticalDefinitenessIndefinite = 1; + static const int NSGrammaticalDefinitenessDefinite = 2; +} + class NSMorphologyCustomPronoun extends NSObject { NSMorphologyCustomPronoun._(ffi.Pointer id, SentryCocoa lib, {bool retain = false, bool release = false}) @@ -60332,12 +60608,12 @@ class NSOperationQueue extends NSObject { } void addOperation_(NSOperation? op) { - _lib._objc_msgSend_818( + _lib._objc_msgSend_832( _id, _lib._sel_addOperation_1, op?._id ?? ffi.nullptr); } void addOperations_waitUntilFinished_(NSArray? ops, bool wait) { - _lib._objc_msgSend_821(_id, _lib._sel_addOperations_waitUntilFinished_1, + _lib._objc_msgSend_835(_id, _lib._sel_addOperations_waitUntilFinished_1, ops?._id ?? ffi.nullptr, wait); } @@ -60387,12 +60663,12 @@ class NSOperationQueue extends NSObject { } NSObject get underlyingQueue { - final _ret = _lib._objc_msgSend_822(_id, _lib._sel_underlyingQueue1); + final _ret = _lib._objc_msgSend_836(_id, _lib._sel_underlyingQueue1); return NSObject._(_ret, _lib, retain: true, release: true); } set underlyingQueue(NSObject value) { - return _lib._objc_msgSend_823( + return _lib._objc_msgSend_837( _id, _lib._sel_setUnderlyingQueue_1, value._id); } @@ -60405,7 +60681,7 @@ class NSOperationQueue extends NSObject { } static NSOperationQueue? getCurrentQueue(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_824( + final _ret = _lib._objc_msgSend_838( _lib._class_NSOperationQueue1, _lib._sel_currentQueue1); return _ret.address == 0 ? null @@ -60413,7 +60689,7 @@ class NSOperationQueue extends NSObject { } static NSOperationQueue? getMainQueue(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_824( + final _ret = _lib._objc_msgSend_838( _lib._class_NSOperationQueue1, _lib._sel_mainQueue1); return _ret.address == 0 ? null @@ -60584,12 +60860,12 @@ class NSOperation extends NSObject { } void addDependency_(NSOperation? op) { - _lib._objc_msgSend_818( + _lib._objc_msgSend_832( _id, _lib._sel_addDependency_1, op?._id ?? ffi.nullptr); } void removeDependency_(NSOperation? op) { - _lib._objc_msgSend_818( + _lib._objc_msgSend_832( _id, _lib._sel_removeDependency_1, op?._id ?? ffi.nullptr); } @@ -60601,11 +60877,11 @@ class NSOperation extends NSObject { } int get queuePriority { - return _lib._objc_msgSend_819(_id, _lib._sel_queuePriority1); + return _lib._objc_msgSend_833(_id, _lib._sel_queuePriority1); } set queuePriority(int value) { - return _lib._objc_msgSend_820(_id, _lib._sel_setQueuePriority_1, value); + return _lib._objc_msgSend_834(_id, _lib._sel_setQueuePriority_1, value); } ObjCBlock_ffiVoid get completionBlock { @@ -60775,26 +61051,26 @@ class NSPointerArray extends NSObject { NSPointerArray initWithOptions_(int options) { final _ret = - _lib._objc_msgSend_825(_id, _lib._sel_initWithOptions_1, options); + _lib._objc_msgSend_839(_id, _lib._sel_initWithOptions_1, options); return NSPointerArray._(_ret, _lib, retain: true, release: true); } NSPointerArray initWithPointerFunctions_(NSPointerFunctions? functions) { - final _ret = _lib._objc_msgSend_839(_id, + final _ret = _lib._objc_msgSend_853(_id, _lib._sel_initWithPointerFunctions_1, functions?._id ?? ffi.nullptr); return NSPointerArray._(_ret, _lib, retain: true, release: true); } static NSPointerArray pointerArrayWithOptions_( SentryCocoa _lib, int options) { - final _ret = _lib._objc_msgSend_840(_lib._class_NSPointerArray1, + final _ret = _lib._objc_msgSend_854(_lib._class_NSPointerArray1, _lib._sel_pointerArrayWithOptions_1, options); return NSPointerArray._(_ret, _lib, retain: true, release: true); } static NSPointerArray pointerArrayWithPointerFunctions_( SentryCocoa _lib, NSPointerFunctions? functions) { - final _ret = _lib._objc_msgSend_841( + final _ret = _lib._objc_msgSend_855( _lib._class_NSPointerArray1, _lib._sel_pointerArrayWithPointerFunctions_1, functions?._id ?? ffi.nullptr); @@ -60802,14 +61078,14 @@ class NSPointerArray extends NSObject { } NSPointerFunctions? get pointerFunctions { - final _ret = _lib._objc_msgSend_842(_id, _lib._sel_pointerFunctions1); + final _ret = _lib._objc_msgSend_856(_id, _lib._sel_pointerFunctions1); return _ret.address == 0 ? null : NSPointerFunctions._(_ret, _lib, retain: true, release: true); } ffi.Pointer pointerAtIndex_(int index) { - return _lib._objc_msgSend_843(_id, _lib._sel_pointerAtIndex_1, index); + return _lib._objc_msgSend_857(_id, _lib._sel_pointerAtIndex_1, index); } void addPointer_(ffi.Pointer pointer) { @@ -60826,7 +61102,7 @@ class NSPointerArray extends NSObject { void replacePointerAtIndex_withPointer_( int index, ffi.Pointer item) { - _lib._objc_msgSend_844( + _lib._objc_msgSend_858( _id, _lib._sel_replacePointerAtIndex_withPointer_1, index, item); } @@ -60855,13 +61131,13 @@ class NSPointerArray extends NSObject { } static NSPointerArray strongObjectsPointerArray(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_845( + final _ret = _lib._objc_msgSend_859( _lib._class_NSPointerArray1, _lib._sel_strongObjectsPointerArray1); return NSPointerArray._(_ret, _lib, retain: true, release: true); } static NSPointerArray weakObjectsPointerArray(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_845( + final _ret = _lib._objc_msgSend_859( _lib._class_NSPointerArray1, _lib._sel_weakObjectsPointerArray1); return NSPointerArray._(_ret, _lib, retain: true, release: true); } @@ -61008,13 +61284,13 @@ class NSPointerFunctions extends NSObject { NSPointerFunctions initWithOptions_(int options) { final _ret = - _lib._objc_msgSend_825(_id, _lib._sel_initWithOptions_1, options); + _lib._objc_msgSend_839(_id, _lib._sel_initWithOptions_1, options); return NSPointerFunctions._(_ret, _lib, retain: true, release: true); } static NSPointerFunctions pointerFunctionsWithOptions_( SentryCocoa _lib, int options) { - final _ret = _lib._objc_msgSend_826(_lib._class_NSPointerFunctions1, + final _ret = _lib._objc_msgSend_840(_lib._class_NSPointerFunctions1, _lib._sel_pointerFunctionsWithOptions_1, options); return NSPointerFunctions._(_ret, _lib, retain: true, release: true); } @@ -61027,7 +61303,7 @@ class NSPointerFunctions extends NSObject { ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>)>> get hashFunction { - return _lib._objc_msgSend_827(_id, _lib._sel_hashFunction1); + return _lib._objc_msgSend_841(_id, _lib._sel_hashFunction1); } set hashFunction( @@ -61040,7 +61316,7 @@ class NSPointerFunctions extends NSObject { ffi.UnsignedLong Function( ffi.Pointer)>>)>> value) { - return _lib._objc_msgSend_828(_id, _lib._sel_setHashFunction_1, value); + return _lib._objc_msgSend_842(_id, _lib._sel_setHashFunction_1, value); } ffi.Pointer< @@ -61052,7 +61328,7 @@ class NSPointerFunctions extends NSObject { ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>)>> get isEqualFunction { - return _lib._objc_msgSend_829(_id, _lib._sel_isEqualFunction1); + return _lib._objc_msgSend_843(_id, _lib._sel_isEqualFunction1); } set isEqualFunction( @@ -61066,13 +61342,13 @@ class NSPointerFunctions extends NSObject { ffi.UnsignedLong Function( ffi.Pointer)>>)>> value) { - return _lib._objc_msgSend_830(_id, _lib._sel_setIsEqualFunction_1, value); + return _lib._objc_msgSend_844(_id, _lib._sel_setIsEqualFunction_1, value); } ffi.Pointer< ffi.NativeFunction)>> get sizeFunction { - return _lib._objc_msgSend_831(_id, _lib._sel_sizeFunction1); + return _lib._objc_msgSend_845(_id, _lib._sel_sizeFunction1); } set sizeFunction( @@ -61080,14 +61356,14 @@ class NSPointerFunctions extends NSObject { ffi .NativeFunction)>> value) { - return _lib._objc_msgSend_832(_id, _lib._sel_setSizeFunction_1, value); + return _lib._objc_msgSend_846(_id, _lib._sel_setSizeFunction_1, value); } ffi.Pointer< ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer)>> get descriptionFunction { - return _lib._objc_msgSend_833(_id, _lib._sel_descriptionFunction1); + return _lib._objc_msgSend_847(_id, _lib._sel_descriptionFunction1); } set descriptionFunction( @@ -61095,7 +61371,7 @@ class NSPointerFunctions extends NSObject { ffi.NativeFunction< ffi.Pointer Function(ffi.Pointer)>> value) { - return _lib._objc_msgSend_834( + return _lib._objc_msgSend_848( _id, _lib._sel_setDescriptionFunction_1, value); } @@ -61107,7 +61383,7 @@ class NSPointerFunctions extends NSObject { ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>)>> get relinquishFunction { - return _lib._objc_msgSend_835(_id, _lib._sel_relinquishFunction1); + return _lib._objc_msgSend_849(_id, _lib._sel_relinquishFunction1); } set relinquishFunction( @@ -61120,7 +61396,7 @@ class NSPointerFunctions extends NSObject { ffi.UnsignedLong Function( ffi.Pointer)>>)>> value) { - return _lib._objc_msgSend_836( + return _lib._objc_msgSend_850( _id, _lib._sel_setRelinquishFunction_1, value); } @@ -61132,7 +61408,7 @@ class NSPointerFunctions extends NSObject { ffi.NativeFunction< ffi.UnsignedLong Function(ffi.Pointer)>>, ffi.Bool)>> get acquireFunction { - return _lib._objc_msgSend_837(_id, _lib._sel_acquireFunction1); + return _lib._objc_msgSend_851(_id, _lib._sel_acquireFunction1); } set acquireFunction( @@ -61146,7 +61422,7 @@ class NSPointerFunctions extends NSObject { ffi.Pointer)>>, ffi.Bool)>> value) { - return _lib._objc_msgSend_838(_id, _lib._sel_setAcquireFunction_1, value); + return _lib._objc_msgSend_852(_id, _lib._sel_setAcquireFunction_1, value); } bool get usesStrongWriteBarrier { @@ -61284,7 +61560,7 @@ class NSProcessInfo extends NSObject { } static NSProcessInfo? getProcessInfo(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_846( + final _ret = _lib._objc_msgSend_860( _lib._class_NSProcessInfo1, _lib._sel_processInfo1); return _ret.address == 0 ? null @@ -61353,7 +61629,7 @@ class NSProcessInfo extends NSObject { } void getOperatingSystemVersion(ffi.Pointer stret) { - _lib._objc_msgSend_847(stret, _id, _lib._sel_operatingSystemVersion1); + _lib._objc_msgSend_861(stret, _id, _lib._sel_operatingSystemVersion1); } int get processorCount { @@ -61369,7 +61645,7 @@ class NSProcessInfo extends NSObject { } bool isOperatingSystemAtLeastVersion_(NSOperatingSystemVersion version) { - return _lib._objc_msgSend_848( + return _lib._objc_msgSend_862( _id, _lib._sel_isOperatingSystemAtLeastVersion_1, version); } @@ -61406,7 +61682,7 @@ class NSProcessInfo extends NSObject { } NSObject beginActivityWithOptions_reason_(int options, NSString? reason) { - final _ret = _lib._objc_msgSend_849( + final _ret = _lib._objc_msgSend_863( _id, _lib._sel_beginActivityWithOptions_reason_1, options, @@ -61421,7 +61697,7 @@ class NSProcessInfo extends NSObject { void performActivityWithOptions_reason_usingBlock_( int options, NSString? reason, ObjCBlock_ffiVoid block) { - _lib._objc_msgSend_850( + _lib._objc_msgSend_864( _id, _lib._sel_performActivityWithOptions_reason_usingBlock_1, options, @@ -61431,7 +61707,7 @@ class NSProcessInfo extends NSObject { void performExpiringActivityWithReason_usingBlock_( NSString? reason, ObjCBlock_ffiVoid_bool block) { - _lib._objc_msgSend_851( + _lib._objc_msgSend_865( _id, _lib._sel_performExpiringActivityWithReason_usingBlock_1, reason?._id ?? ffi.nullptr, @@ -61453,7 +61729,7 @@ class NSProcessInfo extends NSObject { } int get thermalState { - return _lib._objc_msgSend_852(_id, _lib._sel_thermalState1); + return _lib._objc_msgSend_866(_id, _lib._sel_thermalState1); } bool get lowPowerModeEnabled { @@ -61682,7 +61958,7 @@ class NSTextCheckingResult extends NSObject { } int get resultType { - return _lib._objc_msgSend_853(_id, _lib._sel_resultType1); + return _lib._objc_msgSend_867(_id, _lib._sel_resultType1); } void getRange(ffi.Pointer<_NSRange> stret) { @@ -61690,7 +61966,7 @@ class NSTextCheckingResult extends NSObject { } NSOrthography? get orthography { - final _ret = _lib._objc_msgSend_854(_id, _lib._sel_orthography1); + final _ret = _lib._objc_msgSend_868(_id, _lib._sel_orthography1); return _ret.address == 0 ? null : NSOrthography._(_ret, _lib, retain: true, release: true); @@ -61750,7 +62026,7 @@ class NSTextCheckingResult extends NSObject { } NSRegularExpression? get regularExpression { - final _ret = _lib._objc_msgSend_866(_id, _lib._sel_regularExpression1); + final _ret = _lib._objc_msgSend_880(_id, _lib._sel_regularExpression1); return _ret.address == 0 ? null : NSRegularExpression._(_ret, _lib, retain: true, release: true); @@ -61777,7 +62053,7 @@ class NSTextCheckingResult extends NSObject { } NSTextCheckingResult resultByAdjustingRangesWithOffset_(int offset) { - final _ret = _lib._objc_msgSend_867( + final _ret = _lib._objc_msgSend_881( _id, _lib._sel_resultByAdjustingRangesWithOffset_1, offset); return NSTextCheckingResult._(_ret, _lib, retain: true, release: true); } @@ -61791,7 +62067,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult orthographyCheckingResultWithRange_orthography_( SentryCocoa _lib, _NSRange range, NSOrthography? orthography) { - final _ret = _lib._objc_msgSend_868( + final _ret = _lib._objc_msgSend_882( _lib._class_NSTextCheckingResult1, _lib._sel_orthographyCheckingResultWithRange_orthography_1, range, @@ -61801,14 +62077,14 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult spellCheckingResultWithRange_( SentryCocoa _lib, _NSRange range) { - final _ret = _lib._objc_msgSend_869(_lib._class_NSTextCheckingResult1, + final _ret = _lib._objc_msgSend_883(_lib._class_NSTextCheckingResult1, _lib._sel_spellCheckingResultWithRange_1, range); return NSTextCheckingResult._(_ret, _lib, retain: true, release: true); } static NSTextCheckingResult grammarCheckingResultWithRange_details_( SentryCocoa _lib, _NSRange range, NSArray? details) { - final _ret = _lib._objc_msgSend_870( + final _ret = _lib._objc_msgSend_884( _lib._class_NSTextCheckingResult1, _lib._sel_grammarCheckingResultWithRange_details_1, range, @@ -61818,7 +62094,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult dateCheckingResultWithRange_date_( SentryCocoa _lib, _NSRange range, NSDate? date) { - final _ret = _lib._objc_msgSend_871( + final _ret = _lib._objc_msgSend_885( _lib._class_NSTextCheckingResult1, _lib._sel_dateCheckingResultWithRange_date_1, range, @@ -61829,7 +62105,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult dateCheckingResultWithRange_date_timeZone_duration_(SentryCocoa _lib, _NSRange range, NSDate? date, NSTimeZone? timeZone, double duration) { - final _ret = _lib._objc_msgSend_872( + final _ret = _lib._objc_msgSend_886( _lib._class_NSTextCheckingResult1, _lib._sel_dateCheckingResultWithRange_date_timeZone_duration_1, range, @@ -61841,7 +62117,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult addressCheckingResultWithRange_components_( SentryCocoa _lib, _NSRange range, NSDictionary? components) { - final _ret = _lib._objc_msgSend_873( + final _ret = _lib._objc_msgSend_887( _lib._class_NSTextCheckingResult1, _lib._sel_addressCheckingResultWithRange_components_1, range, @@ -61851,7 +62127,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult linkCheckingResultWithRange_URL_( SentryCocoa _lib, _NSRange range, NSURL? url) { - final _ret = _lib._objc_msgSend_874( + final _ret = _lib._objc_msgSend_888( _lib._class_NSTextCheckingResult1, _lib._sel_linkCheckingResultWithRange_URL_1, range, @@ -61861,7 +62137,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult quoteCheckingResultWithRange_replacementString_( SentryCocoa _lib, _NSRange range, NSString? replacementString) { - final _ret = _lib._objc_msgSend_875( + final _ret = _lib._objc_msgSend_889( _lib._class_NSTextCheckingResult1, _lib._sel_quoteCheckingResultWithRange_replacementString_1, range, @@ -61871,7 +62147,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult dashCheckingResultWithRange_replacementString_( SentryCocoa _lib, _NSRange range, NSString? replacementString) { - final _ret = _lib._objc_msgSend_875( + final _ret = _lib._objc_msgSend_889( _lib._class_NSTextCheckingResult1, _lib._sel_dashCheckingResultWithRange_replacementString_1, range, @@ -61882,7 +62158,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult replacementCheckingResultWithRange_replacementString_( SentryCocoa _lib, _NSRange range, NSString? replacementString) { - final _ret = _lib._objc_msgSend_875( + final _ret = _lib._objc_msgSend_889( _lib._class_NSTextCheckingResult1, _lib._sel_replacementCheckingResultWithRange_replacementString_1, range, @@ -61893,7 +62169,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult correctionCheckingResultWithRange_replacementString_( SentryCocoa _lib, _NSRange range, NSString? replacementString) { - final _ret = _lib._objc_msgSend_875( + final _ret = _lib._objc_msgSend_889( _lib._class_NSTextCheckingResult1, _lib._sel_correctionCheckingResultWithRange_replacementString_1, range, @@ -61907,7 +62183,7 @@ class NSTextCheckingResult extends NSObject { _NSRange range, NSString? replacementString, NSArray? alternativeStrings) { - final _ret = _lib._objc_msgSend_876( + final _ret = _lib._objc_msgSend_890( _lib._class_NSTextCheckingResult1, _lib._sel_correctionCheckingResultWithRange_replacementString_alternativeStrings_1, range, @@ -61922,7 +62198,7 @@ class NSTextCheckingResult extends NSObject { ffi.Pointer<_NSRange> ranges, int count, NSRegularExpression? regularExpression) { - final _ret = _lib._objc_msgSend_877( + final _ret = _lib._objc_msgSend_891( _lib._class_NSTextCheckingResult1, _lib._sel_regularExpressionCheckingResultWithRanges_count_regularExpression_1, ranges, @@ -61933,7 +62209,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult phoneNumberCheckingResultWithRange_phoneNumber_( SentryCocoa _lib, _NSRange range, NSString? phoneNumber) { - final _ret = _lib._objc_msgSend_875( + final _ret = _lib._objc_msgSend_889( _lib._class_NSTextCheckingResult1, _lib._sel_phoneNumberCheckingResultWithRange_phoneNumber_1, range, @@ -61944,7 +62220,7 @@ class NSTextCheckingResult extends NSObject { static NSTextCheckingResult transitInformationCheckingResultWithRange_components_( SentryCocoa _lib, _NSRange range, NSDictionary? components) { - final _ret = _lib._objc_msgSend_873( + final _ret = _lib._objc_msgSend_887( _lib._class_NSTextCheckingResult1, _lib._sel_transitInformationCheckingResultWithRange_components_1, range, @@ -62090,7 +62366,7 @@ class NSRegularExpression extends NSObject { NSString? pattern, int options, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_855( + final _ret = _lib._objc_msgSend_869( _lib._class_NSRegularExpression1, _lib._sel_regularExpressionWithPattern_options_error_1, pattern?._id ?? ffi.nullptr, @@ -62101,7 +62377,7 @@ class NSRegularExpression extends NSObject { NSRegularExpression initWithPattern_options_error_(NSString? pattern, int options, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_856( + final _ret = _lib._objc_msgSend_870( _id, _lib._sel_initWithPattern_options_error_1, pattern?._id ?? ffi.nullptr, @@ -62118,7 +62394,7 @@ class NSRegularExpression extends NSObject { } int get options { - return _lib._objc_msgSend_857(_id, _lib._sel_options1); + return _lib._objc_msgSend_871(_id, _lib._sel_options1); } int get numberOfCaptureGroups { @@ -62136,7 +62412,7 @@ class NSRegularExpression extends NSObject { int options, _NSRange range, ObjCBlock_ffiVoid_NSTextCheckingResult_NSMatchingFlags_bool block) { - _lib._objc_msgSend_858( + _lib._objc_msgSend_872( _id, _lib._sel_enumerateMatchesInString_options_range_usingBlock_1, string?._id ?? ffi.nullptr, @@ -62147,7 +62423,7 @@ class NSRegularExpression extends NSObject { NSArray matchesInString_options_range_( NSString? string, int options, _NSRange range) { - final _ret = _lib._objc_msgSend_859( + final _ret = _lib._objc_msgSend_873( _id, _lib._sel_matchesInString_options_range_1, string?._id ?? ffi.nullptr, @@ -62158,7 +62434,7 @@ class NSRegularExpression extends NSObject { int numberOfMatchesInString_options_range_( NSString? string, int options, _NSRange range) { - return _lib._objc_msgSend_860( + return _lib._objc_msgSend_874( _id, _lib._sel_numberOfMatchesInString_options_range_1, string?._id ?? ffi.nullptr, @@ -62168,7 +62444,7 @@ class NSRegularExpression extends NSObject { NSTextCheckingResult firstMatchInString_options_range_( NSString? string, int options, _NSRange range) { - final _ret = _lib._objc_msgSend_861( + final _ret = _lib._objc_msgSend_875( _id, _lib._sel_firstMatchInString_options_range_1, string?._id ?? ffi.nullptr, @@ -62179,7 +62455,7 @@ class NSRegularExpression extends NSObject { void rangeOfFirstMatchInString_options_range_(ffi.Pointer<_NSRange> stret, NSString? string, int options, _NSRange range) { - _lib._objc_msgSend_862( + _lib._objc_msgSend_876( stret, _id, _lib._sel_rangeOfFirstMatchInString_options_range_1, @@ -62190,7 +62466,7 @@ class NSRegularExpression extends NSObject { NSString stringByReplacingMatchesInString_options_range_withTemplate_( NSString? string, int options, _NSRange range, NSString? templ) { - final _ret = _lib._objc_msgSend_863( + final _ret = _lib._objc_msgSend_877( _id, _lib._sel_stringByReplacingMatchesInString_options_range_withTemplate_1, string?._id ?? ffi.nullptr, @@ -62202,7 +62478,7 @@ class NSRegularExpression extends NSObject { int replaceMatchesInString_options_range_withTemplate_( NSMutableString? string, int options, _NSRange range, NSString? templ) { - return _lib._objc_msgSend_864( + return _lib._objc_msgSend_878( _id, _lib._sel_replaceMatchesInString_options_range_withTemplate_1, string?._id ?? ffi.nullptr, @@ -62216,7 +62492,7 @@ class NSRegularExpression extends NSObject { NSString? string, int offset, NSString? templ) { - final _ret = _lib._objc_msgSend_865( + final _ret = _lib._objc_msgSend_879( _id, _lib._sel_replacementStringForResult_inString_offset_template_1, result?._id ?? ffi.nullptr, @@ -62485,7 +62761,7 @@ class NSURLCache extends NSObject { } static NSURLCache? getSharedURLCache(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_878( + final _ret = _lib._objc_msgSend_892( _lib._class_NSURLCache1, _lib._sel_sharedURLCache1); return _ret.address == 0 ? null @@ -62493,13 +62769,13 @@ class NSURLCache extends NSObject { } static void setSharedURLCache(SentryCocoa _lib, NSURLCache? value) { - return _lib._objc_msgSend_879(_lib._class_NSURLCache1, + return _lib._objc_msgSend_893(_lib._class_NSURLCache1, _lib._sel_setSharedURLCache_1, value?._id ?? ffi.nullptr); } NSURLCache initWithMemoryCapacity_diskCapacity_diskPath_( int memoryCapacity, int diskCapacity, NSString? path) { - final _ret = _lib._objc_msgSend_880( + final _ret = _lib._objc_msgSend_894( _id, _lib._sel_initWithMemoryCapacity_diskCapacity_diskPath_1, memoryCapacity, @@ -62510,7 +62786,7 @@ class NSURLCache extends NSObject { NSURLCache initWithMemoryCapacity_diskCapacity_directoryURL_( int memoryCapacity, int diskCapacity, NSURL? directoryURL) { - final _ret = _lib._objc_msgSend_881( + final _ret = _lib._objc_msgSend_895( _id, _lib._sel_initWithMemoryCapacity_diskCapacity_directoryURL_1, memoryCapacity, @@ -62520,19 +62796,19 @@ class NSURLCache extends NSObject { } NSCachedURLResponse cachedResponseForRequest_(NSURLRequest? request) { - final _ret = _lib._objc_msgSend_885( + final _ret = _lib._objc_msgSend_899( _id, _lib._sel_cachedResponseForRequest_1, request?._id ?? ffi.nullptr); return NSCachedURLResponse._(_ret, _lib, retain: true, release: true); } void storeCachedResponse_forRequest_( NSCachedURLResponse? cachedResponse, NSURLRequest? request) { - _lib._objc_msgSend_886(_id, _lib._sel_storeCachedResponse_forRequest_1, + _lib._objc_msgSend_900(_id, _lib._sel_storeCachedResponse_forRequest_1, cachedResponse?._id ?? ffi.nullptr, request?._id ?? ffi.nullptr); } void removeCachedResponseForRequest_(NSURLRequest? request) { - _lib._objc_msgSend_887(_id, _lib._sel_removeCachedResponseForRequest_1, + _lib._objc_msgSend_901(_id, _lib._sel_removeCachedResponseForRequest_1, request?._id ?? ffi.nullptr); } @@ -62571,14 +62847,14 @@ class NSURLCache extends NSObject { void storeCachedResponse_forDataTask_( NSCachedURLResponse? cachedResponse, NSURLSessionDataTask? dataTask) { - _lib._objc_msgSend_888(_id, _lib._sel_storeCachedResponse_forDataTask_1, + _lib._objc_msgSend_902(_id, _lib._sel_storeCachedResponse_forDataTask_1, cachedResponse?._id ?? ffi.nullptr, dataTask?._id ?? ffi.nullptr); } void getCachedResponseForDataTask_completionHandler_( NSURLSessionDataTask? dataTask, ObjCBlock_ffiVoid_NSCachedURLResponse completionHandler) { - _lib._objc_msgSend_889( + _lib._objc_msgSend_903( _id, _lib._sel_getCachedResponseForDataTask_completionHandler_1, dataTask?._id ?? ffi.nullptr, @@ -62586,7 +62862,7 @@ class NSURLCache extends NSObject { } void removeCachedResponseForDataTask_(NSURLSessionDataTask? dataTask) { - _lib._objc_msgSend_890(_id, _lib._sel_removeCachedResponseForDataTask_1, + _lib._objc_msgSend_904(_id, _lib._sel_removeCachedResponseForDataTask_1, dataTask?._id ?? ffi.nullptr); } @@ -62708,7 +62984,7 @@ class NSCachedURLResponse extends NSObject { NSCachedURLResponse initWithResponse_data_( NSURLResponse? response, NSData? data) { - final _ret = _lib._objc_msgSend_882(_id, _lib._sel_initWithResponse_data_1, + final _ret = _lib._objc_msgSend_896(_id, _lib._sel_initWithResponse_data_1, response?._id ?? ffi.nullptr, data?._id ?? ffi.nullptr); return NSCachedURLResponse._(_ret, _lib, retain: true, release: true); } @@ -62718,7 +62994,7 @@ class NSCachedURLResponse extends NSObject { NSData? data, NSDictionary? userInfo, int storagePolicy) { - final _ret = _lib._objc_msgSend_883( + final _ret = _lib._objc_msgSend_897( _id, _lib._sel_initWithResponse_data_userInfo_storagePolicy_1, response?._id ?? ffi.nullptr, @@ -62729,7 +63005,7 @@ class NSCachedURLResponse extends NSObject { } NSURLResponse? get response { - final _ret = _lib._objc_msgSend_797(_id, _lib._sel_response1); + final _ret = _lib._objc_msgSend_801(_id, _lib._sel_response1); return _ret.address == 0 ? null : NSURLResponse._(_ret, _lib, retain: true, release: true); @@ -62750,7 +63026,7 @@ class NSCachedURLResponse extends NSObject { } int get storagePolicy { - return _lib._objc_msgSend_884(_id, _lib._sel_storagePolicy1); + return _lib._objc_msgSend_898(_id, _lib._sel_storagePolicy1); } @override @@ -63067,7 +63343,7 @@ class NSURLConnection extends NSObject { NSURLConnection initWithRequest_delegate_startImmediately_( NSURLRequest? request, NSObject delegate, bool startImmediately) { - final _ret = _lib._objc_msgSend_891( + final _ret = _lib._objc_msgSend_905( _id, _lib._sel_initWithRequest_delegate_startImmediately_1, request?._id ?? ffi.nullptr, @@ -63078,7 +63354,7 @@ class NSURLConnection extends NSObject { NSURLConnection initWithRequest_delegate_( NSURLRequest? request, NSObject delegate) { - final _ret = _lib._objc_msgSend_892( + final _ret = _lib._objc_msgSend_906( _id, _lib._sel_initWithRequest_delegate_1, request?._id ?? ffi.nullptr, @@ -63088,7 +63364,7 @@ class NSURLConnection extends NSObject { static NSURLConnection connectionWithRequest_delegate_( SentryCocoa _lib, NSURLRequest? request, NSObject delegate) { - final _ret = _lib._objc_msgSend_893( + final _ret = _lib._objc_msgSend_907( _lib._class_NSURLConnection1, _lib._sel_connectionWithRequest_delegate_1, request?._id ?? ffi.nullptr, @@ -63097,14 +63373,14 @@ class NSURLConnection extends NSObject { } NSURLRequest? get originalRequest { - final _ret = _lib._objc_msgSend_795(_id, _lib._sel_originalRequest1); + final _ret = _lib._objc_msgSend_799(_id, _lib._sel_originalRequest1); return _ret.address == 0 ? null : NSURLRequest._(_ret, _lib, retain: true, release: true); } NSURLRequest? get currentRequest { - final _ret = _lib._objc_msgSend_795(_id, _lib._sel_currentRequest1); + final _ret = _lib._objc_msgSend_799(_id, _lib._sel_currentRequest1); return _ret.address == 0 ? null : NSURLRequest._(_ret, _lib, retain: true, release: true); @@ -63129,12 +63405,12 @@ class NSURLConnection extends NSObject { } void setDelegateQueue_(NSOperationQueue? queue) { - _lib._objc_msgSend_894( + _lib._objc_msgSend_908( _id, _lib._sel_setDelegateQueue_1, queue?._id ?? ffi.nullptr); } static bool canHandleRequest_(SentryCocoa _lib, NSURLRequest? request) { - return _lib._objc_msgSend_895(_lib._class_NSURLConnection1, + return _lib._objc_msgSend_909(_lib._class_NSURLConnection1, _lib._sel_canHandleRequest_1, request?._id ?? ffi.nullptr); } @@ -63143,7 +63419,7 @@ class NSURLConnection extends NSObject { NSURLRequest? request, ffi.Pointer> response, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_896( + final _ret = _lib._objc_msgSend_910( _lib._class_NSURLConnection1, _lib._sel_sendSynchronousRequest_returningResponse_error_1, request?._id ?? ffi.nullptr, @@ -63157,7 +63433,7 @@ class NSURLConnection extends NSObject { NSURLRequest? request, NSOperationQueue? queue, ObjCBlock_ffiVoid_NSURLResponse_NSData_NSError handler) { - _lib._objc_msgSend_897( + _lib._objc_msgSend_911( _lib._class_NSURLConnection1, _lib._sel_sendAsynchronousRequest_queue_completionHandler_1, request?._id ?? ffi.nullptr, @@ -63393,12 +63669,12 @@ class NSURLCredential extends NSObject { } int get persistence { - return _lib._objc_msgSend_898(_id, _lib._sel_persistence1); + return _lib._objc_msgSend_912(_id, _lib._sel_persistence1); } NSURLCredential initWithUser_password_persistence_( NSString? user, NSString? password, int persistence) { - final _ret = _lib._objc_msgSend_899( + final _ret = _lib._objc_msgSend_913( _id, _lib._sel_initWithUser_password_persistence_1, user?._id ?? ffi.nullptr, @@ -63409,7 +63685,7 @@ class NSURLCredential extends NSObject { static NSURLCredential credentialWithUser_password_persistence_( SentryCocoa _lib, NSString? user, NSString? password, int persistence) { - final _ret = _lib._objc_msgSend_900( + final _ret = _lib._objc_msgSend_914( _lib._class_NSURLCredential1, _lib._sel_credentialWithUser_password_persistence_1, user?._id ?? ffi.nullptr, @@ -63440,7 +63716,7 @@ class NSURLCredential extends NSObject { ffi.Pointer<__SecIdentity> identity, NSArray? certArray, int persistence) { - final _ret = _lib._objc_msgSend_901( + final _ret = _lib._objc_msgSend_915( _id, _lib._sel_initWithIdentity_certificates_persistence_1, identity, @@ -63454,7 +63730,7 @@ class NSURLCredential extends NSObject { ffi.Pointer<__SecIdentity> identity, NSArray? certArray, int persistence) { - final _ret = _lib._objc_msgSend_902( + final _ret = _lib._objc_msgSend_916( _lib._class_NSURLCredential1, _lib._sel_credentialWithIdentity_certificates_persistence_1, identity, @@ -63464,7 +63740,7 @@ class NSURLCredential extends NSObject { } ffi.Pointer<__SecIdentity> get identity { - return _lib._objc_msgSend_903(_id, _lib._sel_identity1); + return _lib._objc_msgSend_917(_id, _lib._sel_identity1); } NSArray? get certificates { @@ -63475,13 +63751,13 @@ class NSURLCredential extends NSObject { } NSURLCredential initWithTrust_(ffi.Pointer<__SecTrust> trust) { - final _ret = _lib._objc_msgSend_904(_id, _lib._sel_initWithTrust_1, trust); + final _ret = _lib._objc_msgSend_918(_id, _lib._sel_initWithTrust_1, trust); return NSURLCredential._(_ret, _lib, retain: true, release: true); } static NSURLCredential credentialForTrust_( SentryCocoa _lib, ffi.Pointer<__SecTrust> trust) { - final _ret = _lib._objc_msgSend_905( + final _ret = _lib._objc_msgSend_919( _lib._class_NSURLCredential1, _lib._sel_credentialForTrust_1, trust); return NSURLCredential._(_ret, _lib, retain: true, release: true); } @@ -63620,7 +63896,7 @@ class NSURLProtectionSpace extends NSObject { NSString? protocol, NSString? realm, NSString? authenticationMethod) { - final _ret = _lib._objc_msgSend_906( + final _ret = _lib._objc_msgSend_920( _id, _lib._sel_initWithHost_port_protocol_realm_authenticationMethod_1, host?._id ?? ffi.nullptr, @@ -63637,7 +63913,7 @@ class NSURLProtectionSpace extends NSObject { NSString? type, NSString? realm, NSString? authenticationMethod) { - final _ret = _lib._objc_msgSend_906( + final _ret = _lib._objc_msgSend_920( _id, _lib._sel_initWithProxyHost_port_type_realm_authenticationMethod_1, host?._id ?? ffi.nullptr, @@ -63703,7 +63979,7 @@ class NSURLProtectionSpace extends NSObject { } ffi.Pointer<__SecTrust> get serverTrust { - return _lib._objc_msgSend_907(_id, _lib._sel_serverTrust1); + return _lib._objc_msgSend_921(_id, _lib._sel_serverTrust1); } @override @@ -63825,7 +64101,7 @@ class NSURLCredentialStorage extends NSObject { } static NSURLCredentialStorage? getSharedCredentialStorage(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_908(_lib._class_NSURLCredentialStorage1, + final _ret = _lib._objc_msgSend_922(_lib._class_NSURLCredentialStorage1, _lib._sel_sharedCredentialStorage1); return _ret.address == 0 ? null @@ -63833,7 +64109,7 @@ class NSURLCredentialStorage extends NSObject { } NSDictionary credentialsForProtectionSpace_(NSURLProtectionSpace? space) { - final _ret = _lib._objc_msgSend_909(_id, + final _ret = _lib._objc_msgSend_923(_id, _lib._sel_credentialsForProtectionSpace_1, space?._id ?? ffi.nullptr); return NSDictionary._(_ret, _lib, retain: true, release: true); } @@ -63847,19 +64123,19 @@ class NSURLCredentialStorage extends NSObject { void setCredential_forProtectionSpace_( NSURLCredential? credential, NSURLProtectionSpace? space) { - _lib._objc_msgSend_910(_id, _lib._sel_setCredential_forProtectionSpace_1, + _lib._objc_msgSend_924(_id, _lib._sel_setCredential_forProtectionSpace_1, credential?._id ?? ffi.nullptr, space?._id ?? ffi.nullptr); } void removeCredential_forProtectionSpace_( NSURLCredential? credential, NSURLProtectionSpace? space) { - _lib._objc_msgSend_910(_id, _lib._sel_removeCredential_forProtectionSpace_1, + _lib._objc_msgSend_924(_id, _lib._sel_removeCredential_forProtectionSpace_1, credential?._id ?? ffi.nullptr, space?._id ?? ffi.nullptr); } void removeCredential_forProtectionSpace_options_(NSURLCredential? credential, NSURLProtectionSpace? space, NSDictionary? options) { - _lib._objc_msgSend_911( + _lib._objc_msgSend_925( _id, _lib._sel_removeCredential_forProtectionSpace_options_1, credential?._id ?? ffi.nullptr, @@ -63869,7 +64145,7 @@ class NSURLCredentialStorage extends NSObject { NSURLCredential defaultCredentialForProtectionSpace_( NSURLProtectionSpace? space) { - final _ret = _lib._objc_msgSend_912( + final _ret = _lib._objc_msgSend_926( _id, _lib._sel_defaultCredentialForProtectionSpace_1, space?._id ?? ffi.nullptr); @@ -63878,7 +64154,7 @@ class NSURLCredentialStorage extends NSObject { void setDefaultCredential_forProtectionSpace_( NSURLCredential? credential, NSURLProtectionSpace? space) { - _lib._objc_msgSend_910( + _lib._objc_msgSend_924( _id, _lib._sel_setDefaultCredential_forProtectionSpace_1, credential?._id ?? ffi.nullptr, @@ -63889,7 +64165,7 @@ class NSURLCredentialStorage extends NSObject { NSURLProtectionSpace? protectionSpace, NSURLSessionTask? task, ObjCBlock_ffiVoid_NSDictionary completionHandler) { - _lib._objc_msgSend_913( + _lib._objc_msgSend_927( _id, _lib._sel_getCredentialsForProtectionSpace_task_completionHandler_1, protectionSpace?._id ?? ffi.nullptr, @@ -63899,7 +64175,7 @@ class NSURLCredentialStorage extends NSObject { void setCredential_forProtectionSpace_task_(NSURLCredential? credential, NSURLProtectionSpace? protectionSpace, NSURLSessionTask? task) { - _lib._objc_msgSend_914( + _lib._objc_msgSend_928( _id, _lib._sel_setCredential_forProtectionSpace_task_1, credential?._id ?? ffi.nullptr, @@ -63912,7 +64188,7 @@ class NSURLCredentialStorage extends NSObject { NSURLProtectionSpace? protectionSpace, NSDictionary? options, NSURLSessionTask? task) { - _lib._objc_msgSend_915( + _lib._objc_msgSend_929( _id, _lib._sel_removeCredential_forProtectionSpace_options_task_1, credential?._id ?? ffi.nullptr, @@ -63925,7 +64201,7 @@ class NSURLCredentialStorage extends NSObject { NSURLProtectionSpace? space, NSURLSessionTask? task, ObjCBlock_ffiVoid_NSURLCredential completionHandler) { - _lib._objc_msgSend_916( + _lib._objc_msgSend_930( _id, _lib._sel_getDefaultCredentialForProtectionSpace_task_completionHandler_1, space?._id ?? ffi.nullptr, @@ -63937,7 +64213,7 @@ class NSURLCredentialStorage extends NSObject { NSURLCredential? credential, NSURLProtectionSpace? protectionSpace, NSURLSessionTask? task) { - _lib._objc_msgSend_914( + _lib._objc_msgSend_928( _id, _lib._sel_setDefaultCredential_forProtectionSpace_task_1, credential?._id ?? ffi.nullptr, @@ -64204,7 +64480,7 @@ class NSURLProtocol extends NSObject { NSURLProtocol initWithRequest_cachedResponse_client_(NSURLRequest? request, NSCachedURLResponse? cachedResponse, NSObject? client) { - final _ret = _lib._objc_msgSend_917( + final _ret = _lib._objc_msgSend_931( _id, _lib._sel_initWithRequest_cachedResponse_client_1, request?._id ?? ffi.nullptr, @@ -64221,34 +64497,34 @@ class NSURLProtocol extends NSObject { } NSURLRequest? get request { - final _ret = _lib._objc_msgSend_795(_id, _lib._sel_request1); + final _ret = _lib._objc_msgSend_799(_id, _lib._sel_request1); return _ret.address == 0 ? null : NSURLRequest._(_ret, _lib, retain: true, release: true); } NSCachedURLResponse? get cachedResponse { - final _ret = _lib._objc_msgSend_918(_id, _lib._sel_cachedResponse1); + final _ret = _lib._objc_msgSend_932(_id, _lib._sel_cachedResponse1); return _ret.address == 0 ? null : NSCachedURLResponse._(_ret, _lib, retain: true, release: true); } static bool canInitWithRequest_(SentryCocoa _lib, NSURLRequest? request) { - return _lib._objc_msgSend_895(_lib._class_NSURLProtocol1, + return _lib._objc_msgSend_909(_lib._class_NSURLProtocol1, _lib._sel_canInitWithRequest_1, request?._id ?? ffi.nullptr); } static NSURLRequest canonicalRequestForRequest_( SentryCocoa _lib, NSURLRequest? request) { - final _ret = _lib._objc_msgSend_919(_lib._class_NSURLProtocol1, + final _ret = _lib._objc_msgSend_933(_lib._class_NSURLProtocol1, _lib._sel_canonicalRequestForRequest_1, request?._id ?? ffi.nullptr); return NSURLRequest._(_ret, _lib, retain: true, release: true); } static bool requestIsCacheEquivalent_toRequest_( SentryCocoa _lib, NSURLRequest? a, NSURLRequest? b) { - return _lib._objc_msgSend_920( + return _lib._objc_msgSend_934( _lib._class_NSURLProtocol1, _lib._sel_requestIsCacheEquivalent_toRequest_1, a?._id ?? ffi.nullptr, @@ -64265,7 +64541,7 @@ class NSURLProtocol extends NSObject { static NSObject propertyForKey_inRequest_( SentryCocoa _lib, NSString? key, NSURLRequest? request) { - final _ret = _lib._objc_msgSend_921( + final _ret = _lib._objc_msgSend_935( _lib._class_NSURLProtocol1, _lib._sel_propertyForKey_inRequest_1, key?._id ?? ffi.nullptr, @@ -64275,7 +64551,7 @@ class NSURLProtocol extends NSObject { static void setProperty_forKey_inRequest_(SentryCocoa _lib, NSObject value, NSString? key, NSMutableURLRequest? request) { - _lib._objc_msgSend_927( + _lib._objc_msgSend_941( _lib._class_NSURLProtocol1, _lib._sel_setProperty_forKey_inRequest_1, value._id, @@ -64285,7 +64561,7 @@ class NSURLProtocol extends NSObject { static void removePropertyForKey_inRequest_( SentryCocoa _lib, NSString? key, NSMutableURLRequest? request) { - _lib._objc_msgSend_928( + _lib._objc_msgSend_942( _lib._class_NSURLProtocol1, _lib._sel_removePropertyForKey_inRequest_1, key?._id ?? ffi.nullptr, @@ -64303,13 +64579,13 @@ class NSURLProtocol extends NSObject { } static bool canInitWithTask_(SentryCocoa _lib, NSURLSessionTask? task) { - return _lib._objc_msgSend_929(_lib._class_NSURLProtocol1, + return _lib._objc_msgSend_943(_lib._class_NSURLProtocol1, _lib._sel_canInitWithTask_1, task?._id ?? ffi.nullptr); } NSURLProtocol initWithTask_cachedResponse_client_(NSURLSessionTask? task, NSCachedURLResponse? cachedResponse, NSObject? client) { - final _ret = _lib._objc_msgSend_930( + final _ret = _lib._objc_msgSend_944( _id, _lib._sel_initWithTask_cachedResponse_client_1, task?._id ?? ffi.nullptr, @@ -64319,7 +64595,7 @@ class NSURLProtocol extends NSObject { } NSURLSessionTask? get task { - final _ret = _lib._objc_msgSend_931(_id, _lib._sel_task1); + final _ret = _lib._objc_msgSend_945(_id, _lib._sel_task1); return _ret.address == 0 ? null : NSURLSessionTask._(_ret, _lib, retain: true, release: true); @@ -64457,11 +64733,11 @@ class NSMutableURLRequest extends NSURLRequest { @override int get cachePolicy { - return _lib._objc_msgSend_782(_id, _lib._sel_cachePolicy1); + return _lib._objc_msgSend_786(_id, _lib._sel_cachePolicy1); } set cachePolicy(int value) { - return _lib._objc_msgSend_922(_id, _lib._sel_setCachePolicy_1, value); + return _lib._objc_msgSend_936(_id, _lib._sel_setCachePolicy_1, value); } @override @@ -64488,11 +64764,11 @@ class NSMutableURLRequest extends NSURLRequest { @override int get networkServiceType { - return _lib._objc_msgSend_783(_id, _lib._sel_networkServiceType1); + return _lib._objc_msgSend_787(_id, _lib._sel_networkServiceType1); } set networkServiceType(int value) { - return _lib._objc_msgSend_923( + return _lib._objc_msgSend_937( _id, _lib._sel_setNetworkServiceType_1, value); } @@ -64539,11 +64815,11 @@ class NSMutableURLRequest extends NSURLRequest { @override int get attribution { - return _lib._objc_msgSend_784(_id, _lib._sel_attribution1); + return _lib._objc_msgSend_788(_id, _lib._sel_attribution1); } set attribution(int value) { - return _lib._objc_msgSend_924(_id, _lib._sel_setAttribution_1, value); + return _lib._objc_msgSend_938(_id, _lib._sel_setAttribution_1, value); } @override @@ -64601,20 +64877,20 @@ class NSMutableURLRequest extends NSURLRequest { } set HTTPBody(NSData? value) { - return _lib._objc_msgSend_925( + return _lib._objc_msgSend_939( _id, _lib._sel_setHTTPBody_1, value?._id ?? ffi.nullptr); } @override NSInputStream? get HTTPBodyStream { - final _ret = _lib._objc_msgSend_794(_id, _lib._sel_HTTPBodyStream1); + final _ret = _lib._objc_msgSend_798(_id, _lib._sel_HTTPBodyStream1); return _ret.address == 0 ? null : NSInputStream._(_ret, _lib, retain: true, release: true); } set HTTPBodyStream(NSInputStream? value) { - return _lib._objc_msgSend_926( + return _lib._objc_msgSend_940( _id, _lib._sel_setHTTPBodyStream_1, value?._id ?? ffi.nullptr); } @@ -64651,7 +64927,7 @@ class NSMutableURLRequest extends NSURLRequest { static NSMutableURLRequest requestWithURL_cachePolicy_timeoutInterval_( SentryCocoa _lib, NSURL? URL, int cachePolicy, double timeoutInterval) { - final _ret = _lib._objc_msgSend_781( + final _ret = _lib._objc_msgSend_785( _lib._class_NSMutableURLRequest1, _lib._sel_requestWithURL_cachePolicy_timeoutInterval_1, URL?._id ?? ffi.nullptr, @@ -64670,7 +64946,7 @@ class NSMutableURLRequest extends NSURLRequest { @override NSMutableURLRequest initWithURL_cachePolicy_timeoutInterval_( NSURL? URL, int cachePolicy, double timeoutInterval) { - final _ret = _lib._objc_msgSend_781( + final _ret = _lib._objc_msgSend_785( _id, _lib._sel_initWithURL_cachePolicy_timeoutInterval_1, URL?._id ?? ffi.nullptr, @@ -64808,7 +65084,7 @@ class NSXMLParser extends NSObject { } NSXMLParser initWithStream_(NSInputStream? stream) { - final _ret = _lib._objc_msgSend_932( + final _ret = _lib._objc_msgSend_946( _id, _lib._sel_initWithStream_1, stream?._id ?? ffi.nullptr); return NSXMLParser._(_ret, _lib, retain: true, release: true); } @@ -64844,12 +65120,12 @@ class NSXMLParser extends NSObject { } int get externalEntityResolvingPolicy { - return _lib._objc_msgSend_933( + return _lib._objc_msgSend_947( _id, _lib._sel_externalEntityResolvingPolicy1); } set externalEntityResolvingPolicy(int value) { - return _lib._objc_msgSend_934( + return _lib._objc_msgSend_948( _id, _lib._sel_setExternalEntityResolvingPolicy_1, value); } @@ -64862,7 +65138,7 @@ class NSXMLParser extends NSObject { } set allowedExternalEntityURLs(NSSet? value) { - return _lib._objc_msgSend_935(_id, _lib._sel_setAllowedExternalEntityURLs_1, + return _lib._objc_msgSend_949(_id, _lib._sel_setAllowedExternalEntityURLs_1, value?._id ?? ffi.nullptr); } @@ -65036,7 +65312,7 @@ class NSFileWrapper extends NSObject { NSFileWrapper initWithURL_options_error_( NSURL? url, int options, ffi.Pointer> outError) { - final _ret = _lib._objc_msgSend_936( + final _ret = _lib._objc_msgSend_950( _id, _lib._sel_initWithURL_options_error_1, url?._id ?? ffi.nullptr, @@ -65138,7 +65414,7 @@ class NSFileWrapper extends NSObject { bool readFromURL_options_error_( NSURL? url, int options, ffi.Pointer> outError) { - return _lib._objc_msgSend_937(_id, _lib._sel_readFromURL_options_error_1, + return _lib._objc_msgSend_951(_id, _lib._sel_readFromURL_options_error_1, url?._id ?? ffi.nullptr, options, outError); } @@ -65147,7 +65423,7 @@ class NSFileWrapper extends NSObject { int options, NSURL? originalContentsURL, ffi.Pointer> outError) { - return _lib._objc_msgSend_938( + return _lib._objc_msgSend_952( _id, _lib._sel_writeToURL_options_originalContentsURL_error_1, url?._id ?? ffi.nullptr, @@ -65165,14 +65441,14 @@ class NSFileWrapper extends NSObject { } NSString addFileWrapper_(NSFileWrapper? child) { - final _ret = _lib._objc_msgSend_939( + final _ret = _lib._objc_msgSend_953( _id, _lib._sel_addFileWrapper_1, child?._id ?? ffi.nullptr); return NSString._(_ret, _lib, retain: true, release: true); } NSString addRegularFileWithContents_preferredFilename_( NSData? data, NSString? fileName) { - final _ret = _lib._objc_msgSend_940( + final _ret = _lib._objc_msgSend_954( _id, _lib._sel_addRegularFileWithContents_preferredFilename_1, data?._id ?? ffi.nullptr, @@ -65181,7 +65457,7 @@ class NSFileWrapper extends NSObject { } void removeFileWrapper_(NSFileWrapper? child) { - _lib._objc_msgSend_941( + _lib._objc_msgSend_955( _id, _lib._sel_removeFileWrapper_1, child?._id ?? ffi.nullptr); } @@ -65193,7 +65469,7 @@ class NSFileWrapper extends NSObject { } NSString keyForFileWrapper_(NSFileWrapper? child) { - final _ret = _lib._objc_msgSend_939( + final _ret = _lib._objc_msgSend_953( _id, _lib._sel_keyForFileWrapper_1, child?._id ?? ffi.nullptr); return NSString._(_ret, _lib, retain: true, release: true); } @@ -65237,7 +65513,7 @@ class NSFileWrapper extends NSObject { bool writeToFile_atomically_updateFilenames_( NSString? path, bool atomicFlag, bool updateFilenamesFlag) { - return _lib._objc_msgSend_942( + return _lib._objc_msgSend_956( _id, _lib._sel_writeToFile_atomically_updateFilenames_1, path?._id ?? ffi.nullptr, @@ -65393,7 +65669,7 @@ class NSURLSession extends NSObject { } static NSURLSession? getSharedSession(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_943( + final _ret = _lib._objc_msgSend_957( _lib._class_NSURLSession1, _lib._sel_sharedSession1); return _ret.address == 0 ? null @@ -65402,7 +65678,7 @@ class NSURLSession extends NSObject { static NSURLSession sessionWithConfiguration_( SentryCocoa _lib, NSURLSessionConfiguration? configuration) { - final _ret = _lib._objc_msgSend_954( + final _ret = _lib._objc_msgSend_968( _lib._class_NSURLSession1, _lib._sel_sessionWithConfiguration_1, configuration?._id ?? ffi.nullptr); @@ -65414,7 +65690,7 @@ class NSURLSession extends NSObject { NSURLSessionConfiguration? configuration, NSObject? delegate, NSOperationQueue? queue) { - final _ret = _lib._objc_msgSend_955( + final _ret = _lib._objc_msgSend_969( _lib._class_NSURLSession1, _lib._sel_sessionWithConfiguration_delegate_delegateQueue_1, configuration?._id ?? ffi.nullptr, @@ -65424,7 +65700,7 @@ class NSURLSession extends NSObject { } NSOperationQueue? get delegateQueue { - final _ret = _lib._objc_msgSend_824(_id, _lib._sel_delegateQueue1); + final _ret = _lib._objc_msgSend_838(_id, _lib._sel_delegateQueue1); return _ret.address == 0 ? null : NSOperationQueue._(_ret, _lib, retain: true, release: true); @@ -65438,7 +65714,7 @@ class NSURLSession extends NSObject { } NSURLSessionConfiguration? get configuration { - final _ret = _lib._objc_msgSend_944(_id, _lib._sel_configuration1); + final _ret = _lib._objc_msgSend_958(_id, _lib._sel_configuration1); return _ret.address == 0 ? null : NSURLSessionConfiguration._(_ret, _lib, retain: true, release: true); @@ -65476,31 +65752,31 @@ class NSURLSession extends NSObject { void getTasksWithCompletionHandler_( ObjCBlock_ffiVoid_NSArray_NSArray_NSArray completionHandler) { - _lib._objc_msgSend_956( + _lib._objc_msgSend_970( _id, _lib._sel_getTasksWithCompletionHandler_1, completionHandler._id); } void getAllTasksWithCompletionHandler_( ObjCBlock_ffiVoid_NSArray completionHandler) { - _lib._objc_msgSend_957(_id, _lib._sel_getAllTasksWithCompletionHandler_1, + _lib._objc_msgSend_971(_id, _lib._sel_getAllTasksWithCompletionHandler_1, completionHandler._id); } NSURLSessionDataTask dataTaskWithRequest_(NSURLRequest? request) { - final _ret = _lib._objc_msgSend_958( + final _ret = _lib._objc_msgSend_972( _id, _lib._sel_dataTaskWithRequest_1, request?._id ?? ffi.nullptr); return NSURLSessionDataTask._(_ret, _lib, retain: true, release: true); } NSURLSessionDataTask dataTaskWithURL_(NSURL? url) { - final _ret = _lib._objc_msgSend_959( + final _ret = _lib._objc_msgSend_973( _id, _lib._sel_dataTaskWithURL_1, url?._id ?? ffi.nullptr); return NSURLSessionDataTask._(_ret, _lib, retain: true, release: true); } NSURLSessionUploadTask uploadTaskWithRequest_fromFile_( NSURLRequest? request, NSURL? fileURL) { - final _ret = _lib._objc_msgSend_960( + final _ret = _lib._objc_msgSend_975( _id, _lib._sel_uploadTaskWithRequest_fromFile_1, request?._id ?? ffi.nullptr, @@ -65510,7 +65786,7 @@ class NSURLSession extends NSObject { NSURLSessionUploadTask uploadTaskWithRequest_fromData_( NSURLRequest? request, NSData? bodyData) { - final _ret = _lib._objc_msgSend_961( + final _ret = _lib._objc_msgSend_976( _id, _lib._sel_uploadTaskWithRequest_fromData_1, request?._id ?? ffi.nullptr, @@ -65518,33 +65794,39 @@ class NSURLSession extends NSObject { return NSURLSessionUploadTask._(_ret, _lib, retain: true, release: true); } + NSURLSessionUploadTask uploadTaskWithResumeData_(NSData? resumeData) { + final _ret = _lib._objc_msgSend_977(_id, + _lib._sel_uploadTaskWithResumeData_1, resumeData?._id ?? ffi.nullptr); + return NSURLSessionUploadTask._(_ret, _lib, retain: true, release: true); + } + NSURLSessionUploadTask uploadTaskWithStreamedRequest_(NSURLRequest? request) { - final _ret = _lib._objc_msgSend_962(_id, + final _ret = _lib._objc_msgSend_978(_id, _lib._sel_uploadTaskWithStreamedRequest_1, request?._id ?? ffi.nullptr); return NSURLSessionUploadTask._(_ret, _lib, retain: true, release: true); } NSURLSessionDownloadTask downloadTaskWithRequest_(NSURLRequest? request) { - final _ret = _lib._objc_msgSend_964( + final _ret = _lib._objc_msgSend_979( _id, _lib._sel_downloadTaskWithRequest_1, request?._id ?? ffi.nullptr); return NSURLSessionDownloadTask._(_ret, _lib, retain: true, release: true); } NSURLSessionDownloadTask downloadTaskWithURL_(NSURL? url) { - final _ret = _lib._objc_msgSend_965( + final _ret = _lib._objc_msgSend_980( _id, _lib._sel_downloadTaskWithURL_1, url?._id ?? ffi.nullptr); return NSURLSessionDownloadTask._(_ret, _lib, retain: true, release: true); } NSURLSessionDownloadTask downloadTaskWithResumeData_(NSData? resumeData) { - final _ret = _lib._objc_msgSend_966(_id, + final _ret = _lib._objc_msgSend_981(_id, _lib._sel_downloadTaskWithResumeData_1, resumeData?._id ?? ffi.nullptr); return NSURLSessionDownloadTask._(_ret, _lib, retain: true, release: true); } NSURLSessionStreamTask streamTaskWithHostName_port_( NSString? hostname, int port) { - final _ret = _lib._objc_msgSend_969( + final _ret = _lib._objc_msgSend_984( _id, _lib._sel_streamTaskWithHostName_port_1, hostname?._id ?? ffi.nullptr, @@ -65553,20 +65835,20 @@ class NSURLSession extends NSObject { } NSURLSessionStreamTask streamTaskWithNetService_(NSNetService? service) { - final _ret = _lib._objc_msgSend_975( + final _ret = _lib._objc_msgSend_990( _id, _lib._sel_streamTaskWithNetService_1, service?._id ?? ffi.nullptr); return NSURLSessionStreamTask._(_ret, _lib, retain: true, release: true); } NSURLSessionWebSocketTask webSocketTaskWithURL_(NSURL? url) { - final _ret = _lib._objc_msgSend_982( + final _ret = _lib._objc_msgSend_997( _id, _lib._sel_webSocketTaskWithURL_1, url?._id ?? ffi.nullptr); return NSURLSessionWebSocketTask._(_ret, _lib, retain: true, release: true); } NSURLSessionWebSocketTask webSocketTaskWithURL_protocols_( NSURL? url, NSArray? protocols) { - final _ret = _lib._objc_msgSend_983( + final _ret = _lib._objc_msgSend_998( _id, _lib._sel_webSocketTaskWithURL_protocols_1, url?._id ?? ffi.nullptr, @@ -65575,7 +65857,7 @@ class NSURLSession extends NSObject { } NSURLSessionWebSocketTask webSocketTaskWithRequest_(NSURLRequest? request) { - final _ret = _lib._objc_msgSend_984( + final _ret = _lib._objc_msgSend_999( _id, _lib._sel_webSocketTaskWithRequest_1, request?._id ?? ffi.nullptr); return NSURLSessionWebSocketTask._(_ret, _lib, retain: true, release: true); } @@ -65595,7 +65877,7 @@ class NSURLSession extends NSObject { NSURLSessionDataTask dataTaskWithRequest_completionHandler_( NSURLRequest? request, ObjCBlock_ffiVoid_NSData_NSURLResponse_NSError completionHandler) { - final _ret = _lib._objc_msgSend_985( + final _ret = _lib._objc_msgSend_1000( _id, _lib._sel_dataTaskWithRequest_completionHandler_1, request?._id ?? ffi.nullptr, @@ -65605,7 +65887,7 @@ class NSURLSession extends NSObject { NSURLSessionDataTask dataTaskWithURL_completionHandler_(NSURL? url, ObjCBlock_ffiVoid_NSData_NSURLResponse_NSError completionHandler) { - final _ret = _lib._objc_msgSend_986( + final _ret = _lib._objc_msgSend_1001( _id, _lib._sel_dataTaskWithURL_completionHandler_1, url?._id ?? ffi.nullptr, @@ -65617,7 +65899,7 @@ class NSURLSession extends NSObject { NSURLRequest? request, NSURL? fileURL, ObjCBlock_ffiVoid_NSData_NSURLResponse_NSError completionHandler) { - final _ret = _lib._objc_msgSend_987( + final _ret = _lib._objc_msgSend_1002( _id, _lib._sel_uploadTaskWithRequest_fromFile_completionHandler_1, request?._id ?? ffi.nullptr, @@ -65630,7 +65912,7 @@ class NSURLSession extends NSObject { NSURLRequest? request, NSData? bodyData, ObjCBlock_ffiVoid_NSData_NSURLResponse_NSError completionHandler) { - final _ret = _lib._objc_msgSend_988( + final _ret = _lib._objc_msgSend_1003( _id, _lib._sel_uploadTaskWithRequest_fromData_completionHandler_1, request?._id ?? ffi.nullptr, @@ -65639,10 +65921,21 @@ class NSURLSession extends NSObject { return NSURLSessionUploadTask._(_ret, _lib, retain: true, release: true); } + NSURLSessionUploadTask uploadTaskWithResumeData_completionHandler_( + NSData? resumeData, + ObjCBlock_ffiVoid_NSData_NSURLResponse_NSError completionHandler) { + final _ret = _lib._objc_msgSend_1004( + _id, + _lib._sel_uploadTaskWithResumeData_completionHandler_1, + resumeData?._id ?? ffi.nullptr, + completionHandler._id); + return NSURLSessionUploadTask._(_ret, _lib, retain: true, release: true); + } + NSURLSessionDownloadTask downloadTaskWithRequest_completionHandler_( NSURLRequest? request, ObjCBlock_ffiVoid_NSURL_NSURLResponse_NSError completionHandler) { - final _ret = _lib._objc_msgSend_989( + final _ret = _lib._objc_msgSend_1005( _id, _lib._sel_downloadTaskWithRequest_completionHandler_1, request?._id ?? ffi.nullptr, @@ -65652,7 +65945,7 @@ class NSURLSession extends NSObject { NSURLSessionDownloadTask downloadTaskWithURL_completionHandler_(NSURL? url, ObjCBlock_ffiVoid_NSURL_NSURLResponse_NSError completionHandler) { - final _ret = _lib._objc_msgSend_990( + final _ret = _lib._objc_msgSend_1006( _id, _lib._sel_downloadTaskWithURL_completionHandler_1, url?._id ?? ffi.nullptr, @@ -65663,7 +65956,7 @@ class NSURLSession extends NSObject { NSURLSessionDownloadTask downloadTaskWithResumeData_completionHandler_( NSData? resumeData, ObjCBlock_ffiVoid_NSURL_NSURLResponse_NSError completionHandler) { - final _ret = _lib._objc_msgSend_991( + final _ret = _lib._objc_msgSend_1007( _id, _lib._sel_downloadTaskWithResumeData_completionHandler_1, resumeData?._id ?? ffi.nullptr, @@ -65779,7 +66072,7 @@ class NSURLSessionConfiguration extends NSObject { static NSURLSessionConfiguration? getDefaultSessionConfiguration( SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_944(_lib._class_NSURLSessionConfiguration1, + final _ret = _lib._objc_msgSend_958(_lib._class_NSURLSessionConfiguration1, _lib._sel_defaultSessionConfiguration1); return _ret.address == 0 ? null @@ -65788,7 +66081,7 @@ class NSURLSessionConfiguration extends NSObject { static NSURLSessionConfiguration? getEphemeralSessionConfiguration( SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_944(_lib._class_NSURLSessionConfiguration1, + final _ret = _lib._objc_msgSend_958(_lib._class_NSURLSessionConfiguration1, _lib._sel_ephemeralSessionConfiguration1); return _ret.address == 0 ? null @@ -65798,7 +66091,7 @@ class NSURLSessionConfiguration extends NSObject { static NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier_( SentryCocoa _lib, NSString? identifier) { - final _ret = _lib._objc_msgSend_945( + final _ret = _lib._objc_msgSend_959( _lib._class_NSURLSessionConfiguration1, _lib._sel_backgroundSessionConfigurationWithIdentifier_1, identifier?._id ?? ffi.nullptr); @@ -65813,11 +66106,11 @@ class NSURLSessionConfiguration extends NSObject { } int get requestCachePolicy { - return _lib._objc_msgSend_782(_id, _lib._sel_requestCachePolicy1); + return _lib._objc_msgSend_786(_id, _lib._sel_requestCachePolicy1); } set requestCachePolicy(int value) { - return _lib._objc_msgSend_922( + return _lib._objc_msgSend_936( _id, _lib._sel_setRequestCachePolicy_1, value); } @@ -65840,11 +66133,11 @@ class NSURLSessionConfiguration extends NSObject { } int get networkServiceType { - return _lib._objc_msgSend_783(_id, _lib._sel_networkServiceType1); + return _lib._objc_msgSend_787(_id, _lib._sel_networkServiceType1); } set networkServiceType(int value) { - return _lib._objc_msgSend_923( + return _lib._objc_msgSend_937( _id, _lib._sel_setNetworkServiceType_1, value); } @@ -65938,40 +66231,40 @@ class NSURLSessionConfiguration extends NSObject { } int get TLSMinimumSupportedProtocol { - return _lib._objc_msgSend_946(_id, _lib._sel_TLSMinimumSupportedProtocol1); + return _lib._objc_msgSend_960(_id, _lib._sel_TLSMinimumSupportedProtocol1); } set TLSMinimumSupportedProtocol(int value) { - return _lib._objc_msgSend_947( + return _lib._objc_msgSend_961( _id, _lib._sel_setTLSMinimumSupportedProtocol_1, value); } int get TLSMaximumSupportedProtocol { - return _lib._objc_msgSend_946(_id, _lib._sel_TLSMaximumSupportedProtocol1); + return _lib._objc_msgSend_960(_id, _lib._sel_TLSMaximumSupportedProtocol1); } set TLSMaximumSupportedProtocol(int value) { - return _lib._objc_msgSend_947( + return _lib._objc_msgSend_961( _id, _lib._sel_setTLSMaximumSupportedProtocol_1, value); } int get TLSMinimumSupportedProtocolVersion { - return _lib._objc_msgSend_948( + return _lib._objc_msgSend_962( _id, _lib._sel_TLSMinimumSupportedProtocolVersion1); } set TLSMinimumSupportedProtocolVersion(int value) { - return _lib._objc_msgSend_949( + return _lib._objc_msgSend_963( _id, _lib._sel_setTLSMinimumSupportedProtocolVersion_1, value); } int get TLSMaximumSupportedProtocolVersion { - return _lib._objc_msgSend_948( + return _lib._objc_msgSend_962( _id, _lib._sel_TLSMaximumSupportedProtocolVersion1); } set TLSMaximumSupportedProtocolVersion(int value) { - return _lib._objc_msgSend_949( + return _lib._objc_msgSend_963( _id, _lib._sel_setTLSMaximumSupportedProtocolVersion_1, value); } @@ -65994,11 +66287,11 @@ class NSURLSessionConfiguration extends NSObject { } int get HTTPCookieAcceptPolicy { - return _lib._objc_msgSend_779(_id, _lib._sel_HTTPCookieAcceptPolicy1); + return _lib._objc_msgSend_783(_id, _lib._sel_HTTPCookieAcceptPolicy1); } set HTTPCookieAcceptPolicy(int value) { - return _lib._objc_msgSend_780( + return _lib._objc_msgSend_784( _id, _lib._sel_setHTTPCookieAcceptPolicy_1, value); } @@ -66024,38 +66317,38 @@ class NSURLSessionConfiguration extends NSObject { } NSHTTPCookieStorage? get HTTPCookieStorage { - final _ret = _lib._objc_msgSend_773(_id, _lib._sel_HTTPCookieStorage1); + final _ret = _lib._objc_msgSend_777(_id, _lib._sel_HTTPCookieStorage1); return _ret.address == 0 ? null : NSHTTPCookieStorage._(_ret, _lib, retain: true, release: true); } set HTTPCookieStorage(NSHTTPCookieStorage? value) { - return _lib._objc_msgSend_950( + return _lib._objc_msgSend_964( _id, _lib._sel_setHTTPCookieStorage_1, value?._id ?? ffi.nullptr); } NSURLCredentialStorage? get URLCredentialStorage { - final _ret = _lib._objc_msgSend_908(_id, _lib._sel_URLCredentialStorage1); + final _ret = _lib._objc_msgSend_922(_id, _lib._sel_URLCredentialStorage1); return _ret.address == 0 ? null : NSURLCredentialStorage._(_ret, _lib, retain: true, release: true); } set URLCredentialStorage(NSURLCredentialStorage? value) { - return _lib._objc_msgSend_951( + return _lib._objc_msgSend_965( _id, _lib._sel_setURLCredentialStorage_1, value?._id ?? ffi.nullptr); } NSURLCache? get URLCache { - final _ret = _lib._objc_msgSend_878(_id, _lib._sel_URLCache1); + final _ret = _lib._objc_msgSend_892(_id, _lib._sel_URLCache1); return _ret.address == 0 ? null : NSURLCache._(_ret, _lib, retain: true, release: true); } set URLCache(NSURLCache? value) { - return _lib._objc_msgSend_879( + return _lib._objc_msgSend_893( _id, _lib._sel_setURLCache_1, value?._id ?? ffi.nullptr); } @@ -66077,16 +66370,16 @@ class NSURLSessionConfiguration extends NSObject { } set protocolClasses(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setProtocolClasses_1, value?._id ?? ffi.nullptr); } int get multipathServiceType { - return _lib._objc_msgSend_952(_id, _lib._sel_multipathServiceType1); + return _lib._objc_msgSend_966(_id, _lib._sel_multipathServiceType1); } set multipathServiceType(int value) { - return _lib._objc_msgSend_953( + return _lib._objc_msgSend_967( _id, _lib._sel_setMultipathServiceType_1, value); } @@ -66105,7 +66398,7 @@ class NSURLSessionConfiguration extends NSObject { static NSURLSessionConfiguration backgroundSessionConfiguration_( SentryCocoa _lib, NSString? identifier) { - final _ret = _lib._objc_msgSend_945( + final _ret = _lib._objc_msgSend_959( _lib._class_NSURLSessionConfiguration1, _lib._sel_backgroundSessionConfiguration_1, identifier?._id ?? ffi.nullptr); @@ -66371,6 +66664,12 @@ class NSURLSessionUploadTask extends NSURLSessionDataTask { return NSURLSessionUploadTask._(_ret, _lib, retain: false, release: true); } + void cancelByProducingResumeData_( + ObjCBlock_ffiVoid_NSData completionHandler) { + _lib._objc_msgSend_974( + _id, _lib._sel_cancelByProducingResumeData_1, completionHandler._id); + } + static NSURLSessionUploadTask allocWithZone_( SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { final _ret = _lib._objc_msgSend_3( @@ -66452,130 +66751,6 @@ class NSURLSessionUploadTask extends NSURLSessionDataTask { } } -class NSURLSessionDownloadTask extends NSURLSessionTask { - NSURLSessionDownloadTask._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); - - /// Returns a [NSURLSessionDownloadTask] that points to the same underlying object as [other]. - static NSURLSessionDownloadTask castFrom(T other) { - return NSURLSessionDownloadTask._(other._id, other._lib, - retain: true, release: true); - } - - /// Returns a [NSURLSessionDownloadTask] that wraps the given raw object pointer. - static NSURLSessionDownloadTask castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return NSURLSessionDownloadTask._(other, lib, - retain: retain, release: release); - } - - /// Returns whether [obj] is an instance of [NSURLSessionDownloadTask]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_NSURLSessionDownloadTask1); - } - - void cancelByProducingResumeData_( - ObjCBlock_ffiVoid_NSData completionHandler) { - _lib._objc_msgSend_963( - _id, _lib._sel_cancelByProducingResumeData_1, completionHandler._id); - } - - @override - NSURLSessionDownloadTask init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return NSURLSessionDownloadTask._(_ret, _lib, retain: true, release: true); - } - - static NSURLSessionDownloadTask new1(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_NSURLSessionDownloadTask1, _lib._sel_new1); - return NSURLSessionDownloadTask._(_ret, _lib, retain: false, release: true); - } - - static NSURLSessionDownloadTask allocWithZone_( - SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { - final _ret = _lib._objc_msgSend_3( - _lib._class_NSURLSessionDownloadTask1, _lib._sel_allocWithZone_1, zone); - return NSURLSessionDownloadTask._(_ret, _lib, retain: false, release: true); - } - - static NSURLSessionDownloadTask alloc(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_NSURLSessionDownloadTask1, _lib._sel_alloc1); - return NSURLSessionDownloadTask._(_ret, _lib, retain: false, release: true); - } - - static void cancelPreviousPerformRequestsWithTarget_selector_object_( - SentryCocoa _lib, - NSObject aTarget, - ffi.Pointer aSelector, - NSObject anArgument) { - _lib._objc_msgSend_14( - _lib._class_NSURLSessionDownloadTask1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, - aTarget._id, - aSelector, - anArgument._id); - } - - static void cancelPreviousPerformRequestsWithTarget_( - SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_NSURLSessionDownloadTask1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); - } - - static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12(_lib._class_NSURLSessionDownloadTask1, - _lib._sel_accessInstanceVariablesDirectly1); - } - - static bool useStoredAccessor(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_NSURLSessionDownloadTask1, _lib._sel_useStoredAccessor1); - } - - static NSSet keyPathsForValuesAffectingValueForKey_( - SentryCocoa _lib, NSString? key) { - final _ret = _lib._objc_msgSend_58( - _lib._class_NSURLSessionDownloadTask1, - _lib._sel_keyPathsForValuesAffectingValueForKey_1, - key?._id ?? ffi.nullptr); - return NSSet._(_ret, _lib, retain: true, release: true); - } - - static bool automaticallyNotifiesObserversForKey_( - SentryCocoa _lib, NSString? key) { - return _lib._objc_msgSend_59( - _lib._class_NSURLSessionDownloadTask1, - _lib._sel_automaticallyNotifiesObserversForKey_1, - key?._id ?? ffi.nullptr); - } - - static void setKeys_triggerChangeNotificationsForDependentKey_( - SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { - _lib._objc_msgSend_82( - _lib._class_NSURLSessionDownloadTask1, - _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, - keys?._id ?? ffi.nullptr, - dependentKey?._id ?? ffi.nullptr); - } - - static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79(_lib._class_NSURLSessionDownloadTask1, - _lib._sel_classFallbacksForKeyedArchiver1); - return NSArray._(_ret, _lib, retain: true, release: true); - } - - static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_NSURLSessionDownloadTask1, - _lib._sel_classForKeyedUnarchiver1); - return NSObject._(_ret, _lib, retain: true, release: true); - } -} - void _ObjCBlock_ffiVoid_NSData_fnPtrTrampoline( ffi.Pointer<_ObjCBlock> block, ffi.Pointer arg0) { return block.ref.target @@ -66645,6 +66820,130 @@ class ObjCBlock_ffiVoid_NSData extends _ObjCBlockBase { } } +class NSURLSessionDownloadTask extends NSURLSessionTask { + NSURLSessionDownloadTask._(ffi.Pointer id, SentryCocoa lib, + {bool retain = false, bool release = false}) + : super._(id, lib, retain: retain, release: release); + + /// Returns a [NSURLSessionDownloadTask] that points to the same underlying object as [other]. + static NSURLSessionDownloadTask castFrom(T other) { + return NSURLSessionDownloadTask._(other._id, other._lib, + retain: true, release: true); + } + + /// Returns a [NSURLSessionDownloadTask] that wraps the given raw object pointer. + static NSURLSessionDownloadTask castFromPointer( + SentryCocoa lib, ffi.Pointer other, + {bool retain = false, bool release = false}) { + return NSURLSessionDownloadTask._(other, lib, + retain: retain, release: release); + } + + /// Returns whether [obj] is an instance of [NSURLSessionDownloadTask]. + static bool isInstance(_ObjCWrapper obj) { + return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, + obj._lib._class_NSURLSessionDownloadTask1); + } + + void cancelByProducingResumeData_( + ObjCBlock_ffiVoid_NSData completionHandler) { + _lib._objc_msgSend_974( + _id, _lib._sel_cancelByProducingResumeData_1, completionHandler._id); + } + + @override + NSURLSessionDownloadTask init() { + final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); + return NSURLSessionDownloadTask._(_ret, _lib, retain: true, release: true); + } + + static NSURLSessionDownloadTask new1(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2( + _lib._class_NSURLSessionDownloadTask1, _lib._sel_new1); + return NSURLSessionDownloadTask._(_ret, _lib, retain: false, release: true); + } + + static NSURLSessionDownloadTask allocWithZone_( + SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { + final _ret = _lib._objc_msgSend_3( + _lib._class_NSURLSessionDownloadTask1, _lib._sel_allocWithZone_1, zone); + return NSURLSessionDownloadTask._(_ret, _lib, retain: false, release: true); + } + + static NSURLSessionDownloadTask alloc(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2( + _lib._class_NSURLSessionDownloadTask1, _lib._sel_alloc1); + return NSURLSessionDownloadTask._(_ret, _lib, retain: false, release: true); + } + + static void cancelPreviousPerformRequestsWithTarget_selector_object_( + SentryCocoa _lib, + NSObject aTarget, + ffi.Pointer aSelector, + NSObject anArgument) { + _lib._objc_msgSend_14( + _lib._class_NSURLSessionDownloadTask1, + _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, + aTarget._id, + aSelector, + anArgument._id); + } + + static void cancelPreviousPerformRequestsWithTarget_( + SentryCocoa _lib, NSObject aTarget) { + _lib._objc_msgSend_15(_lib._class_NSURLSessionDownloadTask1, + _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); + } + + static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { + return _lib._objc_msgSend_12(_lib._class_NSURLSessionDownloadTask1, + _lib._sel_accessInstanceVariablesDirectly1); + } + + static bool useStoredAccessor(SentryCocoa _lib) { + return _lib._objc_msgSend_12( + _lib._class_NSURLSessionDownloadTask1, _lib._sel_useStoredAccessor1); + } + + static NSSet keyPathsForValuesAffectingValueForKey_( + SentryCocoa _lib, NSString? key) { + final _ret = _lib._objc_msgSend_58( + _lib._class_NSURLSessionDownloadTask1, + _lib._sel_keyPathsForValuesAffectingValueForKey_1, + key?._id ?? ffi.nullptr); + return NSSet._(_ret, _lib, retain: true, release: true); + } + + static bool automaticallyNotifiesObserversForKey_( + SentryCocoa _lib, NSString? key) { + return _lib._objc_msgSend_59( + _lib._class_NSURLSessionDownloadTask1, + _lib._sel_automaticallyNotifiesObserversForKey_1, + key?._id ?? ffi.nullptr); + } + + static void setKeys_triggerChangeNotificationsForDependentKey_( + SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { + _lib._objc_msgSend_82( + _lib._class_NSURLSessionDownloadTask1, + _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, + keys?._id ?? ffi.nullptr, + dependentKey?._id ?? ffi.nullptr); + } + + static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_79(_lib._class_NSURLSessionDownloadTask1, + _lib._sel_classFallbacksForKeyedArchiver1); + return NSArray._(_ret, _lib, retain: true, release: true); + } + + static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_NSURLSessionDownloadTask1, + _lib._sel_classForKeyedUnarchiver1); + return NSObject._(_ret, _lib, retain: true, release: true); + } +} + class NSURLSessionStreamTask extends NSURLSessionTask { NSURLSessionStreamTask._(ffi.Pointer id, SentryCocoa lib, {bool retain = false, bool release = false}) @@ -66675,7 +66974,7 @@ class NSURLSessionStreamTask extends NSURLSessionTask { int maxBytes, double timeout, ObjCBlock_ffiVoid_NSData_bool_NSError completionHandler) { - _lib._objc_msgSend_967( + _lib._objc_msgSend_982( _id, _lib._sel_readDataOfMinLength_maxLength_timeout_completionHandler_1, minBytes, @@ -66686,7 +66985,7 @@ class NSURLSessionStreamTask extends NSURLSessionTask { void writeData_timeout_completionHandler_(NSData? data, double timeout, ObjCBlock_ffiVoid_NSError completionHandler) { - _lib._objc_msgSend_968(_id, _lib._sel_writeData_timeout_completionHandler_1, + _lib._objc_msgSend_983(_id, _lib._sel_writeData_timeout_completionHandler_1, data?._id ?? ffi.nullptr, timeout, completionHandler._id); } @@ -66929,7 +67228,7 @@ class NSNetService extends NSObject { NSNetService initWithDomain_type_name_port_( NSString? domain, NSString? type, NSString? name, int port) { - final _ret = _lib._objc_msgSend_970( + final _ret = _lib._objc_msgSend_985( _id, _lib._sel_initWithDomain_type_name_port_1, domain?._id ?? ffi.nullptr, @@ -67025,7 +67324,7 @@ class NSNetService extends NSObject { } void publishWithOptions_(int options) { - _lib._objc_msgSend_971(_id, _lib._sel_publishWithOptions_1, options); + _lib._objc_msgSend_986(_id, _lib._sel_publishWithOptions_1, options); } void resolve() { @@ -67038,14 +67337,14 @@ class NSNetService extends NSObject { static NSDictionary dictionaryFromTXTRecordData_( SentryCocoa _lib, NSData? txtData) { - final _ret = _lib._objc_msgSend_972(_lib._class_NSNetService1, + final _ret = _lib._objc_msgSend_987(_lib._class_NSNetService1, _lib._sel_dictionaryFromTXTRecordData_1, txtData?._id ?? ffi.nullptr); return NSDictionary._(_ret, _lib, retain: true, release: true); } static NSData dataFromTXTRecordDictionary_( SentryCocoa _lib, NSDictionary? txtDictionary) { - final _ret = _lib._objc_msgSend_973( + final _ret = _lib._objc_msgSend_988( _lib._class_NSNetService1, _lib._sel_dataFromTXTRecordDictionary_1, txtDictionary?._id ?? ffi.nullptr); @@ -67059,7 +67358,7 @@ class NSNetService extends NSObject { bool getInputStream_outputStream_( ffi.Pointer> inputStream, ffi.Pointer> outputStream) { - return _lib._objc_msgSend_974(_id, _lib._sel_getInputStream_outputStream_1, + return _lib._objc_msgSend_989(_id, _lib._sel_getInputStream_outputStream_1, inputStream, outputStream); } @@ -67206,25 +67505,25 @@ class NSURLSessionWebSocketTask extends NSURLSessionTask { void sendMessage_completionHandler_(NSURLSessionWebSocketMessage? message, ObjCBlock_ffiVoid_NSError completionHandler) { - _lib._objc_msgSend_977(_id, _lib._sel_sendMessage_completionHandler_1, + _lib._objc_msgSend_992(_id, _lib._sel_sendMessage_completionHandler_1, message?._id ?? ffi.nullptr, completionHandler._id); } void receiveMessageWithCompletionHandler_( ObjCBlock_ffiVoid_NSURLSessionWebSocketMessage_NSError completionHandler) { - _lib._objc_msgSend_978(_id, _lib._sel_receiveMessageWithCompletionHandler_1, + _lib._objc_msgSend_993(_id, _lib._sel_receiveMessageWithCompletionHandler_1, completionHandler._id); } void sendPingWithPongReceiveHandler_( ObjCBlock_ffiVoid_NSError pongReceiveHandler) { - _lib._objc_msgSend_979(_id, _lib._sel_sendPingWithPongReceiveHandler_1, + _lib._objc_msgSend_994(_id, _lib._sel_sendPingWithPongReceiveHandler_1, pongReceiveHandler._id); } void cancelWithCloseCode_reason_(int closeCode, NSData? reason) { - _lib._objc_msgSend_980(_id, _lib._sel_cancelWithCloseCode_reason_1, + _lib._objc_msgSend_995(_id, _lib._sel_cancelWithCloseCode_reason_1, closeCode, reason?._id ?? ffi.nullptr); } @@ -67238,7 +67537,7 @@ class NSURLSessionWebSocketTask extends NSURLSessionTask { } int get closeCode { - return _lib._objc_msgSend_981(_id, _lib._sel_closeCode1); + return _lib._objc_msgSend_996(_id, _lib._sel_closeCode1); } NSData? get closeReason { @@ -67385,7 +67684,7 @@ class NSURLSessionWebSocketMessage extends NSObject { } int get type { - return _lib._objc_msgSend_976(_id, _lib._sel_type1); + return _lib._objc_msgSend_991(_id, _lib._sel_type1); } NSData? get data { @@ -67866,14 +68165,14 @@ class NSProtocolChecker extends NSProxy { } Protocol? get protocol { - final _ret = _lib._objc_msgSend_992(_id, _lib._sel_protocol1); + final _ret = _lib._objc_msgSend_1008(_id, _lib._sel_protocol1); return _ret.address == 0 ? null : Protocol._(_ret, _lib, retain: true, release: true); } NSObject? get target { - final _ret = _lib._objc_msgSend_822(_id, _lib._sel_target1); + final _ret = _lib._objc_msgSend_836(_id, _lib._sel_target1); return _ret.address == 0 ? null : NSObject._(_ret, _lib, retain: true, release: true); @@ -67881,7 +68180,7 @@ class NSProtocolChecker extends NSProxy { static NSProtocolChecker protocolCheckerWithTarget_protocol_( SentryCocoa _lib, NSObject? anObject, Protocol? aProtocol) { - final _ret = _lib._objc_msgSend_993( + final _ret = _lib._objc_msgSend_1009( _lib._class_NSProtocolChecker1, _lib._sel_protocolCheckerWithTarget_protocol_1, anObject?._id ?? ffi.nullptr, @@ -67891,7 +68190,7 @@ class NSProtocolChecker extends NSProxy { NSProtocolChecker initWithTarget_protocol_( NSObject? anObject, Protocol? aProtocol) { - final _ret = _lib._objc_msgSend_993( + final _ret = _lib._objc_msgSend_1009( _id, _lib._sel_initWithTarget_protocol_1, anObject?._id ?? ffi.nullptr, @@ -67960,7 +68259,7 @@ class NSTask extends NSObject { } set arguments(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setArguments_1, value?._id ?? ffi.nullptr); } @@ -68049,16 +68348,16 @@ class NSTask extends NSObject { } int get terminationReason { - return _lib._objc_msgSend_994(_id, _lib._sel_terminationReason1); + return _lib._objc_msgSend_1010(_id, _lib._sel_terminationReason1); } ObjCBlock_ffiVoid_NSTask get terminationHandler { - final _ret = _lib._objc_msgSend_995(_id, _lib._sel_terminationHandler1); + final _ret = _lib._objc_msgSend_1011(_id, _lib._sel_terminationHandler1); return ObjCBlock_ffiVoid_NSTask._(_ret, _lib); } set terminationHandler(ObjCBlock_ffiVoid_NSTask value) { - return _lib._objc_msgSend_996( + return _lib._objc_msgSend_1012( _id, _lib._sel_setTerminationHandler_1, value._id); } @@ -68077,7 +68376,7 @@ class NSTask extends NSObject { NSArray? arguments, ffi.Pointer> error, ObjCBlock_ffiVoid_NSTask terminationHandler) { - final _ret = _lib._objc_msgSend_997( + final _ret = _lib._objc_msgSend_1013( _lib._class_NSTask1, _lib._sel_launchedTaskWithExecutableURL_arguments_error_terminationHandler_1, url?._id ?? ffi.nullptr, @@ -68121,7 +68420,7 @@ class NSTask extends NSObject { static NSTask launchedTaskWithLaunchPath_arguments_( SentryCocoa _lib, NSString? path, NSArray? arguments) { - final _ret = _lib._objc_msgSend_998( + final _ret = _lib._objc_msgSend_1014( _lib._class_NSTask1, _lib._sel_launchedTaskWithLaunchPath_arguments_1, path?._id ?? ffi.nullptr, @@ -68340,7 +68639,7 @@ class NSXMLElement extends NSXMLNode { @override NSXMLElement initWithKind_options_(int kind, int options) { - final _ret = _lib._objc_msgSend_1000( + final _ret = _lib._objc_msgSend_1016( _id, _lib._sel_initWithKind_options_1, kind, options); return NSXMLElement._(_ret, _lib, retain: true, release: true); } @@ -68361,7 +68660,7 @@ class NSXMLElement extends NSXMLNode { } void addAttribute_(NSXMLNode? attribute) { - _lib._objc_msgSend_1012( + _lib._objc_msgSend_1028( _id, _lib._sel_addAttribute_1, attribute?._id ?? ffi.nullptr); } @@ -68378,7 +68677,7 @@ class NSXMLElement extends NSXMLNode { } set attributes(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setAttributes_1, value?._id ?? ffi.nullptr); } @@ -68388,13 +68687,13 @@ class NSXMLElement extends NSXMLNode { } NSXMLNode attributeForName_(NSString? name) { - final _ret = _lib._objc_msgSend_1016( + final _ret = _lib._objc_msgSend_1032( _id, _lib._sel_attributeForName_1, name?._id ?? ffi.nullptr); return NSXMLNode._(_ret, _lib, retain: true, release: true); } NSXMLNode attributeForLocalName_URI_(NSString? localName, NSString? URI) { - final _ret = _lib._objc_msgSend_1033( + final _ret = _lib._objc_msgSend_1049( _id, _lib._sel_attributeForLocalName_URI_1, localName?._id ?? ffi.nullptr, @@ -68403,7 +68702,7 @@ class NSXMLElement extends NSXMLNode { } void addNamespace_(NSXMLNode? aNamespace) { - _lib._objc_msgSend_1012( + _lib._objc_msgSend_1028( _id, _lib._sel_addNamespace_1, aNamespace?._id ?? ffi.nullptr); } @@ -68420,18 +68719,18 @@ class NSXMLElement extends NSXMLNode { } set namespaces(NSArray? value) { - return _lib._objc_msgSend_731( + return _lib._objc_msgSend_735( _id, _lib._sel_setNamespaces_1, value?._id ?? ffi.nullptr); } NSXMLNode namespaceForPrefix_(NSString? name) { - final _ret = _lib._objc_msgSend_1016( + final _ret = _lib._objc_msgSend_1032( _id, _lib._sel_namespaceForPrefix_1, name?._id ?? ffi.nullptr); return NSXMLNode._(_ret, _lib, retain: true, release: true); } NSXMLNode resolveNamespaceForName_(NSString? name) { - final _ret = _lib._objc_msgSend_1016( + final _ret = _lib._objc_msgSend_1032( _id, _lib._sel_resolveNamespaceForName_1, name?._id ?? ffi.nullptr); return NSXMLNode._(_ret, _lib, retain: true, release: true); } @@ -68445,12 +68744,12 @@ class NSXMLElement extends NSXMLNode { } void insertChild_atIndex_(NSXMLNode? child, int index) { - _lib._objc_msgSend_1010( + _lib._objc_msgSend_1026( _id, _lib._sel_insertChild_atIndex_1, child?._id ?? ffi.nullptr, index); } void insertChildren_atIndex_(NSArray? children, int index) { - _lib._objc_msgSend_1011(_id, _lib._sel_insertChildren_atIndex_1, + _lib._objc_msgSend_1027(_id, _lib._sel_insertChildren_atIndex_1, children?._id ?? ffi.nullptr, index); } @@ -68464,17 +68763,17 @@ class NSXMLElement extends NSXMLNode { } void addChild_(NSXMLNode? child) { - _lib._objc_msgSend_1012( + _lib._objc_msgSend_1028( _id, _lib._sel_addChild_1, child?._id ?? ffi.nullptr); } void replaceChildAtIndex_withNode_(int index, NSXMLNode? node) { - _lib._objc_msgSend_1013(_id, _lib._sel_replaceChildAtIndex_withNode_1, + _lib._objc_msgSend_1029(_id, _lib._sel_replaceChildAtIndex_withNode_1, index, node?._id ?? ffi.nullptr); } void normalizeAdjacentTextNodesPreservingCDATA_(bool preserve) { - _lib._objc_msgSend_790( + _lib._objc_msgSend_794( _id, _lib._sel_normalizeAdjacentTextNodesPreservingCDATA_1, preserve); } @@ -68491,7 +68790,7 @@ class NSXMLElement extends NSXMLNode { @override NSXMLElement initWithKind_(int kind) { - final _ret = _lib._objc_msgSend_999(_id, _lib._sel_initWithKind_1, kind); + final _ret = _lib._objc_msgSend_1015(_id, _lib._sel_initWithKind_1, kind); return NSXMLElement._(_ret, _lib, retain: true, release: true); } @@ -68503,7 +68802,7 @@ class NSXMLElement extends NSXMLNode { static NSObject documentWithRootElement_( SentryCocoa _lib, NSXMLElement? element) { - final _ret = _lib._objc_msgSend_1001(_lib._class_NSXMLElement1, + final _ret = _lib._objc_msgSend_1017(_lib._class_NSXMLElement1, _lib._sel_documentWithRootElement_1, element?._id ?? ffi.nullptr); return NSObject._(_ret, _lib, retain: true, release: true); } @@ -68536,7 +68835,7 @@ class NSXMLElement extends NSXMLNode { static NSObject elementWithName_children_attributes_(SentryCocoa _lib, NSString? name, NSArray? children, NSArray? attributes) { - final _ret = _lib._objc_msgSend_1002( + final _ret = _lib._objc_msgSend_1018( _lib._class_NSXMLElement1, _lib._sel_elementWithName_children_attributes_1, name?._id ?? ffi.nullptr, @@ -68620,7 +68919,7 @@ class NSXMLElement extends NSXMLNode { static NSXMLNode predefinedNamespaceForPrefix_( SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_1016(_lib._class_NSXMLElement1, + final _ret = _lib._objc_msgSend_1032(_lib._class_NSXMLElement1, _lib._sel_predefinedNamespaceForPrefix_1, name?._id ?? ffi.nullptr); return NSXMLNode._(_ret, _lib, retain: true, release: true); } @@ -68742,12 +69041,12 @@ class NSXMLNode extends NSObject { } NSXMLNode initWithKind_(int kind) { - final _ret = _lib._objc_msgSend_999(_id, _lib._sel_initWithKind_1, kind); + final _ret = _lib._objc_msgSend_1015(_id, _lib._sel_initWithKind_1, kind); return NSXMLNode._(_ret, _lib, retain: true, release: true); } NSXMLNode initWithKind_options_(int kind, int options) { - final _ret = _lib._objc_msgSend_1000( + final _ret = _lib._objc_msgSend_1016( _id, _lib._sel_initWithKind_options_1, kind, options); return NSXMLNode._(_ret, _lib, retain: true, release: true); } @@ -68760,7 +69059,7 @@ class NSXMLNode extends NSObject { static NSObject documentWithRootElement_( SentryCocoa _lib, NSXMLElement? element) { - final _ret = _lib._objc_msgSend_1001(_lib._class_NSXMLNode1, + final _ret = _lib._objc_msgSend_1017(_lib._class_NSXMLNode1, _lib._sel_documentWithRootElement_1, element?._id ?? ffi.nullptr); return NSObject._(_ret, _lib, retain: true, release: true); } @@ -68793,7 +69092,7 @@ class NSXMLNode extends NSObject { static NSObject elementWithName_children_attributes_(SentryCocoa _lib, NSString? name, NSArray? children, NSArray? attributes) { - final _ret = _lib._objc_msgSend_1002( + final _ret = _lib._objc_msgSend_1018( _lib._class_NSXMLNode1, _lib._sel_elementWithName_children_attributes_1, name?._id ?? ffi.nullptr, @@ -68864,7 +69163,7 @@ class NSXMLNode extends NSObject { } int get kind { - return _lib._objc_msgSend_1003(_id, _lib._sel_kind1); + return _lib._objc_msgSend_1019(_id, _lib._sel_kind1); } NSString? get name { @@ -68901,7 +69200,7 @@ class NSXMLNode extends NSObject { } void setStringValue_resolvingEntities_(NSString? string, bool resolve) { - _lib._objc_msgSend_1004(_id, _lib._sel_setStringValue_resolvingEntities_1, + _lib._objc_msgSend_1020(_id, _lib._sel_setStringValue_resolvingEntities_1, string?._id ?? ffi.nullptr, resolve); } @@ -68914,14 +69213,14 @@ class NSXMLNode extends NSObject { } NSXMLDocument? get rootDocument { - final _ret = _lib._objc_msgSend_1027(_id, _lib._sel_rootDocument1); + final _ret = _lib._objc_msgSend_1043(_id, _lib._sel_rootDocument1); return _ret.address == 0 ? null : NSXMLDocument._(_ret, _lib, retain: true, release: true); } NSXMLNode? get parent { - final _ret = _lib._objc_msgSend_1028(_id, _lib._sel_parent1); + final _ret = _lib._objc_msgSend_1044(_id, _lib._sel_parent1); return _ret.address == 0 ? null : NSXMLNode._(_ret, _lib, retain: true, release: true); @@ -68939,33 +69238,33 @@ class NSXMLNode extends NSObject { } NSXMLNode childAtIndex_(int index) { - final _ret = _lib._objc_msgSend_1029(_id, _lib._sel_childAtIndex_1, index); + final _ret = _lib._objc_msgSend_1045(_id, _lib._sel_childAtIndex_1, index); return NSXMLNode._(_ret, _lib, retain: true, release: true); } NSXMLNode? get previousSibling { - final _ret = _lib._objc_msgSend_1028(_id, _lib._sel_previousSibling1); + final _ret = _lib._objc_msgSend_1044(_id, _lib._sel_previousSibling1); return _ret.address == 0 ? null : NSXMLNode._(_ret, _lib, retain: true, release: true); } NSXMLNode? get nextSibling { - final _ret = _lib._objc_msgSend_1028(_id, _lib._sel_nextSibling1); + final _ret = _lib._objc_msgSend_1044(_id, _lib._sel_nextSibling1); return _ret.address == 0 ? null : NSXMLNode._(_ret, _lib, retain: true, release: true); } NSXMLNode? get previousNode { - final _ret = _lib._objc_msgSend_1028(_id, _lib._sel_previousNode1); + final _ret = _lib._objc_msgSend_1044(_id, _lib._sel_previousNode1); return _ret.address == 0 ? null : NSXMLNode._(_ret, _lib, retain: true, release: true); } NSXMLNode? get nextNode { - final _ret = _lib._objc_msgSend_1028(_id, _lib._sel_nextNode1); + final _ret = _lib._objc_msgSend_1044(_id, _lib._sel_nextNode1); return _ret.address == 0 ? null : NSXMLNode._(_ret, _lib, retain: true, release: true); @@ -69022,7 +69321,7 @@ class NSXMLNode extends NSObject { static NSXMLNode predefinedNamespaceForPrefix_( SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_1016(_lib._class_NSXMLNode1, + final _ret = _lib._objc_msgSend_1032(_lib._class_NSXMLNode1, _lib._sel_predefinedNamespaceForPrefix_1, name?._id ?? ffi.nullptr); return NSXMLNode._(_ret, _lib, retain: true, release: true); } @@ -69043,12 +69342,12 @@ class NSXMLNode extends NSObject { NSString XMLStringWithOptions_(int options) { final _ret = - _lib._objc_msgSend_1030(_id, _lib._sel_XMLStringWithOptions_1, options); + _lib._objc_msgSend_1046(_id, _lib._sel_XMLStringWithOptions_1, options); return NSString._(_ret, _lib, retain: true, release: true); } NSString canonicalXMLStringPreservingComments_(bool comments) { - final _ret = _lib._objc_msgSend_1031( + final _ret = _lib._objc_msgSend_1047( _id, _lib._sel_canonicalXMLStringPreservingComments_1, comments); return NSString._(_ret, _lib, retain: true, release: true); } @@ -69062,7 +69361,7 @@ class NSXMLNode extends NSObject { NSArray objectsForXQuery_constants_error_(NSString? xquery, NSDictionary? constants, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1032( + final _ret = _lib._objc_msgSend_1048( _id, _lib._sel_objectsForXQuery_constants_error_1, xquery?._id ?? ffi.nullptr, @@ -69240,7 +69539,7 @@ class NSXMLDocument extends NSXMLNode { NSXMLDocument initWithXMLString_options_error_( NSString? string, int mask, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1005( + final _ret = _lib._objc_msgSend_1021( _id, _lib._sel_initWithXMLString_options_error_1, string?._id ?? ffi.nullptr, @@ -69251,7 +69550,7 @@ class NSXMLDocument extends NSXMLNode { NSXMLDocument initWithContentsOfURL_options_error_( NSURL? url, int mask, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1006( + final _ret = _lib._objc_msgSend_1022( _id, _lib._sel_initWithContentsOfURL_options_error_1, url?._id ?? ffi.nullptr, @@ -69262,7 +69561,7 @@ class NSXMLDocument extends NSXMLNode { NSXMLDocument initWithData_options_error_( NSData? data, int mask, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1007( + final _ret = _lib._objc_msgSend_1023( _id, _lib._sel_initWithData_options_error_1, data?._id ?? ffi.nullptr, @@ -69272,7 +69571,7 @@ class NSXMLDocument extends NSXMLNode { } NSXMLDocument initWithRootElement_(NSXMLElement? element) { - final _ret = _lib._objc_msgSend_1001( + final _ret = _lib._objc_msgSend_1017( _id, _lib._sel_initWithRootElement_1, element?._id ?? ffi.nullptr); return NSXMLDocument._(_ret, _lib, retain: true, release: true); } @@ -69316,11 +69615,11 @@ class NSXMLDocument extends NSXMLNode { } int get documentContentKind { - return _lib._objc_msgSend_1008(_id, _lib._sel_documentContentKind1); + return _lib._objc_msgSend_1024(_id, _lib._sel_documentContentKind1); } set documentContentKind(int value) { - return _lib._objc_msgSend_1009( + return _lib._objc_msgSend_1025( _id, _lib._sel_setDocumentContentKind_1, value); } @@ -69337,34 +69636,34 @@ class NSXMLDocument extends NSXMLNode { } NSXMLDTD? get DTD { - final _ret = _lib._objc_msgSend_1019(_id, _lib._sel_DTD1); + final _ret = _lib._objc_msgSend_1035(_id, _lib._sel_DTD1); return _ret.address == 0 ? null : NSXMLDTD._(_ret, _lib, retain: true, release: true); } set DTD(NSXMLDTD? value) { - return _lib._objc_msgSend_1020( + return _lib._objc_msgSend_1036( _id, _lib._sel_setDTD_1, value?._id ?? ffi.nullptr); } void setRootElement_(NSXMLElement? root) { - _lib._objc_msgSend_1021( + _lib._objc_msgSend_1037( _id, _lib._sel_setRootElement_1, root?._id ?? ffi.nullptr); } NSXMLElement rootElement() { - final _ret = _lib._objc_msgSend_1022(_id, _lib._sel_rootElement1); + final _ret = _lib._objc_msgSend_1038(_id, _lib._sel_rootElement1); return NSXMLElement._(_ret, _lib, retain: true, release: true); } void insertChild_atIndex_(NSXMLNode? child, int index) { - _lib._objc_msgSend_1010( + _lib._objc_msgSend_1026( _id, _lib._sel_insertChild_atIndex_1, child?._id ?? ffi.nullptr, index); } void insertChildren_atIndex_(NSArray? children, int index) { - _lib._objc_msgSend_1011(_id, _lib._sel_insertChildren_atIndex_1, + _lib._objc_msgSend_1027(_id, _lib._sel_insertChildren_atIndex_1, children?._id ?? ffi.nullptr, index); } @@ -69378,12 +69677,12 @@ class NSXMLDocument extends NSXMLNode { } void addChild_(NSXMLNode? child) { - _lib._objc_msgSend_1012( + _lib._objc_msgSend_1028( _id, _lib._sel_addChild_1, child?._id ?? ffi.nullptr); } void replaceChildAtIndex_withNode_(int index, NSXMLNode? node) { - _lib._objc_msgSend_1013(_id, _lib._sel_replaceChildAtIndex_withNode_1, + _lib._objc_msgSend_1029(_id, _lib._sel_replaceChildAtIndex_withNode_1, index, node?._id ?? ffi.nullptr); } @@ -69396,13 +69695,13 @@ class NSXMLDocument extends NSXMLNode { NSData XMLDataWithOptions_(int options) { final _ret = - _lib._objc_msgSend_1023(_id, _lib._sel_XMLDataWithOptions_1, options); + _lib._objc_msgSend_1039(_id, _lib._sel_XMLDataWithOptions_1, options); return NSData._(_ret, _lib, retain: true, release: true); } NSObject objectByApplyingXSLT_arguments_error_(NSData? xslt, NSDictionary? arguments, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1024( + final _ret = _lib._objc_msgSend_1040( _id, _lib._sel_objectByApplyingXSLT_arguments_error_1, xslt?._id ?? ffi.nullptr, @@ -69413,7 +69712,7 @@ class NSXMLDocument extends NSXMLNode { NSObject objectByApplyingXSLTString_arguments_error_(NSString? xslt, NSDictionary? arguments, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1025( + final _ret = _lib._objc_msgSend_1041( _id, _lib._sel_objectByApplyingXSLTString_arguments_error_1, xslt?._id ?? ffi.nullptr, @@ -69424,7 +69723,7 @@ class NSXMLDocument extends NSXMLNode { NSObject objectByApplyingXSLTAtURL_arguments_error_(NSURL? xsltURL, NSDictionary? argument, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1026( + final _ret = _lib._objc_msgSend_1042( _id, _lib._sel_objectByApplyingXSLTAtURL_arguments_error_1, xsltURL?._id ?? ffi.nullptr, @@ -69440,13 +69739,13 @@ class NSXMLDocument extends NSXMLNode { @override NSXMLDocument initWithKind_(int kind) { - final _ret = _lib._objc_msgSend_999(_id, _lib._sel_initWithKind_1, kind); + final _ret = _lib._objc_msgSend_1015(_id, _lib._sel_initWithKind_1, kind); return NSXMLDocument._(_ret, _lib, retain: true, release: true); } @override NSXMLDocument initWithKind_options_(int kind, int options) { - final _ret = _lib._objc_msgSend_1000( + final _ret = _lib._objc_msgSend_1016( _id, _lib._sel_initWithKind_options_1, kind, options); return NSXMLDocument._(_ret, _lib, retain: true, release: true); } @@ -69459,7 +69758,7 @@ class NSXMLDocument extends NSXMLNode { static NSObject documentWithRootElement_( SentryCocoa _lib, NSXMLElement? element) { - final _ret = _lib._objc_msgSend_1001(_lib._class_NSXMLDocument1, + final _ret = _lib._objc_msgSend_1017(_lib._class_NSXMLDocument1, _lib._sel_documentWithRootElement_1, element?._id ?? ffi.nullptr); return NSObject._(_ret, _lib, retain: true, release: true); } @@ -69492,7 +69791,7 @@ class NSXMLDocument extends NSXMLNode { static NSObject elementWithName_children_attributes_(SentryCocoa _lib, NSString? name, NSArray? children, NSArray? attributes) { - final _ret = _lib._objc_msgSend_1002( + final _ret = _lib._objc_msgSend_1018( _lib._class_NSXMLDocument1, _lib._sel_elementWithName_children_attributes_1, name?._id ?? ffi.nullptr, @@ -69576,7 +69875,7 @@ class NSXMLDocument extends NSXMLNode { static NSXMLNode predefinedNamespaceForPrefix_( SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_1016(_lib._class_NSXMLDocument1, + final _ret = _lib._objc_msgSend_1032(_lib._class_NSXMLDocument1, _lib._sel_predefinedNamespaceForPrefix_1, name?._id ?? ffi.nullptr); return NSXMLNode._(_ret, _lib, retain: true, release: true); } @@ -69706,14 +70005,14 @@ class NSXMLDTD extends NSXMLNode { @override NSXMLDTD initWithKind_options_(int kind, int options) { - final _ret = _lib._objc_msgSend_1000( + final _ret = _lib._objc_msgSend_1016( _id, _lib._sel_initWithKind_options_1, kind, options); return NSXMLDTD._(_ret, _lib, retain: true, release: true); } NSXMLDTD initWithContentsOfURL_options_error_( NSURL? url, int mask, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1006( + final _ret = _lib._objc_msgSend_1022( _id, _lib._sel_initWithContentsOfURL_options_error_1, url?._id ?? ffi.nullptr, @@ -69724,7 +70023,7 @@ class NSXMLDTD extends NSXMLNode { NSXMLDTD initWithData_options_error_( NSData? data, int mask, ffi.Pointer> error) { - final _ret = _lib._objc_msgSend_1007( + final _ret = _lib._objc_msgSend_1023( _id, _lib._sel_initWithData_options_error_1, data?._id ?? ffi.nullptr, @@ -69758,12 +70057,12 @@ class NSXMLDTD extends NSXMLNode { } void insertChild_atIndex_(NSXMLNode? child, int index) { - _lib._objc_msgSend_1010( + _lib._objc_msgSend_1026( _id, _lib._sel_insertChild_atIndex_1, child?._id ?? ffi.nullptr, index); } void insertChildren_atIndex_(NSArray? children, int index) { - _lib._objc_msgSend_1011(_id, _lib._sel_insertChildren_atIndex_1, + _lib._objc_msgSend_1027(_id, _lib._sel_insertChildren_atIndex_1, children?._id ?? ffi.nullptr, index); } @@ -69777,36 +70076,36 @@ class NSXMLDTD extends NSXMLNode { } void addChild_(NSXMLNode? child) { - _lib._objc_msgSend_1012( + _lib._objc_msgSend_1028( _id, _lib._sel_addChild_1, child?._id ?? ffi.nullptr); } void replaceChildAtIndex_withNode_(int index, NSXMLNode? node) { - _lib._objc_msgSend_1013(_id, _lib._sel_replaceChildAtIndex_withNode_1, + _lib._objc_msgSend_1029(_id, _lib._sel_replaceChildAtIndex_withNode_1, index, node?._id ?? ffi.nullptr); } NSXMLDTDNode entityDeclarationForName_(NSString? name) { - final _ret = _lib._objc_msgSend_1017( + final _ret = _lib._objc_msgSend_1033( _id, _lib._sel_entityDeclarationForName_1, name?._id ?? ffi.nullptr); return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); } NSXMLDTDNode notationDeclarationForName_(NSString? name) { - final _ret = _lib._objc_msgSend_1017( + final _ret = _lib._objc_msgSend_1033( _id, _lib._sel_notationDeclarationForName_1, name?._id ?? ffi.nullptr); return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); } NSXMLDTDNode elementDeclarationForName_(NSString? name) { - final _ret = _lib._objc_msgSend_1017( + final _ret = _lib._objc_msgSend_1033( _id, _lib._sel_elementDeclarationForName_1, name?._id ?? ffi.nullptr); return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); } NSXMLDTDNode attributeDeclarationForName_elementName_( NSString? name, NSString? elementName) { - final _ret = _lib._objc_msgSend_1018( + final _ret = _lib._objc_msgSend_1034( _id, _lib._sel_attributeDeclarationForName_elementName_1, name?._id ?? ffi.nullptr, @@ -69816,7 +70115,7 @@ class NSXMLDTD extends NSXMLNode { static NSXMLDTDNode predefinedEntityDeclarationForName_( SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_1017( + final _ret = _lib._objc_msgSend_1033( _lib._class_NSXMLDTD1, _lib._sel_predefinedEntityDeclarationForName_1, name?._id ?? ffi.nullptr); @@ -69825,7 +70124,7 @@ class NSXMLDTD extends NSXMLNode { @override NSXMLDTD initWithKind_(int kind) { - final _ret = _lib._objc_msgSend_999(_id, _lib._sel_initWithKind_1, kind); + final _ret = _lib._objc_msgSend_1015(_id, _lib._sel_initWithKind_1, kind); return NSXMLDTD._(_ret, _lib, retain: true, release: true); } @@ -69837,7 +70136,7 @@ class NSXMLDTD extends NSXMLNode { static NSObject documentWithRootElement_( SentryCocoa _lib, NSXMLElement? element) { - final _ret = _lib._objc_msgSend_1001(_lib._class_NSXMLDTD1, + final _ret = _lib._objc_msgSend_1017(_lib._class_NSXMLDTD1, _lib._sel_documentWithRootElement_1, element?._id ?? ffi.nullptr); return NSObject._(_ret, _lib, retain: true, release: true); } @@ -69870,7 +70169,7 @@ class NSXMLDTD extends NSXMLNode { static NSObject elementWithName_children_attributes_(SentryCocoa _lib, NSString? name, NSArray? children, NSArray? attributes) { - final _ret = _lib._objc_msgSend_1002( + final _ret = _lib._objc_msgSend_1018( _lib._class_NSXMLDTD1, _lib._sel_elementWithName_children_attributes_1, name?._id ?? ffi.nullptr, @@ -69891,1068 +70190,88 @@ class NSXMLDTD extends NSXMLNode { static NSObject attributeWithName_URI_stringValue_( SentryCocoa _lib, NSString? name, NSString? URI, NSString? stringValue) { - final _ret = _lib._objc_msgSend_26( - _lib._class_NSXMLDTD1, - _lib._sel_attributeWithName_URI_stringValue_1, - name?._id ?? ffi.nullptr, - URI?._id ?? ffi.nullptr, - stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject namespaceWithName_stringValue_( - SentryCocoa _lib, NSString? name, NSString? stringValue) { - final _ret = _lib._objc_msgSend_165( - _lib._class_NSXMLDTD1, - _lib._sel_namespaceWithName_stringValue_1, - name?._id ?? ffi.nullptr, - stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject processingInstructionWithName_stringValue_( - SentryCocoa _lib, NSString? name, NSString? stringValue) { - final _ret = _lib._objc_msgSend_165( - _lib._class_NSXMLDTD1, - _lib._sel_processingInstructionWithName_stringValue_1, - name?._id ?? ffi.nullptr, - stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject commentWithStringValue_( - SentryCocoa _lib, NSString? stringValue) { - final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTD1, - _lib._sel_commentWithStringValue_1, stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject textWithStringValue_( - SentryCocoa _lib, NSString? stringValue) { - final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTD1, - _lib._sel_textWithStringValue_1, stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject DTDNodeWithXMLString_(SentryCocoa _lib, NSString? string) { - final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTD1, - _lib._sel_DTDNodeWithXMLString_1, string?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSString localNameForName_(SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTD1, - _lib._sel_localNameForName_1, name?._id ?? ffi.nullptr); - return NSString._(_ret, _lib, retain: true, release: true); - } - - static NSString prefixForName_(SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTD1, - _lib._sel_prefixForName_1, name?._id ?? ffi.nullptr); - return NSString._(_ret, _lib, retain: true, release: true); - } - - static NSXMLNode predefinedNamespaceForPrefix_( - SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_1016(_lib._class_NSXMLDTD1, - _lib._sel_predefinedNamespaceForPrefix_1, name?._id ?? ffi.nullptr); - return NSXMLNode._(_ret, _lib, retain: true, release: true); - } - - static NSXMLDTD new1(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_NSXMLDTD1, _lib._sel_new1); - return NSXMLDTD._(_ret, _lib, retain: false, release: true); - } - - static NSXMLDTD allocWithZone_(SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { - final _ret = _lib._objc_msgSend_3( - _lib._class_NSXMLDTD1, _lib._sel_allocWithZone_1, zone); - return NSXMLDTD._(_ret, _lib, retain: false, release: true); - } - - static NSXMLDTD alloc(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_NSXMLDTD1, _lib._sel_alloc1); - return NSXMLDTD._(_ret, _lib, retain: false, release: true); - } - - static void cancelPreviousPerformRequestsWithTarget_selector_object_( - SentryCocoa _lib, - NSObject aTarget, - ffi.Pointer aSelector, - NSObject anArgument) { - _lib._objc_msgSend_14( - _lib._class_NSXMLDTD1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, - aTarget._id, - aSelector, - anArgument._id); - } - - static void cancelPreviousPerformRequestsWithTarget_( - SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_NSXMLDTD1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); - } - - static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_NSXMLDTD1, _lib._sel_accessInstanceVariablesDirectly1); - } - - static bool useStoredAccessor(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_NSXMLDTD1, _lib._sel_useStoredAccessor1); - } - - static NSSet keyPathsForValuesAffectingValueForKey_( - SentryCocoa _lib, NSString? key) { - final _ret = _lib._objc_msgSend_58( - _lib._class_NSXMLDTD1, - _lib._sel_keyPathsForValuesAffectingValueForKey_1, - key?._id ?? ffi.nullptr); - return NSSet._(_ret, _lib, retain: true, release: true); - } - - static bool automaticallyNotifiesObserversForKey_( - SentryCocoa _lib, NSString? key) { - return _lib._objc_msgSend_59( - _lib._class_NSXMLDTD1, - _lib._sel_automaticallyNotifiesObserversForKey_1, - key?._id ?? ffi.nullptr); - } - - static void setKeys_triggerChangeNotificationsForDependentKey_( - SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { - _lib._objc_msgSend_82( - _lib._class_NSXMLDTD1, - _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, - keys?._id ?? ffi.nullptr, - dependentKey?._id ?? ffi.nullptr); - } - - static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79( - _lib._class_NSXMLDTD1, _lib._sel_classFallbacksForKeyedArchiver1); - return NSArray._(_ret, _lib, retain: true, release: true); - } - - static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_NSXMLDTD1, _lib._sel_classForKeyedUnarchiver1); - return NSObject._(_ret, _lib, retain: true, release: true); - } -} - -class NSXMLDTDNode extends NSXMLNode { - NSXMLDTDNode._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); - - /// Returns a [NSXMLDTDNode] that points to the same underlying object as [other]. - static NSXMLDTDNode castFrom(T other) { - return NSXMLDTDNode._(other._id, other._lib, retain: true, release: true); - } - - /// Returns a [NSXMLDTDNode] that wraps the given raw object pointer. - static NSXMLDTDNode castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return NSXMLDTDNode._(other, lib, retain: retain, release: release); - } - - /// Returns whether [obj] is an instance of [NSXMLDTDNode]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0( - obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_NSXMLDTDNode1); - } - - NSXMLDTDNode initWithXMLString_(NSString? string) { - final _ret = _lib._objc_msgSend_30( - _id, _lib._sel_initWithXMLString_1, string?._id ?? ffi.nullptr); - return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); - } - - @override - NSXMLDTDNode initWithKind_options_(int kind, int options) { - final _ret = _lib._objc_msgSend_1000( - _id, _lib._sel_initWithKind_options_1, kind, options); - return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); - } - - @override - NSXMLDTDNode init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); - } - - int get DTDKind { - return _lib._objc_msgSend_1014(_id, _lib._sel_DTDKind1); - } - - set DTDKind(int value) { - return _lib._objc_msgSend_1015(_id, _lib._sel_setDTDKind_1, value); - } - - bool get external1 { - return _lib._objc_msgSend_12(_id, _lib._sel_isExternal1); - } - - NSString? get publicID { - final _ret = _lib._objc_msgSend_20(_id, _lib._sel_publicID1); - return _ret.address == 0 - ? null - : NSString._(_ret, _lib, retain: true, release: true); - } - - set publicID(NSString? value) { - return _lib._objc_msgSend_509( - _id, _lib._sel_setPublicID_1, value?._id ?? ffi.nullptr); - } - - NSString? get systemID { - final _ret = _lib._objc_msgSend_20(_id, _lib._sel_systemID1); - return _ret.address == 0 - ? null - : NSString._(_ret, _lib, retain: true, release: true); - } - - set systemID(NSString? value) { - return _lib._objc_msgSend_509( - _id, _lib._sel_setSystemID_1, value?._id ?? ffi.nullptr); - } - - NSString? get notationName { - final _ret = _lib._objc_msgSend_20(_id, _lib._sel_notationName1); - return _ret.address == 0 - ? null - : NSString._(_ret, _lib, retain: true, release: true); - } - - set notationName(NSString? value) { - return _lib._objc_msgSend_509( - _id, _lib._sel_setNotationName_1, value?._id ?? ffi.nullptr); - } - - @override - NSXMLDTDNode initWithKind_(int kind) { - final _ret = _lib._objc_msgSend_999(_id, _lib._sel_initWithKind_1, kind); - return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); - } - - static NSObject document(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_NSXMLDTDNode1, _lib._sel_document1); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject documentWithRootElement_( - SentryCocoa _lib, NSXMLElement? element) { - final _ret = _lib._objc_msgSend_1001(_lib._class_NSXMLDTDNode1, - _lib._sel_documentWithRootElement_1, element?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject elementWithName_(SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, - _lib._sel_elementWithName_1, name?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject elementWithName_URI_( - SentryCocoa _lib, NSString? name, NSString? URI) { - final _ret = _lib._objc_msgSend_165( - _lib._class_NSXMLDTDNode1, - _lib._sel_elementWithName_URI_1, - name?._id ?? ffi.nullptr, - URI?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject elementWithName_stringValue_( - SentryCocoa _lib, NSString? name, NSString? string) { - final _ret = _lib._objc_msgSend_165( - _lib._class_NSXMLDTDNode1, - _lib._sel_elementWithName_stringValue_1, - name?._id ?? ffi.nullptr, - string?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject elementWithName_children_attributes_(SentryCocoa _lib, - NSString? name, NSArray? children, NSArray? attributes) { - final _ret = _lib._objc_msgSend_1002( - _lib._class_NSXMLDTDNode1, - _lib._sel_elementWithName_children_attributes_1, - name?._id ?? ffi.nullptr, - children?._id ?? ffi.nullptr, - attributes?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject attributeWithName_stringValue_( - SentryCocoa _lib, NSString? name, NSString? stringValue) { - final _ret = _lib._objc_msgSend_165( - _lib._class_NSXMLDTDNode1, - _lib._sel_attributeWithName_stringValue_1, - name?._id ?? ffi.nullptr, - stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject attributeWithName_URI_stringValue_( - SentryCocoa _lib, NSString? name, NSString? URI, NSString? stringValue) { - final _ret = _lib._objc_msgSend_26( - _lib._class_NSXMLDTDNode1, - _lib._sel_attributeWithName_URI_stringValue_1, - name?._id ?? ffi.nullptr, - URI?._id ?? ffi.nullptr, - stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject namespaceWithName_stringValue_( - SentryCocoa _lib, NSString? name, NSString? stringValue) { - final _ret = _lib._objc_msgSend_165( - _lib._class_NSXMLDTDNode1, - _lib._sel_namespaceWithName_stringValue_1, - name?._id ?? ffi.nullptr, - stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject processingInstructionWithName_stringValue_( - SentryCocoa _lib, NSString? name, NSString? stringValue) { - final _ret = _lib._objc_msgSend_165( - _lib._class_NSXMLDTDNode1, - _lib._sel_processingInstructionWithName_stringValue_1, - name?._id ?? ffi.nullptr, - stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject commentWithStringValue_( - SentryCocoa _lib, NSString? stringValue) { - final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, - _lib._sel_commentWithStringValue_1, stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject textWithStringValue_( - SentryCocoa _lib, NSString? stringValue) { - final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, - _lib._sel_textWithStringValue_1, stringValue?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSObject DTDNodeWithXMLString_(SentryCocoa _lib, NSString? string) { - final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, - _lib._sel_DTDNodeWithXMLString_1, string?._id ?? ffi.nullptr); - return NSObject._(_ret, _lib, retain: true, release: true); - } - - static NSString localNameForName_(SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTDNode1, - _lib._sel_localNameForName_1, name?._id ?? ffi.nullptr); - return NSString._(_ret, _lib, retain: true, release: true); - } - - static NSString prefixForName_(SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTDNode1, - _lib._sel_prefixForName_1, name?._id ?? ffi.nullptr); - return NSString._(_ret, _lib, retain: true, release: true); - } - - static NSXMLNode predefinedNamespaceForPrefix_( - SentryCocoa _lib, NSString? name) { - final _ret = _lib._objc_msgSend_1016(_lib._class_NSXMLDTDNode1, - _lib._sel_predefinedNamespaceForPrefix_1, name?._id ?? ffi.nullptr); - return NSXMLNode._(_ret, _lib, retain: true, release: true); - } - - static NSXMLDTDNode new1(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_NSXMLDTDNode1, _lib._sel_new1); - return NSXMLDTDNode._(_ret, _lib, retain: false, release: true); - } - - static NSXMLDTDNode allocWithZone_( - SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { - final _ret = _lib._objc_msgSend_3( - _lib._class_NSXMLDTDNode1, _lib._sel_allocWithZone_1, zone); - return NSXMLDTDNode._(_ret, _lib, retain: false, release: true); - } - - static NSXMLDTDNode alloc(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_NSXMLDTDNode1, _lib._sel_alloc1); - return NSXMLDTDNode._(_ret, _lib, retain: false, release: true); - } - - static void cancelPreviousPerformRequestsWithTarget_selector_object_( - SentryCocoa _lib, - NSObject aTarget, - ffi.Pointer aSelector, - NSObject anArgument) { - _lib._objc_msgSend_14( - _lib._class_NSXMLDTDNode1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, - aTarget._id, - aSelector, - anArgument._id); - } - - static void cancelPreviousPerformRequestsWithTarget_( - SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_NSXMLDTDNode1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); - } - - static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_NSXMLDTDNode1, _lib._sel_accessInstanceVariablesDirectly1); - } - - static bool useStoredAccessor(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_NSXMLDTDNode1, _lib._sel_useStoredAccessor1); - } - - static NSSet keyPathsForValuesAffectingValueForKey_( - SentryCocoa _lib, NSString? key) { - final _ret = _lib._objc_msgSend_58( - _lib._class_NSXMLDTDNode1, - _lib._sel_keyPathsForValuesAffectingValueForKey_1, - key?._id ?? ffi.nullptr); - return NSSet._(_ret, _lib, retain: true, release: true); - } - - static bool automaticallyNotifiesObserversForKey_( - SentryCocoa _lib, NSString? key) { - return _lib._objc_msgSend_59( - _lib._class_NSXMLDTDNode1, - _lib._sel_automaticallyNotifiesObserversForKey_1, - key?._id ?? ffi.nullptr); - } - - static void setKeys_triggerChangeNotificationsForDependentKey_( - SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { - _lib._objc_msgSend_82( - _lib._class_NSXMLDTDNode1, - _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, - keys?._id ?? ffi.nullptr, - dependentKey?._id ?? ffi.nullptr); - } - - static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79( - _lib._class_NSXMLDTDNode1, _lib._sel_classFallbacksForKeyedArchiver1); - return NSArray._(_ret, _lib, retain: true, release: true); - } - - static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_NSXMLDTDNode1, _lib._sel_classForKeyedUnarchiver1); - return NSObject._(_ret, _lib, retain: true, release: true); - } -} - -abstract class NSXMLDTDNodeKind { - static const int NSXMLEntityGeneralKind = 1; - static const int NSXMLEntityParsedKind = 2; - static const int NSXMLEntityUnparsedKind = 3; - static const int NSXMLEntityParameterKind = 4; - static const int NSXMLEntityPredefined = 5; - static const int NSXMLAttributeCDATAKind = 6; - static const int NSXMLAttributeIDKind = 7; - static const int NSXMLAttributeIDRefKind = 8; - static const int NSXMLAttributeIDRefsKind = 9; - static const int NSXMLAttributeEntityKind = 10; - static const int NSXMLAttributeEntitiesKind = 11; - static const int NSXMLAttributeNMTokenKind = 12; - static const int NSXMLAttributeNMTokensKind = 13; - static const int NSXMLAttributeEnumerationKind = 14; - static const int NSXMLAttributeNotationKind = 15; - static const int NSXMLElementDeclarationUndefinedKind = 16; - static const int NSXMLElementDeclarationEmptyKind = 17; - static const int NSXMLElementDeclarationAnyKind = 18; - static const int NSXMLElementDeclarationMixedKind = 19; - static const int NSXMLElementDeclarationElementKind = 20; -} - -/// @warning This class is reserved for hybrid SDKs. Methods may be changed, renamed or removed -/// without notice. If you want to use one of these methods here please open up an issue and let us -/// know. -/// @note The name of this class is supposed to be a bit weird and ugly. The name starts with private -/// on purpose so users don't see it in code completion when typing Sentry. We also add only at the -/// end to make it more obvious you shouldn't use it. -class PrivateSentrySDKOnly extends NSObject { - PrivateSentrySDKOnly._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); - - /// Returns a [PrivateSentrySDKOnly] that points to the same underlying object as [other]. - static PrivateSentrySDKOnly castFrom(T other) { - return PrivateSentrySDKOnly._(other._id, other._lib, - retain: true, release: true); - } - - /// Returns a [PrivateSentrySDKOnly] that wraps the given raw object pointer. - static PrivateSentrySDKOnly castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return PrivateSentrySDKOnly._(other, lib, retain: retain, release: release); - } - - /// Returns whether [obj] is an instance of [PrivateSentrySDKOnly]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_PrivateSentrySDKOnly1); - } - - /// For storing an envelope synchronously to disk. - static void storeEnvelope_(SentryCocoa _lib, SentryEnvelope? envelope) { - _lib._objc_msgSend_1055(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_storeEnvelope_1, envelope?._id ?? ffi.nullptr); - } - - static void captureEnvelope_(SentryCocoa _lib, SentryEnvelope? envelope) { - _lib._objc_msgSend_1055(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_captureEnvelope_1, envelope?._id ?? ffi.nullptr); - } - - /// Create an envelope from @c NSData. Needed for example by Flutter. - static SentryEnvelope envelopeWithData_(SentryCocoa _lib, NSData? data) { - final _ret = _lib._objc_msgSend_1056(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_envelopeWithData_1, data?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - /// Returns the current list of debug images. Be aware that the @c SentryDebugMeta is actually - /// describing a debug image. - /// @warning This assumes a crash has occurred and attempts to read the crash information from each - /// image's data segment, which may not be present or be invalid if a crash has not actually - /// occurred. To avoid this, use the new @c +[getDebugImagesCrashed:] instead. - static NSArray getDebugImages(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_getDebugImages1); - return NSArray._(_ret, _lib, retain: true, release: true); - } - - /// Returns the current list of debug images. Be aware that the @c SentryDebugMeta is actually - /// describing a debug image. - /// @param isCrash @c YES if we're collecting binary images for a crash report, @c NO if we're - /// gathering them for other backtrace information, like a performance transaction. If this is for a - /// crash, each image's data section crash info is also included. - static NSArray getDebugImagesCrashed_(SentryCocoa _lib, bool isCrash) { - final _ret = _lib._objc_msgSend_1057(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_getDebugImagesCrashed_1, isCrash); - return NSArray._(_ret, _lib, retain: true, release: true); - } - - /// Override SDK information. - static void setSdkName_andVersionString_( - SentryCocoa _lib, NSString? sdkName, NSString? versionString) { - _lib._objc_msgSend_515( - _lib._class_PrivateSentrySDKOnly1, - _lib._sel_setSdkName_andVersionString_1, - sdkName?._id ?? ffi.nullptr, - versionString?._id ?? ffi.nullptr); - } - - /// Override SDK information. - static void setSdkName_(SentryCocoa _lib, NSString? sdkName) { - _lib._objc_msgSend_192(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_setSdkName_1, sdkName?._id ?? ffi.nullptr); - } - - /// Retrieves the SDK name - static NSString getSdkName(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_20( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_getSdkName1); - return NSString._(_ret, _lib, retain: true, release: true); - } - - /// Retrieves the SDK version string - static NSString getSdkVersionString(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_20( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_getSdkVersionString1); - return NSString._(_ret, _lib, retain: true, release: true); - } - - /// Retrieves extra context - static NSDictionary getExtraContext(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_170( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_getExtraContext1); - return NSDictionary._(_ret, _lib, retain: true, release: true); - } - - /// Start a profiler session associated with the given @c SentryId. - /// @return The system time when the profiler session started. - static int startProfilerForTrace_(SentryCocoa _lib, SentryId? traceId) { - return _lib._objc_msgSend_1058(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_startProfilerForTrace_1, traceId?._id ?? ffi.nullptr); - } - - /// Collect a profiler session data associated with the given @c SentryId. - /// This also discards the profiler. - static NSDictionary collectProfileBetween_and_forTrace_(SentryCocoa _lib, - int startSystemTime, int endSystemTime, SentryId? traceId) { - final _ret = _lib._objc_msgSend_1059( - _lib._class_PrivateSentrySDKOnly1, - _lib._sel_collectProfileBetween_and_forTrace_1, - startSystemTime, - endSystemTime, - traceId?._id ?? ffi.nullptr); - return NSDictionary._(_ret, _lib, retain: true, release: true); - } - - /// Discard profiler session data associated with the given @c SentryId. - /// This only needs to be called in case you haven't collected the profile (and don't intend to). - static void discardProfilerForTrace_(SentryCocoa _lib, SentryId? traceId) { - _lib._objc_msgSend_1060(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_discardProfilerForTrace_1, traceId?._id ?? ffi.nullptr); - } - - static ObjCBlock_ffiVoid_SentryAppStartMeasurement - getOnAppStartMeasurementAvailable(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_1061(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_onAppStartMeasurementAvailable1); - return ObjCBlock_ffiVoid_SentryAppStartMeasurement._(_ret, _lib); - } - - static void setOnAppStartMeasurementAvailable( - SentryCocoa _lib, ObjCBlock_ffiVoid_SentryAppStartMeasurement value) { - return _lib._objc_msgSend_1062(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_setOnAppStartMeasurementAvailable_1, value._id); - } - - static SentryAppStartMeasurement? getAppStartMeasurement(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_1063( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_appStartMeasurement1); - return _ret.address == 0 - ? null - : SentryAppStartMeasurement._(_ret, _lib, retain: true, release: true); - } - - static NSString? getInstallationID(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_20( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_installationID1); - return _ret.address == 0 - ? null - : NSString._(_ret, _lib, retain: true, release: true); - } - - static SentryOptions? getOptions(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_1064( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_options1); - return _ret.address == 0 - ? null - : SentryOptions._(_ret, _lib, retain: true, release: true); - } - - /// If enabled, the SDK won't send the app start measurement with the first transaction. Instead, if - /// @c enableAutoPerformanceTracing is enabled, the SDK measures the app start and then calls - /// @c onAppStartMeasurementAvailable. Furthermore, the SDK doesn't set all values for the app start - /// measurement because the HybridSDKs initialize the Cocoa SDK too late to receive all - /// notifications. Instead, the SDK sets the @c appStartDuration to @c 0 and the - /// @c didFinishLaunchingTimestamp to @c timeIntervalSinceReferenceDate. - /// @note Default is @c NO. - static bool getAppStartMeasurementHybridSDKMode(SentryCocoa _lib) { - return _lib._objc_msgSend_12(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_appStartMeasurementHybridSDKMode1); - } - - /// If enabled, the SDK won't send the app start measurement with the first transaction. Instead, if - /// @c enableAutoPerformanceTracing is enabled, the SDK measures the app start and then calls - /// @c onAppStartMeasurementAvailable. Furthermore, the SDK doesn't set all values for the app start - /// measurement because the HybridSDKs initialize the Cocoa SDK too late to receive all - /// notifications. Instead, the SDK sets the @c appStartDuration to @c 0 and the - /// @c didFinishLaunchingTimestamp to @c timeIntervalSinceReferenceDate. - /// @note Default is @c NO. - static void setAppStartMeasurementHybridSDKMode( - SentryCocoa _lib, bool value) { - return _lib._objc_msgSend_492(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_setAppStartMeasurementHybridSDKMode_1, value); - } - - static SentryUser userWithDictionary_( - SentryCocoa _lib, NSDictionary? dictionary) { - final _ret = _lib._objc_msgSend_1065(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_userWithDictionary_1, dictionary?._id ?? ffi.nullptr); - return SentryUser._(_ret, _lib, retain: true, release: true); - } - - static SentryBreadcrumb breadcrumbWithDictionary_( - SentryCocoa _lib, NSDictionary? dictionary) { - final _ret = _lib._objc_msgSend_1066(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_breadcrumbWithDictionary_1, dictionary?._id ?? ffi.nullptr); - return SentryBreadcrumb._(_ret, _lib, retain: true, release: true); - } - - @override - PrivateSentrySDKOnly init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return PrivateSentrySDKOnly._(_ret, _lib, retain: true, release: true); - } - - static PrivateSentrySDKOnly new1(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_PrivateSentrySDKOnly1, _lib._sel_new1); - return PrivateSentrySDKOnly._(_ret, _lib, retain: false, release: true); - } - - static PrivateSentrySDKOnly allocWithZone_( - SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { - final _ret = _lib._objc_msgSend_3( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_allocWithZone_1, zone); - return PrivateSentrySDKOnly._(_ret, _lib, retain: false, release: true); - } - - static PrivateSentrySDKOnly alloc(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_alloc1); - return PrivateSentrySDKOnly._(_ret, _lib, retain: false, release: true); - } - - static void cancelPreviousPerformRequestsWithTarget_selector_object_( - SentryCocoa _lib, - NSObject aTarget, - ffi.Pointer aSelector, - NSObject anArgument) { - _lib._objc_msgSend_14( - _lib._class_PrivateSentrySDKOnly1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, - aTarget._id, - aSelector, - anArgument._id); - } - - static void cancelPreviousPerformRequestsWithTarget_( - SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); - } - - static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_accessInstanceVariablesDirectly1); - } - - static bool useStoredAccessor(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_useStoredAccessor1); - } - - static NSSet keyPathsForValuesAffectingValueForKey_( - SentryCocoa _lib, NSString? key) { - final _ret = _lib._objc_msgSend_58( - _lib._class_PrivateSentrySDKOnly1, - _lib._sel_keyPathsForValuesAffectingValueForKey_1, - key?._id ?? ffi.nullptr); - return NSSet._(_ret, _lib, retain: true, release: true); - } - - static bool automaticallyNotifiesObserversForKey_( - SentryCocoa _lib, NSString? key) { - return _lib._objc_msgSend_59( - _lib._class_PrivateSentrySDKOnly1, - _lib._sel_automaticallyNotifiesObserversForKey_1, - key?._id ?? ffi.nullptr); - } - - static void setKeys_triggerChangeNotificationsForDependentKey_( - SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { - _lib._objc_msgSend_82( - _lib._class_PrivateSentrySDKOnly1, - _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, - keys?._id ?? ffi.nullptr, - dependentKey?._id ?? ffi.nullptr); - } - - static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79(_lib._class_PrivateSentrySDKOnly1, - _lib._sel_classFallbacksForKeyedArchiver1); - return NSArray._(_ret, _lib, retain: true, release: true); - } - - static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_PrivateSentrySDKOnly1, _lib._sel_classForKeyedUnarchiver1); - return NSObject._(_ret, _lib, retain: true, release: true); - } -} - -class SentryEnvelope extends NSObject { - SentryEnvelope._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); - - /// Returns a [SentryEnvelope] that points to the same underlying object as [other]. - static SentryEnvelope castFrom(T other) { - return SentryEnvelope._(other._id, other._lib, retain: true, release: true); - } - - /// Returns a [SentryEnvelope] that wraps the given raw object pointer. - static SentryEnvelope castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentryEnvelope._(other, lib, retain: retain, release: release); - } - - /// Returns whether [obj] is an instance of [SentryEnvelope]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_SentryEnvelope1); - } - - @override - SentryEnvelope init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - static SentryEnvelope new1(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_SentryEnvelope1, _lib._sel_new1); - return SentryEnvelope._(_ret, _lib, retain: false, release: true); - } - - SentryEnvelope initWithId_singleItem_( - SentryId? id, SentryEnvelopeItem? item) { - final _ret = _lib._objc_msgSend_1045(_id, _lib._sel_initWithId_singleItem_1, - id?._id ?? ffi.nullptr, item?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - SentryEnvelope initWithHeader_singleItem_( - SentryEnvelopeHeader? header, SentryEnvelopeItem? item) { - final _ret = _lib._objc_msgSend_1051( - _id, - _lib._sel_initWithHeader_singleItem_1, - header?._id ?? ffi.nullptr, - item?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - SentryEnvelope initWithId_items_(SentryId? id, NSArray? items) { - final _ret = _lib._objc_msgSend_1052(_id, _lib._sel_initWithId_items_1, - id?._id ?? ffi.nullptr, items?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - /// Initializes a @c SentryEnvelope with a single session. - /// @param session to init the envelope with. - SentryEnvelope initWithSession_(SentrySession? session) { - final _ret = _lib._objc_msgSend_1040( - _id, _lib._sel_initWithSession_1, session?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - /// Initializes a @c SentryEnvelope with a list of sessions. - /// Can be used when an operation that starts a session closes an ongoing session. - /// @param sessions to init the envelope with. - SentryEnvelope initWithSessions_(NSArray? sessions) { - final _ret = _lib._objc_msgSend_67( - _id, _lib._sel_initWithSessions_1, sessions?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - SentryEnvelope initWithHeader_items_( - SentryEnvelopeHeader? header, NSArray? items) { - final _ret = _lib._objc_msgSend_1053(_id, _lib._sel_initWithHeader_items_1, - header?._id ?? ffi.nullptr, items?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - /// Convenience init for a single event. - SentryEnvelope initWithEvent_(SentryEvent? event) { - final _ret = _lib._objc_msgSend_1039( - _id, _lib._sel_initWithEvent_1, event?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - SentryEnvelope initWithUserFeedback_(SentryUserFeedback? userFeedback) { - final _ret = _lib._objc_msgSend_1041(_id, _lib._sel_initWithUserFeedback_1, - userFeedback?._id ?? ffi.nullptr); - return SentryEnvelope._(_ret, _lib, retain: true, release: true); - } - - /// The envelope header. - SentryEnvelopeHeader? get header { - final _ret = _lib._objc_msgSend_1054(_id, _lib._sel_header1); - return _ret.address == 0 - ? null - : SentryEnvelopeHeader._(_ret, _lib, retain: true, release: true); - } - - /// The envelope items. - NSArray? get items { - final _ret = _lib._objc_msgSend_79(_id, _lib._sel_items1); - return _ret.address == 0 - ? null - : NSArray._(_ret, _lib, retain: true, release: true); - } - - static SentryEnvelope allocWithZone_( - SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { - final _ret = _lib._objc_msgSend_3( - _lib._class_SentryEnvelope1, _lib._sel_allocWithZone_1, zone); - return SentryEnvelope._(_ret, _lib, retain: false, release: true); - } - - static SentryEnvelope alloc(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_SentryEnvelope1, _lib._sel_alloc1); - return SentryEnvelope._(_ret, _lib, retain: false, release: true); - } - - static void cancelPreviousPerformRequestsWithTarget_selector_object_( - SentryCocoa _lib, - NSObject aTarget, - ffi.Pointer aSelector, - NSObject anArgument) { - _lib._objc_msgSend_14( - _lib._class_SentryEnvelope1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, - aTarget._id, - aSelector, - anArgument._id); - } - - static void cancelPreviousPerformRequestsWithTarget_( - SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_SentryEnvelope1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); - } - - static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12(_lib._class_SentryEnvelope1, - _lib._sel_accessInstanceVariablesDirectly1); - } - - static bool useStoredAccessor(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_SentryEnvelope1, _lib._sel_useStoredAccessor1); - } - - static NSSet keyPathsForValuesAffectingValueForKey_( - SentryCocoa _lib, NSString? key) { - final _ret = _lib._objc_msgSend_58( - _lib._class_SentryEnvelope1, - _lib._sel_keyPathsForValuesAffectingValueForKey_1, - key?._id ?? ffi.nullptr); - return NSSet._(_ret, _lib, retain: true, release: true); - } - - static bool automaticallyNotifiesObserversForKey_( - SentryCocoa _lib, NSString? key) { - return _lib._objc_msgSend_59( - _lib._class_SentryEnvelope1, - _lib._sel_automaticallyNotifiesObserversForKey_1, - key?._id ?? ffi.nullptr); - } - - static void setKeys_triggerChangeNotificationsForDependentKey_( - SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { - _lib._objc_msgSend_82( - _lib._class_SentryEnvelope1, - _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, - keys?._id ?? ffi.nullptr, - dependentKey?._id ?? ffi.nullptr); - } - - static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79( - _lib._class_SentryEnvelope1, _lib._sel_classFallbacksForKeyedArchiver1); - return NSArray._(_ret, _lib, retain: true, release: true); - } - - static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_SentryEnvelope1, _lib._sel_classForKeyedUnarchiver1); + final _ret = _lib._objc_msgSend_26( + _lib._class_NSXMLDTD1, + _lib._sel_attributeWithName_URI_stringValue_1, + name?._id ?? ffi.nullptr, + URI?._id ?? ffi.nullptr, + stringValue?._id ?? ffi.nullptr); return NSObject._(_ret, _lib, retain: true, release: true); } -} - -class SentryId extends NSObject { - SentryId._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); - /// Returns a [SentryId] that points to the same underlying object as [other]. - static SentryId castFrom(T other) { - return SentryId._(other._id, other._lib, retain: true, release: true); + static NSObject namespaceWithName_stringValue_( + SentryCocoa _lib, NSString? name, NSString? stringValue) { + final _ret = _lib._objc_msgSend_165( + _lib._class_NSXMLDTD1, + _lib._sel_namespaceWithName_stringValue_1, + name?._id ?? ffi.nullptr, + stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - /// Returns a [SentryId] that wraps the given raw object pointer. - static SentryId castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentryId._(other, lib, retain: retain, release: release); + static NSObject processingInstructionWithName_stringValue_( + SentryCocoa _lib, NSString? name, NSString? stringValue) { + final _ret = _lib._objc_msgSend_165( + _lib._class_NSXMLDTD1, + _lib._sel_processingInstructionWithName_stringValue_1, + name?._id ?? ffi.nullptr, + stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - /// Returns whether [obj] is an instance of [SentryId]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0( - obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_SentryId1); + static NSObject commentWithStringValue_( + SentryCocoa _lib, NSString? stringValue) { + final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTD1, + _lib._sel_commentWithStringValue_1, stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - /// Creates a @c SentryId with a random UUID. - @override - SentryId init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return SentryId._(_ret, _lib, retain: true, release: true); + static NSObject textWithStringValue_( + SentryCocoa _lib, NSString? stringValue) { + final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTD1, + _lib._sel_textWithStringValue_1, stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - /// Creates a SentryId with the given UUID. - SentryId initWithUUID_(NSUUID? uuid) { - final _ret = _lib._objc_msgSend_1037( - _id, _lib._sel_initWithUUID_1, uuid?._id ?? ffi.nullptr); - return SentryId._(_ret, _lib, retain: true, release: true); + static NSObject DTDNodeWithXMLString_(SentryCocoa _lib, NSString? string) { + final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTD1, + _lib._sel_DTDNodeWithXMLString_1, string?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - /// Creates a @c SentryId from a 32 character hexadecimal string without dashes such as - /// "12c2d058d58442709aa2eca08bf20986" or a 36 character hexadecimal string such as such as - /// "12c2d058-d584-4270-9aa2-eca08bf20986". - /// @return SentryId.empty for invalid strings. - SentryId initWithUUIDString_(NSString? string) { - final _ret = _lib._objc_msgSend_30( - _id, _lib._sel_initWithUUIDString_1, string?._id ?? ffi.nullptr); - return SentryId._(_ret, _lib, retain: true, release: true); + static NSString localNameForName_(SentryCocoa _lib, NSString? name) { + final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTD1, + _lib._sel_localNameForName_1, name?._id ?? ffi.nullptr); + return NSString._(_ret, _lib, retain: true, release: true); } - /// Returns a 32 lowercase character hexadecimal string description of the @c SentryId, such as - /// "12c2d058d58442709aa2eca08bf20986". - NSString? get sentryIdString { - final _ret = _lib._objc_msgSend_20(_id, _lib._sel_sentryIdString1); - return _ret.address == 0 - ? null - : NSString._(_ret, _lib, retain: true, release: true); + static NSString prefixForName_(SentryCocoa _lib, NSString? name) { + final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTD1, + _lib._sel_prefixForName_1, name?._id ?? ffi.nullptr); + return NSString._(_ret, _lib, retain: true, release: true); } - /// A @c SentryId with an empty UUID "00000000000000000000000000000000". - static SentryId? getEmpty(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_1038(_lib._class_SentryId1, _lib._sel_empty1); - return _ret.address == 0 - ? null - : SentryId._(_ret, _lib, retain: true, release: true); + static NSXMLNode predefinedNamespaceForPrefix_( + SentryCocoa _lib, NSString? name) { + final _ret = _lib._objc_msgSend_1032(_lib._class_NSXMLDTD1, + _lib._sel_predefinedNamespaceForPrefix_1, name?._id ?? ffi.nullptr); + return NSXMLNode._(_ret, _lib, retain: true, release: true); } - static SentryId new1(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_SentryId1, _lib._sel_new1); - return SentryId._(_ret, _lib, retain: false, release: true); + static NSXMLDTD new1(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_NSXMLDTD1, _lib._sel_new1); + return NSXMLDTD._(_ret, _lib, retain: false, release: true); } - static SentryId allocWithZone_(SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { + static NSXMLDTD allocWithZone_(SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { final _ret = _lib._objc_msgSend_3( - _lib._class_SentryId1, _lib._sel_allocWithZone_1, zone); - return SentryId._(_ret, _lib, retain: false, release: true); + _lib._class_NSXMLDTD1, _lib._sel_allocWithZone_1, zone); + return NSXMLDTD._(_ret, _lib, retain: false, release: true); } - static SentryId alloc(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_SentryId1, _lib._sel_alloc1); - return SentryId._(_ret, _lib, retain: false, release: true); + static NSXMLDTD alloc(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_NSXMLDTD1, _lib._sel_alloc1); + return NSXMLDTD._(_ret, _lib, retain: false, release: true); } static void cancelPreviousPerformRequestsWithTarget_selector_object_( @@ -70961,7 +70280,7 @@ class SentryId extends NSObject { ffi.Pointer aSelector, NSObject anArgument) { _lib._objc_msgSend_14( - _lib._class_SentryId1, + _lib._class_NSXMLDTD1, _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, aTarget._id, aSelector, @@ -70970,24 +70289,24 @@ class SentryId extends NSObject { static void cancelPreviousPerformRequestsWithTarget_( SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_SentryId1, + _lib._objc_msgSend_15(_lib._class_NSXMLDTD1, _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); } static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { return _lib._objc_msgSend_12( - _lib._class_SentryId1, _lib._sel_accessInstanceVariablesDirectly1); + _lib._class_NSXMLDTD1, _lib._sel_accessInstanceVariablesDirectly1); } static bool useStoredAccessor(SentryCocoa _lib) { return _lib._objc_msgSend_12( - _lib._class_SentryId1, _lib._sel_useStoredAccessor1); + _lib._class_NSXMLDTD1, _lib._sel_useStoredAccessor1); } static NSSet keyPathsForValuesAffectingValueForKey_( SentryCocoa _lib, NSString? key) { final _ret = _lib._objc_msgSend_58( - _lib._class_SentryId1, + _lib._class_NSXMLDTD1, _lib._sel_keyPathsForValuesAffectingValueForKey_1, key?._id ?? ffi.nullptr); return NSSet._(_ret, _lib, retain: true, release: true); @@ -70996,7 +70315,7 @@ class SentryId extends NSObject { static bool automaticallyNotifiesObserversForKey_( SentryCocoa _lib, NSString? key) { return _lib._objc_msgSend_59( - _lib._class_SentryId1, + _lib._class_NSXMLDTD1, _lib._sel_automaticallyNotifiesObserversForKey_1, key?._id ?? ffi.nullptr); } @@ -71004,7 +70323,7 @@ class SentryId extends NSObject { static void setKeys_triggerChangeNotificationsForDependentKey_( SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { _lib._objc_msgSend_82( - _lib._class_SentryId1, + _lib._class_NSXMLDTD1, _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, keys?._id ?? ffi.nullptr, dependentKey?._id ?? ffi.nullptr); @@ -71012,260 +70331,260 @@ class SentryId extends NSObject { static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { final _ret = _lib._objc_msgSend_79( - _lib._class_SentryId1, _lib._sel_classFallbacksForKeyedArchiver1); + _lib._class_NSXMLDTD1, _lib._sel_classFallbacksForKeyedArchiver1); return NSArray._(_ret, _lib, retain: true, release: true); } static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { final _ret = _lib._objc_msgSend_2( - _lib._class_SentryId1, _lib._sel_classForKeyedUnarchiver1); + _lib._class_NSXMLDTD1, _lib._sel_classForKeyedUnarchiver1); return NSObject._(_ret, _lib, retain: true, release: true); } } -class NSUUID extends NSObject { - NSUUID._(ffi.Pointer id, SentryCocoa lib, +class NSXMLDTDNode extends NSXMLNode { + NSXMLDTDNode._(ffi.Pointer id, SentryCocoa lib, {bool retain = false, bool release = false}) : super._(id, lib, retain: retain, release: release); - /// Returns a [NSUUID] that points to the same underlying object as [other]. - static NSUUID castFrom(T other) { - return NSUUID._(other._id, other._lib, retain: true, release: true); + /// Returns a [NSXMLDTDNode] that points to the same underlying object as [other]. + static NSXMLDTDNode castFrom(T other) { + return NSXMLDTDNode._(other._id, other._lib, retain: true, release: true); } - /// Returns a [NSUUID] that wraps the given raw object pointer. - static NSUUID castFromPointer(SentryCocoa lib, ffi.Pointer other, + /// Returns a [NSXMLDTDNode] that wraps the given raw object pointer. + static NSXMLDTDNode castFromPointer( + SentryCocoa lib, ffi.Pointer other, {bool retain = false, bool release = false}) { - return NSUUID._(other, lib, retain: retain, release: release); + return NSXMLDTDNode._(other, lib, retain: retain, release: release); } - /// Returns whether [obj] is an instance of [NSUUID]. + /// Returns whether [obj] is an instance of [NSXMLDTDNode]. static bool isInstance(_ObjCWrapper obj) { return obj._lib._objc_msgSend_0( - obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_NSUUID1); + obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_NSXMLDTDNode1); } - static NSUUID UUID(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_NSUUID1, _lib._sel_UUID1); - return NSUUID._(_ret, _lib, retain: true, release: true); + NSXMLDTDNode initWithXMLString_(NSString? string) { + final _ret = _lib._objc_msgSend_30( + _id, _lib._sel_initWithXMLString_1, string?._id ?? ffi.nullptr); + return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); } @override - NSUUID init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return NSUUID._(_ret, _lib, retain: true, release: true); + NSXMLDTDNode initWithKind_options_(int kind, int options) { + final _ret = _lib._objc_msgSend_1016( + _id, _lib._sel_initWithKind_options_1, kind, options); + return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); } - NSUUID initWithUUIDString_(NSString? string) { - final _ret = _lib._objc_msgSend_30( - _id, _lib._sel_initWithUUIDString_1, string?._id ?? ffi.nullptr); - return NSUUID._(_ret, _lib, retain: true, release: true); + @override + NSXMLDTDNode init() { + final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); + return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); } - NSUUID initWithUUIDBytes_(ffi.Pointer bytes) { - final _ret = - _lib._objc_msgSend_1034(_id, _lib._sel_initWithUUIDBytes_1, bytes); - return NSUUID._(_ret, _lib, retain: true, release: true); + int get DTDKind { + return _lib._objc_msgSend_1030(_id, _lib._sel_DTDKind1); } - void getUUIDBytes_(ffi.Pointer uuid) { - _lib._objc_msgSend_1035(_id, _lib._sel_getUUIDBytes_1, uuid); + set DTDKind(int value) { + return _lib._objc_msgSend_1031(_id, _lib._sel_setDTDKind_1, value); } - int compare_(NSUUID? otherUUID) { - return _lib._objc_msgSend_1036( - _id, _lib._sel_compare_1, otherUUID?._id ?? ffi.nullptr); + bool get external1 { + return _lib._objc_msgSend_12(_id, _lib._sel_isExternal1); } - NSString? get UUIDString { - final _ret = _lib._objc_msgSend_20(_id, _lib._sel_UUIDString1); + NSString? get publicID { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_publicID1); return _ret.address == 0 ? null : NSString._(_ret, _lib, retain: true, release: true); } - static NSUUID new1(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_NSUUID1, _lib._sel_new1); - return NSUUID._(_ret, _lib, retain: false, release: true); - } - - static NSUUID allocWithZone_(SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { - final _ret = _lib._objc_msgSend_3( - _lib._class_NSUUID1, _lib._sel_allocWithZone_1, zone); - return NSUUID._(_ret, _lib, retain: false, release: true); + set publicID(NSString? value) { + return _lib._objc_msgSend_509( + _id, _lib._sel_setPublicID_1, value?._id ?? ffi.nullptr); } - static NSUUID alloc(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2(_lib._class_NSUUID1, _lib._sel_alloc1); - return NSUUID._(_ret, _lib, retain: false, release: true); + NSString? get systemID { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_systemID1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); } - static void cancelPreviousPerformRequestsWithTarget_selector_object_( - SentryCocoa _lib, - NSObject aTarget, - ffi.Pointer aSelector, - NSObject anArgument) { - _lib._objc_msgSend_14( - _lib._class_NSUUID1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, - aTarget._id, - aSelector, - anArgument._id); + set systemID(NSString? value) { + return _lib._objc_msgSend_509( + _id, _lib._sel_setSystemID_1, value?._id ?? ffi.nullptr); } - static void cancelPreviousPerformRequestsWithTarget_( - SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_NSUUID1, - _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); + NSString? get notationName { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_notationName1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); } - static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_NSUUID1, _lib._sel_accessInstanceVariablesDirectly1); + set notationName(NSString? value) { + return _lib._objc_msgSend_509( + _id, _lib._sel_setNotationName_1, value?._id ?? ffi.nullptr); } - static bool useStoredAccessor(SentryCocoa _lib) { - return _lib._objc_msgSend_12( - _lib._class_NSUUID1, _lib._sel_useStoredAccessor1); + @override + NSXMLDTDNode initWithKind_(int kind) { + final _ret = _lib._objc_msgSend_1015(_id, _lib._sel_initWithKind_1, kind); + return NSXMLDTDNode._(_ret, _lib, retain: true, release: true); } - static NSSet keyPathsForValuesAffectingValueForKey_( - SentryCocoa _lib, NSString? key) { - final _ret = _lib._objc_msgSend_58( - _lib._class_NSUUID1, - _lib._sel_keyPathsForValuesAffectingValueForKey_1, - key?._id ?? ffi.nullptr); - return NSSet._(_ret, _lib, retain: true, release: true); + static NSObject document(SentryCocoa _lib) { + final _ret = + _lib._objc_msgSend_2(_lib._class_NSXMLDTDNode1, _lib._sel_document1); + return NSObject._(_ret, _lib, retain: true, release: true); } - static bool automaticallyNotifiesObserversForKey_( - SentryCocoa _lib, NSString? key) { - return _lib._objc_msgSend_59( - _lib._class_NSUUID1, - _lib._sel_automaticallyNotifiesObserversForKey_1, - key?._id ?? ffi.nullptr); + static NSObject documentWithRootElement_( + SentryCocoa _lib, NSXMLElement? element) { + final _ret = _lib._objc_msgSend_1017(_lib._class_NSXMLDTDNode1, + _lib._sel_documentWithRootElement_1, element?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - static void setKeys_triggerChangeNotificationsForDependentKey_( - SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { - _lib._objc_msgSend_82( - _lib._class_NSUUID1, - _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, - keys?._id ?? ffi.nullptr, - dependentKey?._id ?? ffi.nullptr); + static NSObject elementWithName_(SentryCocoa _lib, NSString? name) { + final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, + _lib._sel_elementWithName_1, name?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79( - _lib._class_NSUUID1, _lib._sel_classFallbacksForKeyedArchiver1); - return NSArray._(_ret, _lib, retain: true, release: true); + static NSObject elementWithName_URI_( + SentryCocoa _lib, NSString? name, NSString? URI) { + final _ret = _lib._objc_msgSend_165( + _lib._class_NSXMLDTDNode1, + _lib._sel_elementWithName_URI_1, + name?._id ?? ffi.nullptr, + URI?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_2( - _lib._class_NSUUID1, _lib._sel_classForKeyedUnarchiver1); + static NSObject elementWithName_stringValue_( + SentryCocoa _lib, NSString? name, NSString? string) { + final _ret = _lib._objc_msgSend_165( + _lib._class_NSXMLDTDNode1, + _lib._sel_elementWithName_stringValue_1, + name?._id ?? ffi.nullptr, + string?._id ?? ffi.nullptr); return NSObject._(_ret, _lib, retain: true, release: true); } -} - -class SentryEnvelopeItem extends NSObject { - SentryEnvelopeItem._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); - /// Returns a [SentryEnvelopeItem] that points to the same underlying object as [other]. - static SentryEnvelopeItem castFrom(T other) { - return SentryEnvelopeItem._(other._id, other._lib, - retain: true, release: true); + static NSObject elementWithName_children_attributes_(SentryCocoa _lib, + NSString? name, NSArray? children, NSArray? attributes) { + final _ret = _lib._objc_msgSend_1018( + _lib._class_NSXMLDTDNode1, + _lib._sel_elementWithName_children_attributes_1, + name?._id ?? ffi.nullptr, + children?._id ?? ffi.nullptr, + attributes?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - /// Returns a [SentryEnvelopeItem] that wraps the given raw object pointer. - static SentryEnvelopeItem castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentryEnvelopeItem._(other, lib, retain: retain, release: release); + static NSObject attributeWithName_stringValue_( + SentryCocoa _lib, NSString? name, NSString? stringValue) { + final _ret = _lib._objc_msgSend_165( + _lib._class_NSXMLDTDNode1, + _lib._sel_attributeWithName_stringValue_1, + name?._id ?? ffi.nullptr, + stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - /// Returns whether [obj] is an instance of [SentryEnvelopeItem]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_SentryEnvelopeItem1); + static NSObject attributeWithName_URI_stringValue_( + SentryCocoa _lib, NSString? name, NSString? URI, NSString? stringValue) { + final _ret = _lib._objc_msgSend_26( + _lib._class_NSXMLDTDNode1, + _lib._sel_attributeWithName_URI_stringValue_1, + name?._id ?? ffi.nullptr, + URI?._id ?? ffi.nullptr, + stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - @override - SentryEnvelopeItem init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return SentryEnvelopeItem._(_ret, _lib, retain: true, release: true); + static NSObject namespaceWithName_stringValue_( + SentryCocoa _lib, NSString? name, NSString? stringValue) { + final _ret = _lib._objc_msgSend_165( + _lib._class_NSXMLDTDNode1, + _lib._sel_namespaceWithName_stringValue_1, + name?._id ?? ffi.nullptr, + stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - static SentryEnvelopeItem new1(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_SentryEnvelopeItem1, _lib._sel_new1); - return SentryEnvelopeItem._(_ret, _lib, retain: false, release: true); + static NSObject processingInstructionWithName_stringValue_( + SentryCocoa _lib, NSString? name, NSString? stringValue) { + final _ret = _lib._objc_msgSend_165( + _lib._class_NSXMLDTDNode1, + _lib._sel_processingInstructionWithName_stringValue_1, + name?._id ?? ffi.nullptr, + stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - SentryEnvelopeItem initWithEvent_(SentryEvent? event) { - final _ret = _lib._objc_msgSend_1039( - _id, _lib._sel_initWithEvent_1, event?._id ?? ffi.nullptr); - return SentryEnvelopeItem._(_ret, _lib, retain: true, release: true); + static NSObject commentWithStringValue_( + SentryCocoa _lib, NSString? stringValue) { + final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, + _lib._sel_commentWithStringValue_1, stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - SentryEnvelopeItem initWithSession_(SentrySession? session) { - final _ret = _lib._objc_msgSend_1040( - _id, _lib._sel_initWithSession_1, session?._id ?? ffi.nullptr); - return SentryEnvelopeItem._(_ret, _lib, retain: true, release: true); + static NSObject textWithStringValue_( + SentryCocoa _lib, NSString? stringValue) { + final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, + _lib._sel_textWithStringValue_1, stringValue?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - SentryEnvelopeItem initWithUserFeedback_(SentryUserFeedback? userFeedback) { - final _ret = _lib._objc_msgSend_1041(_id, _lib._sel_initWithUserFeedback_1, - userFeedback?._id ?? ffi.nullptr); - return SentryEnvelopeItem._(_ret, _lib, retain: true, release: true); + static NSObject DTDNodeWithXMLString_(SentryCocoa _lib, NSString? string) { + final _ret = _lib._objc_msgSend_30(_lib._class_NSXMLDTDNode1, + _lib._sel_DTDNodeWithXMLString_1, string?._id ?? ffi.nullptr); + return NSObject._(_ret, _lib, retain: true, release: true); } - SentryEnvelopeItem initWithAttachment_maxAttachmentSize_( - SentryAttachment? attachment, int maxAttachmentSize) { - final _ret = _lib._objc_msgSend_1042( - _id, - _lib._sel_initWithAttachment_maxAttachmentSize_1, - attachment?._id ?? ffi.nullptr, - maxAttachmentSize); - return SentryEnvelopeItem._(_ret, _lib, retain: true, release: true); + static NSString localNameForName_(SentryCocoa _lib, NSString? name) { + final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTDNode1, + _lib._sel_localNameForName_1, name?._id ?? ffi.nullptr); + return NSString._(_ret, _lib, retain: true, release: true); } - SentryEnvelopeItem initWithHeader_data_( - SentryEnvelopeItemHeader? header, NSData? data) { - final _ret = _lib._objc_msgSend_1043(_id, _lib._sel_initWithHeader_data_1, - header?._id ?? ffi.nullptr, data?._id ?? ffi.nullptr); - return SentryEnvelopeItem._(_ret, _lib, retain: true, release: true); + static NSString prefixForName_(SentryCocoa _lib, NSString? name) { + final _ret = _lib._objc_msgSend_64(_lib._class_NSXMLDTDNode1, + _lib._sel_prefixForName_1, name?._id ?? ffi.nullptr); + return NSString._(_ret, _lib, retain: true, release: true); } - /// The envelope item header. - SentryEnvelopeItemHeader? get header { - final _ret = _lib._objc_msgSend_1044(_id, _lib._sel_header1); - return _ret.address == 0 - ? null - : SentryEnvelopeItemHeader._(_ret, _lib, retain: true, release: true); + static NSXMLNode predefinedNamespaceForPrefix_( + SentryCocoa _lib, NSString? name) { + final _ret = _lib._objc_msgSend_1032(_lib._class_NSXMLDTDNode1, + _lib._sel_predefinedNamespaceForPrefix_1, name?._id ?? ffi.nullptr); + return NSXMLNode._(_ret, _lib, retain: true, release: true); } - /// The envelope payload. - NSData? get data { - final _ret = _lib._objc_msgSend_39(_id, _lib._sel_data1); - return _ret.address == 0 - ? null - : NSData._(_ret, _lib, retain: true, release: true); + static NSXMLDTDNode new1(SentryCocoa _lib) { + final _ret = + _lib._objc_msgSend_2(_lib._class_NSXMLDTDNode1, _lib._sel_new1); + return NSXMLDTDNode._(_ret, _lib, retain: false, release: true); } - static SentryEnvelopeItem allocWithZone_( + static NSXMLDTDNode allocWithZone_( SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { final _ret = _lib._objc_msgSend_3( - _lib._class_SentryEnvelopeItem1, _lib._sel_allocWithZone_1, zone); - return SentryEnvelopeItem._(_ret, _lib, retain: false, release: true); + _lib._class_NSXMLDTDNode1, _lib._sel_allocWithZone_1, zone); + return NSXMLDTDNode._(_ret, _lib, retain: false, release: true); } - static SentryEnvelopeItem alloc(SentryCocoa _lib) { + static NSXMLDTDNode alloc(SentryCocoa _lib) { final _ret = - _lib._objc_msgSend_2(_lib._class_SentryEnvelopeItem1, _lib._sel_alloc1); - return SentryEnvelopeItem._(_ret, _lib, retain: false, release: true); + _lib._objc_msgSend_2(_lib._class_NSXMLDTDNode1, _lib._sel_alloc1); + return NSXMLDTDNode._(_ret, _lib, retain: false, release: true); } static void cancelPreviousPerformRequestsWithTarget_selector_object_( @@ -71274,7 +70593,7 @@ class SentryEnvelopeItem extends NSObject { ffi.Pointer aSelector, NSObject anArgument) { _lib._objc_msgSend_14( - _lib._class_SentryEnvelopeItem1, + _lib._class_NSXMLDTDNode1, _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, aTarget._id, aSelector, @@ -71283,24 +70602,24 @@ class SentryEnvelopeItem extends NSObject { static void cancelPreviousPerformRequestsWithTarget_( SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_SentryEnvelopeItem1, + _lib._objc_msgSend_15(_lib._class_NSXMLDTDNode1, _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); } static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12(_lib._class_SentryEnvelopeItem1, - _lib._sel_accessInstanceVariablesDirectly1); + return _lib._objc_msgSend_12( + _lib._class_NSXMLDTDNode1, _lib._sel_accessInstanceVariablesDirectly1); } static bool useStoredAccessor(SentryCocoa _lib) { return _lib._objc_msgSend_12( - _lib._class_SentryEnvelopeItem1, _lib._sel_useStoredAccessor1); + _lib._class_NSXMLDTDNode1, _lib._sel_useStoredAccessor1); } static NSSet keyPathsForValuesAffectingValueForKey_( SentryCocoa _lib, NSString? key) { final _ret = _lib._objc_msgSend_58( - _lib._class_SentryEnvelopeItem1, + _lib._class_NSXMLDTDNode1, _lib._sel_keyPathsForValuesAffectingValueForKey_1, key?._id ?? ffi.nullptr); return NSSet._(_ret, _lib, retain: true, release: true); @@ -71309,7 +70628,7 @@ class SentryEnvelopeItem extends NSObject { static bool automaticallyNotifiesObserversForKey_( SentryCocoa _lib, NSString? key) { return _lib._objc_msgSend_59( - _lib._class_SentryEnvelopeItem1, + _lib._class_NSXMLDTDNode1, _lib._sel_automaticallyNotifiesObserversForKey_1, key?._id ?? ffi.nullptr); } @@ -71317,287 +70636,311 @@ class SentryEnvelopeItem extends NSObject { static void setKeys_triggerChangeNotificationsForDependentKey_( SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { _lib._objc_msgSend_82( - _lib._class_SentryEnvelopeItem1, + _lib._class_NSXMLDTDNode1, _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, keys?._id ?? ffi.nullptr, dependentKey?._id ?? ffi.nullptr); } static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79(_lib._class_SentryEnvelopeItem1, - _lib._sel_classFallbacksForKeyedArchiver1); + final _ret = _lib._objc_msgSend_79( + _lib._class_NSXMLDTDNode1, _lib._sel_classFallbacksForKeyedArchiver1); return NSArray._(_ret, _lib, retain: true, release: true); } static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { final _ret = _lib._objc_msgSend_2( - _lib._class_SentryEnvelopeItem1, _lib._sel_classForKeyedUnarchiver1); + _lib._class_NSXMLDTDNode1, _lib._sel_classForKeyedUnarchiver1); return NSObject._(_ret, _lib, retain: true, release: true); } } -class SentryEvent extends _ObjCWrapper { - SentryEvent._(ffi.Pointer id, SentryCocoa lib, +abstract class NSXMLDTDNodeKind { + static const int NSXMLEntityGeneralKind = 1; + static const int NSXMLEntityParsedKind = 2; + static const int NSXMLEntityUnparsedKind = 3; + static const int NSXMLEntityParameterKind = 4; + static const int NSXMLEntityPredefined = 5; + static const int NSXMLAttributeCDATAKind = 6; + static const int NSXMLAttributeIDKind = 7; + static const int NSXMLAttributeIDRefKind = 8; + static const int NSXMLAttributeIDRefsKind = 9; + static const int NSXMLAttributeEntityKind = 10; + static const int NSXMLAttributeEntitiesKind = 11; + static const int NSXMLAttributeNMTokenKind = 12; + static const int NSXMLAttributeNMTokensKind = 13; + static const int NSXMLAttributeEnumerationKind = 14; + static const int NSXMLAttributeNotationKind = 15; + static const int NSXMLElementDeclarationUndefinedKind = 16; + static const int NSXMLElementDeclarationEmptyKind = 17; + static const int NSXMLElementDeclarationAnyKind = 18; + static const int NSXMLElementDeclarationMixedKind = 19; + static const int NSXMLElementDeclarationElementKind = 20; +} + +/// @warning This class is reserved for hybrid SDKs. Methods may be changed, renamed or removed +/// without notice. If you want to use one of these methods here please open up an issue and let us +/// know. +/// @note The name of this class is supposed to be a bit weird and ugly. The name starts with private +/// on purpose so users don't see it in code completion when typing Sentry. We also add only at the +/// end to make it more obvious you shouldn't use it. +class PrivateSentrySDKOnly extends NSObject { + PrivateSentrySDKOnly._(ffi.Pointer id, SentryCocoa lib, {bool retain = false, bool release = false}) : super._(id, lib, retain: retain, release: release); - /// Returns a [SentryEvent] that points to the same underlying object as [other]. - static SentryEvent castFrom(T other) { - return SentryEvent._(other._id, other._lib, retain: true, release: true); + /// Returns a [PrivateSentrySDKOnly] that points to the same underlying object as [other]. + static PrivateSentrySDKOnly castFrom(T other) { + return PrivateSentrySDKOnly._(other._id, other._lib, + retain: true, release: true); } - /// Returns a [SentryEvent] that wraps the given raw object pointer. - static SentryEvent castFromPointer( + /// Returns a [PrivateSentrySDKOnly] that wraps the given raw object pointer. + static PrivateSentrySDKOnly castFromPointer( SentryCocoa lib, ffi.Pointer other, {bool retain = false, bool release = false}) { - return SentryEvent._(other, lib, retain: retain, release: release); + return PrivateSentrySDKOnly._(other, lib, retain: retain, release: release); } - /// Returns whether [obj] is an instance of [SentryEvent]. + /// Returns whether [obj] is an instance of [PrivateSentrySDKOnly]. static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0( - obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_SentryEvent1); + return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, + obj._lib._class_PrivateSentrySDKOnly1); } -} -class SentrySession extends _ObjCWrapper { - SentrySession._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); + /// For storing an envelope synchronously to disk. + static void storeEnvelope_(SentryCocoa _lib, SentryEnvelope? envelope) { + _lib._objc_msgSend_1050(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_storeEnvelope_1, envelope?._id ?? ffi.nullptr); + } - /// Returns a [SentrySession] that points to the same underlying object as [other]. - static SentrySession castFrom(T other) { - return SentrySession._(other._id, other._lib, retain: true, release: true); + static void captureEnvelope_(SentryCocoa _lib, SentryEnvelope? envelope) { + _lib._objc_msgSend_1050(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_captureEnvelope_1, envelope?._id ?? ffi.nullptr); } - /// Returns a [SentrySession] that wraps the given raw object pointer. - static SentrySession castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentrySession._(other, lib, retain: retain, release: release); + /// Create an envelope from @c NSData. Needed for example by Flutter. + static SentryEnvelope envelopeWithData_(SentryCocoa _lib, NSData? data) { + final _ret = _lib._objc_msgSend_1051(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_envelopeWithData_1, data?._id ?? ffi.nullptr); + return SentryEnvelope._(_ret, _lib, retain: true, release: true); } - /// Returns whether [obj] is an instance of [SentrySession]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0( - obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_SentrySession1); + /// Returns the current list of debug images. Be aware that the @c SentryDebugMeta is actually + /// describing a debug image. + /// @warning This assumes a crash has occurred and attempts to read the crash information from each + /// image's data segment, which may not be present or be invalid if a crash has not actually + /// occurred. To avoid this, use the new @c +[getDebugImagesCrashed:] instead. + static NSArray getDebugImages(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_79( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_getDebugImages1); + return NSArray._(_ret, _lib, retain: true, release: true); } -} -class SentryUserFeedback extends _ObjCWrapper { - SentryUserFeedback._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); + /// Returns the current list of debug images. Be aware that the @c SentryDebugMeta is actually + /// describing a debug image. + /// @param isCrash @c YES if we're collecting binary images for a crash report, @c NO if we're + /// gathering them for other backtrace information, like a performance transaction. If this is for a + /// crash, each image's data section crash info is also included. + static NSArray getDebugImagesCrashed_(SentryCocoa _lib, bool isCrash) { + final _ret = _lib._objc_msgSend_1052(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_getDebugImagesCrashed_1, isCrash); + return NSArray._(_ret, _lib, retain: true, release: true); + } - /// Returns a [SentryUserFeedback] that points to the same underlying object as [other]. - static SentryUserFeedback castFrom(T other) { - return SentryUserFeedback._(other._id, other._lib, - retain: true, release: true); + /// Override SDK information. + static void setSdkName_andVersionString_( + SentryCocoa _lib, NSString? sdkName, NSString? versionString) { + _lib._objc_msgSend_515( + _lib._class_PrivateSentrySDKOnly1, + _lib._sel_setSdkName_andVersionString_1, + sdkName?._id ?? ffi.nullptr, + versionString?._id ?? ffi.nullptr); } - /// Returns a [SentryUserFeedback] that wraps the given raw object pointer. - static SentryUserFeedback castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentryUserFeedback._(other, lib, retain: retain, release: release); + /// Override SDK information. + static void setSdkName_(SentryCocoa _lib, NSString? sdkName) { + _lib._objc_msgSend_192(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_setSdkName_1, sdkName?._id ?? ffi.nullptr); } - /// Returns whether [obj] is an instance of [SentryUserFeedback]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_SentryUserFeedback1); + /// Retrieves the SDK name + static NSString getSdkName(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_20( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_getSdkName1); + return NSString._(_ret, _lib, retain: true, release: true); } -} -class SentryAttachment extends _ObjCWrapper { - SentryAttachment._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); + /// Retrieves the SDK version string + static NSString getSdkVersionString(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_20( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_getSdkVersionString1); + return NSString._(_ret, _lib, retain: true, release: true); + } - /// Returns a [SentryAttachment] that points to the same underlying object as [other]. - static SentryAttachment castFrom(T other) { - return SentryAttachment._(other._id, other._lib, - retain: true, release: true); + /// Retrieves extra context + static NSDictionary getExtraContext(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_170( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_getExtraContext1); + return NSDictionary._(_ret, _lib, retain: true, release: true); + } + + /// Start a profiler session associated with the given @c SentryId. + /// @return The system time when the profiler session started. + static int startProfilerForTrace_(SentryCocoa _lib, SentryId1? traceId) { + return _lib._objc_msgSend_1053(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_startProfilerForTrace_1, traceId?._id ?? ffi.nullptr); + } + + /// Collect a profiler session data associated with the given @c SentryId. + /// This also discards the profiler. + static NSMutableDictionary collectProfileBetween_and_forTrace_( + SentryCocoa _lib, + int startSystemTime, + int endSystemTime, + SentryId? traceId) { + final _ret = _lib._objc_msgSend_1054( + _lib._class_PrivateSentrySDKOnly1, + _lib._sel_collectProfileBetween_and_forTrace_1, + startSystemTime, + endSystemTime, + traceId?._id ?? ffi.nullptr); + return NSMutableDictionary._(_ret, _lib, retain: true, release: true); } - /// Returns a [SentryAttachment] that wraps the given raw object pointer. - static SentryAttachment castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentryAttachment._(other, lib, retain: retain, release: release); + /// Discard profiler session data associated with the given @c SentryId. + /// This only needs to be called in case you haven't collected the profile (and don't intend to). + static void discardProfilerForTrace_(SentryCocoa _lib, SentryId? traceId) { + _lib._objc_msgSend_1055(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_discardProfilerForTrace_1, traceId?._id ?? ffi.nullptr); } - /// Returns whether [obj] is an instance of [SentryAttachment]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_SentryAttachment1); + static ObjCBlock_ffiVoid_SentryAppStartMeasurement + getOnAppStartMeasurementAvailable(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_1056(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_onAppStartMeasurementAvailable1); + return ObjCBlock_ffiVoid_SentryAppStartMeasurement._(_ret, _lib); } -} -class SentryEnvelopeItemHeader extends _ObjCWrapper { - SentryEnvelopeItemHeader._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); + static void setOnAppStartMeasurementAvailable( + SentryCocoa _lib, ObjCBlock_ffiVoid_SentryAppStartMeasurement value) { + return _lib._objc_msgSend_1057(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_setOnAppStartMeasurementAvailable_1, value._id); + } - /// Returns a [SentryEnvelopeItemHeader] that points to the same underlying object as [other]. - static SentryEnvelopeItemHeader castFrom(T other) { - return SentryEnvelopeItemHeader._(other._id, other._lib, - retain: true, release: true); + static SentryAppStartMeasurement? getAppStartMeasurement(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_1058( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_appStartMeasurement1); + return _ret.address == 0 + ? null + : SentryAppStartMeasurement._(_ret, _lib, retain: true, release: true); } - /// Returns a [SentryEnvelopeItemHeader] that wraps the given raw object pointer. - static SentryEnvelopeItemHeader castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentryEnvelopeItemHeader._(other, lib, - retain: retain, release: release); + static NSString? getInstallationID(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_20( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_installationID1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); } - /// Returns whether [obj] is an instance of [SentryEnvelopeItemHeader]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_SentryEnvelopeItemHeader1); + static SentryOptions? getOptions(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_1059( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_options1); + return _ret.address == 0 + ? null + : SentryOptions._(_ret, _lib, retain: true, release: true); } -} -class SentryEnvelopeHeader extends NSObject { - SentryEnvelopeHeader._(ffi.Pointer id, SentryCocoa lib, - {bool retain = false, bool release = false}) - : super._(id, lib, retain: retain, release: release); + /// If enabled, the SDK won't send the app start measurement with the first transaction. Instead, if + /// @c enableAutoPerformanceTracing is enabled, the SDK measures the app start and then calls + /// @c onAppStartMeasurementAvailable. Furthermore, the SDK doesn't set all values for the app start + /// measurement because the HybridSDKs initialize the Cocoa SDK too late to receive all + /// notifications. Instead, the SDK sets the @c appStartDuration to @c 0 and the + /// @c didFinishLaunchingTimestamp to @c timeIntervalSinceReferenceDate. + /// @note Default is @c NO. + static bool getAppStartMeasurementHybridSDKMode(SentryCocoa _lib) { + return _lib._objc_msgSend_12(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_appStartMeasurementHybridSDKMode1); + } - /// Returns a [SentryEnvelopeHeader] that points to the same underlying object as [other]. - static SentryEnvelopeHeader castFrom(T other) { - return SentryEnvelopeHeader._(other._id, other._lib, - retain: true, release: true); + /// If enabled, the SDK won't send the app start measurement with the first transaction. Instead, if + /// @c enableAutoPerformanceTracing is enabled, the SDK measures the app start and then calls + /// @c onAppStartMeasurementAvailable. Furthermore, the SDK doesn't set all values for the app start + /// measurement because the HybridSDKs initialize the Cocoa SDK too late to receive all + /// notifications. Instead, the SDK sets the @c appStartDuration to @c 0 and the + /// @c didFinishLaunchingTimestamp to @c timeIntervalSinceReferenceDate. + /// @note Default is @c NO. + static void setAppStartMeasurementHybridSDKMode( + SentryCocoa _lib, bool value) { + return _lib._objc_msgSend_492(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_setAppStartMeasurementHybridSDKMode_1, value); } - /// Returns a [SentryEnvelopeHeader] that wraps the given raw object pointer. - static SentryEnvelopeHeader castFromPointer( - SentryCocoa lib, ffi.Pointer other, - {bool retain = false, bool release = false}) { - return SentryEnvelopeHeader._(other, lib, retain: retain, release: release); + static NSDictionary appStartMeasurementWithSpans(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_170(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_appStartMeasurementWithSpans1); + return NSDictionary._(_ret, _lib, retain: true, release: true); } - /// Returns whether [obj] is an instance of [SentryEnvelopeHeader]. - static bool isInstance(_ObjCWrapper obj) { - return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_SentryEnvelopeHeader1); + static SentryUser userWithDictionary_( + SentryCocoa _lib, NSDictionary? dictionary) { + final _ret = _lib._objc_msgSend_1060(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_userWithDictionary_1, dictionary?._id ?? ffi.nullptr); + return SentryUser._(_ret, _lib, retain: true, release: true); } - @override - SentryEnvelopeHeader init() { - final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); - return SentryEnvelopeHeader._(_ret, _lib, retain: true, release: true); + static SentryBreadcrumb breadcrumbWithDictionary_( + SentryCocoa _lib, NSDictionary? dictionary) { + final _ret = _lib._objc_msgSend_1061(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_breadcrumbWithDictionary_1, dictionary?._id ?? ffi.nullptr); + return SentryBreadcrumb._(_ret, _lib, retain: true, release: true); } - static SentryEnvelopeHeader new1(SentryCocoa _lib) { - final _ret = - _lib._objc_msgSend_2(_lib._class_SentryEnvelopeHeader1, _lib._sel_new1); - return SentryEnvelopeHeader._(_ret, _lib, retain: false, release: true); - } - - /// Initializes an @c SentryEnvelopeHeader object with the specified eventId. - /// @note Sets the @c sdkInfo from @c SentryMeta. - /// @param eventId The identifier of the event. Can be nil if no event in the envelope or attachment - /// related to event. - SentryEnvelopeHeader initWithId_(SentryId? eventId) { - final _ret = _lib._objc_msgSend_1046( - _id, _lib._sel_initWithId_1, eventId?._id ?? ffi.nullptr); - return SentryEnvelopeHeader._(_ret, _lib, retain: true, release: true); - } - - /// Initializes a @c SentryEnvelopeHeader object with the specified @c eventId and @c traceContext. - /// @param eventId The identifier of the event. Can be @c nil if no event in the envelope or - /// attachment related to event. - /// @param traceContext Current trace state. - SentryEnvelopeHeader initWithId_traceContext_( - SentryId? eventId, SentryTraceContext? traceContext) { - final _ret = _lib._objc_msgSend_1047( - _id, - _lib._sel_initWithId_traceContext_1, - eventId?._id ?? ffi.nullptr, - traceContext?._id ?? ffi.nullptr); - return SentryEnvelopeHeader._(_ret, _lib, retain: true, release: true); - } - - /// Initializes a @c SentryEnvelopeHeader object with the specified @c eventId, @c skdInfo and - /// @c traceContext. It is recommended to use @c initWithId:traceContext: because it sets the - /// @c sdkInfo for you. - /// @param eventId The identifier of the event. Can be @c nil if no event in the envelope or - /// attachment related to event. - /// @param sdkInfo Describes the Sentry SDK. Can be @c nil for backwards compatibility. New - /// instances should always provide a version. - /// @param traceContext Current trace state. - SentryEnvelopeHeader initWithId_sdkInfo_traceContext_(SentryId? eventId, - SentrySdkInfo? sdkInfo, SentryTraceContext? traceContext) { - final _ret = _lib._objc_msgSend_1048( - _id, - _lib._sel_initWithId_sdkInfo_traceContext_1, - eventId?._id ?? ffi.nullptr, - sdkInfo?._id ?? ffi.nullptr, - traceContext?._id ?? ffi.nullptr); - return SentryEnvelopeHeader._(_ret, _lib, retain: true, release: true); + static void captureReplay(SentryCocoa _lib) { + _lib._objc_msgSend_1( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_captureReplay1); } - /// The event identifier, if available. - /// An event id exist if the envelope contains an event of items within it are related. i.e - /// Attachments - SentryId? get eventId { - final _ret = _lib._objc_msgSend_1038(_id, _lib._sel_eventId1); - return _ret.address == 0 - ? null - : SentryId._(_ret, _lib, retain: true, release: true); + static NSString getReplayId(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_20( + _lib._class_PrivateSentrySDKOnly1, _lib._sel_getReplayId1); + return NSString._(_ret, _lib, retain: true, release: true); } - SentrySdkInfo? get sdkInfo { - final _ret = _lib._objc_msgSend_1049(_id, _lib._sel_sdkInfo1); - return _ret.address == 0 - ? null - : SentrySdkInfo._(_ret, _lib, retain: true, release: true); + static void addReplayIgnoreClasses_(SentryCocoa _lib, NSArray? classes) { + _lib._objc_msgSend_441(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_addReplayIgnoreClasses_1, classes?._id ?? ffi.nullptr); } - SentryTraceContext? get traceContext { - final _ret = _lib._objc_msgSend_1050(_id, _lib._sel_traceContext1); - return _ret.address == 0 - ? null - : SentryTraceContext._(_ret, _lib, retain: true, release: true); + static void addReplayRedactClasses_(SentryCocoa _lib, NSArray? classes) { + _lib._objc_msgSend_441(_lib._class_PrivateSentrySDKOnly1, + _lib._sel_addReplayRedactClasses_1, classes?._id ?? ffi.nullptr); } - /// The timestamp when the event was sent from the SDK as string in RFC 3339 format. Used - /// for clock drift correction of the event timestamp. The time zone must be UTC. - /// - /// The timestamp should be generated as close as possible to the transmision of the event, - /// so that the delay between sending the envelope and receiving it on the server-side is - /// minimized. - NSDate? get sentAt { - final _ret = _lib._objc_msgSend_162(_id, _lib._sel_sentAt1); - return _ret.address == 0 - ? null - : NSDate._(_ret, _lib, retain: true, release: true); + @override + PrivateSentrySDKOnly init() { + final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); + return PrivateSentrySDKOnly._(_ret, _lib, retain: true, release: true); } - /// The timestamp when the event was sent from the SDK as string in RFC 3339 format. Used - /// for clock drift correction of the event timestamp. The time zone must be UTC. - /// - /// The timestamp should be generated as close as possible to the transmision of the event, - /// so that the delay between sending the envelope and receiving it on the server-side is - /// minimized. - set sentAt(NSDate? value) { - return _lib._objc_msgSend_525( - _id, _lib._sel_setSentAt_1, value?._id ?? ffi.nullptr); + static PrivateSentrySDKOnly new1(SentryCocoa _lib) { + final _ret = + _lib._objc_msgSend_2(_lib._class_PrivateSentrySDKOnly1, _lib._sel_new1); + return PrivateSentrySDKOnly._(_ret, _lib, retain: false, release: true); } - static SentryEnvelopeHeader allocWithZone_( + static PrivateSentrySDKOnly allocWithZone_( SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { final _ret = _lib._objc_msgSend_3( - _lib._class_SentryEnvelopeHeader1, _lib._sel_allocWithZone_1, zone); - return SentryEnvelopeHeader._(_ret, _lib, retain: false, release: true); + _lib._class_PrivateSentrySDKOnly1, _lib._sel_allocWithZone_1, zone); + return PrivateSentrySDKOnly._(_ret, _lib, retain: false, release: true); } - static SentryEnvelopeHeader alloc(SentryCocoa _lib) { + static PrivateSentrySDKOnly alloc(SentryCocoa _lib) { final _ret = _lib._objc_msgSend_2( - _lib._class_SentryEnvelopeHeader1, _lib._sel_alloc1); - return SentryEnvelopeHeader._(_ret, _lib, retain: false, release: true); + _lib._class_PrivateSentrySDKOnly1, _lib._sel_alloc1); + return PrivateSentrySDKOnly._(_ret, _lib, retain: false, release: true); } static void cancelPreviousPerformRequestsWithTarget_selector_object_( @@ -71606,7 +70949,7 @@ class SentryEnvelopeHeader extends NSObject { ffi.Pointer aSelector, NSObject anArgument) { _lib._objc_msgSend_14( - _lib._class_SentryEnvelopeHeader1, + _lib._class_PrivateSentrySDKOnly1, _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, aTarget._id, aSelector, @@ -71615,24 +70958,24 @@ class SentryEnvelopeHeader extends NSObject { static void cancelPreviousPerformRequestsWithTarget_( SentryCocoa _lib, NSObject aTarget) { - _lib._objc_msgSend_15(_lib._class_SentryEnvelopeHeader1, + _lib._objc_msgSend_15(_lib._class_PrivateSentrySDKOnly1, _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); } static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { - return _lib._objc_msgSend_12(_lib._class_SentryEnvelopeHeader1, + return _lib._objc_msgSend_12(_lib._class_PrivateSentrySDKOnly1, _lib._sel_accessInstanceVariablesDirectly1); } static bool useStoredAccessor(SentryCocoa _lib) { return _lib._objc_msgSend_12( - _lib._class_SentryEnvelopeHeader1, _lib._sel_useStoredAccessor1); + _lib._class_PrivateSentrySDKOnly1, _lib._sel_useStoredAccessor1); } static NSSet keyPathsForValuesAffectingValueForKey_( SentryCocoa _lib, NSString? key) { final _ret = _lib._objc_msgSend_58( - _lib._class_SentryEnvelopeHeader1, + _lib._class_PrivateSentrySDKOnly1, _lib._sel_keyPathsForValuesAffectingValueForKey_1, key?._id ?? ffi.nullptr); return NSSet._(_ret, _lib, retain: true, release: true); @@ -71641,7 +70984,7 @@ class SentryEnvelopeHeader extends NSObject { static bool automaticallyNotifiesObserversForKey_( SentryCocoa _lib, NSString? key) { return _lib._objc_msgSend_59( - _lib._class_SentryEnvelopeHeader1, + _lib._class_PrivateSentrySDKOnly1, _lib._sel_automaticallyNotifiesObserversForKey_1, key?._id ?? ffi.nullptr); } @@ -71649,71 +70992,70 @@ class SentryEnvelopeHeader extends NSObject { static void setKeys_triggerChangeNotificationsForDependentKey_( SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { _lib._objc_msgSend_82( - _lib._class_SentryEnvelopeHeader1, + _lib._class_PrivateSentrySDKOnly1, _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, keys?._id ?? ffi.nullptr, dependentKey?._id ?? ffi.nullptr); } static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { - final _ret = _lib._objc_msgSend_79(_lib._class_SentryEnvelopeHeader1, + final _ret = _lib._objc_msgSend_79(_lib._class_PrivateSentrySDKOnly1, _lib._sel_classFallbacksForKeyedArchiver1); return NSArray._(_ret, _lib, retain: true, release: true); } static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { final _ret = _lib._objc_msgSend_2( - _lib._class_SentryEnvelopeHeader1, _lib._sel_classForKeyedUnarchiver1); + _lib._class_PrivateSentrySDKOnly1, _lib._sel_classForKeyedUnarchiver1); return NSObject._(_ret, _lib, retain: true, release: true); } } -class SentryTraceContext extends _ObjCWrapper { - SentryTraceContext._(ffi.Pointer id, SentryCocoa lib, +class SentryEnvelope extends _ObjCWrapper { + SentryEnvelope._(ffi.Pointer id, SentryCocoa lib, {bool retain = false, bool release = false}) : super._(id, lib, retain: retain, release: release); - /// Returns a [SentryTraceContext] that points to the same underlying object as [other]. - static SentryTraceContext castFrom(T other) { - return SentryTraceContext._(other._id, other._lib, - retain: true, release: true); + /// Returns a [SentryEnvelope] that points to the same underlying object as [other]. + static SentryEnvelope castFrom(T other) { + return SentryEnvelope._(other._id, other._lib, retain: true, release: true); } - /// Returns a [SentryTraceContext] that wraps the given raw object pointer. - static SentryTraceContext castFromPointer( + /// Returns a [SentryEnvelope] that wraps the given raw object pointer. + static SentryEnvelope castFromPointer( SentryCocoa lib, ffi.Pointer other, {bool retain = false, bool release = false}) { - return SentryTraceContext._(other, lib, retain: retain, release: release); + return SentryEnvelope._(other, lib, retain: retain, release: release); } - /// Returns whether [obj] is an instance of [SentryTraceContext]. + /// Returns whether [obj] is an instance of [SentryEnvelope]. static bool isInstance(_ObjCWrapper obj) { return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, - obj._lib._class_SentryTraceContext1); + obj._lib._class_SentryEnvelope1); } } -class SentrySdkInfo extends _ObjCWrapper { - SentrySdkInfo._(ffi.Pointer id, SentryCocoa lib, +class SentryId extends _ObjCWrapper { + SentryId._(ffi.Pointer id, SentryCocoa lib, {bool retain = false, bool release = false}) : super._(id, lib, retain: retain, release: release); - /// Returns a [SentrySdkInfo] that points to the same underlying object as [other]. - static SentrySdkInfo castFrom(T other) { - return SentrySdkInfo._(other._id, other._lib, retain: true, release: true); + /// Returns a [SentryId] that points to the same underlying object as [other]. + static SentryId castFrom(T other) { + return SentryId._(other._id, other._lib, retain: true, release: true); } - /// Returns a [SentrySdkInfo] that wraps the given raw object pointer. - static SentrySdkInfo castFromPointer( + /// Returns a [SentryId] that wraps the given raw object pointer. + static SentryId castFromPointer( SentryCocoa lib, ffi.Pointer other, {bool retain = false, bool release = false}) { - return SentrySdkInfo._(other, lib, retain: retain, release: release); + return SentryId._(other, lib, retain: retain, release: release); } - /// Returns whether [obj] is an instance of [SentrySdkInfo]. + /// Returns whether [obj] is an instance of [SentryId]. static bool isInstance(_ObjCWrapper obj) { return obj._lib._objc_msgSend_0( - obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_SentrySdkInfo1); + obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_SentryId2); } } @@ -71889,3 +71231,458 @@ class SentryBreadcrumb extends _ObjCWrapper { obj._lib._class_SentryBreadcrumb1); } } + +class SentryCurrentDateProvider extends NSObject { + SentryCurrentDateProvider._(ffi.Pointer id, SentryCocoa lib, + {bool retain = false, bool release = false}) + : super._(id, lib, retain: retain, release: release); + + /// Returns a [SentryCurrentDateProvider] that points to the same underlying object as [other]. + static SentryCurrentDateProvider castFrom(T other) { + return SentryCurrentDateProvider._(other._id, other._lib, + retain: true, release: true); + } + + /// Returns a [SentryCurrentDateProvider] that wraps the given raw object pointer. + static SentryCurrentDateProvider castFromPointer( + SentryCocoa lib, ffi.Pointer other, + {bool retain = false, bool release = false}) { + return SentryCurrentDateProvider._(other, lib, + retain: retain, release: release); + } + + /// Returns whether [obj] is an instance of [SentryCurrentDateProvider]. + static bool isInstance(_ObjCWrapper obj) { + return obj._lib._objc_msgSend_0(obj._id, obj._lib._sel_isKindOfClass_1, + obj._lib._class_SentryCurrentDateProvider1); + } + + NSDate date() { + final _ret = _lib._objc_msgSend_162(_id, _lib._sel_date1); + return NSDate._(_ret, _lib, retain: true, release: true); + } + + int timezoneOffset() { + return _lib._objc_msgSend_78(_id, _lib._sel_timezoneOffset1); + } + + int systemTime() { + return _lib._objc_msgSend_1062(_id, _lib._sel_systemTime1); + } + + double systemUptime() { + return _lib._objc_msgSend_155(_id, _lib._sel_systemUptime1); + } + + @override + SentryCurrentDateProvider init() { + final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); + return SentryCurrentDateProvider._(_ret, _lib, retain: true, release: true); + } + + int get bucketTimestamp { + return _lib._objc_msgSend_1062(_id, _lib._sel_bucketTimestamp1); + } + + static SentryCurrentDateProvider new1(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2( + _lib._class_SentryCurrentDateProvider1, _lib._sel_new1); + return SentryCurrentDateProvider._(_ret, _lib, + retain: false, release: true); + } + + static SentryCurrentDateProvider allocWithZone_( + SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { + final _ret = _lib._objc_msgSend_3(_lib._class_SentryCurrentDateProvider1, + _lib._sel_allocWithZone_1, zone); + return SentryCurrentDateProvider._(_ret, _lib, + retain: false, release: true); + } + + static SentryCurrentDateProvider alloc(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2( + _lib._class_SentryCurrentDateProvider1, _lib._sel_alloc1); + return SentryCurrentDateProvider._(_ret, _lib, + retain: false, release: true); + } + + static void cancelPreviousPerformRequestsWithTarget_selector_object_( + SentryCocoa _lib, + NSObject aTarget, + ffi.Pointer aSelector, + NSObject anArgument) { + _lib._objc_msgSend_14( + _lib._class_SentryCurrentDateProvider1, + _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, + aTarget._id, + aSelector, + anArgument._id); + } + + static void cancelPreviousPerformRequestsWithTarget_( + SentryCocoa _lib, NSObject aTarget) { + _lib._objc_msgSend_15(_lib._class_SentryCurrentDateProvider1, + _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); + } + + static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { + return _lib._objc_msgSend_12(_lib._class_SentryCurrentDateProvider1, + _lib._sel_accessInstanceVariablesDirectly1); + } + + static bool useStoredAccessor(SentryCocoa _lib) { + return _lib._objc_msgSend_12( + _lib._class_SentryCurrentDateProvider1, _lib._sel_useStoredAccessor1); + } + + static NSSet keyPathsForValuesAffectingValueForKey_( + SentryCocoa _lib, NSString? key) { + final _ret = _lib._objc_msgSend_58( + _lib._class_SentryCurrentDateProvider1, + _lib._sel_keyPathsForValuesAffectingValueForKey_1, + key?._id ?? ffi.nullptr); + return NSSet._(_ret, _lib, retain: true, release: true); + } + + static bool automaticallyNotifiesObserversForKey_( + SentryCocoa _lib, NSString? key) { + return _lib._objc_msgSend_59( + _lib._class_SentryCurrentDateProvider1, + _lib._sel_automaticallyNotifiesObserversForKey_1, + key?._id ?? ffi.nullptr); + } + + static void setKeys_triggerChangeNotificationsForDependentKey_( + SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { + _lib._objc_msgSend_82( + _lib._class_SentryCurrentDateProvider1, + _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, + keys?._id ?? ffi.nullptr, + dependentKey?._id ?? ffi.nullptr); + } + + static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_79(_lib._class_SentryCurrentDateProvider1, + _lib._sel_classFallbacksForKeyedArchiver1); + return NSArray._(_ret, _lib, retain: true, release: true); + } + + static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_SentryCurrentDateProvider1, + _lib._sel_classForKeyedUnarchiver1); + return NSObject._(_ret, _lib, retain: true, release: true); + } +} + +class SentryId1 extends NSObject { + SentryId1._(ffi.Pointer id, SentryCocoa lib, + {bool retain = false, bool release = false}) + : super._(id, lib, retain: retain, release: release); + + /// Returns a [SentryId1] that points to the same underlying object as [other]. + static SentryId1 castFrom(T other) { + return SentryId1._(other._id, other._lib, retain: true, release: true); + } + + /// Returns a [SentryId1] that wraps the given raw object pointer. + static SentryId1 castFromPointer( + SentryCocoa lib, ffi.Pointer other, + {bool retain = false, bool release = false}) { + return SentryId1._(other, lib, retain: retain, release: release); + } + + /// Returns whether [obj] is an instance of [SentryId1]. + static bool isInstance(_ObjCWrapper obj) { + return obj._lib._objc_msgSend_0( + obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_SentryId11); + } + + static SentryId1? getEmpty(SentryCocoa _lib) { + final _ret = + _lib._objc_msgSend_1063(_lib._class_SentryId11, _lib._sel_empty1); + return _ret.address == 0 + ? null + : SentryId1._(_ret, _lib, retain: true, release: true); + } + + static void setEmpty(SentryCocoa _lib, SentryId1? value) { + return _lib._objc_msgSend_1064(_lib._class_SentryId11, _lib._sel_setEmpty_1, + value?._id ?? ffi.nullptr); + } + + /// Returns a 32 lowercase character hexadecimal string description of the @c SentryId, such as + /// “12c2d058d58442709aa2eca08bf20986”. + NSString? get sentryIdString { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_sentryIdString1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); + } + + /// Creates a @c SentryId with a random UUID. + @override + SentryId1 init() { + final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); + return SentryId1._(_ret, _lib, retain: true, release: true); + } + + /// Creates a SentryId with the given UUID. + SentryId1 initWithUuid_(NSUUID? uuid) { + final _ret = _lib._objc_msgSend_1068( + _id, _lib._sel_initWithUuid_1, uuid?._id ?? ffi.nullptr); + return SentryId1._(_ret, _lib, retain: true, release: true); + } + + /// Creates a @c SentryId from a 32 character hexadecimal string without dashes such as + /// “12c2d058d58442709aa2eca08bf20986” or a 36 character hexadecimal string such as such as + /// “12c2d058-d584-4270-9aa2-eca08bf20986”. + /// @return SentryId.empty for invalid strings. + SentryId1 initWithUUIDString_(NSString? uuidString) { + final _ret = _lib._objc_msgSend_30( + _id, _lib._sel_initWithUUIDString_1, uuidString?._id ?? ffi.nullptr); + return SentryId1._(_ret, _lib, retain: true, release: true); + } + + bool isEqual_(NSObject object) { + return _lib._objc_msgSend_0(_id, _lib._sel_isEqual_1, object._id); + } + + NSString? get description { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_description1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); + } + + int get hash { + return _lib._objc_msgSend_10(_id, _lib._sel_hash1); + } + + static SentryId1 new1(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_SentryId11, _lib._sel_new1); + return SentryId1._(_ret, _lib, retain: false, release: true); + } + + static SentryId1 allocWithZone_(SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { + final _ret = _lib._objc_msgSend_3( + _lib._class_SentryId11, _lib._sel_allocWithZone_1, zone); + return SentryId1._(_ret, _lib, retain: false, release: true); + } + + static SentryId1 alloc(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_SentryId11, _lib._sel_alloc1); + return SentryId1._(_ret, _lib, retain: false, release: true); + } + + static void cancelPreviousPerformRequestsWithTarget_selector_object_( + SentryCocoa _lib, + NSObject aTarget, + ffi.Pointer aSelector, + NSObject anArgument) { + _lib._objc_msgSend_14( + _lib._class_SentryId11, + _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, + aTarget._id, + aSelector, + anArgument._id); + } + + static void cancelPreviousPerformRequestsWithTarget_( + SentryCocoa _lib, NSObject aTarget) { + _lib._objc_msgSend_15(_lib._class_SentryId11, + _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); + } + + static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { + return _lib._objc_msgSend_12( + _lib._class_SentryId11, _lib._sel_accessInstanceVariablesDirectly1); + } + + static bool useStoredAccessor(SentryCocoa _lib) { + return _lib._objc_msgSend_12( + _lib._class_SentryId11, _lib._sel_useStoredAccessor1); + } + + static NSSet keyPathsForValuesAffectingValueForKey_( + SentryCocoa _lib, NSString? key) { + final _ret = _lib._objc_msgSend_58( + _lib._class_SentryId11, + _lib._sel_keyPathsForValuesAffectingValueForKey_1, + key?._id ?? ffi.nullptr); + return NSSet._(_ret, _lib, retain: true, release: true); + } + + static bool automaticallyNotifiesObserversForKey_( + SentryCocoa _lib, NSString? key) { + return _lib._objc_msgSend_59( + _lib._class_SentryId11, + _lib._sel_automaticallyNotifiesObserversForKey_1, + key?._id ?? ffi.nullptr); + } + + static void setKeys_triggerChangeNotificationsForDependentKey_( + SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { + _lib._objc_msgSend_82( + _lib._class_SentryId11, + _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, + keys?._id ?? ffi.nullptr, + dependentKey?._id ?? ffi.nullptr); + } + + static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_79( + _lib._class_SentryId11, _lib._sel_classFallbacksForKeyedArchiver1); + return NSArray._(_ret, _lib, retain: true, release: true); + } + + static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2( + _lib._class_SentryId11, _lib._sel_classForKeyedUnarchiver1); + return NSObject._(_ret, _lib, retain: true, release: true); + } +} + +class NSUUID extends NSObject { + NSUUID._(ffi.Pointer id, SentryCocoa lib, + {bool retain = false, bool release = false}) + : super._(id, lib, retain: retain, release: release); + + /// Returns a [NSUUID] that points to the same underlying object as [other]. + static NSUUID castFrom(T other) { + return NSUUID._(other._id, other._lib, retain: true, release: true); + } + + /// Returns a [NSUUID] that wraps the given raw object pointer. + static NSUUID castFromPointer(SentryCocoa lib, ffi.Pointer other, + {bool retain = false, bool release = false}) { + return NSUUID._(other, lib, retain: retain, release: release); + } + + /// Returns whether [obj] is an instance of [NSUUID]. + static bool isInstance(_ObjCWrapper obj) { + return obj._lib._objc_msgSend_0( + obj._id, obj._lib._sel_isKindOfClass_1, obj._lib._class_NSUUID1); + } + + static NSUUID UUID(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_NSUUID1, _lib._sel_UUID1); + return NSUUID._(_ret, _lib, retain: true, release: true); + } + + @override + NSUUID init() { + final _ret = _lib._objc_msgSend_2(_id, _lib._sel_init1); + return NSUUID._(_ret, _lib, retain: true, release: true); + } + + NSUUID initWithUUIDString_(NSString? string) { + final _ret = _lib._objc_msgSend_30( + _id, _lib._sel_initWithUUIDString_1, string?._id ?? ffi.nullptr); + return NSUUID._(_ret, _lib, retain: true, release: true); + } + + NSUUID initWithUUIDBytes_(ffi.Pointer bytes) { + final _ret = + _lib._objc_msgSend_1065(_id, _lib._sel_initWithUUIDBytes_1, bytes); + return NSUUID._(_ret, _lib, retain: true, release: true); + } + + void getUUIDBytes_(ffi.Pointer uuid) { + _lib._objc_msgSend_1066(_id, _lib._sel_getUUIDBytes_1, uuid); + } + + int compare_(NSUUID? otherUUID) { + return _lib._objc_msgSend_1067( + _id, _lib._sel_compare_1, otherUUID?._id ?? ffi.nullptr); + } + + NSString? get UUIDString { + final _ret = _lib._objc_msgSend_20(_id, _lib._sel_UUIDString1); + return _ret.address == 0 + ? null + : NSString._(_ret, _lib, retain: true, release: true); + } + + static NSUUID new1(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_NSUUID1, _lib._sel_new1); + return NSUUID._(_ret, _lib, retain: false, release: true); + } + + static NSUUID allocWithZone_(SentryCocoa _lib, ffi.Pointer<_NSZone> zone) { + final _ret = _lib._objc_msgSend_3( + _lib._class_NSUUID1, _lib._sel_allocWithZone_1, zone); + return NSUUID._(_ret, _lib, retain: false, release: true); + } + + static NSUUID alloc(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2(_lib._class_NSUUID1, _lib._sel_alloc1); + return NSUUID._(_ret, _lib, retain: false, release: true); + } + + static void cancelPreviousPerformRequestsWithTarget_selector_object_( + SentryCocoa _lib, + NSObject aTarget, + ffi.Pointer aSelector, + NSObject anArgument) { + _lib._objc_msgSend_14( + _lib._class_NSUUID1, + _lib._sel_cancelPreviousPerformRequestsWithTarget_selector_object_1, + aTarget._id, + aSelector, + anArgument._id); + } + + static void cancelPreviousPerformRequestsWithTarget_( + SentryCocoa _lib, NSObject aTarget) { + _lib._objc_msgSend_15(_lib._class_NSUUID1, + _lib._sel_cancelPreviousPerformRequestsWithTarget_1, aTarget._id); + } + + static bool getAccessInstanceVariablesDirectly(SentryCocoa _lib) { + return _lib._objc_msgSend_12( + _lib._class_NSUUID1, _lib._sel_accessInstanceVariablesDirectly1); + } + + static bool useStoredAccessor(SentryCocoa _lib) { + return _lib._objc_msgSend_12( + _lib._class_NSUUID1, _lib._sel_useStoredAccessor1); + } + + static NSSet keyPathsForValuesAffectingValueForKey_( + SentryCocoa _lib, NSString? key) { + final _ret = _lib._objc_msgSend_58( + _lib._class_NSUUID1, + _lib._sel_keyPathsForValuesAffectingValueForKey_1, + key?._id ?? ffi.nullptr); + return NSSet._(_ret, _lib, retain: true, release: true); + } + + static bool automaticallyNotifiesObserversForKey_( + SentryCocoa _lib, NSString? key) { + return _lib._objc_msgSend_59( + _lib._class_NSUUID1, + _lib._sel_automaticallyNotifiesObserversForKey_1, + key?._id ?? ffi.nullptr); + } + + static void setKeys_triggerChangeNotificationsForDependentKey_( + SentryCocoa _lib, NSArray? keys, NSString? dependentKey) { + _lib._objc_msgSend_82( + _lib._class_NSUUID1, + _lib._sel_setKeys_triggerChangeNotificationsForDependentKey_1, + keys?._id ?? ffi.nullptr, + dependentKey?._id ?? ffi.nullptr); + } + + static NSArray classFallbacksForKeyedArchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_79( + _lib._class_NSUUID1, _lib._sel_classFallbacksForKeyedArchiver1); + return NSArray._(_ret, _lib, retain: true, release: true); + } + + static NSObject classForKeyedUnarchiver(SentryCocoa _lib) { + final _ret = _lib._objc_msgSend_2( + _lib._class_NSUUID1, _lib._sel_classForKeyedUnarchiver1); + return NSObject._(_ret, _lib, retain: true, release: true); + } +} diff --git a/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart b/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart index 0e6817cb48..d6912c107c 100644 --- a/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart +++ b/flutter/lib/src/native/cocoa/sentry_native_cocoa.dart @@ -14,7 +14,7 @@ class SentryNativeCocoa extends SentryNativeChannel { @override int? startProfiler(SentryId traceId) { - final cSentryId = cocoa.SentryId.alloc(_lib) + final cSentryId = cocoa.SentryId1.alloc(_lib) ..initWithUUIDString_(cocoa.NSString(_lib, traceId.toString())); final startTime = cocoa.PrivateSentrySDKOnly.startProfilerForTrace_(_lib, cSentryId); diff --git a/flutter/lib/src/native/factory_real.dart b/flutter/lib/src/native/factory_real.dart index 3c918b7be7..d5ee4f5cca 100644 --- a/flutter/lib/src/native/factory_real.dart +++ b/flutter/lib/src/native/factory_real.dart @@ -2,12 +2,15 @@ import 'package:flutter/services.dart'; import '../../sentry_flutter.dart'; import 'cocoa/sentry_native_cocoa.dart'; +import 'java/sentry_native_java.dart'; import 'sentry_native_binding.dart'; import 'sentry_native_channel.dart'; SentryNativeBinding createBinding(PlatformChecker pc, MethodChannel channel) { if (pc.platform.isIOS || pc.platform.isMacOS) { return SentryNativeCocoa(channel); + } else if (pc.platform.isAndroid) { + return SentryNativeJava(channel); } else { return SentryNativeChannel(channel); } diff --git a/flutter/lib/src/native/factory_web.dart b/flutter/lib/src/native/factory_web.dart index 8038ea9780..c2cd57ada7 100644 --- a/flutter/lib/src/native/factory_web.dart +++ b/flutter/lib/src/native/factory_web.dart @@ -4,6 +4,6 @@ import '../../sentry_flutter.dart'; import 'sentry_native_binding.dart'; // This isn't actually called, see SentryFlutter.init() -SentryNativeBinding createBinding(PlatformChecker pc, MethodChannel channel) { +SentryNativeBinding createBinding(PlatformChecker _, MethodChannel __) { throw UnsupportedError("Native binding is not supported on this platform."); } diff --git a/flutter/lib/src/native/java/sentry_native_java.dart b/flutter/lib/src/native/java/sentry_native_java.dart new file mode 100644 index 0000000000..20774e11fa --- /dev/null +++ b/flutter/lib/src/native/java/sentry_native_java.dart @@ -0,0 +1,10 @@ +import 'package:meta/meta.dart'; + +import '../sentry_native_channel.dart'; + +// Note: currently this doesn't do anything. Later, it shall be used with +// generated JNI bindings. See https://github.com/getsentry/sentry-dart/issues/1444 +@internal +class SentryNativeJava extends SentryNativeChannel { + SentryNativeJava(super.channel); +} diff --git a/flutter/lib/src/native/sentry_native.dart b/flutter/lib/src/native/sentry_native.dart index b8d2206a8d..d8d9c5a964 100644 --- a/flutter/lib/src/native/sentry_native.dart +++ b/flutter/lib/src/native/sentry_native.dart @@ -27,6 +27,14 @@ class SentryNative { /// Flag indicating if app start was already fetched. bool get didFetchAppStart => _didFetchAppStart; + /// Flag indicating if app start measurement was added to the first transaction. + bool didAddAppStartMeasurement = false; + + Future init(SentryFlutterOptions options) async => + _invoke("init", () => _binding.init(options)); + + Future close() async => _invoke("close", _binding.close); + /// Fetch [NativeAppStart] from native channels. Can only be called once. Future fetchNativeAppStart() async { _didFetchAppStart = true; @@ -126,15 +134,23 @@ class SentryNative { } class NativeAppStart { - NativeAppStart(this.appStartTime, this.isColdStart); + NativeAppStart( + {required this.appStartTime, + required this.pluginRegistrationTime, + required this.isColdStart, + required this.nativeSpanTimes}); double appStartTime; + int pluginRegistrationTime; bool isColdStart; + Map nativeSpanTimes; factory NativeAppStart.fromJson(Map json) { return NativeAppStart( - json['appStartTime'] as double, - json['isColdStart'] as bool, + appStartTime: json['appStartTime'] as double, + pluginRegistrationTime: json['pluginRegistrationTime'] as int, + isColdStart: json['isColdStart'] as bool, + nativeSpanTimes: json['nativeSpanTimes'] as Map, ); } } diff --git a/flutter/lib/src/native/sentry_native_binding.dart b/flutter/lib/src/native/sentry_native_binding.dart index 54d335d529..950e7f9994 100644 --- a/flutter/lib/src/native/sentry_native_binding.dart +++ b/flutter/lib/src/native/sentry_native_binding.dart @@ -9,6 +9,9 @@ import 'sentry_native.dart'; @internal abstract class SentryNativeBinding { // TODO Move other native calls here. + Future init(SentryFlutterOptions options); + + Future close(); Future fetchNativeAppStart(); diff --git a/flutter/lib/src/native/sentry_native_channel.dart b/flutter/lib/src/native/sentry_native_channel.dart index 4bf9745cb3..61b361de30 100644 --- a/flutter/lib/src/native/sentry_native_channel.dart +++ b/flutter/lib/src/native/sentry_native_channel.dart @@ -17,6 +17,49 @@ class SentryNativeChannel implements SentryNativeBinding { // TODO Move other native calls here. + @override + Future init(SentryFlutterOptions options) async => + _channel.invokeMethod('initNativeSdk', { + 'dsn': options.dsn, + 'debug': options.debug, + 'environment': options.environment, + 'release': options.release, + 'enableAutoSessionTracking': options.enableAutoSessionTracking, + 'enableNativeCrashHandling': options.enableNativeCrashHandling, + 'attachStacktrace': options.attachStacktrace, + 'attachThreads': options.attachThreads, + 'autoSessionTrackingIntervalMillis': + options.autoSessionTrackingInterval.inMilliseconds, + 'dist': options.dist, + 'integrations': options.sdk.integrations, + 'packages': + options.sdk.packages.map((e) => e.toJson()).toList(growable: false), + 'diagnosticLevel': options.diagnosticLevel.name, + 'maxBreadcrumbs': options.maxBreadcrumbs, + 'anrEnabled': options.anrEnabled, + 'anrTimeoutIntervalMillis': options.anrTimeoutInterval.inMilliseconds, + 'enableAutoNativeBreadcrumbs': options.enableAutoNativeBreadcrumbs, + 'maxCacheItems': options.maxCacheItems, + 'sendDefaultPii': options.sendDefaultPii, + 'enableWatchdogTerminationTracking': + options.enableWatchdogTerminationTracking, + 'enableNdkScopeSync': options.enableNdkScopeSync, + 'enableAutoPerformanceTracing': options.enableAutoPerformanceTracing, + 'sendClientReports': options.sendClientReports, + 'proguardUuid': options.proguardUuid, + 'maxAttachmentSize': options.maxAttachmentSize, + 'recordHttpBreadcrumbs': options.recordHttpBreadcrumbs, + 'captureFailedRequests': options.captureFailedRequests, + 'enableAppHangTracking': options.enableAppHangTracking, + 'connectionTimeoutMillis': options.connectionTimeout.inMilliseconds, + 'readTimeoutMillis': options.readTimeout.inMilliseconds, + 'appHangTimeoutIntervalMillis': + options.appHangTimeoutInterval.inMilliseconds, + }); + + @override + Future close() async => _channel.invokeMethod('closeNativeSdk'); + @override Future fetchNativeAppStart() async { final json = diff --git a/flutter/lib/src/navigation/sentry_display_widget.dart b/flutter/lib/src/navigation/sentry_display_widget.dart new file mode 100644 index 0000000000..e42f5c4f72 --- /dev/null +++ b/flutter/lib/src/navigation/sentry_display_widget.dart @@ -0,0 +1,60 @@ +import 'package:flutter/cupertino.dart'; +import 'time_to_initial_display_tracker.dart'; + +import '../frame_callback_handler.dart'; + +/// A widget that reports the Time To Initially Displayed (TTID) of its child widget. +/// +/// This widget wraps around another widget to measure and report the time it takes +/// for the child widget to be initially displayed on the screen. This method +/// allows a more accurate measurement than what the default TTID implementation +/// provides. The TTID measurement begins when the route to the widget is pushed and ends +/// when `addPostFramecallback` is triggered. +/// +/// Wrap the widget you want to measure with [SentryDisplayWidget], and ensure that you +/// have set up Sentry's routing instrumentation according to the Sentry documentation. +/// +/// ```dart +/// SentryDisplayWidget( +/// child: MyWidget(), +/// ) +/// ``` +/// +/// Make sure to configure Sentry's routing instrumentation in your app by following +/// the guidelines provided in Sentry's documentation for Flutter integrations: +/// https://docs.sentry.io/platforms/flutter/integrations/routing-instrumentation/ +/// +/// See also: +/// - [Sentry's documentation on Flutter integrations](https://docs.sentry.io/platforms/flutter/) +/// for more information on how to integrate Sentry into your Flutter application. +class SentryDisplayWidget extends StatefulWidget { + final Widget child; + final FrameCallbackHandler _frameCallbackHandler; + + SentryDisplayWidget({ + super.key, + required this.child, + @visibleForTesting FrameCallbackHandler? frameCallbackHandler, + }) : _frameCallbackHandler = + frameCallbackHandler ?? DefaultFrameCallbackHandler(); + + @override + _SentryDisplayWidgetState createState() => _SentryDisplayWidgetState(); +} + +class _SentryDisplayWidgetState extends State { + @override + void initState() { + super.initState(); + TimeToInitialDisplayTracker().markAsManual(); + + widget._frameCallbackHandler.addPostFrameCallback((_) { + TimeToInitialDisplayTracker().completeTracking(); + }); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/flutter/lib/src/navigation/sentry_navigator_observer.dart b/flutter/lib/src/navigation/sentry_navigator_observer.dart index bfe1c0c6a2..fbfc12b6ee 100644 --- a/flutter/lib/src/navigation/sentry_navigator_observer.dart +++ b/flutter/lib/src/navigation/sentry_navigator_observer.dart @@ -1,10 +1,20 @@ +// ignore_for_file: invalid_use_of_internal_member + +import 'dart:async'; + +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:meta/meta.dart'; +import '../integrations/integrations.dart'; +import 'time_to_display_tracker.dart'; import '../../sentry_flutter.dart'; import '../event_processor/flutter_enricher_event_processor.dart'; import '../native/sentry_native.dart'; +// ignore: implementation_imports +import 'package:sentry/src/sentry_tracer.dart'; + /// This key must be used so that the web interface displays the events nicely /// See https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/ const _navigationKey = 'navigation'; @@ -19,6 +29,8 @@ typedef AdditionalInfoExtractor = Map? Function( /// This is a navigation observer to record navigational breadcrumbs. /// For now it only records navigation events and no gestures. /// +/// It also records Time to Initial Display (TTID). +/// /// [Route]s can always be null and their [Route.settings] can also always be null. /// For example, if the application starts, there is no previous route. /// The [RouteSettings] is null if a developer has not specified any @@ -66,6 +78,7 @@ class SentryNavigatorObserver extends RouteObserver> { bool setRouteNameAsTransaction = false, RouteNameExtractor? routeNameExtractor, AdditionalInfoExtractor? additionalInfoProvider, + @visibleForTesting TimeToDisplayTracker? timeToDisplayTracker, }) : _hub = hub ?? HubAdapter(), _enableAutoTransactions = enableAutoTransactions, _autoFinishAfter = autoFinishAfter, @@ -73,10 +86,23 @@ class SentryNavigatorObserver extends RouteObserver> { _routeNameExtractor = routeNameExtractor, _additionalInfoProvider = additionalInfoProvider, _native = SentryFlutter.native { + _isCreated = true; if (enableAutoTransactions) { - // ignore: invalid_use_of_internal_member _hub.options.sdk.addIntegration('UINavigationTracing'); } + _timeToDisplayTracker = + timeToDisplayTracker ?? _initializeTimeToDisplayTracker(); + } + + /// Initializes the TimeToDisplayTracker with the option to enable time to full display tracing. + TimeToDisplayTracker _initializeTimeToDisplayTracker() { + bool enableTimeToFullDisplayTracing = false; + final options = _hub.options; + if (options is SentryFlutterOptions) { + enableTimeToFullDisplayTracing = options.enableTimeToFullDisplayTracing; + } + return TimeToDisplayTracker( + enableTimeToFullDisplayTracing: enableTimeToFullDisplayTracing); } final Hub _hub; @@ -86,14 +112,30 @@ class SentryNavigatorObserver extends RouteObserver> { final RouteNameExtractor? _routeNameExtractor; final AdditionalInfoExtractor? _additionalInfoProvider; final SentryNative? _native; + static TimeToDisplayTracker? _timeToDisplayTracker; + + @internal + static TimeToDisplayTracker? get timeToDisplayTracker => + _timeToDisplayTracker; ISentrySpan? _transaction; static String? _currentRouteName; + static bool _isCreated = false; + + @internal + static bool get isCreated => _isCreated; + @internal static String? get currentRouteName => _currentRouteName; + Completer? _completedDisplayTracking = Completer(); + + // Since didPush does not have a future, we can keep track of when the display tracking has finished + @visibleForTesting + Completer? get completedDisplayTracking => _completedDisplayTracking; + @override void didPush(Route route, Route? previousRoute) { super.didPush(route, previousRoute); @@ -107,8 +149,10 @@ class SentryNavigatorObserver extends RouteObserver> { to: route.settings, ); - _finishTransaction(); - _startTransaction(route); + // Clearing the display tracker here is safe since didPush happens before the Widget is built + _timeToDisplayTracker?.clear(); + _finishTimeToDisplayTracking(); + _startTimeToDisplayTracking(route); } @override @@ -138,8 +182,7 @@ class SentryNavigatorObserver extends RouteObserver> { to: previousRoute?.settings, ); - _finishTransaction(); - _startTransaction(previousRoute); + _finishTimeToDisplayTracking(clearAfter: true); } void _addBreadcrumb({ @@ -151,7 +194,6 @@ class SentryNavigatorObserver extends RouteObserver> { navigationType: type, from: _routeNameExtractor?.call(from) ?? from, to: _routeNameExtractor?.call(to) ?? to, - // ignore: invalid_use_of_internal_member timestamp: _hub.options.clock(), data: _additionalInfoProvider?.call(from, to), )); @@ -178,11 +220,8 @@ class SentryNavigatorObserver extends RouteObserver> { } } - Future _startTransaction(Route? route) async { - if (!_enableAutoTransactions) { - return; - } - + Future _startTransaction( + Route? route, DateTime startTimestamp) async { String? name = _getRouteName(route); final arguments = route?.settings.arguments; @@ -191,22 +230,23 @@ class SentryNavigatorObserver extends RouteObserver> { } if (name == '/') { - name = 'root ("/")'; + name = rootScreenName; } final transactionContext = SentryTransactionContext( name, - 'navigation', + SentrySpanOperations.uiLoad, transactionNameSource: SentryTransactionNameSource.component, - // ignore: invalid_use_of_internal_member origin: SentryTraceOrigins.autoNavigationRouteObserver, ); _transaction = _hub.startTransactionWithContext( transactionContext, + startTimestamp: startTimestamp, waitForChildren: true, autoFinishAfter: _autoFinishAfter, trimEnd: true, onFinish: (transaction) async { + _transaction = null; final nativeFrames = await _native ?.endNativeFramesCollection(transaction.context.traceId); if (nativeFrames != null) { @@ -240,10 +280,101 @@ class SentryNavigatorObserver extends RouteObserver> { await _native?.beginNativeFramesCollection(); } - Future _finishTransaction() async { - _transaction?.status ??= SpanStatus.ok(); - await _transaction?.finish(); + Future _finishTimeToDisplayTracking({bool clearAfter = false}) async { + final transaction = _transaction; + _transaction = null; + try { + _hub.configureScope((scope) { + if (scope.span == transaction) { + scope.span = null; + } + }); + + if (transaction == null || transaction.finished) { + return; + } + + // Cancel unfinished TTID/TTFD spans, e.g this might happen if the user navigates + // away from the current route before TTFD or TTID is finished. + for (final child in (transaction as SentryTracer).children) { + final isTTIDSpan = child.context.operation == + SentrySpanOperations.uiTimeToInitialDisplay; + final isTTFDSpan = + child.context.operation == SentrySpanOperations.uiTimeToFullDisplay; + if (!child.finished && (isTTIDSpan || isTTFDSpan)) { + await child.finish(status: SpanStatus.deadlineExceeded()); + } + } + } catch (exception, stacktrace) { + _hub.options.logger( + SentryLevel.error, + 'Error while finishing time to display tracking', + exception: exception, + stackTrace: stacktrace, + ); + } finally { + await transaction?.finish(); + if (clearAfter) { + _clear(); + } + } + } + + Future _startTimeToDisplayTracking(Route? route) async { + try { + final routeName = _getRouteName(route) ?? _currentRouteName; + if (!_enableAutoTransactions || routeName == null) { + return; + } + + bool isAppStart = routeName == '/'; + DateTime startTimestamp = _hub.options.clock(); + DateTime? endTimestamp; + + if (isAppStart) { + final appStartInfo = await NativeAppStartIntegration.getAppStartInfo(); + if (appStartInfo == null) return; + + startTimestamp = appStartInfo.start; + endTimestamp = appStartInfo.end; + } + + await _startTransaction(route, startTimestamp); + + final transaction = _transaction; + if (transaction == null) { + return; + } + + if (isAppStart && endTimestamp != null) { + await _timeToDisplayTracker?.trackAppStartTTD(transaction, + startTimestamp: startTimestamp, endTimestamp: endTimestamp); + } else { + await _timeToDisplayTracker?.trackRegularRouteTTD(transaction, + startTimestamp: startTimestamp); + } + } catch (exception, stacktrace) { + _hub.options.logger( + SentryLevel.error, + 'Error while tracking time to display', + exception: exception, + stackTrace: stacktrace, + ); + } finally { + _clear(); + } + } + + void _clear() { + if (_completedDisplayTracking?.isCompleted == false) { + _completedDisplayTracking?.complete(); + } + _completedDisplayTracking = Completer(); + _timeToDisplayTracker?.clear(); } + + @internal + static const String rootScreenName = 'root /'; } /// This class makes it easier to record breadcrumbs for events of Flutters @@ -283,14 +414,12 @@ class RouteObserverBreadcrumb extends Breadcrumb { dynamic fromArgs, String? to, dynamic toArgs, - SentryLevel? level, - DateTime? timestamp, + super.level, + super.timestamp, Map? data, }) : super( category: _navigationKey, type: _navigationKey, - level: level, - timestamp: timestamp, data: { 'state': navigationType, if (from != null) 'from': from, diff --git a/flutter/lib/src/navigation/time_to_display_tracker.dart b/flutter/lib/src/navigation/time_to_display_tracker.dart new file mode 100644 index 0000000000..342e305c75 --- /dev/null +++ b/flutter/lib/src/navigation/time_to_display_tracker.dart @@ -0,0 +1,55 @@ +// ignore_for_file: invalid_use_of_internal_member + +import 'package:meta/meta.dart'; + +import '../../sentry_flutter.dart'; +import 'time_to_full_display_tracker.dart'; +import 'time_to_initial_display_tracker.dart'; + +@internal +class TimeToDisplayTracker { + final TimeToInitialDisplayTracker _ttidTracker; + final TimeToFullDisplayTracker? _ttfdTracker; + final bool enableTimeToFullDisplayTracing; + + TimeToDisplayTracker({ + TimeToInitialDisplayTracker? ttidTracker, + TimeToFullDisplayTracker? ttfdTracker, + required this.enableTimeToFullDisplayTracing, + }) : _ttidTracker = ttidTracker ?? TimeToInitialDisplayTracker(), + _ttfdTracker = enableTimeToFullDisplayTracing + ? ttfdTracker ?? TimeToFullDisplayTracker() + : null; + + Future trackAppStartTTD(ISentrySpan transaction, + {required DateTime startTimestamp, + required DateTime endTimestamp}) async { + // We start and immediately finish the spans since we cannot mutate the history of spans. + await _ttidTracker.trackAppStart(transaction, + startTimestamp: startTimestamp, endTimestamp: endTimestamp); + await _trackTTFDIfEnabled(transaction, startTimestamp); + } + + Future trackRegularRouteTTD(ISentrySpan transaction, + {required DateTime startTimestamp}) async { + await _ttidTracker.trackRegularRoute(transaction, startTimestamp); + await _trackTTFDIfEnabled(transaction, startTimestamp); + } + + Future _trackTTFDIfEnabled( + ISentrySpan transaction, DateTime startTimestamp) async { + if (enableTimeToFullDisplayTracing) { + await _ttfdTracker?.track(transaction, startTimestamp); + } + } + + @internal + Future reportFullyDisplayed() async { + return _ttfdTracker?.reportFullyDisplayed(); + } + + void clear() { + _ttidTracker.clear(); + _ttfdTracker?.clear(); + } +} diff --git a/flutter/lib/src/navigation/time_to_full_display_tracker.dart b/flutter/lib/src/navigation/time_to_full_display_tracker.dart new file mode 100644 index 0000000000..385c25c38f --- /dev/null +++ b/flutter/lib/src/navigation/time_to_full_display_tracker.dart @@ -0,0 +1,113 @@ +// ignore_for_file: invalid_use_of_internal_member + +import 'dart:async'; + +import 'package:meta/meta.dart'; + +// ignore: implementation_imports +import 'package:sentry/src/sentry_tracer.dart'; + +import '../../sentry_flutter.dart'; +import 'time_to_initial_display_tracker.dart'; + +@internal +class TimeToFullDisplayTracker { + static final TimeToFullDisplayTracker _instance = + TimeToFullDisplayTracker._(); + + TimeToFullDisplayTracker._(); + + factory TimeToFullDisplayTracker( + {EndTimestampProvider? endTimestampProvider, Duration? autoFinishAfter}) { + if (autoFinishAfter != null) { + _instance._autoFinishAfter = autoFinishAfter; + } + if (endTimestampProvider != null) { + _instance._endTimestampProvider = endTimestampProvider; + } + return _instance; + } + + DateTime? _startTimestamp; + ISentrySpan? _ttfdSpan; + ISentrySpan? _transaction; + Duration _autoFinishAfter = const Duration(seconds: 30); + + // End timestamp provider is only needed when the TTFD timeout is triggered + EndTimestampProvider _endTimestampProvider = ttidEndTimestampProvider(); + Completer _completedTTFDTracking = Completer(); + + Future track(ISentrySpan transaction, DateTime startTimestamp) async { + _startTimestamp = startTimestamp; + _transaction = transaction as SentryTracer; + _ttfdSpan = transaction.startChild(SentrySpanOperations.uiTimeToFullDisplay, + description: '${transaction.name} full display', + startTimestamp: startTimestamp); + _ttfdSpan?.origin = SentryTraceOrigins.manualUiTimeToDisplay; + // Wait for TTFD to finish + await _completedTTFDTracking.future + .timeout(_autoFinishAfter, onTimeout: handleTimeout); + + clear(); + } + + void handleTimeout() { + final ttfdSpan = _ttfdSpan; + final startTimestamp = _startTimestamp; + final endTimestamp = _endTimestampProvider(); + + if (ttfdSpan == null || + ttfdSpan.finished == true || + startTimestamp == null || + endTimestamp == null) { + _completedTTFDTracking.complete(); + return; + } + + _setTTFDMeasurement(startTimestamp, endTimestamp); + ttfdSpan.finish( + status: SpanStatus.deadlineExceeded(), endTimestamp: endTimestamp); + + _completedTTFDTracking.complete(); + } + + Future reportFullyDisplayed() async { + final endTimestamp = getUtcDateTime(); + final startTimestamp = _startTimestamp; + final ttfdSpan = _ttfdSpan; + + if (ttfdSpan?.finished == true || startTimestamp == null) { + _completedTTFDTracking.complete(); + return; + } + + _setTTFDMeasurement(startTimestamp, endTimestamp); + await ttfdSpan?.finish(status: SpanStatus.ok(), endTimestamp: endTimestamp); + + _completedTTFDTracking.complete(); + } + + void _setTTFDMeasurement(DateTime startTimestamp, DateTime endTimestamp) { + final duration = endTimestamp.difference(startTimestamp); + final measurement = SentryMeasurement.timeToFullDisplay(duration); + _transaction?.setMeasurement(measurement.name, measurement.value, + unit: measurement.unit); + } + + void clear() { + _startTimestamp = null; + _ttfdSpan = null; + _transaction = null; + _completedTTFDTracking = Completer(); + } +} + +/// We need to retrieve the end time stamp in case TTFD timeout is triggered. +/// In those cases TTFD end time should match TTID end time. +/// This provider allows us to inject endTimestamps for testing as well. +@internal +typedef EndTimestampProvider = DateTime? Function(); + +@internal +EndTimestampProvider ttidEndTimestampProvider() => + () => TimeToInitialDisplayTracker().endTimestamp; diff --git a/flutter/lib/src/navigation/time_to_initial_display_tracker.dart b/flutter/lib/src/navigation/time_to_initial_display_tracker.dart new file mode 100644 index 0000000000..ce2f7b9e9c --- /dev/null +++ b/flutter/lib/src/navigation/time_to_initial_display_tracker.dart @@ -0,0 +1,136 @@ +// ignore_for_file: invalid_use_of_internal_member + +import 'dart:async'; + +import 'package:meta/meta.dart'; + +// ignore: implementation_imports +import 'package:sentry/src/sentry_tracer.dart'; + +import '../../sentry_flutter.dart'; +import '../frame_callback_handler.dart'; + +@internal +class TimeToInitialDisplayTracker { + static final TimeToInitialDisplayTracker _instance = + TimeToInitialDisplayTracker._(); + + factory TimeToInitialDisplayTracker( + {FrameCallbackHandler? frameCallbackHandler}) { + if (frameCallbackHandler != null) { + _instance._frameCallbackHandler = frameCallbackHandler; + } + return _instance; + } + + TimeToInitialDisplayTracker._(); + + FrameCallbackHandler _frameCallbackHandler = DefaultFrameCallbackHandler(); + bool _isManual = false; + Completer? _trackingCompleter; + DateTime? _endTimestamp; + final Duration _determineEndtimeTimeout = Duration(seconds: 5); + + /// This endTimestamp is needed in the [TimeToFullDisplayTracker] class + @internal + DateTime? get endTimestamp => _endTimestamp; + + Future trackRegularRoute( + ISentrySpan transaction, + DateTime startTimestamp, + ) async { + await _trackTimeToInitialDisplay( + transaction: transaction, + startTimestamp: startTimestamp, + ); + } + + Future trackAppStart(ISentrySpan transaction, + {required DateTime startTimestamp, + required DateTime endTimestamp}) async { + await _trackTimeToInitialDisplay( + transaction: transaction, + startTimestamp: startTimestamp, + endTimestamp: endTimestamp, + origin: SentryTraceOrigins.autoUiTimeToDisplay, + ); + + // Store the end timestamp for potential use by TTFD tracking + _endTimestamp = endTimestamp; + } + + Future _trackTimeToInitialDisplay({ + required ISentrySpan transaction, + required DateTime startTimestamp, + DateTime? endTimestamp, + String? origin, + }) async { + final _endTimestamp = endTimestamp ?? await determineEndTime(); + if (_endTimestamp == null) return; + + final tracer = transaction as SentryTracer; + + final ttidSpan = transaction.startChild( + SentrySpanOperations.uiTimeToInitialDisplay, + description: '${tracer.name} initial display', + startTimestamp: startTimestamp, + ); + + ttidSpan.origin = origin ?? + (_isManual + ? SentryTraceOrigins.manualUiTimeToDisplay + : SentryTraceOrigins.autoUiTimeToDisplay); + + final duration = Duration( + milliseconds: _endTimestamp.difference(startTimestamp).inMilliseconds); + final ttidMeasurement = SentryMeasurement.timeToInitialDisplay(duration); + + transaction.setMeasurement(ttidMeasurement.name, ttidMeasurement.value, + unit: ttidMeasurement.unit); + await ttidSpan.finish(endTimestamp: _endTimestamp); + } + + Future? determineEndTime() { + _trackingCompleter = Completer(); + final future = _trackingCompleter?.future.timeout( + _determineEndtimeTimeout, + onTimeout: () { + return Future.value(null); + }, + ); + + // If we already know it's manual we can return the future immediately + if (_isManual) { + return future; + } + + // Schedules a check at the end of the frame to determine if the tracking + // should be completed immediately (approximation mode) or deferred (manual mode). + _frameCallbackHandler.addPostFrameCallback((_) { + if (!_isManual) { + completeTracking(); + } + }); + + return future; + } + + void markAsManual() { + _isManual = true; + } + + void completeTracking() { + if (_trackingCompleter != null && !_trackingCompleter!.isCompleted) { + final endTimestamp = DateTime.now(); + _endTimestamp = endTimestamp; + _trackingCompleter?.complete(endTimestamp); + } + } + + void clear() { + _isManual = false; + _trackingCompleter = null; + // We can't clear the ttid end time stamp here, because it might be needed + // in the [TimeToFullDisplayTracker] class + } +} diff --git a/flutter/lib/src/screenshot/sentry_screenshot_widget.dart b/flutter/lib/src/screenshot/sentry_screenshot_widget.dart index b11b511bb3..e83d46d0c5 100644 --- a/flutter/lib/src/screenshot/sentry_screenshot_widget.dart +++ b/flutter/lib/src/screenshot/sentry_screenshot_widget.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:meta/meta.dart'; +import '../../sentry_flutter.dart'; + /// Key which is used to identify the [RepaintBoundary] @internal final sentryScreenshotWidgetGlobalKey = @@ -22,21 +24,37 @@ final sentryScreenshotWidgetGlobalKey = /// - You can only have one [SentryScreenshotWidget] widget in your widget tree at all /// times. class SentryScreenshotWidget extends StatefulWidget { - const SentryScreenshotWidget({Key? key, required this.child}) - : super(key: key); - final Widget child; + late final Hub _hub; + + SentryFlutterOptions? get _options => + // ignore: invalid_use_of_internal_member + _hub.options is SentryFlutterOptions + // ignore: invalid_use_of_internal_member + ? _hub.options as SentryFlutterOptions + : null; + + SentryScreenshotWidget({ + super.key, + required this.child, + @internal Hub? hub, + }) : _hub = hub ?? HubAdapter(); @override _SentryScreenshotWidgetState createState() => _SentryScreenshotWidgetState(); } class _SentryScreenshotWidgetState extends State { + SentryFlutterOptions? get _options => widget._options; + @override Widget build(BuildContext context) { - return RepaintBoundary( - key: sentryScreenshotWidgetGlobalKey, - child: widget.child, - ); + if (_options?.attachScreenshot ?? false) { + return RepaintBoundary( + key: sentryScreenshotWidgetGlobalKey, + child: widget.child, + ); + } + return widget.child; } } diff --git a/flutter/lib/src/sentry_flutter.dart b/flutter/lib/src/sentry_flutter.dart index cef52ee564..e0d4415de5 100644 --- a/flutter/lib/src/sentry_flutter.dart +++ b/flutter/lib/src/sentry_flutter.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:ui'; -import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:meta/meta.dart'; @@ -9,6 +8,9 @@ import '../sentry_flutter.dart'; import 'event_processor/android_platform_exception_event_processor.dart'; import 'event_processor/flutter_exception_event_processor.dart'; import 'event_processor/platform_exception_event_processor.dart'; +import 'event_processor/widget_event_processor.dart'; +import 'frame_callback_handler.dart'; +import 'integrations/connectivity/connectivity_integration.dart'; import 'integrations/screenshot_integration.dart'; import 'native/factory.dart'; import 'native/native_scope_observer.dart'; @@ -32,6 +34,11 @@ typedef FlutterOptionsConfiguration = FutureOr Function( mixin SentryFlutter { static const _channel = MethodChannel('sentry_flutter'); + /// Represents the time when the Sentry init set up has started. + @internal + // ignore: invalid_use_of_internal_member + static DateTime? sentrySetupStartTime; + static Future init( FlutterOptionsConfiguration optionsConfiguration, { AppRunner? appRunner, @@ -41,6 +48,9 @@ mixin SentryFlutter { }) async { final flutterOptions = SentryFlutterOptions(); + // ignore: invalid_use_of_internal_member + sentrySetupStartTime ??= flutterOptions.clock(); + if (platformChecker != null) { flutterOptions.platformChecker = platformChecker; } @@ -109,12 +119,13 @@ mixin SentryFlutter { options.addScopeObserver(NativeScopeObserver(_native!)); } - var flutterEventProcessor = FlutterEnricherEventProcessor(options); - options.addEventProcessor(flutterEventProcessor); + options.addEventProcessor(FlutterEnricherEventProcessor(options)); + options.addEventProcessor(WidgetEventProcessor()); if (options.platformChecker.platform.isAndroid) { - options - .addEventProcessor(AndroidPlatformExceptionEventProcessor(options)); + options.addEventProcessor( + AndroidPlatformExceptionEventProcessor(options), + ); } options.addEventProcessor(PlatformExceptionEventProcessor()); @@ -150,14 +161,14 @@ mixin SentryFlutter { // The ordering here matters, as we'd like to first start the native integration. // That allow us to send events to the network and then the Flutter integrations. // Flutter Web doesn't need that, only Android and iOS. - if (platformChecker.hasNativeIntegration) { - integrations.add(NativeSdkIntegration(channel)); + if (_native != null) { + integrations.add(NativeSdkIntegration(_native!)); } // Will enrich events with device context, native packages and integrations if (platformChecker.hasNativeIntegration && !platformChecker.isWeb && - (platform.isIOS || platform.isMacOS)) { + (platform.isIOS || platform.isMacOS || platform.isAndroid)) { integrations.add(LoadContextsIntegration(channel)); } @@ -171,6 +182,10 @@ mixin SentryFlutter { integrations.add(ScreenshotIntegration()); } + if (platformChecker.isWeb) { + integrations.add(ConnectivityIntegration()); + } + // works with Skia, CanvasKit and HTML renderer integrations.add(SentryViewHierarchyIntegration()); @@ -184,13 +199,7 @@ mixin SentryFlutter { if (_native != null) { integrations.add(NativeAppStartIntegration( _native!, - () { - try { - /// Flutter >= 2.12 throws if SchedulerBinding.instance isn't initialized. - return SchedulerBinding.instance; - } catch (_) {} - return null; - }, + DefaultFrameCallbackHandler(), )); } return integrations; @@ -224,8 +233,15 @@ mixin SentryFlutter { options.sdk = sdk; } + /// Reports the time it took for the screen to be fully displayed. + /// This requires the [SentryFlutterOptions.enableTimeToFullDisplayTracing] option to be set to `true`. + static Future reportFullyDisplayed() async { + return SentryNavigatorObserver.timeToDisplayTracker?.reportFullyDisplayed(); + } + @internal static SentryNative? get native => _native; + @internal static set native(SentryNative? value) => _native = value; static SentryNative? _native; diff --git a/flutter/lib/src/sentry_flutter_options.dart b/flutter/lib/src/sentry_flutter_options.dart index 1a71a0d37e..ae83de611e 100644 --- a/flutter/lib/src/sentry_flutter_options.dart +++ b/flutter/lib/src/sentry_flutter_options.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; import 'package:flutter/widgets.dart'; @@ -5,13 +7,16 @@ import 'package:flutter/widgets.dart'; import 'binding_wrapper.dart'; import 'renderer/renderer.dart'; import 'screenshot/sentry_screenshot_quality.dart'; +import 'event_processor/screenshot_event_processor.dart'; +import 'screenshot/sentry_screenshot_widget.dart'; +import 'sentry_flutter.dart'; +import 'user_interaction/sentry_user_interaction_widget.dart'; -/// This class adds options which are only availble in a Flutter environment. +/// This class adds options which are only available in a Flutter environment. /// Note that some of these options require native Sentry integration, which is /// not available on all platforms. class SentryFlutterOptions extends SentryOptions { - SentryFlutterOptions({String? dsn, PlatformChecker? checker}) - : super(dsn: dsn, checker: checker) { + SentryFlutterOptions({super.dsn, super.checker}) { enableBreadcrumbTrackingForCurrentPlatform(); } @@ -170,6 +175,11 @@ class SentryFlutterOptions extends SentryOptions { /// Only attach a screenshot when the app is resumed. bool attachScreenshotOnlyWhenResumed = false; + /// Sets a callback which is executed before capturing screenshots. Only + /// relevant if `attachScreenshot` is set to true. When false is returned + /// from the function, no screenshot will be attached. + BeforeScreenshotCallback? beforeScreenshot; + /// Enable or disable automatic breadcrumbs for User interactions Using [Listener] /// /// Requires adding the [SentryUserInteractionWidget] to the widget tree. @@ -184,6 +194,12 @@ class SentryFlutterOptions extends SentryOptions { /// runApp(SentryUserInteractionWidget(child: App())); bool enableUserInteractionTracing = true; + /// Enable or disable the tracing of time to full display (TTFD). + /// If `SentryFlutter.reportFullyDisplayed()` is not called within 30 seconds + /// after the creation of the TTFD span, it will finish with the status [SpanStatus.deadlineExceeded]. + /// This feature requires using the [Routing Instrumentation](https://docs.sentry.io/platforms/flutter/integrations/routing-instrumentation/). + bool enableTimeToFullDisplayTracing = false; + /// Sets the Proguard uuid for Android platform. String? proguardUuid; @@ -290,3 +306,10 @@ class SentryFlutterOptions extends SentryOptions { /// The [navigatorKey] is used to add information of the currently used locale to the contexts. GlobalKey? navigatorKey; } + +/// Callback being executed in [ScreenshotEventProcessor], deciding if a +/// screenshot should be recorded and attached. +typedef BeforeScreenshotCallback = FutureOr Function( + SentryEvent event, { + Hint? hint, +}); diff --git a/flutter/lib/src/sentry_widget.dart b/flutter/lib/src/sentry_widget.dart new file mode 100644 index 0000000000..40709a5465 --- /dev/null +++ b/flutter/lib/src/sentry_widget.dart @@ -0,0 +1,31 @@ +import 'package:flutter/cupertino.dart'; +import 'package:meta/meta.dart'; +import '../sentry_flutter.dart'; + +/// Key which is used to identify the [SentryWidget] +@internal +final sentryWidgetGlobalKey = GlobalKey(debugLabel: 'sentry_widget'); + +/// This widget serves as a wrapper to include Sentry widgets such +/// as [SentryScreenshotWidget] and [SentryUserInteractionWidget]. +class SentryWidget extends StatefulWidget { + final Widget child; + + const SentryWidget({super.key, required this.child}); + + @override + _SentryWidgetState createState() => _SentryWidgetState(); +} + +class _SentryWidgetState extends State { + @override + Widget build(BuildContext context) { + Widget content = widget.child; + content = SentryScreenshotWidget(child: content); + content = SentryUserInteractionWidget(child: content); + return Container( + key: sentryWidgetGlobalKey, + child: content, + ); + } +} diff --git a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart index f98a919065..018f750a2e 100644 --- a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart +++ b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart @@ -234,10 +234,10 @@ Element? _clickTrackerElement; /// [SentryUserInteractionWidget] as a child of [SentryScreenshotWidget]. class SentryUserInteractionWidget extends StatefulWidget { SentryUserInteractionWidget({ - Key? key, + super.key, required this.child, @internal Hub? hub, - }) : super(key: key) { + }) { _hub = hub ?? HubAdapter(); if (_options?.enableUserInteractionTracing ?? false) { @@ -281,12 +281,16 @@ class _SentryUserInteractionWidgetState @override Widget build(BuildContext context) { - return Listener( - behavior: HitTestBehavior.translucent, - onPointerDown: _onPointerDown, - onPointerUp: _onPointerUp, - child: widget.child, - ); + if ((_options?.enableUserInteractionTracing ?? true) || + (_options?.enableUserInteractionBreadcrumbs ?? true)) { + return Listener( + behavior: HitTestBehavior.translucent, + onPointerDown: _onPointerDown, + onPointerUp: _onPointerUp, + child: widget.child, + ); + } + return widget.child; } void _onPointerDown(PointerDownEvent event) { @@ -313,7 +317,8 @@ class _SentryUserInteractionWidgetState void _onTappedAt(Offset position) { final tappedWidget = _getElementAt(position); - final keyValue = tappedWidget?.element.widget.key?.toStringValue(); + final keyValue = + WidgetUtils.toStringValue(tappedWidget?.element.widget.key); if (tappedWidget == null || keyValue == null) { return; } diff --git a/flutter/lib/src/version.dart b/flutter/lib/src/version.dart index 8dfdd16262..0a431dd2de 100644 --- a/flutter/lib/src/version.dart +++ b/flutter/lib/src/version.dart @@ -1,5 +1,5 @@ /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; /// The default SDK name reported to Sentry.io in the submitted events. const String sdkName = 'sentry.dart.flutter'; diff --git a/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart b/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart index 2a85bf49be..41b03f4808 100644 --- a/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart +++ b/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart @@ -281,7 +281,7 @@ class _TreeWalker { return SentryViewHierarchyElement( element.widget.runtimeType.toString(), depth: element.depth, - identifier: element.widget.key?.toStringValue(), + identifier: WidgetUtils.toStringValue(element.widget.key), width: width, height: height, x: x, diff --git a/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart b/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart index 99d43ad982..c3fefe52f5 100644 --- a/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart +++ b/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart @@ -1,7 +1,7 @@ import '../../sentry_flutter.dart'; import 'sentry_tree_walker.dart'; -/// A [EventProcessor] that renders an ASCII represention of the entire view +/// A [EventProcessor] that renders an ASCII representation of the entire view /// hierarchy of the application when an error happens and includes it as an /// attachment to the [Hint]. class SentryViewHierarchyEventProcessor implements EventProcessor { @@ -10,7 +10,7 @@ class SentryViewHierarchyEventProcessor implements EventProcessor { final SentryFlutterOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } @@ -31,7 +31,7 @@ class SentryViewHierarchyEventProcessor implements EventProcessor { final viewHierarchy = SentryAttachment.fromViewHierarchy(sentryViewHierarchy); - hint?.viewHierarchy = viewHierarchy; + hint.viewHierarchy = viewHierarchy; return event; } } diff --git a/flutter/lib/src/widget_utils.dart b/flutter/lib/src/widget_utils.dart index 9d63b8d5a3..97d51a990a 100644 --- a/flutter/lib/src/widget_utils.dart +++ b/flutter/lib/src/widget_utils.dart @@ -1,8 +1,12 @@ import 'package:flutter/widgets.dart'; +import 'package:meta/meta.dart'; -extension WidgetExtension on Key { - String? toStringValue() { - final key = this; +@internal +class WidgetUtils { + static String? toStringValue(Key? key) { + if (key == null) { + return null; + } if (key is ValueKey) { return key.value; } else if (key is ValueKey) { diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index c6880608ca..d2a244f171 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -1,5 +1,5 @@ name: sentry_flutter -version: 7.13.1 +version: 8.3.0 description: Sentry SDK for Flutter. This package aims to support different Flutter targets by relying on the many platforms supported by Sentry with native SDKs. homepage: https://docs.sentry.io/platforms/flutter/ repository: https://github.com/getsentry/sentry-dart @@ -10,13 +10,21 @@ environment: sdk: '>=2.17.0 <4.0.0' flutter: '>=3.0.0' +platforms: + android: + ios: + macos: + linux: + windows: + web: + dependencies: flutter: sdk: flutter flutter_web_plugins: sdk: flutter - sentry: 7.13.1 - package_info_plus: '>=1.0.0 <5.0.0' + sentry: 8.3.0 + package_info_plus: '>=1.0.0' meta: ^1.3.0 ffi: ^2.0.0 @@ -26,7 +34,7 @@ dev_dependencies: sdk: flutter mockito: ^5.1.0 yaml: ^3.1.0 # needed for version match (code and pubspec) - flutter_lints: ^2.0.0 + flutter_lints: ^4.0.0 collection: ^1.16.0 remove_from_coverage: ^2.0.0 flutter_localizations: diff --git a/flutter/scripts/generate-cocoa-bindings.sh b/flutter/scripts/generate-cocoa-bindings.sh index 3381089df5..722a52fb32 100755 --- a/flutter/scripts/generate-cocoa-bindings.sh +++ b/flutter/scripts/generate-cocoa-bindings.sh @@ -28,11 +28,12 @@ dart pub add 'dev:ffigen:{"git":{"url":"https://github.com/getsentry/ffigen","re temp="cocoa_bindings_temp" rm -rf $temp mkdir -p $temp -curl -Lv https://github.com/getsentry/sentry-cocoa/releases/download/$cocoa_version/Sentry.xcframework.zip -o $temp/Sentry.xcframework.zip -subdir="Carthage/Build/Sentry.xcframework/macos-arm64_x86_64/Sentry.framework" +curl -Lv --fail-with-body https://github.com/getsentry/sentry-cocoa/releases/download/$cocoa_version/Sentry.xcframework.zip -o $temp/Sentry.xcframework.zip +subdir="Sentry.xcframework/macos-arm64_x86_64/Sentry.framework" unzip -q $temp/Sentry.xcframework.zip "$subdir/*" -d $temp mv "$temp/$subdir" $temp/Sentry.framework dart run ffigen --config ffi-cocoa.yaml sed -i.bak 's|final class|class|g' lib/src/native/cocoa/binding.dart +sed -i.bak 's|static int startProfilerForTrace_(SentryCocoa _lib, SentryId? traceId)|static int startProfilerForTrace_(SentryCocoa _lib, SentryId1? traceId)|g' lib/src/native/cocoa/binding.dart rm lib/src/native/cocoa/binding.dart.bak diff --git a/flutter/scripts/update-android.sh b/flutter/scripts/update-android.sh index 183441bee7..fc1f3460bd 100755 --- a/flutter/scripts/update-android.sh +++ b/flutter/scripts/update-android.sh @@ -4,7 +4,7 @@ set -euo pipefail cd $(dirname "$0")/../android file='build.gradle' content=$(cat $file) -regex='(io\.sentry:sentry-android:)([0-9\.]+)' +regex='(io\.sentry:sentry-android:)([0-9\.]+(\-[a-z0-9\.]+)?)' if ! [[ $content =~ $regex ]]; then echo "Failed to find the android plugin version in $file" exit 1 diff --git a/flutter/scripts/update-cocoa.sh b/flutter/scripts/update-cocoa.sh index d54a754399..55f1c854db 100755 --- a/flutter/scripts/update-cocoa.sh +++ b/flutter/scripts/update-cocoa.sh @@ -4,7 +4,7 @@ set -euo pipefail cd $(dirname "$0")/../ios file='sentry_flutter.podspec' content=$(cat $file) -regex="('Sentry/HybridSDK', *)'([0-9\.]+)'" +regex="('Sentry/HybridSDK', *)'([0-9\.]+(\-[a-z0-9\.]+)?)'" if ! [[ $content =~ $regex ]]; then echo "Failed to find the plugin version in $file" exit 1 diff --git a/flutter/test/android_platform_exception_event_processor_test.dart b/flutter/test/android_platform_exception_event_processor_test.dart index f98bedbe26..9ebae071c7 100644 --- a/flutter/test/android_platform_exception_event_processor_test.dart +++ b/flutter/test/android_platform_exception_event_processor_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; // ignore_for_file: invalid_use_of_internal_member import 'package:flutter/services.dart'; @@ -25,21 +26,22 @@ void main() { }); group(AndroidPlatformExceptionEventProcessor, () { - test('exception is correctly parsed', () async { - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + test('platform exception with details and stackTrace is correctly parsed', + () async { + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformDetailsAndStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 3); - final platformException = exceptions[1]; + final platformException_1 = exceptions[1]; - expect(platformException.type, 'IllegalArgumentException'); + expect(platformException_1.type, 'IllegalArgumentException'); expect( - platformException.value, + platformException_1.value, "Unsupported value: '[Ljava.lang.StackTraceElement;@ba6feed' of type 'class [Ljava.lang.StackTraceElement;'", ); - expect(platformException.stackTrace!.frames.length, 18); + expect(platformException_1.stackTrace!.frames.length, 18); final platformException_2 = exceptions[2]; @@ -51,11 +53,47 @@ void main() { expect(platformException_2.stackTrace!.frames.length, 18); }); + test('platform exception with details correctly parsed', () async { + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformDetails, Hint()); + + final exceptions = platformExceptionEvent!.exceptions!; + expect(exceptions.length, 2); + + final platformException_1 = exceptions[1]; + + expect(platformException_1.type, 'Resources\$NotFoundException'); + expect(platformException_1.module, 'android.content.res'); + expect( + platformException_1.value, + "Unable to find resource ID #0x7f14000d", + ); + expect(platformException_1.stackTrace!.frames.length, 19); + }); + + test('platform exception with stackTrace correctly parsed', () async { + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformStackTrace, Hint()); + + final exceptions = platformExceptionEvent!.exceptions!; + expect(exceptions.length, 2); + + final platformException_1 = exceptions[1]; + + expect(platformException_1.type, 'IllegalArgumentException'); + expect(platformException_1.module, 'java.lang'); + expect( + platformException_1.value, + "Not supported, use openfile", + ); + expect(platformException_1.stackTrace!.frames.length, 22); + }); + test( 'Dart thread is current and not crashed if Android exception is present', () async { - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformDetailsAndStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 3); @@ -65,8 +103,8 @@ void main() { }); test('platformexception has Android thread attached', () async { - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformDetailsAndStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 3); @@ -83,10 +121,11 @@ void main() { test('platformexception has no Android thread attached if disabled', () async { fixture.options.attachThreads = false; - final threadCount = fixture.eventWithPlatformStackTrace.threads?.length; + final threadCount = + fixture.eventWithPlatformDetailsAndStackTrace.threads?.length; - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformDetailsAndStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 3); @@ -96,23 +135,24 @@ void main() { test('does nothing if no PlatformException is there', () async { final exception = fixture.options.exceptionFactory - .getSentryException(testPlatformException); + .getSentryException(detailsAndStackTracePlatformException); final event = SentryEvent( exceptions: [exception], throwable: null, ); - final platformExceptionEvent = await fixture.processor.apply(event); + final platformExceptionEvent = + await fixture.processor.apply(event, Hint()); expect(event, platformExceptionEvent); }); test('does nothing if PlatformException has no stackTrace', () async { final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithoutPlatformStackTrace); + await fixture.processor.apply(fixture.eventWithPlatformEmpty, Hint()); - expect(fixture.eventWithoutPlatformStackTrace, platformExceptionEvent); + expect(fixture.eventWithPlatformEmpty, platformExceptionEvent); }); }); } @@ -121,22 +161,43 @@ class Fixture { late AndroidPlatformExceptionEventProcessor processor = AndroidPlatformExceptionEventProcessor(options); - late SentryException withPlatformStackTrace = options.exceptionFactory - .getSentryException(testPlatformException) + late SentryException withPlatformDetailsAndStackTrace = options + .exceptionFactory + .getSentryException(detailsAndStackTracePlatformException) .copyWith(threadId: 1); - late SentryException withoutPlatformStackTrace = options.exceptionFactory - .getSentryException(emptyPlatformException) + late SentryEvent eventWithPlatformDetailsAndStackTrace = SentryEvent( + exceptions: [withPlatformDetailsAndStackTrace], + throwable: detailsAndStackTracePlatformException, + threads: [dartThread], + ); + + late SentryException withPlatformDetails = options.exceptionFactory + .getSentryException(detailsPlatformException) + .copyWith(threadId: 1); + + late SentryEvent eventWithPlatformDetails = SentryEvent( + exceptions: [withPlatformDetails], + throwable: detailsPlatformException, + threads: [dartThread], + ); + + late SentryException withPlatformStackTrace = options.exceptionFactory + .getSentryException(stackTracePlatformException) .copyWith(threadId: 1); late SentryEvent eventWithPlatformStackTrace = SentryEvent( - exceptions: [withPlatformStackTrace], - throwable: testPlatformException, + exceptions: [withPlatformDetails], + throwable: stackTracePlatformException, threads: [dartThread], ); - late SentryEvent eventWithoutPlatformStackTrace = SentryEvent( - exceptions: [withoutPlatformStackTrace], + late SentryException withPlatformEmpty = options.exceptionFactory + .getSentryException(emptyPlatformException) + .copyWith(threadId: 1); + + late SentryEvent eventWithPlatformEmpty = SentryEvent( + exceptions: [withPlatformEmpty], throwable: emptyPlatformException, threads: [dartThread], ); @@ -152,22 +213,14 @@ class Fixture { ..attachThreads = true; } -final testPlatformException = PlatformException( +final detailsAndStackTracePlatformException = PlatformException( code: 'error', - details: + message: "Unsupported value: '[Ljava.lang.StackTraceElement;@fa902f1' of type 'class [Ljava.lang.StackTraceElement;'", - message: _jvmStackTrace, + details: _jvmStackTrace, stacktrace: _jvmStackTrace, ); -final emptyPlatformException = PlatformException( - code: 'error', - details: - "Unsupported value: '[Ljava.lang.StackTraceElement;@fa902f1' of type 'class [Ljava.lang.StackTraceElement;'", - message: null, - stacktrace: null, -); - const _jvmStackTrace = """java.lang.IllegalArgumentException: Unsupported value: '[Ljava.lang.StackTraceElement;@ba6feed' of type 'class [Ljava.lang.StackTraceElement;' at io.flutter.plugin.common.StandardMessageCodec.writeValue(StandardMessageCodec.java:292) @@ -188,3 +241,67 @@ const _jvmStackTrace = at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit\$MethodAndArgsCaller.run(RuntimeInit.java:556) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1037)"""; + +final detailsPlatformException = PlatformException( + code: 'getNotificationChannelsError', + message: 'Unable to find resource ID #0x7f14000d', + details: + """android.content.res.Resources\$NotFoundException: Unable to find resource ID #0x7f14000d + at android.content.res.ResourcesImpl.getResourceEntryName(ResourcesImpl.java:493) + at android.content.res.Resources.getResourceEntryName(Resources.java:2441) + at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.getMappedNotificationChannel(FlutterLocalNotificationsPlugin.java:170) + at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.getNotificationChannels(FlutterLocalNotificationsPlugin.java:32) + at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:399) + at be.j\$a.a(MethodChannel.java:18) + at pd.c.l(DartMessenger.java:19) + at pd.c.m(DartMessenger.java:42) + at pd.c.h(Unknown Source:0) + at pd.b.run(Unknown Source:12) + at android.os.Handler.handleCallback(Handler.java:966) + at android.os.Handler.dispatchMessage(Handler.java:110) + at android.os.Looper.loopOnce(Looper.java:205) + at android.os.Looper.loop(Looper.java:293) + at android.app.ActivityThread.loopProcess(ActivityThread.java:9832) + at android.app.ActivityThread.main(ActivityThread.java:9821) + at java.lang.reflect.Method.invoke(Native Method) + at com.android.internal.os.RuntimeInit\$MethodAndArgsCaller.run(RuntimeInit.java:586) + at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1201)""", + stacktrace: null, +); + +final stackTracePlatformException = PlatformException( + code: "error", + message: "Not supported, use openfile", + details: null, + stacktrace: """java.lang.IllegalArgumentException: Not supported, use openfile + at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:172) + at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:153) + at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:814) + at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:2043) + at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1981) + at io.flutter.plugin.platform.f.q(PlatformPlugin.java:57) + at io.flutter.plugin.platform.f.c(PlatformPlugin.java:1) + at io.flutter.plugin.platform.f\$a.g(PlatformPlugin.java:3) + at lb.j\$a.onMethodCall(PlatformChannel.java:294) + at mb.j\$a.a(MethodChannel.java:18) + at za.c.l(DartMessenger.java:19) + at za.c.m(DartMessenger.java:41) + at za.c.i(Unknown Source:0) + at za.b.run(Unknown Source:12) + at android.os.Handler.handleCallback(Handler.java:958) + at android.os.Handler.dispatchMessage(Handler.java:99) + at android.os.Looper.loopOnce(Looper.java:230) + at android.os.Looper.loop(Looper.java:319) + at android.app.ActivityThread.main(ActivityThread.java:8893) + at java.lang.reflect.Method.invoke(Native Method) + at com.android.internal.os.RuntimeInit\$MethodAndArgsCaller.run(RuntimeInit.java:608) + at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)""", +); + +final emptyPlatformException = PlatformException( + code: 'error', + message: + "Unsupported value: '[Ljava.lang.StackTraceElement;@fa902f1' of type 'class [Ljava.lang.StackTraceElement;'", + details: null, + stacktrace: null, +); diff --git a/flutter/test/event_processor/flutter_enricher_event_processor_test.dart b/flutter/test/event_processor/flutter_enricher_event_processor_test.dart index 5fbc1d7034..892e7ff517 100644 --- a/flutter/test/event_processor/flutter_enricher_event_processor_test.dart +++ b/flutter/test/event_processor/flutter_enricher_event_processor_test.dart @@ -39,7 +39,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); debugBrightnessOverride = null; debugDefaultTargetPlatformOverride = null; @@ -65,7 +65,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); debugBrightnessOverride = null; debugDefaultTargetPlatformOverride = null; @@ -81,7 +81,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final accessibility = event?.contexts['accessibility']; @@ -98,7 +98,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final culture = event?.contexts.culture; @@ -133,7 +133,7 @@ void main() { }, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.culture?.locale, 'de-DE'); }); @@ -144,7 +144,7 @@ void main() { ); tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final app = event?.contexts.app; @@ -157,7 +157,7 @@ void main() { ); tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final app = event?.contexts.app; @@ -175,7 +175,7 @@ void main() { final event = SentryEvent(); event.contexts.app = SentryApp(name: appName); - final mutatedEvent = await enricher.apply(event); + final mutatedEvent = await enricher.apply(event, Hint()); final app = mutatedEvent?.contexts.app; @@ -190,7 +190,7 @@ void main() { hasNativeIntegration: true, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNull); }); @@ -202,7 +202,7 @@ void main() { hasNativeIntegration: false, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNotNull); }); @@ -212,7 +212,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final flutterRuntime = event?.contexts.runtimes .firstWhere((element) => element.name == 'Flutter'); @@ -236,7 +236,7 @@ void main() { checker: pair.key, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final flutterRuntime = event?.contexts.runtimes .firstWhere((element) => element.name == 'Flutter'); @@ -264,7 +264,7 @@ void main() { ), ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.modules, { 'foo_package': 'unknown', @@ -292,7 +292,7 @@ void main() { ), ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.modules, null); }); @@ -316,7 +316,7 @@ void main() { ), ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.modules, {'foo_package': 'unknown'}); }); @@ -341,7 +341,7 @@ void main() { hasNativeIntegration: false, ); - final event = await enricher.apply(fakeEvent); + final event = await enricher.apply(fakeEvent, Hint()); // contexts.device expect( @@ -401,7 +401,7 @@ void main() { final enricher = fixture.getSut( binding: () => tester.binding, ); - final event = await enricher.apply(eventWithContextsApp); + final event = await enricher.apply(eventWithContextsApp, Hint()); expect(event?.contexts.app?.viewNames, ['fixture-currentRouteName']); }); diff --git a/flutter/test/event_processor/flutter_exception_event_processor_test.dart b/flutter/test/event_processor/flutter_exception_event_processor_test.dart index aaca15e2af..8dc4f5c528 100644 --- a/flutter/test/event_processor/flutter_exception_event_processor_test.dart +++ b/flutter/test/event_processor/flutter_exception_event_processor_test.dart @@ -20,6 +20,7 @@ void main() { uri: Uri.parse('https://example.org/foo/bar?foo=bar'), ), ), + Hint(), ); expect(event?.request, isNotNull); diff --git a/flutter/test/event_processor/platform_exception_event_processor_test.dart b/flutter/test/event_processor/platform_exception_event_processor_test.dart index d4bf2d9c99..ecc3d7130b 100644 --- a/flutter/test/event_processor/platform_exception_event_processor_test.dart +++ b/flutter/test/event_processor/platform_exception_event_processor_test.dart @@ -26,7 +26,7 @@ void main() { var event = SentryEvent(exceptions: [sentryException]); final sut = fixture.getSut(); - event = (sut.apply(event))!; + event = (sut.apply(event, Hint()))!; expect(event.exceptions?.first.mechanism?.data["code"], "fixture-code"); expect(event.exceptions?.first.mechanism?.data["message"], @@ -46,7 +46,7 @@ void main() { var event = SentryEvent(exceptions: [sentryException]); final sut = fixture.getSut(); - event = (sut.apply(event))!; + event = (sut.apply(event, Hint()))!; expect(event.exceptions?.first.mechanism?.type, "platformException"); }); diff --git a/flutter/test/event_processor/screenshot_event_processor_test.dart b/flutter/test/event_processor/screenshot_event_processor_test.dart index e0ed2eb182..3a00f10ced 100644 --- a/flutter/test/event_processor/screenshot_event_processor_test.dart +++ b/flutter/test/event_processor/screenshot_event_processor_test.dart @@ -1,4 +1,5 @@ @Tags(['canvasKit']) // Web renderer where this test can run +library flutter_test; import 'dart:math'; import 'dart:ui'; @@ -14,6 +15,9 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); late Fixture fixture; + late SentryEvent event; + late Hint hint; + setUp(() { fixture = Fixture(); }); @@ -30,13 +34,14 @@ void main() { final sut = fixture.getSut(renderer, isWeb); await tester.pumpWidget(SentryScreenshotWidget( + hub: fixture.hub, child: Text('Catching Pokémon is a snap!', textDirection: TextDirection.ltr))); final throwable = Exception(); - final event = SentryEvent(throwable: throwable); - final hint = Hint(); - await sut.apply(event, hint: hint); + event = SentryEvent(throwable: throwable); + hint = Hint(); + await sut.apply(event, hint); expect(hint.screenshot != null, added); if (expectedMaxWidthOrHeight != null) { @@ -91,11 +96,98 @@ void main() { await _addScreenshotAttachment(tester, null, added: true, isWeb: false, expectedMaxWidthOrHeight: widthOrHeight); }); + + group('beforeScreenshot', () { + testWidgets('does add screenshot if beforeScreenshot returns true', + (tester) async { + fixture.options.beforeScreenshot = (SentryEvent event, {Hint? hint}) { + return true; + }; + await _addScreenshotAttachment(tester, FlutterRenderer.canvasKit, + added: true, isWeb: false); + }); + + testWidgets('does add screenshot if async beforeScreenshot returns true', + (tester) async { + fixture.options.beforeScreenshot = + (SentryEvent event, {Hint? hint}) async { + await Future.delayed(Duration(milliseconds: 1)); + return true; + }; + await _addScreenshotAttachment(tester, FlutterRenderer.canvasKit, + added: true, isWeb: false); + }); + + testWidgets('does not add screenshot if beforeScreenshot returns false', + (tester) async { + fixture.options.beforeScreenshot = (SentryEvent event, {Hint? hint}) { + return false; + }; + await _addScreenshotAttachment(tester, FlutterRenderer.canvasKit, + added: false, isWeb: false); + }); + + testWidgets( + 'does not add screenshot if async beforeScreenshot returns false', + (tester) async { + fixture.options.beforeScreenshot = + (SentryEvent event, {Hint? hint}) async { + await Future.delayed(Duration(milliseconds: 1)); + return false; + }; + await _addScreenshotAttachment(tester, FlutterRenderer.canvasKit, + added: false, isWeb: false); + }); + + testWidgets('does add screenshot if beforeScreenshot throws', + (tester) async { + fixture.options.beforeScreenshot = (SentryEvent event, {Hint? hint}) { + throw Error(); + }; + await _addScreenshotAttachment(tester, FlutterRenderer.canvasKit, + added: true, isWeb: false); + }); + + testWidgets('does add screenshot if async beforeScreenshot throws', + (tester) async { + fixture.options.beforeScreenshot = + (SentryEvent event, {Hint? hint}) async { + await Future.delayed(Duration(milliseconds: 1)); + throw Error(); + }; + await _addScreenshotAttachment(tester, FlutterRenderer.canvasKit, + added: true, isWeb: false); + }); + + testWidgets('passes event & hint to beforeScreenshot callback', + (tester) async { + SentryEvent? beforeScreenshotEvent; + Hint? beforeScreenshotHint; + + fixture.options.beforeScreenshot = (SentryEvent event, {Hint? hint}) { + beforeScreenshotEvent = event; + beforeScreenshotHint = hint; + return true; + }; + + await _addScreenshotAttachment(tester, FlutterRenderer.canvasKit, + added: true, isWeb: false); + + expect(beforeScreenshotEvent, event); + expect(beforeScreenshotHint, hint); + }); + }); } class Fixture { + late Hub hub; SentryFlutterOptions options = SentryFlutterOptions(dsn: fakeDsn); + Fixture() { + options.attachScreenshot = true; + hub = Hub(options); + } + ScreenshotEventProcessor getSut( FlutterRenderer? flutterRenderer, bool isWeb) { options.rendererWrapper = MockRendererWrapper(flutterRenderer); diff --git a/flutter/test/event_processor/widget_event_processor_test.dart b/flutter/test/event_processor/widget_event_processor_test.dart new file mode 100644 index 0000000000..4744b58ad2 --- /dev/null +++ b/flutter/test/event_processor/widget_event_processor_test.dart @@ -0,0 +1,44 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/event_processor/widget_event_processor.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + testWidgets('adds screenshot attachment dart:io', (tester) async { + await tester.runAsync(() async { + final sut = fixture.getSut(); + await tester.pumpWidget( + SentryWidget( + child: Text( + 'Catching Pokémon is a snap!', + textDirection: TextDirection.ltr, + ), + ), + ); + + final throwable = Exception(); + SentryEvent? event = SentryEvent(throwable: throwable); + event = event.copyWith( + contexts: event.contexts.copyWith( + app: SentryApp(), + ), + ); + event = await sut.apply(event, Hint()); + + expect(event?.contexts.app?.textScale, 1.0); + }); + }); +} + +class Fixture { + WidgetEventProcessor getSut() { + return WidgetEventProcessor(); + } +} diff --git a/flutter/test/fake_frame_callback_handler.dart b/flutter/test/fake_frame_callback_handler.dart new file mode 100644 index 0000000000..0dc968f22c --- /dev/null +++ b/flutter/test/fake_frame_callback_handler.dart @@ -0,0 +1,18 @@ +import 'package:flutter/scheduler.dart'; +import 'package:sentry_flutter/src/frame_callback_handler.dart'; + +class FakeFrameCallbackHandler implements FrameCallbackHandler { + FrameCallback? storedCallback; + + final Duration finishAfterDuration; + + FakeFrameCallbackHandler( + {this.finishAfterDuration = const Duration(milliseconds: 50)}); + + @override + void addPostFrameCallback(FrameCallback callback) async { + // ignore: inference_failure_on_instance_creation + await Future.delayed(finishAfterDuration); + callback(Duration.zero); + } +} diff --git a/flutter/test/file_system_transport_test.dart b/flutter/test/file_system_transport_test.dart index ba6d3d3bf8..aa948e56fb 100644 --- a/flutter/test/file_system_transport_test.dart +++ b/flutter/test/file_system_transport_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'dart:convert'; // backcompatibility for Flutter < 3.3 diff --git a/flutter/test/initialization_test.dart b/flutter/test/initialization_test.dart index 29d5e42c96..7b59c173bf 100644 --- a/flutter/test/initialization_test.dart +++ b/flutter/test/initialization_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; diff --git a/flutter/test/integrations/connectivity_integration_test.dart b/flutter/test/integrations/connectivity_integration_test.dart new file mode 100644 index 0000000000..2f0781e9ec --- /dev/null +++ b/flutter/test/integrations/connectivity_integration_test.dart @@ -0,0 +1,56 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:sentry/sentry.dart'; +import 'package:sentry_flutter/src/integrations/connectivity/connectivity_integration.dart'; +import 'package:sentry_flutter/src/sentry_flutter_options.dart'; + +import '../mocks.dart'; +import '../mocks.mocks.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + verifyBreadcrumb(Breadcrumb crumb, String connectivityData) { + expect(crumb.category, 'device.connectivity'); + expect(crumb.type, 'connectivity'); + expect(crumb.level, SentryLevel.info); + expect(crumb.data?['connectivity'], connectivityData); + } + + test('adds integration', () { + final sut = fixture.getSut(); + sut(fixture.hub, fixture.options); + + expect(fixture.options.sdk.integrations.contains('connectivityIntegration'), + true); + }); + + test('$ConnectivityIntegration: addsBreadcrumb', () { + final integration = fixture.getSut(); + integration.call(fixture.hub, fixture.options); + + integration.addBreadcrumb('wifi'); + + final crumb = verify( + fixture.hub.addBreadcrumb(captureAny), + ).captured.first as Breadcrumb; + + verifyBreadcrumb(crumb, 'wifi'); + }); +} + +class Fixture { + final hub = MockHub(); + final options = SentryFlutterOptions(dsn: fakeDsn); + + ConnectivityIntegration getSut() { + return ConnectivityIntegration(); + } +} diff --git a/flutter/test/integrations/flutter_error_integration_test.dart b/flutter/test/integrations/flutter_error_integration_test.dart index 53446caeda..401b606bc4 100644 --- a/flutter/test/integrations/flutter_error_integration_test.dart +++ b/flutter/test/integrations/flutter_error_integration_test.dart @@ -70,7 +70,7 @@ void main() { final throwableMechanism = event.throwableMechanism as ThrowableMechanism; expect(throwableMechanism.mechanism.type, 'FlutterError'); - expect(throwableMechanism.mechanism.handled, true); + expect(throwableMechanism.mechanism.handled, false); expect(throwableMechanism.throwable, exception); expect(event.contexts['flutter_error_details']['library'], 'sentry'); @@ -102,7 +102,7 @@ void main() { final throwableMechanism = event.throwableMechanism as ThrowableMechanism; expect(throwableMechanism.mechanism.type, 'FlutterError'); - expect(throwableMechanism.mechanism.handled, true); + expect(throwableMechanism.mechanism.handled, false); expect(event.contexts['flutter_error_details']['library'], 'sentry'); expect(event.contexts['flutter_error_details']['context'], @@ -126,7 +126,7 @@ void main() { final throwableMechanism = event.throwableMechanism as ThrowableMechanism; expect(throwableMechanism.mechanism.type, 'FlutterError'); - expect(throwableMechanism.mechanism.handled, true); + expect(throwableMechanism.mechanism.handled, false); expect(throwableMechanism.mechanism.data['hint'], isNull); expect(event.contexts['flutter_error_details'], isNull); @@ -246,6 +246,20 @@ void main() { await span?.finish(); }); + + test('captures error with level error', () async { + final exception = StateError('error'); + + fixture.options.markAutomaticallyCollectedErrorsAsFatal = false; + + _reportError(exception: exception); + + final event = verify( + await fixture.hub.captureEvent(captureAny, hint: anyNamed('hint')), + ).captured.first as SentryEvent; + + expect(event.level, SentryLevel.error); + }); }); } diff --git a/flutter/test/integrations/init_native_sdk_integration_test.dart b/flutter/test/integrations/init_native_sdk_integration_test.dart deleted file mode 100644 index 4ed6a3d3b9..0000000000 --- a/flutter/test/integrations/init_native_sdk_integration_test.dart +++ /dev/null @@ -1,207 +0,0 @@ -@TestOn('vm') - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:sentry_flutter/src/integrations/native_sdk_integration.dart'; -import 'package:sentry_flutter/src/version.dart'; - -import '../mocks.dart'; - -void main() { - group(NativeSdkIntegration, () { - late Fixture fixture; - setUp(() { - fixture = Fixture(); - TestWidgetsFlutterBinding.ensureInitialized(); - }); - - test('test default values', () async { - String? methodName; - dynamic arguments; - final channel = createChannelWithCallback((call) async { - methodName = call.method; - arguments = call.arguments; - }); - var sut = fixture.getSut(channel); - - await sut.call(HubAdapter(), createOptions()); - - channel.setMethodCallHandler(null); - - expect(methodName, 'initNativeSdk'); - expect(arguments, { - 'dsn': fakeDsn, - 'debug': false, - 'environment': null, - 'release': null, - 'enableAutoSessionTracking': true, - 'enableNativeCrashHandling': true, - 'attachStacktrace': true, - 'attachThreads': false, - 'autoSessionTrackingIntervalMillis': 30000, - 'dist': null, - 'integrations': [], - 'packages': [ - {'name': 'pub:sentry_flutter', 'version': sdkVersion} - ], - 'diagnosticLevel': 'debug', - 'maxBreadcrumbs': 100, - 'anrEnabled': false, - 'anrTimeoutIntervalMillis': 5000, - 'enableAutoNativeBreadcrumbs': true, - 'maxCacheItems': 30, - 'sendDefaultPii': false, - 'enableWatchdogTerminationTracking': true, - 'enableNdkScopeSync': true, - 'enableAutoPerformanceTracing': true, - 'sendClientReports': true, - 'proguardUuid': null, - 'maxAttachmentSize': 20 * 1024 * 1024, - 'captureFailedRequests': true, - 'enableAppHangTracking': true, - 'connectionTimeoutMillis': 5000, - 'readTimeoutMillis': 5000, - 'appHangTimeoutIntervalMillis': 2000, - }); - }); - - test('test custom values', () async { - String? methodName; - dynamic arguments; - final channel = createChannelWithCallback((call) async { - methodName = call.method; - arguments = call.arguments; - }); - var sut = fixture.getSut(channel); - - final options = createOptions() - ..debug = false - ..environment = 'foo' - ..release = 'foo@bar+1' - ..enableAutoSessionTracking = false - ..enableNativeCrashHandling = false - ..attachStacktrace = false - ..attachThreads = true - ..autoSessionTrackingInterval = Duration(milliseconds: 240000) - ..dist = 'distfoo' - ..diagnosticLevel = SentryLevel.error - ..maxBreadcrumbs = 0 - ..anrEnabled = false - ..anrTimeoutInterval = Duration(seconds: 1) - ..enableAutoNativeBreadcrumbs = false - ..maxCacheItems = 0 - ..sendDefaultPii = true - ..enableWatchdogTerminationTracking = false - ..enableAutoPerformanceTracing = false - ..sendClientReports = false - ..enableNdkScopeSync = true - ..proguardUuid = fakeProguardUuid - ..maxAttachmentSize = 10 - ..captureFailedRequests = false - ..enableAppHangTracking = false - ..connectionTimeout = Duration(milliseconds: 9001) - ..readTimeout = Duration(milliseconds: 9002) - ..appHangTimeoutInterval = Duration(milliseconds: 9003); - - options.sdk.addIntegration('foo'); - options.sdk.addPackage('bar', '1'); - - await sut.call(HubAdapter(), options); - - channel.setMethodCallHandler(null); - - expect(methodName, 'initNativeSdk'); - expect(arguments, { - 'dsn': fakeDsn, - 'debug': false, - 'environment': 'foo', - 'release': 'foo@bar+1', - 'enableAutoSessionTracking': false, - 'enableNativeCrashHandling': false, - 'attachStacktrace': false, - 'attachThreads': true, - 'autoSessionTrackingIntervalMillis': 240000, - 'dist': 'distfoo', - 'integrations': ['foo'], - 'packages': [ - {'name': 'pub:sentry_flutter', 'version': sdkVersion}, - {'name': 'bar', 'version': '1'}, - ], - 'diagnosticLevel': 'error', - 'maxBreadcrumbs': 0, - 'anrEnabled': false, - 'anrTimeoutIntervalMillis': 1000, - 'enableAutoNativeBreadcrumbs': false, - 'maxCacheItems': 0, - 'sendDefaultPii': true, - 'enableWatchdogTerminationTracking': false, - 'enableNdkScopeSync': true, - 'enableAutoPerformanceTracing': false, - 'sendClientReports': false, - 'proguardUuid': fakeProguardUuid, - 'maxAttachmentSize': 10, - 'captureFailedRequests': false, - 'enableAppHangTracking': false, - 'connectionTimeoutMillis': 9001, - 'readTimeoutMillis': 9002, - 'appHangTimeoutIntervalMillis': 9003, - }); - }); - - test('adds integration', () async { - final channel = createChannelWithCallback((call) async {}); - var sut = fixture.getSut(channel); - - final options = createOptions(); - await sut.call(HubAdapter(), options); - - expect(options.sdk.integrations, ['nativeSdkIntegration']); - - channel.setMethodCallHandler(null); - }); - - test('integration is not added in case of an exception', () async { - final channel = createChannelWithCallback((call) async { - throw Exception('foo'); - }); - var sut = fixture.getSut(channel); - - final options = createOptions(); - await sut.call(NoOpHub(), options); - - expect(options.sdk.integrations, []); - - channel.setMethodCallHandler(null); - }); - }); -} - -MethodChannel createChannelWithCallback( - Future? Function(MethodCall call)? handler, -) { - final channel = MethodChannel('initNativeSdk'); - // ignore: deprecated_member_use - channel.setMockMethodCallHandler(handler); - return channel; -} - -SentryFlutterOptions createOptions() { - final mockPlatformChecker = MockPlatformChecker(hasNativeIntegration: true); - final options = SentryFlutterOptions( - dsn: fakeDsn, - checker: mockPlatformChecker, - ); - options.sdk = SdkVersion( - name: sdkName, - version: sdkVersion, - ); - options.sdk.addPackage('pub:sentry_flutter', sdkVersion); - return options; -} - -class Fixture { - NativeSdkIntegration getSut(MethodChannel channel) { - return NativeSdkIntegration(channel); - } -} diff --git a/flutter/test/integrations/init_native_sdk_test.dart b/flutter/test/integrations/init_native_sdk_test.dart new file mode 100644 index 0000000000..6d3bd57e22 --- /dev/null +++ b/flutter/test/integrations/init_native_sdk_test.dart @@ -0,0 +1,183 @@ +@TestOn('vm') +library flutter_test; + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/native/sentry_native_channel.dart'; +import 'package:sentry_flutter/src/version.dart'; + +import '../mocks.dart'; + +void main() { + late Fixture fixture; + setUp(() { + fixture = Fixture(); + TestWidgetsFlutterBinding.ensureInitialized(); + }); + + test('test default values', () async { + String? methodName; + dynamic arguments; + final channel = createChannelWithCallback((call) async { + methodName = call.method; + arguments = call.arguments; + }); + var sut = fixture.getSut(channel); + + await sut.init(createOptions()); + + channel.setMethodCallHandler(null); + + expect(methodName, 'initNativeSdk'); + expect(arguments, { + 'dsn': fakeDsn, + 'debug': false, + 'environment': null, + 'release': null, + 'enableAutoSessionTracking': true, + 'enableNativeCrashHandling': true, + 'attachStacktrace': true, + 'attachThreads': false, + 'autoSessionTrackingIntervalMillis': 30000, + 'dist': null, + 'integrations': [], + 'packages': [ + {'name': 'pub:sentry_flutter', 'version': sdkVersion} + ], + 'diagnosticLevel': 'debug', + 'maxBreadcrumbs': 100, + 'anrEnabled': false, + 'anrTimeoutIntervalMillis': 5000, + 'enableAutoNativeBreadcrumbs': true, + 'maxCacheItems': 30, + 'sendDefaultPii': false, + 'enableWatchdogTerminationTracking': true, + 'enableNdkScopeSync': true, + 'enableAutoPerformanceTracing': true, + 'sendClientReports': true, + 'proguardUuid': null, + 'maxAttachmentSize': 20 * 1024 * 1024, + 'recordHttpBreadcrumbs': true, + 'captureFailedRequests': true, + 'enableAppHangTracking': true, + 'connectionTimeoutMillis': 5000, + 'readTimeoutMillis': 5000, + 'appHangTimeoutIntervalMillis': 2000, + }); + }); + + test('test custom values', () async { + String? methodName; + dynamic arguments; + final channel = createChannelWithCallback((call) async { + methodName = call.method; + arguments = call.arguments; + }); + var sut = fixture.getSut(channel); + + final options = createOptions() + ..debug = false + ..environment = 'foo' + ..release = 'foo@bar+1' + ..enableAutoSessionTracking = false + ..enableNativeCrashHandling = false + ..attachStacktrace = false + ..attachThreads = true + ..autoSessionTrackingInterval = Duration(milliseconds: 240000) + ..dist = 'distfoo' + ..diagnosticLevel = SentryLevel.error + ..maxBreadcrumbs = 0 + ..anrEnabled = false + ..anrTimeoutInterval = Duration(seconds: 1) + ..enableAutoNativeBreadcrumbs = false + ..maxCacheItems = 0 + ..sendDefaultPii = true + ..enableWatchdogTerminationTracking = false + ..enableAutoPerformanceTracing = false + ..sendClientReports = false + ..enableNdkScopeSync = true + ..proguardUuid = fakeProguardUuid + ..maxAttachmentSize = 10 + ..recordHttpBreadcrumbs = false + ..captureFailedRequests = false + ..enableAppHangTracking = false + ..connectionTimeout = Duration(milliseconds: 9001) + ..readTimeout = Duration(milliseconds: 9002) + ..appHangTimeoutInterval = Duration(milliseconds: 9003); + + options.sdk.addIntegration('foo'); + options.sdk.addPackage('bar', '1'); + + await sut.init(options); + + channel.setMethodCallHandler(null); + + expect(methodName, 'initNativeSdk'); + expect(arguments, { + 'dsn': fakeDsn, + 'debug': false, + 'environment': 'foo', + 'release': 'foo@bar+1', + 'enableAutoSessionTracking': false, + 'enableNativeCrashHandling': false, + 'attachStacktrace': false, + 'attachThreads': true, + 'autoSessionTrackingIntervalMillis': 240000, + 'dist': 'distfoo', + 'integrations': ['foo'], + 'packages': [ + {'name': 'pub:sentry_flutter', 'version': sdkVersion}, + {'name': 'bar', 'version': '1'}, + ], + 'diagnosticLevel': 'error', + 'maxBreadcrumbs': 0, + 'anrEnabled': false, + 'anrTimeoutIntervalMillis': 1000, + 'enableAutoNativeBreadcrumbs': false, + 'maxCacheItems': 0, + 'sendDefaultPii': true, + 'enableWatchdogTerminationTracking': false, + 'enableNdkScopeSync': true, + 'enableAutoPerformanceTracing': false, + 'sendClientReports': false, + 'proguardUuid': fakeProguardUuid, + 'maxAttachmentSize': 10, + 'recordHttpBreadcrumbs': false, + 'captureFailedRequests': false, + 'enableAppHangTracking': false, + 'connectionTimeoutMillis': 9001, + 'readTimeoutMillis': 9002, + 'appHangTimeoutIntervalMillis': 9003, + }); + }); +} + +MethodChannel createChannelWithCallback( + Future? Function(MethodCall call)? handler, +) { + final channel = MethodChannel('initNativeSdk'); + // ignore: deprecated_member_use + channel.setMockMethodCallHandler(handler); + return channel; +} + +SentryFlutterOptions createOptions() { + final mockPlatformChecker = MockPlatformChecker(hasNativeIntegration: true); + final options = SentryFlutterOptions( + dsn: fakeDsn, + checker: mockPlatformChecker, + ); + options.sdk = SdkVersion( + name: sdkName, + version: sdkVersion, + ); + options.sdk.addPackage('pub:sentry_flutter', sdkVersion); + return options; +} + +class Fixture { + SentryNativeChannel getSut(MethodChannel native) { + return SentryNativeChannel(native); + } +} diff --git a/flutter/test/integrations/load_contexts_integration_test.dart b/flutter/test/integrations/load_contexts_integration_test.dart index a97b35db77..a3bbbcbab7 100644 --- a/flutter/test/integrations/load_contexts_integration_test.dart +++ b/flutter/test/integrations/load_contexts_integration_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -58,7 +59,8 @@ void main() { final integration = LoadContextsIntegration(fixture.methodChannel); integration.call(fixture.hub, fixture.options); - event = (await fixture.options.eventProcessors.first.apply(event))!; + event = + (await fixture.options.eventProcessors.first.apply(event, Hint()))!; expect(event.breadcrumbs!.length, 1); expect(event.breadcrumbs!.first.message, 'native'); @@ -83,11 +85,88 @@ void main() { final integration = LoadContextsIntegration(fixture.methodChannel); integration.call(fixture.hub, fixture.options); - event = (await fixture.options.eventProcessors.first.apply(event))!; + event = + (await fixture.options.eventProcessors.first.apply(event, Hint()))!; expect(event.breadcrumbs!.length, 1); expect(event.breadcrumbs!.first.message, 'event'); }); + + test('apply beforeBreadcrumb to native breadcrumbs', () async { + fixture.options.enableScopeSync = true; + fixture.options.beforeBreadcrumb = (breadcrumb, hint) { + if (breadcrumb?.message == 'native-mutated') { + return breadcrumb?.copyWith(message: 'native-mutated-applied'); + } else { + return null; + } + }; + + final eventBreadcrumb = Breadcrumb(message: 'event'); + var event = SentryEvent(breadcrumbs: [eventBreadcrumb]); + + final nativeMutatedBreadcrumb = Breadcrumb(message: 'native-mutated'); + final nativeDeletedBreadcrumb = Breadcrumb(message: 'native-deleted'); + Map loadContexts = { + 'breadcrumbs': [ + nativeMutatedBreadcrumb.toJson(), + nativeDeletedBreadcrumb.toJson(), + ] + }; + + final future = Future.value(loadContexts); + when(fixture.methodChannel.invokeMethod('loadContexts')) + .thenAnswer((_) => future); + // ignore: deprecated_member_use + _channel.setMockMethodCallHandler((MethodCall methodCall) async {}); + + final integration = LoadContextsIntegration(fixture.methodChannel); + integration.call(fixture.hub, fixture.options); + event = + (await fixture.options.eventProcessors.first.apply(event, Hint()))!; + + expect(event.breadcrumbs!.length, 1); + expect(event.breadcrumbs!.first.message, 'native-mutated-applied'); + }); + + test('apply default IP to user during captureEvent after loading context', + () async { + fixture.options.enableScopeSync = true; + + const expectedIp = '{{auto}}'; + String? actualIp; + + const expectedId = '1'; + String? actualId; + + fixture.options.beforeSend = (event, hint) { + actualIp = event.user?.ipAddress; + actualId = event.user?.id; + return event; + }; + + final options = fixture.options; + + final user = SentryUser(id: expectedId); + Map loadContexts = {'user': user.toJson()}; + final future = Future.value(loadContexts); + when(fixture.methodChannel.invokeMethod('loadContexts')) + .thenAnswer((_) => future); + // ignore: deprecated_member_use + _channel.setMockMethodCallHandler((MethodCall methodCall) async {}); + + final integration = LoadContextsIntegration(fixture.methodChannel); + options.addIntegration(integration); + options.integrations.first.call(fixture.hub, options); + + final client = SentryClient(options); + final event = SentryEvent(); + + await client.captureEvent(event); + + expect(expectedIp, actualIp); + expect(expectedId, actualId); + }); }); } diff --git a/flutter/test/integrations/load_contexts_integrations_test.dart b/flutter/test/integrations/load_contexts_integrations_test.dart index c6bb98f0b7..8c7ae456e0 100644 --- a/flutter/test/integrations/load_contexts_integrations_test.dart +++ b/flutter/test/integrations/load_contexts_integrations_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -81,7 +82,7 @@ void main() { e.contexts.operatingSystem = SentryOperatingSystem(theme: 'theme1'); e.contexts.app = SentryApp(inForeground: true); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(fixture.called, true); expect(event?.contexts.device?.name, 'Device1'); @@ -121,7 +122,7 @@ void main() { final e = SentryEvent(contexts: eventContexts, user: SentryUser(id: 'myId')); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(fixture.called, true); expect(event?.contexts.device?.name, 'eDevice'); @@ -145,7 +146,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.packages.any((element) => element.name == 'native-package'), @@ -169,7 +171,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.integrations @@ -189,7 +192,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.packages @@ -210,7 +214,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.packages @@ -239,7 +244,7 @@ void main() { integration(fixture.hub, fixture.options); final e = SentryEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event, isNotNull); }); @@ -252,7 +257,8 @@ void main() { final eventSdk = getSdkVersion(name: 'sentry.dart.flutter'); final e = getEvent(sdk: eventSdk); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?['event.origin'], 'flutter'); expect(event?.tags?['event.environment'], 'dart'); @@ -270,7 +276,8 @@ void main() { sdk: eventSdk, tags: {'a': 'b'}, ); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?['event.origin'], 'flutter'); expect(event?.tags?['event.environment'], 'dart'); @@ -285,7 +292,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(tags: {}); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?.containsKey('event.origin'), false); expect(event?.tags?.containsKey('event.environment'), false); @@ -298,7 +306,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(tags: {'key': 'flutter', 'key-a': 'flutter'}); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?['key'], 'flutter'); expect(event?.tags?['key-a'], 'flutter'); @@ -311,7 +319,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(extra: {'key': 'flutter', 'key-a': 'flutter'}); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); // ignore: deprecated_member_use expect(event?.extra?['key'], 'flutter'); @@ -326,7 +334,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.user?.id, '196E065A-AAF7-409A-9A6C-A81F40274CB9'); expect(event?.user?.username, 'fixture-username'); @@ -340,7 +348,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(user: SentryUser(id: 'abc')); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.user?.id, 'abc'); }); @@ -350,7 +358,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.dist, 'fixture-dist'); }); @@ -360,7 +368,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(dist: 'abc'); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.dist, 'abc'); }); @@ -370,7 +378,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.environment, 'fixture-environment'); }); @@ -380,7 +388,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(environment: 'abc'); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.environment, 'abc'); }); @@ -391,7 +399,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(fingerprint: ['fingerprint-a', 'fingerprint-b']); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.fingerprint, ['fingerprint-a', 'fingerprint-b']); }); @@ -401,7 +409,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.level, SentryLevel.error); }); @@ -411,7 +419,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(level: SentryLevel.fatal); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.level, SentryLevel.fatal); }); diff --git a/flutter/test/integrations/load_image_list_test.dart b/flutter/test/integrations/load_image_list_test.dart index bb78561dae..f7c72fc95e 100644 --- a/flutter/test/integrations/load_image_list_test.dart +++ b/flutter/test/integrations/load_image_list_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -135,7 +136,7 @@ void main() { final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); expect(1, event!.debugMeta!.images.length); }); @@ -146,7 +147,7 @@ void main() { sut.call(fixture.hub, fixture.options); final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); final image = event!.debugMeta!.images.first; @@ -187,12 +188,7 @@ void main() { SentryEvent _getEvent() { final frame = SentryStackFrame(platform: 'native'); final st = SentryStackTrace(frames: [frame]); - final ex = SentryException( - type: 'type', - value: 'value', - stackTrace: st, - ); - return SentryEvent(exceptions: [ex]); + return SentryEvent(threads: [SentryThread(stacktrace: st)]); } class Fixture { diff --git a/flutter/test/integrations/native_app_start_integration_test.dart b/flutter/test/integrations/native_app_start_integration_test.dart index d4b8deaaf5..eb13b41a8d 100644 --- a/flutter/test/integrations/native_app_start_integration_test.dart +++ b/flutter/test/integrations/native_app_start_integration_test.dart @@ -1,5 +1,7 @@ @TestOn('vm') +library flutter_test; +import 'package:collection/collection.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -7,10 +9,21 @@ import 'package:sentry_flutter/src/integrations/native_app_start_integration.dar import 'package:sentry_flutter/src/native/sentry_native.dart'; import 'package:sentry/src/sentry_tracer.dart'; +import '../fake_frame_callback_handler.dart'; import '../mocks.dart'; import '../mocks.mocks.dart'; void main() { + void setupMocks(Fixture fixture) { + when(fixture.hub.startTransaction('root /', 'ui.load', + description: null, startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(fixture.createTracer()); + when(fixture.hub.configureScope(captureAny)).thenAnswer((_) {}); + when(fixture.hub + .captureTransaction(any, traceContext: anyNamed('traceContext'))) + .thenAnswer((_) async => SentryId.empty()); + } + group('$NativeAppStartIntegration', () { late Fixture fixture; @@ -18,12 +31,18 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); fixture = Fixture(); + setupMocks(fixture); + + NativeAppStartIntegration.clearAppStartInfo(); }); test('native app start measurement added to first transaction', () async { - fixture.options.autoAppStart = false; fixture.native.appStartEnd = DateTime.fromMillisecondsSinceEpoch(10); - fixture.binding.nativeAppStart = NativeAppStart(0, true); + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); @@ -31,7 +50,8 @@ void main() { final transaction = SentryTransaction(tracer); final processor = fixture.options.eventProcessors.first; - final enriched = await processor.apply(transaction) as SentryTransaction; + final enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; final measurement = enriched.measurements['app_start_cold']!; expect(measurement.value, 10); @@ -40,9 +60,12 @@ void main() { test('native app start measurement not added to following transactions', () async { - fixture.options.autoAppStart = false; fixture.native.appStartEnd = DateTime.fromMillisecondsSinceEpoch(10); - fixture.binding.nativeAppStart = NativeAppStart(0, true); + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); @@ -51,16 +74,21 @@ void main() { final processor = fixture.options.eventProcessors.first; - var enriched = await processor.apply(transaction) as SentryTransaction; - var secondEnriched = await processor.apply(enriched) as SentryTransaction; + var enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + var secondEnriched = + await processor.apply(enriched, Hint()) as SentryTransaction; expect(secondEnriched.measurements.length, 1); }); test('measurements appended', () async { - fixture.options.autoAppStart = false; fixture.native.appStartEnd = DateTime.fromMillisecondsSinceEpoch(10); - fixture.binding.nativeAppStart = NativeAppStart(0, true); + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); final measurement = SentryMeasurement.warmAppStart(Duration(seconds: 1)); fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); @@ -71,17 +99,22 @@ void main() { final processor = fixture.options.eventProcessors.first; - var enriched = await processor.apply(transaction) as SentryTransaction; - var secondEnriched = await processor.apply(enriched) as SentryTransaction; + var enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + var secondEnriched = + await processor.apply(enriched, Hint()) as SentryTransaction; expect(secondEnriched.measurements.length, 2); expect(secondEnriched.measurements.containsKey(measurement.name), true); }); test('native app start measurement not added if more than 60s', () async { - fixture.options.autoAppStart = false; fixture.native.appStartEnd = DateTime.fromMillisecondsSinceEpoch(60001); - fixture.binding.nativeAppStart = NativeAppStart(0, true); + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); @@ -89,10 +122,284 @@ void main() { final transaction = SentryTransaction(tracer); final processor = fixture.options.eventProcessors.first; - final enriched = await processor.apply(transaction) as SentryTransaction; + final enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; expect(enriched.measurements.isEmpty, true); }); + + test('native app start integration is called and sets app start info', + () async { + fixture.native.appStartEnd = DateTime.fromMillisecondsSinceEpoch(10); + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); + + fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); + + final appStartInfo = await NativeAppStartIntegration.getAppStartInfo(); + expect(appStartInfo?.start, DateTime.fromMillisecondsSinceEpoch(0)); + expect(appStartInfo?.end, DateTime.fromMillisecondsSinceEpoch(10)); + }); + + test( + 'autoAppStart is false and appStartEnd is not set does not add app start measurement', + () async { + fixture.options.autoAppStart = false; + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); + + fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); + + final tracer = fixture.createTracer(); + final transaction = SentryTransaction(tracer); + + final processor = fixture.options.eventProcessors.first; + final enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + + expect(enriched.measurements.isEmpty, true); + expect(enriched.spans.isEmpty, true); + }); + + test( + 'autoAppStart is false and appStartEnd is set adds app start measurement', + () async { + fixture.options.autoAppStart = false; + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); + SentryFlutter.native = fixture.native; + + fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); + + SentryFlutter.setAppStartEnd(DateTime.fromMillisecondsSinceEpoch(10)); + + final tracer = fixture.createTracer(); + final transaction = SentryTransaction(tracer); + + final processor = fixture.options.eventProcessors.first; + final enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + + final measurement = enriched.measurements['app_start_cold']!; + expect(measurement.value, 10); + expect(measurement.unit, DurationSentryMeasurementUnit.milliSecond); + + final appStartInfo = await NativeAppStartIntegration.getAppStartInfo(); + + final appStartSpan = enriched.spans.firstWhereOrNull((element) => + element.context.description == appStartInfo!.appStartTypeDescription); + final pluginRegistrationSpan = enriched.spans.firstWhereOrNull( + (element) => + element.context.description == + appStartInfo!.pluginRegistrationDescription); + final sentrySetupSpan = enriched.spans.firstWhereOrNull((element) => + element.context.description == appStartInfo!.sentrySetupDescription); + final firstFrameRenderSpan = enriched.spans.firstWhereOrNull((element) => + element.context.description == + appStartInfo!.firstFrameRenderDescription); + + expect(appStartSpan, isNotNull); + expect(pluginRegistrationSpan, isNotNull); + expect(sentrySetupSpan, isNotNull); + expect(firstFrameRenderSpan, isNotNull); + }); + }); + + group('App start spans', () { + late SentrySpan? coldStartSpan, + pluginRegistrationSpan, + sentrySetupSpan, + firstFrameRenderSpan; + // ignore: invalid_use_of_internal_member + late SentryTracer tracer; + late Fixture fixture; + late SentryTransaction enriched; + + final validNativeSpanTimes = { + 'correct span description': { + 'startTimestampMsSinceEpoch': 1, + 'stopTimestampMsSinceEpoch': 2, + }, + 'correct span description 2': { + 'startTimestampMsSinceEpoch': 4, + 'stopTimestampMsSinceEpoch': 6, + }, + 'correct span description 3': { + 'startTimestampMsSinceEpoch': 3, + 'stopTimestampMsSinceEpoch': 4, + }, + }; + + final invalidNativeSpanTimes = { + 'failing span with null timestamp': { + 'startTimestampMsSinceEpoch': null, + 'stopTimestampMsSinceEpoch': 3, + }, + 'failing span with string timestamp': { + 'startTimestampMsSinceEpoch': '1', + 'stopTimestampMsSinceEpoch': 3, + }, + }; + + final allNativeSpanTimes = { + ...validNativeSpanTimes, + ...invalidNativeSpanTimes, + }; + + setUp(() async { + TestWidgetsFlutterBinding.ensureInitialized(); + + fixture = Fixture(); + NativeAppStartIntegration.clearAppStartInfo(); + + fixture.native.appStartEnd = DateTime.fromMillisecondsSinceEpoch(50); + fixture.binding.nativeAppStart = NativeAppStart( + appStartTime: 0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: allNativeSpanTimes); + // dartLoadingEnd needs to be set after engine end (see MockNativeChannel) + SentryFlutter.sentrySetupStartTime = + DateTime.fromMillisecondsSinceEpoch(15); + + setupMocks(fixture); + fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options); + + final processor = fixture.options.eventProcessors.first; + tracer = fixture.createTracer(); + final transaction = SentryTransaction(tracer); + enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + + final appStartInfo = await NativeAppStartIntegration.getAppStartInfo(); + + coldStartSpan = enriched.spans.firstWhereOrNull((element) => + element.context.description == appStartInfo?.appStartTypeDescription); + pluginRegistrationSpan = enriched.spans.firstWhereOrNull((element) => + element.context.description == + appStartInfo?.pluginRegistrationDescription); + sentrySetupSpan = enriched.spans.firstWhereOrNull((element) => + element.context.description == appStartInfo?.sentrySetupDescription); + firstFrameRenderSpan = enriched.spans.firstWhereOrNull((element) => + element.context.description == + appStartInfo?.firstFrameRenderDescription); + }); + + test('native app start spans not added to following transactions', + () async { + final processor = fixture.options.eventProcessors.first; + + final transaction = SentryTransaction(fixture.createTracer()); + + final secondEnriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + + expect(secondEnriched.spans.length, 0); + }); + + test('includes only valid native spans', () async { + final spans = + enriched.spans.where((element) => element.data['native'] == true); + + expect(spans.length, validNativeSpanTimes.length); + + for (final span in spans) { + final validSpan = validNativeSpanTimes[span.context.description]; + expect(validSpan, isNotNull); + expect( + span.startTimestamp, + DateTime.fromMillisecondsSinceEpoch( + validSpan!['startTimestampMsSinceEpoch']!) + .toUtc()); + expect( + span.endTimestamp, + DateTime.fromMillisecondsSinceEpoch( + validSpan['stopTimestampMsSinceEpoch']!) + .toUtc()); + } + }); + + test('are correctly ordered', () async { + final spans = + enriched.spans.where((element) => element.data['native'] == true); + + final orderedSpans = spans.toList() + ..sort((a, b) => a.startTimestamp.compareTo(b.startTimestamp)); + + expect(spans, orderedEquals(orderedSpans)); + }); + + test('ignores invalid spans', () async { + final spans = + enriched.spans.where((element) => element.data['native'] == true); + + expect(spans, isNot(contains('failing span'))); + }); + + test('are added by event processor', () async { + expect(coldStartSpan, isNotNull); + expect(pluginRegistrationSpan, isNotNull); + expect(sentrySetupSpan, isNotNull); + expect(firstFrameRenderSpan, isNotNull); + }); + + test('have correct op', () async { + const op = 'app.start.cold'; + expect(coldStartSpan?.context.operation, op); + expect(pluginRegistrationSpan?.context.operation, op); + expect(sentrySetupSpan?.context.operation, op); + expect(firstFrameRenderSpan?.context.operation, op); + }); + + test('have correct parents', () async { + expect(coldStartSpan?.context.parentSpanId, tracer.context.spanId); + expect(pluginRegistrationSpan?.context.parentSpanId, + coldStartSpan?.context.spanId); + expect( + sentrySetupSpan?.context.parentSpanId, coldStartSpan?.context.spanId); + expect(firstFrameRenderSpan?.context.parentSpanId, + coldStartSpan?.context.spanId); + }); + + test('have correct traceId', () async { + final traceId = tracer.context.traceId; + expect(coldStartSpan?.context.traceId, traceId); + expect(pluginRegistrationSpan?.context.traceId, traceId); + expect(sentrySetupSpan?.context.traceId, traceId); + expect(firstFrameRenderSpan?.context.traceId, traceId); + }); + + test('have correct startTimestamp', () async { + final appStartTime = DateTime.fromMillisecondsSinceEpoch( + fixture.binding.nativeAppStart!.appStartTime.toInt()) + .toUtc(); + expect(coldStartSpan?.startTimestamp, appStartTime); + expect(pluginRegistrationSpan?.startTimestamp, appStartTime); + expect(sentrySetupSpan?.startTimestamp, + pluginRegistrationSpan?.endTimestamp); + expect( + firstFrameRenderSpan?.startTimestamp, sentrySetupSpan?.endTimestamp); + }); + + test('have correct endTimestamp', () async { + final engineReadyEndtime = DateTime.fromMillisecondsSinceEpoch( + fixture.binding.nativeAppStart!.pluginRegistrationTime.toInt()) + .toUtc(); + expect(coldStartSpan?.endTimestamp, fixture.native.appStartEnd?.toUtc()); + expect(pluginRegistrationSpan?.endTimestamp, engineReadyEndtime); + expect(sentrySetupSpan?.endTimestamp, + SentryFlutter.sentrySetupStartTime?.toUtc()); + expect(firstFrameRenderSpan?.endTimestamp, coldStartSpan?.endTimestamp); + }); }); } @@ -105,14 +412,13 @@ class Fixture { Fixture() { native.reset(); when(hub.options).thenReturn(options); + SentryFlutter.sentrySetupStartTime = DateTime.now().toUtc(); } NativeAppStartIntegration getNativeAppStartIntegration() { return NativeAppStartIntegration( native, - () { - return TestWidgetsFlutterBinding.ensureInitialized(); - }, + FakeFrameCallbackHandler(), ); } diff --git a/flutter/test/integrations/native_sdk_integration_test.dart b/flutter/test/integrations/native_sdk_integration_test.dart index e48a22933a..1826bd38f2 100644 --- a/flutter/test/integrations/native_sdk_integration_test.dart +++ b/flutter/test/integrations/native_sdk_integration_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -9,93 +10,90 @@ import '../mocks.dart'; import '../mocks.mocks.dart'; void main() { - const _channel = MethodChannel('sentry_flutter'); + group(NativeSdkIntegration, () { + const _channel = MethodChannel('sentry_flutter'); - TestWidgetsFlutterBinding.ensureInitialized(); + TestWidgetsFlutterBinding.ensureInitialized(); - late Fixture fixture; + late Fixture fixture; - setUp(() { - fixture = Fixture(); - }); + setUp(() { + fixture = Fixture(); + }); - tearDown(() { - // ignore: deprecated_member_use - _channel.setMockMethodCallHandler(null); - }); + tearDown(() { + // ignore: deprecated_member_use + _channel.setMockMethodCallHandler(null); + }); + + test('adds integration', () async { + // ignore: deprecated_member_use + _channel.setMockMethodCallHandler((MethodCall methodCall) async {}); + final mock = TestMockSentryNative(); + final integration = NativeSdkIntegration(mock); - test('nativeSdkIntegration adds integration', () async { - // ignore: deprecated_member_use - _channel.setMockMethodCallHandler((MethodCall methodCall) async {}); + await integration(fixture.hub, fixture.options); - final integration = NativeSdkIntegration(_channel); + expect( + fixture.options.sdk.integrations, contains('nativeSdkIntegration')); + expect(mock.numberOfInitCalls, 1); + }); - await integration(fixture.hub, fixture.options); + test('do not throw', () async { + final integration = NativeSdkIntegration(_ThrowingMockSentryNative()); - expect(fixture.options.sdk.integrations.contains('nativeSdkIntegration'), - true); - }); + await integration(fixture.hub, fixture.options); - test('nativeSdkIntegration do not throw', () async { - // ignore: deprecated_member_use - _channel.setMockMethodCallHandler((MethodCall methodCall) async { - throw Exception(); + expect(fixture.options.sdk.integrations.contains('nativeSdkIntegration'), + false); }); - final integration = NativeSdkIntegration(_channel); + test('closes native SDK', () async { + final mock = TestMockSentryNative(); + final integration = NativeSdkIntegration(mock); - await integration(fixture.hub, fixture.options); + await integration.call(fixture.hub, fixture.options); + await integration.close(); - expect(fixture.options.sdk.integrations.contains('nativeSdkIntegration'), - false); - }); - - test('nativeSdkIntegration closes native SDK', () async { - var closeCalled = false; - // ignore: deprecated_member_use - _channel.setMockMethodCallHandler((MethodCall methodCall) async { - expect(methodCall.method, 'closeNativeSdk'); - closeCalled = true; + expect(mock.numberOfCloseCalls, 1); }); - final integration = NativeSdkIntegration(_channel); + test('does not call native sdk when auto init disabled', () async { + final mock = TestMockSentryNative(); + final integration = NativeSdkIntegration(mock); + fixture.options.autoInitializeNativeSdk = false; - await integration.close(); + await integration.call(fixture.hub, fixture.options); - expect(closeCalled, true); - }); - - test('nativeSdkIntegration does not call native sdk when auto init disabled', - () async { - var methodChannelCalled = false; - // ignore: deprecated_member_use - _channel.setMockMethodCallHandler((MethodCall methodCall) async { - methodChannelCalled = true; + expect(mock.numberOfInitCalls, 0); }); - fixture.options.autoInitializeNativeSdk = false; - - final integration = NativeSdkIntegration(_channel); - await integration.call(fixture.hub, fixture.options); + test('does not close native when auto init disabled', () async { + final mock = TestMockSentryNative(); + final integration = NativeSdkIntegration(mock); + fixture.options.autoInitializeNativeSdk = false; - expect(methodChannelCalled, false); - }); + await integration(fixture.hub, fixture.options); + await integration.close(); - test('nativeSdkIntegration does not close native when auto init disabled', - () async { - var methodChannelCalled = false; - // ignore: deprecated_member_use - _channel.setMockMethodCallHandler((MethodCall methodCall) async { - methodChannelCalled = true; + expect(mock.numberOfCloseCalls, 0); }); - fixture.options.autoInitializeNativeSdk = false; - final integration = NativeSdkIntegration(_channel); + test('adds integration', () async { + final mock = TestMockSentryNative(); + final integration = NativeSdkIntegration(mock); - await integration(fixture.hub, fixture.options); - await integration.close(); + await integration.call(fixture.hub, fixture.options); + + expect(fixture.options.sdk.integrations, ['nativeSdkIntegration']); + }); - expect(methodChannelCalled, false); + test(' is not added in case of an exception', () async { + final integration = NativeSdkIntegration(_ThrowingMockSentryNative()); + + await integration.call(fixture.hub, fixture.options); + expect(fixture.options.sdk.integrations, []); + }); }); } @@ -103,3 +101,10 @@ class Fixture { final hub = MockHub(); final options = SentryFlutterOptions(dsn: fakeDsn); } + +class _ThrowingMockSentryNative extends TestMockSentryNative { + @override + Future init(SentryFlutterOptions options) async { + throw Exception(); + } +} diff --git a/flutter/test/jvm/jvm_exception_test.dart b/flutter/test/jvm/jvm_exception_test.dart index de8a3b4e29..9f3f0d2ef9 100644 --- a/flutter/test/jvm/jvm_exception_test.dart +++ b/flutter/test/jvm/jvm_exception_test.dart @@ -86,6 +86,25 @@ void main() { expect(exception.stackTrace[0].lineNumber, 292); }); + test('parse other Flutter Android PlatformException', () { + final exception = JvmException.parse(otherFlutterAndroidPlatformException); + expect( + exception.description, + "Unable to find resource ID #0x7f14000d", + ); + expect(exception.thread, null); + expect(exception.type, 'android.content.res.Resources\$NotFoundException'); + expect(exception.stackTrace.length, 19); + expect(exception.causes, null); + expect(exception.suppressed, null); + + expect( + exception.stackTrace[0].className, 'android.content.res.ResourcesImpl'); + expect(exception.stackTrace[0].method, 'getResourceEntryName'); + expect(exception.stackTrace[0].fileName, 'ResourcesImpl.java'); + expect(exception.stackTrace[0].lineNumber, 493); + }); + test('parse drops empty frames', () { final exception = JvmException.parse(platformExceptionWithEmptyStackFrames); expect(exception.stackTrace.length, 13); @@ -205,6 +224,28 @@ java.lang.IllegalArgumentException: Unsupported value: '[Ljava.lang.StackTraceEl at com.android.internal.os.RuntimeInit\$MethodAndArgsCaller.run(RuntimeInit.java:556) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1037)'''; +const otherFlutterAndroidPlatformException = ''' +android.content.res.Resources\$NotFoundException: Unable to find resource ID #0x7f14000d + at android.content.res.ResourcesImpl.getResourceEntryName(ResourcesImpl.java:493) + at android.content.res.Resources.getResourceEntryName(Resources.java:2441) + at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.getMappedNotificationChannel(FlutterLocalNotificationsPlugin.java:170) + at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.getNotificationChannels(FlutterLocalNotificationsPlugin.java:32) + at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:399) + at be.j\$a.a(MethodChannel.java:18) + at pd.c.l(DartMessenger.java:19) + at pd.c.m(DartMessenger.java:42) + at pd.c.h(Unknown Source:0) + at pd.b.run(Unknown Source:12) + at android.os.Handler.handleCallback(Handler.java:966) + at android.os.Handler.dispatchMessage(Handler.java:110) + at android.os.Looper.loopOnce(Looper.java:205) + at android.os.Looper.loop(Looper.java:293) + at android.app.ActivityThread.loopProcess(ActivityThread.java:9832) + at android.app.ActivityThread.main(ActivityThread.java:9821) + at java.lang.reflect.Method.invoke(Native Method) + at com.android.internal.os.RuntimeInit\$MethodAndArgsCaller.run(RuntimeInit.java:586) + at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1201)'''; + const platformExceptionWithEmptyStackFrames = ''' java.lang.RuntimeException: Catch this platform exception! at io.sentry.samples.flutter.MainActivity\$configureFlutterEngine\$1.onMethodCall(MainActivity.kt:40) diff --git a/flutter/test/load_image_list_test.dart b/flutter/test/load_image_list_test.dart index 0afff01b97..472aac0947 100644 --- a/flutter/test/load_image_list_test.dart +++ b/flutter/test/load_image_list_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -127,7 +128,7 @@ void main() { final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); expect(1, event!.debugMeta!.images.length); }); @@ -138,7 +139,7 @@ void main() { sut.call(fixture.hub, fixture.options); final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); final image = event!.debugMeta!.images.first; diff --git a/flutter/test/mocks.dart b/flutter/test/mocks.dart index b2e01788c1..a373ee7511 100644 --- a/flutter/test/mocks.dart +++ b/flutter/test/mocks.dart @@ -46,6 +46,7 @@ ISentrySpan startTransactionShim( // ignore: invalid_use_of_internal_member SentryTracer, SentryTransaction, + SentrySpan, MethodChannel, ], customMocks: [ MockSpec(fallbackGenerators: {#startTransaction: startTransactionShim}) @@ -171,6 +172,9 @@ class TestMockSentryNative implements SentryNative { @override bool get didFetchAppStart => _didFetchAppStart; + @override + bool didAddAppStartMeasurement = false; + Breadcrumb? breadcrumb; var numberOfAddBreadcrumbCalls = 0; var numberOfBeginNativeFramesCollectionCalls = 0; @@ -195,6 +199,9 @@ class TestMockSentryNative implements SentryNative { var numberOfStartProfilerCalls = 0; var numberOfDiscardProfilerCalls = 0; var numberOfCollectProfileCalls = 0; + var numberOfInitCalls = 0; + SentryFlutterOptions? initOptions; + var numberOfCloseCalls = 0; @override Future addBreadcrumb(Breadcrumb breadcrumb) async { @@ -290,6 +297,19 @@ class TestMockSentryNative implements SentryNative { numberOfDiscardProfilerCalls++; return Future.value(null); } + + @override + Future init(SentryFlutterOptions options) { + numberOfInitCalls++; + initOptions = options; + return Future.value(null); + } + + @override + Future close() { + numberOfCloseCalls++; + return Future.value(null); + } } // TODO can this be replaced with https://pub.dev/packages/mockito#verifying-exact-number-of-invocations--at-least-x--never @@ -312,6 +332,8 @@ class MockNativeChannel implements SentryNativeBinding { int numberOfStartProfilerCalls = 0; int numberOfDiscardProfilerCalls = 0; int numberOfCollectProfileCalls = 0; + int numberOfInitCalls = 0; + int numberOfCloseCalls = 0; @override Future fetchNativeAppStart() async => nativeAppStart; @@ -391,6 +413,18 @@ class MockNativeChannel implements SentryNativeBinding { numberOfDiscardProfilerCalls++; return Future.value(null); } + + @override + Future init(SentryFlutterOptions options) { + numberOfInitCalls++; + return Future.value(null); + } + + @override + Future close() { + numberOfCloseCalls++; + return Future.value(null); + } } class MockRendererWrapper implements RendererWrapper { diff --git a/flutter/test/mocks.mocks.dart b/flutter/test/mocks.mocks.dart index e2807ef405..ee81d44430 100644 --- a/flutter/test/mocks.mocks.dart +++ b/flutter/test/mocks.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.2 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in sentry_flutter/test/mocks.dart. // Do not manually edit this file. @@ -7,20 +7,23 @@ import 'dart:async' as _i7; import 'package:flutter/src/services/binary_messenger.dart' as _i6; import 'package:flutter/src/services/message_codec.dart' as _i5; -import 'package:flutter/src/services/platform_channel.dart' as _i10; +import 'package:flutter/src/services/platform_channel.dart' as _i11; import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i9; import 'package:sentry/sentry.dart' as _i2; -import 'package:sentry/src/profiling.dart' as _i9; +import 'package:sentry/src/profiling.dart' as _i10; import 'package:sentry/src/protocol.dart' as _i3; import 'package:sentry/src/sentry_envelope.dart' as _i8; import 'package:sentry/src/sentry_tracer.dart' as _i4; -import 'mocks.dart' as _i11; +import 'mocks.dart' as _i12; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors @@ -192,7 +195,10 @@ class MockSentryTracer extends _i1.Mock implements _i4.SentryTracer { @override String get name => (super.noSuchMethod( Invocation.getter(#name), - returnValue: '', + returnValue: _i9.dummyValue( + this, + Invocation.getter(#name), + ), ) as String); @override @@ -223,7 +229,7 @@ class MockSentryTracer extends _i1.Mock implements _i4.SentryTracer { ); @override - set profiler(_i9.SentryProfiler? _profiler) => super.noSuchMethod( + set profiler(_i10.SentryProfiler? _profiler) => super.noSuchMethod( Invocation.setter( #profiler, _profiler, @@ -232,7 +238,7 @@ class MockSentryTracer extends _i1.Mock implements _i4.SentryTracer { ); @override - set profileInfo(_i9.SentryProfileInfo? _profileInfo) => super.noSuchMethod( + set profileInfo(_i10.SentryProfileInfo? _profileInfo) => super.noSuchMethod( Invocation.setter( #profileInfo, _profileInfo, @@ -634,6 +640,7 @@ class MockSentryTransaction extends _i1.Mock implements _i3.SentryTransaction { List<_i3.SentryThread>? threads, String? type, Map? measurements, + Map>? metricSummaries, _i3.SentryTransactionInfo? transactionInfo, }) => (super.noSuchMethod( @@ -668,6 +675,7 @@ class MockSentryTransaction extends _i1.Mock implements _i3.SentryTransaction { #threads: threads, #type: type, #measurements: measurements, + #metricSummaries: metricSummaries, #transactionInfo: transactionInfo, }, ), @@ -711,10 +719,229 @@ class MockSentryTransaction extends _i1.Mock implements _i3.SentryTransaction { ) as _i3.SentryTransaction); } +/// A class which mocks [SentrySpan]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockSentrySpan extends _i1.Mock implements _i3.SentrySpan { + MockSentrySpan() { + _i1.throwOnMissingStub(this); + } + + @override + set status(_i3.SpanStatus? status) => super.noSuchMethod( + Invocation.setter( + #status, + status, + ), + returnValueForMissingStub: null, + ); + + @override + DateTime get startTimestamp => (super.noSuchMethod( + Invocation.getter(#startTimestamp), + returnValue: _FakeDateTime_1( + this, + Invocation.getter(#startTimestamp), + ), + ) as DateTime); + + @override + _i2.SentrySpanContext get context => (super.noSuchMethod( + Invocation.getter(#context), + returnValue: _FakeSentrySpanContext_0( + this, + Invocation.getter(#context), + ), + ) as _i2.SentrySpanContext); + + @override + set origin(String? origin) => super.noSuchMethod( + Invocation.setter( + #origin, + origin, + ), + returnValueForMissingStub: null, + ); + + @override + bool get finished => (super.noSuchMethod( + Invocation.getter(#finished), + returnValue: false, + ) as bool); + + @override + set throwable(dynamic throwable) => super.noSuchMethod( + Invocation.setter( + #throwable, + throwable, + ), + returnValueForMissingStub: null, + ); + + @override + Map get tags => (super.noSuchMethod( + Invocation.getter(#tags), + returnValue: {}, + ) as Map); + + @override + Map get data => (super.noSuchMethod( + Invocation.getter(#data), + returnValue: {}, + ) as Map); + + @override + _i7.Future finish({ + _i3.SpanStatus? status, + DateTime? endTimestamp, + }) => + (super.noSuchMethod( + Invocation.method( + #finish, + [], + { + #status: status, + #endTimestamp: endTimestamp, + }, + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + void removeData(String? key) => super.noSuchMethod( + Invocation.method( + #removeData, + [key], + ), + returnValueForMissingStub: null, + ); + + @override + void removeTag(String? key) => super.noSuchMethod( + Invocation.method( + #removeTag, + [key], + ), + returnValueForMissingStub: null, + ); + + @override + void setData( + String? key, + dynamic value, + ) => + super.noSuchMethod( + Invocation.method( + #setData, + [ + key, + value, + ], + ), + returnValueForMissingStub: null, + ); + + @override + void setTag( + String? key, + String? value, + ) => + super.noSuchMethod( + Invocation.method( + #setTag, + [ + key, + value, + ], + ), + returnValueForMissingStub: null, + ); + + @override + _i2.ISentrySpan startChild( + String? operation, { + String? description, + DateTime? startTimestamp, + }) => + (super.noSuchMethod( + Invocation.method( + #startChild, + [operation], + { + #description: description, + #startTimestamp: startTimestamp, + }, + ), + returnValue: _FakeISentrySpan_2( + this, + Invocation.method( + #startChild, + [operation], + { + #description: description, + #startTimestamp: startTimestamp, + }, + ), + ), + ) as _i2.ISentrySpan); + + @override + Map toJson() => (super.noSuchMethod( + Invocation.method( + #toJson, + [], + ), + returnValue: {}, + ) as Map); + + @override + _i3.SentryTraceHeader toSentryTrace() => (super.noSuchMethod( + Invocation.method( + #toSentryTrace, + [], + ), + returnValue: _FakeSentryTraceHeader_3( + this, + Invocation.method( + #toSentryTrace, + [], + ), + ), + ) as _i3.SentryTraceHeader); + + @override + void setMeasurement( + String? name, + num? value, { + _i2.SentryMeasurementUnit? unit, + }) => + super.noSuchMethod( + Invocation.method( + #setMeasurement, + [ + name, + value, + ], + {#unit: unit}, + ), + returnValueForMissingStub: null, + ); + + @override + void scheduleFinish() => super.noSuchMethod( + Invocation.method( + #scheduleFinish, + [], + ), + returnValueForMissingStub: null, + ); +} + /// A class which mocks [MethodChannel]. /// /// See the documentation for Mockito's code generation for more information. -class MockMethodChannel extends _i1.Mock implements _i10.MethodChannel { +class MockMethodChannel extends _i1.Mock implements _i11.MethodChannel { MockMethodChannel() { _i1.throwOnMissingStub(this); } @@ -722,7 +949,10 @@ class MockMethodChannel extends _i1.Mock implements _i10.MethodChannel { @override String get name => (super.noSuchMethod( Invocation.getter(#name), - returnValue: '', + returnValue: _i9.dummyValue( + this, + Invocation.getter(#name), + ), ) as String); @override @@ -845,7 +1075,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { ) as _i2.Scope); @override - set profilerFactory(_i9.SentryProfilerFactory? value) => super.noSuchMethod( + set profilerFactory(_i10.SentryProfilerFactory? value) => super.noSuchMethod( Invocation.setter( #profilerFactory, value, @@ -1050,7 +1280,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { #customSamplingContext: customSamplingContext, }, ), - returnValue: _i11.startTransactionShim( + returnValue: _i12.startTransactionShim( name, operation, description: description, diff --git a/flutter/test/native_scope_observer_test.dart b/flutter/test/native_scope_observer_test.dart index 916bd4b7be..980449b11f 100644 --- a/flutter/test/native_scope_observer_test.dart +++ b/flutter/test/native_scope_observer_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter_test/flutter_test.dart'; import 'package:sentry/sentry.dart'; diff --git a/flutter/test/navigation/sentry_display_widget_test.dart b/flutter/test/navigation/sentry_display_widget_test.dart new file mode 100644 index 0000000000..2cafb706d5 --- /dev/null +++ b/flutter/test/navigation/sentry_display_widget_test.dart @@ -0,0 +1,125 @@ +// ignore_for_file: invalid_use_of_internal_member + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry/src/sentry_tracer.dart'; +import 'package:sentry_flutter/src/integrations/integrations.dart'; + +import '../fake_frame_callback_handler.dart'; +import '../mocks.dart'; + +void main() { + PageRoute route(RouteSettings? settings) => PageRouteBuilder( + pageBuilder: (_, __, ___) => Container(), + settings: settings, + ); + + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + testWidgets('SentryDisplayWidget reports manual ttid span after didPush', + (WidgetTester tester) async { + final currentRoute = route(RouteSettings(name: 'Current Route')); + + await tester.runAsync(() async { + fixture.navigatorObserver.didPush(currentRoute, null); + await tester.pumpWidget(fixture.getSut()); + await fixture.navigatorObserver.completedDisplayTracking?.future; + }); + + final tracer = fixture.hub.getSpan() as SentryTracer; + final spans = tracer.children.where((element) => + element.context.operation == + SentrySpanOperations.uiTimeToInitialDisplay); + + expect(spans, hasLength(1)); + + final ttidSpan = spans.first; + expect(ttidSpan.context.operation, + SentrySpanOperations.uiTimeToInitialDisplay); + expect(ttidSpan.finished, isTrue); + expect(ttidSpan.context.description, 'Current Route initial display'); + expect(ttidSpan.origin, SentryTraceOrigins.manualUiTimeToDisplay); + final ttidSpanDuration = + ttidSpan.endTimestamp!.difference(ttidSpan.startTimestamp); + + expect(tracer.measurements, hasLength(1)); + final measurement = tracer.measurements['time_to_initial_display']; + expect(measurement, isNotNull); + expect(measurement?.unit, DurationSentryMeasurementUnit.milliSecond); + expect(measurement?.value, ttidSpanDuration.inMilliseconds); + }); + + testWidgets('SentryDisplayWidget is ignored for app starts', + (WidgetTester tester) async { + final currentRoute = route(RouteSettings(name: '/')); + final appStartInfo = AppStartInfo( + AppStartType.cold, + start: getUtcDateTime().add(Duration(seconds: 1)), + end: getUtcDateTime().add(Duration(seconds: 2)), + pluginRegistration: getUtcDateTime().add(Duration(seconds: 3)), + sentrySetupStart: getUtcDateTime().add(Duration(seconds: 4)), + nativeSpanTimes: [], + ); + NativeAppStartIntegration.setAppStartInfo(appStartInfo); + + await tester.runAsync(() async { + fixture.navigatorObserver.didPush(currentRoute, null); + await tester.pumpWidget(fixture.getSut()); + await fixture.navigatorObserver.completedDisplayTracking?.future; + }); + + final tracer = fixture.hub.getSpan() as SentryTracer; + final spans = tracer.children.where((element) => + element.context.operation == + SentrySpanOperations.uiTimeToInitialDisplay); + + expect(spans, hasLength(1)); + + final ttidSpan = spans.first; + expect(ttidSpan.context.operation, + SentrySpanOperations.uiTimeToInitialDisplay); + expect(ttidSpan.finished, isTrue); + expect(ttidSpan.context.description, 'root / initial display'); + expect(ttidSpan.origin, SentryTraceOrigins.autoUiTimeToDisplay); + + expect(ttidSpan.startTimestamp, appStartInfo.start); + expect(ttidSpan.endTimestamp, appStartInfo.end); + final ttidSpanDuration = + ttidSpan.endTimestamp!.difference(ttidSpan.startTimestamp); + + expect(tracer.measurements, hasLength(1)); + final measurement = tracer.measurements['time_to_initial_display']; + expect(measurement, isNotNull); + expect(measurement?.value, appStartInfo.duration?.inMilliseconds); + expect(measurement?.value, ttidSpanDuration.inMilliseconds); + expect(measurement?.unit, DurationSentryMeasurementUnit.milliSecond); + }); +} + +class Fixture { + final Hub hub = + Hub(SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0); + late final SentryNavigatorObserver navigatorObserver; + final fakeFrameCallbackHandler = FakeFrameCallbackHandler(); + + Fixture() { + SentryFlutter.native = TestMockSentryNative(); + navigatorObserver = SentryNavigatorObserver(hub: hub); + } + + MaterialApp getSut() { + return MaterialApp( + home: SentryDisplayWidget( + frameCallbackHandler: FakeFrameCallbackHandler( + finishAfterDuration: Duration(milliseconds: 50), + ), + child: Text('my text'), + ), + ); + } +} diff --git a/flutter/test/navigation/time_to_display_tracker_test.dart b/flutter/test/navigation/time_to_display_tracker_test.dart new file mode 100644 index 0000000000..ca9d0425a0 --- /dev/null +++ b/flutter/test/navigation/time_to_display_tracker_test.dart @@ -0,0 +1,289 @@ +// ignore_for_file: invalid_use_of_internal_member +// ignore_for_file: inference_failure_on_instance_creation + +import 'package:collection/collection.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/frame_callback_handler.dart'; +import 'package:sentry_flutter/src/navigation/time_to_display_tracker.dart'; +import 'package:sentry/src/sentry_tracer.dart'; +import 'package:sentry_flutter/src/navigation/time_to_full_display_tracker.dart'; +import 'package:sentry_flutter/src/navigation/time_to_initial_display_tracker.dart'; + +import '../fake_frame_callback_handler.dart'; +import '../mocks.dart'; + +void main() { + late Fixture fixture; + + setUp(() { + TestWidgetsFlutterBinding.ensureInitialized(); + fixture = Fixture(); + }); + + tearDown(() { + fixture.ttidTracker?.clear(); + }); + + ISentrySpan? _getTTIDSpan(SentryTracer transaction) { + return transaction.children.firstWhereOrNull((element) => + element.context.operation == + SentrySpanOperations.uiTimeToInitialDisplay); + } + + ISentrySpan? _getTTFDSpan(SentryTracer transaction) { + return transaction.children.firstWhereOrNull((element) => + element.context.operation == SentrySpanOperations.uiTimeToFullDisplay); + } + + group('time to initial display', () { + group('in root screen app start route', () { + test('matches startTimestamp of transaction', () async { + final sut = fixture.getSut(); + + final transaction = fixture.getTransaction(name: '/') as SentryTracer; + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttidSpan = _getTTIDSpan(transaction); + expect(transaction, isNotNull); + expect(transaction.context.operation, SentrySpanOperations.uiLoad); + expect(transaction.startTimestamp, ttidSpan?.startTimestamp); + }); + + test('finishes ttid span', () async { + SentryFlutter.native = TestMockSentryNative(); + final sut = fixture.getSut(); + final endTimestamp = + fixture.startTimestamp.add(const Duration(milliseconds: 10)); + + final transaction = fixture.getTransaction(name: '/') as SentryTracer; + await sut.trackAppStartTTD(transaction, + startTimestamp: fixture.startTimestamp, endTimestamp: endTimestamp); + + final ttidSpan = _getTTIDSpan(transaction); + expect(ttidSpan?.context.operation, + SentrySpanOperations.uiTimeToInitialDisplay); + expect(ttidSpan?.finished, isTrue); + expect(ttidSpan?.origin, SentryTraceOrigins.autoUiTimeToDisplay); + }); + }); + + group('in regular routes', () { + test('matches startTimestamp of transaction', () async { + final sut = fixture.getSut(); + + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttidSpan = _getTTIDSpan(transaction); + expect(transaction, isNotNull); + expect(transaction.context.operation, SentrySpanOperations.uiLoad); + expect(transaction.startTimestamp, ttidSpan?.startTimestamp); + }); + + group('with approximation strategy', () { + test('finishes ttid span', () async { + final sut = fixture.getSut(); + + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttidSpan = _getTTIDSpan(transaction); + expect(ttidSpan?.context.operation, + SentrySpanOperations.uiTimeToInitialDisplay); + expect(ttidSpan?.finished, isTrue); + expect(ttidSpan?.origin, SentryTraceOrigins.autoUiTimeToDisplay); + }); + + test('completes with timeout when not completing the tracking', + () async { + final sut = fixture.getSut(triggerApproximationTimeout: true); + + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + }); + }); + + group('with manual strategy', () { + test('finishes ttid span', () async { + final sut = fixture.getSut(); + + Future.delayed(const Duration(milliseconds: 1), () { + fixture.ttidTracker?.markAsManual(); + fixture.ttidTracker?.completeTracking(); + }); + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttidSpan = _getTTIDSpan(transaction); + expect(ttidSpan, isNotNull); + expect(ttidSpan?.finished, isTrue); + expect(ttidSpan?.origin, SentryTraceOrigins.manualUiTimeToDisplay); + }); + + test('completes with timeout when not completing the tracking', + () async { + final sut = fixture.getSut(); + + fixture.ttidTracker?.markAsManual(); + // Not calling completeTracking() triggers the manual timeout + + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + }); + }); + }); + }); + + group('time to full display', () { + setUp(() { + fixture.options.enableTimeToFullDisplayTracing = true; + }); + + group('in regular routes', () { + test( + 'finishes span after timeout with deadline exceeded and ttid matching end time', + () async { + final sut = fixture.getSut(); + final transaction = fixture.getTransaction() as SentryTracer; + + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttidSpan = _getTTIDSpan(transaction); + expect(ttidSpan, isNotNull); + + final ttfdSpan = _getTTFDSpan(transaction); + expect(ttfdSpan?.finished, isTrue); + expect(ttfdSpan?.status, SpanStatus.deadlineExceeded()); + expect(ttfdSpan?.endTimestamp, ttidSpan?.endTimestamp); + expect(ttfdSpan?.startTimestamp, ttidSpan?.startTimestamp); + }); + }); + + group('in root screen app start route', () { + test( + 'finishes span after timeout with deadline exceeded and ttid matching end time', + () async { + final sut = fixture.getSut(); + final transaction = + fixture.getTransaction(name: 'root ("/")') as SentryTracer; + final endTimestamp = + fixture.startTimestamp.add(const Duration(milliseconds: 10)); + + await sut.trackAppStartTTD(transaction, + startTimestamp: fixture.startTimestamp, endTimestamp: endTimestamp); + + final ttidSpan = _getTTIDSpan(transaction); + expect(ttidSpan, isNotNull); + + final ttfdSpan = _getTTFDSpan(transaction); + expect(ttfdSpan, isNotNull); + + expect(ttfdSpan?.finished, isTrue); + expect(ttfdSpan?.status, SpanStatus.deadlineExceeded()); + expect(ttfdSpan?.endTimestamp, ttidSpan?.endTimestamp); + expect(ttfdSpan?.startTimestamp, ttidSpan?.startTimestamp); + }); + }); + + test('multiple ttfd timeouts have correct ttid matching end time', + () async { + final sut = fixture.getSut(); + final transaction = fixture.getTransaction() as SentryTracer; + + // First ttfd timeout + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttidSpanA = _getTTIDSpan(transaction); + expect(ttidSpanA, isNotNull); + + final ttfdSpanA = _getTTFDSpan(transaction); + expect(ttfdSpanA?.finished, isTrue); + expect(ttfdSpanA?.status, SpanStatus.deadlineExceeded()); + expect(ttfdSpanA?.endTimestamp, ttidSpanA?.endTimestamp); + expect(ttfdSpanA?.startTimestamp, ttidSpanA?.startTimestamp); + + // Second ttfd timeout + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttidSpanB = _getTTIDSpan(transaction); + expect(ttidSpanB, isNotNull); + + final ttfdSpanB = _getTTFDSpan(transaction); + expect(ttfdSpanB?.finished, isTrue); + expect(ttfdSpanB?.status, SpanStatus.deadlineExceeded()); + expect(ttfdSpanB?.endTimestamp, ttidSpanB?.endTimestamp); + expect(ttfdSpanB?.startTimestamp, ttidSpanB?.startTimestamp); + }); + + test('does not create ttfd span when not enabled', () async { + fixture.options.enableTimeToFullDisplayTracing = false; + + SentryFlutter.native = TestMockSentryNative(); + final sut = fixture.getSut(); + + final transaction = fixture.getTransaction() as SentryTracer; + + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + final ttfdSpan = transaction.children.firstWhereOrNull((element) => + element.context.operation == + SentrySpanOperations.uiTimeToFullDisplay); + expect(ttfdSpan, isNull); + }); + }); + + test('screen load tracking creates ui.load transaction', () async { + final sut = fixture.getSut(); + + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRouteTTD(transaction, + startTimestamp: fixture.startTimestamp); + + expect(transaction, isNotNull); + expect(transaction.context.operation, SentrySpanOperations.uiLoad); + }); +} + +class Fixture { + final startTimestamp = getUtcDateTime(); + final options = SentryFlutterOptions() + ..dsn = fakeDsn + ..tracesSampleRate = 1.0; + late final endTimeProvider = ttidEndTimestampProvider(); + late final hub = Hub(options); + + TimeToInitialDisplayTracker? ttidTracker; + TimeToFullDisplayTracker? ttfdTracker; + + ISentrySpan getTransaction({String? name = "Current route"}) { + return hub.startTransaction(name!, 'ui.load', + startTimestamp: startTimestamp); + } + + TimeToDisplayTracker getSut({bool triggerApproximationTimeout = false}) { + ttidTracker = TimeToInitialDisplayTracker( + frameCallbackHandler: triggerApproximationTimeout + ? DefaultFrameCallbackHandler() + : FakeFrameCallbackHandler()); + ttfdTracker = TimeToFullDisplayTracker( + autoFinishAfter: Duration(seconds: 2), + endTimestampProvider: endTimeProvider, + ); + return TimeToDisplayTracker( + ttidTracker: ttidTracker, + ttfdTracker: ttfdTracker, + enableTimeToFullDisplayTracing: options.enableTimeToFullDisplayTracing, + ); + } +} diff --git a/flutter/test/navigation/time_to_full_display_tracker_test.dart b/flutter/test/navigation/time_to_full_display_tracker_test.dart new file mode 100644 index 0000000000..50609f2692 --- /dev/null +++ b/flutter/test/navigation/time_to_full_display_tracker_test.dart @@ -0,0 +1,87 @@ +// ignore_for_file: invalid_use_of_internal_member + +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/navigation/time_to_full_display_tracker.dart'; +import 'package:sentry/src/sentry_tracer.dart'; + +import '../mocks.dart'; + +void main() { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('reportFullyDisplayed() finishes span', () async { + final sut = fixture.getSut(); + final transaction = fixture.getTransaction() as SentryTracer; + const finishAfterDuration = Duration(seconds: 1); + + Future.delayed(finishAfterDuration, () { + sut.reportFullyDisplayed(); + }); + + await sut.track(transaction, fixture.startTimestamp); + + final ttfdSpan = transaction.children.first; + expect(transaction.children, hasLength(1)); + expect(ttfdSpan.context.operation, + equals(SentrySpanOperations.uiTimeToFullDisplay)); + expect(ttfdSpan.finished, isTrue); + expect(ttfdSpan.context.description, equals('Current route full display')); + expect(ttfdSpan.origin, equals(SentryTraceOrigins.manualUiTimeToDisplay)); + expect(ttfdSpan.startTimestamp, equals(fixture.startTimestamp)); + + // Ensure endTimestamp is within an acceptable range + final expectedEndTimestamp = + fixture.startTimestamp.add(finishAfterDuration); + final actualEndTimestamp = ttfdSpan.endTimestamp!; + final differenceInSeconds = + actualEndTimestamp.difference(expectedEndTimestamp).inSeconds.abs(); + expect(differenceInSeconds, lessThanOrEqualTo(1)); + }); + + test( + 'span finishes automatically after timeout with deadline_exceeded status', + () async { + final sut = fixture.getSut(); + final transaction = fixture.getTransaction() as SentryTracer; + + await sut.track(transaction, fixture.startTimestamp); + + final ttfdSpan = transaction.children.first; + expect(transaction.children, hasLength(1)); + expect(ttfdSpan.endTimestamp, equals(fixture.endTimestampProvider())); + expect(ttfdSpan.context.operation, + equals(SentrySpanOperations.uiTimeToFullDisplay)); + expect(ttfdSpan.finished, isTrue); + expect(ttfdSpan.status, equals(SpanStatus.deadlineExceeded())); + expect(ttfdSpan.context.description, equals('Current route full display')); + expect(ttfdSpan.origin, equals(SentryTraceOrigins.manualUiTimeToDisplay)); + }); +} + +class Fixture { + final startTimestamp = getUtcDateTime(); + final hub = Hub(SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0); + final autoFinishAfter = const Duration(seconds: 2); + late final endTimestampProvider = fakeTTIDEndTimestampProvider(); + + ISentrySpan getTransaction({String? name = "Current route"}) { + return hub.startTransaction(name!, SentrySpanOperations.uiLoad, + bindToScope: true, startTimestamp: startTimestamp); + } + + EndTimestampProvider fakeTTIDEndTimestampProvider() => + () => startTimestamp.add(const Duration(seconds: 1)); + + TimeToFullDisplayTracker getSut( + {EndTimestampProvider? endTimestampProvider}) { + endTimestampProvider ??= this.endTimestampProvider; + return TimeToFullDisplayTracker( + endTimestampProvider: endTimestampProvider, + autoFinishAfter: autoFinishAfter); + } +} diff --git a/flutter/test/navigation/time_to_initial_display_tracker_test.dart b/flutter/test/navigation/time_to_initial_display_tracker_test.dart new file mode 100644 index 0000000000..6e55029572 --- /dev/null +++ b/flutter/test/navigation/time_to_initial_display_tracker_test.dart @@ -0,0 +1,201 @@ +// ignore_for_file: invalid_use_of_internal_member + +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/frame_callback_handler.dart'; +import 'package:sentry_flutter/src/navigation/time_to_initial_display_tracker.dart'; + +import '../fake_frame_callback_handler.dart'; +import '../mocks.dart'; +import 'package:sentry/src/sentry_tracer.dart'; + +void main() { + late Fixture fixture; + late TimeToInitialDisplayTracker sut; + + setUp(() { + fixture = Fixture(); + sut = fixture.getSut(); + }); + + tearDown(() { + sut.clear(); + }); + + group('app start', () { + test('tracking creates and finishes ttid span with correct measurements', + () async { + final endTimestamp = + fixture.startTimestamp.add(const Duration(milliseconds: 10)); + + final transaction = + fixture.getTransaction(name: 'root ("/")') as SentryTracer; + await sut.trackAppStart(transaction, + startTimestamp: fixture.startTimestamp, endTimestamp: endTimestamp); + + final children = transaction.children; + expect(children, hasLength(1)); + + final ttidSpan = children.first; + expect(ttidSpan.context.operation, + SentrySpanOperations.uiTimeToInitialDisplay); + expect(ttidSpan.finished, isTrue); + expect(ttidSpan.context.description, 'root ("/") initial display'); + expect(ttidSpan.origin, SentryTraceOrigins.autoUiTimeToDisplay); + expect(ttidSpan.startTimestamp, fixture.startTimestamp); + expect(ttidSpan.endTimestamp, endTimestamp); + + final ttidMeasurement = + transaction.measurements['time_to_initial_display']; + expect(ttidMeasurement, isNotNull); + expect(ttidMeasurement?.unit, DurationSentryMeasurementUnit.milliSecond); + expect( + ttidMeasurement?.value, + ttidSpan.endTimestamp! + .difference(ttidSpan.startTimestamp) + .inMilliseconds); + }); + }); + + group('regular route', () { + test( + 'approximation tracking creates and finishes ttid span with correct measurements', + () async { + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRoute(transaction, fixture.startTimestamp); + + final children = transaction.children; + expect(children, hasLength(1)); + + final ttidSpan = children.first; + expect(ttidSpan.context.operation, + SentrySpanOperations.uiTimeToInitialDisplay); + expect(ttidSpan.finished, isTrue); + expect(ttidSpan.context.description, 'Regular route initial display'); + expect(ttidSpan.origin, SentryTraceOrigins.autoUiTimeToDisplay); + + final ttidMeasurement = + transaction.measurements['time_to_initial_display']; + expect(ttidMeasurement, isNotNull); + expect(ttidMeasurement?.unit, DurationSentryMeasurementUnit.milliSecond); + expect(ttidMeasurement?.value, + greaterThanOrEqualTo(fixture.finishFrameDuration.inMilliseconds)); + expect( + ttidMeasurement?.value, + ttidSpan.endTimestamp! + .difference(ttidSpan.startTimestamp) + .inMilliseconds); + }); + + test( + 'manual tracking creates and finishes ttid span with correct measurements', + () async { + sut.markAsManual(); + Future.delayed(fixture.finishFrameDuration, () { + sut.completeTracking(); + }); + + final transaction = fixture.getTransaction() as SentryTracer; + await sut.trackRegularRoute(transaction, fixture.startTimestamp); + + final children = transaction.children; + expect(children, hasLength(1)); + + final ttidSpan = children.first; + expect(ttidSpan.context.operation, + SentrySpanOperations.uiTimeToInitialDisplay); + expect(ttidSpan.finished, isTrue); + expect(ttidSpan.context.description, 'Regular route initial display'); + expect(ttidSpan.origin, SentryTraceOrigins.manualUiTimeToDisplay); + final ttidMeasurement = + transaction.measurements['time_to_initial_display']; + expect(ttidMeasurement, isNotNull); + expect(ttidMeasurement?.unit, DurationSentryMeasurementUnit.milliSecond); + expect(ttidMeasurement?.value, + greaterThanOrEqualTo(fixture.finishFrameDuration.inMilliseconds)); + expect( + ttidMeasurement?.value, + ttidSpan.endTimestamp! + .difference(ttidSpan.startTimestamp) + .inMilliseconds); + }); + }); + + group('determineEndtime', () { + test('can complete as null in approximation mode with timeout', () async { + final futureEndTime = await fixture + .getSut(triggerApproximationTimeout: true) + .determineEndTime(); + + expect(futureEndTime, null); + }); + + test('can complete as null in manual mode with timeout', () async { + final sut = fixture.getSut(); + sut.markAsManual(); + // Not calling completeTracking() triggers the manual timeout + + final futureEndTime = await sut.determineEndTime(); + + expect(futureEndTime, null); + }); + + test('can complete automatically in approximation mode', () async { + final futureEndTime = await sut.determineEndTime(); + + expect(futureEndTime, isNotNull); + }); + + test('can complete manually in manual mode', () async { + sut.markAsManual(); + Future.delayed(Duration(milliseconds: 1), () { + sut.completeTracking(); + }); + final futureEndTime = await sut.determineEndTime(); + + expect(futureEndTime, isNotNull); + }); + + test('returns the correct approximation end time', () async { + final endTme = await sut.determineEndTime(); + + expect(endTme?.difference(fixture.startTimestamp).inSeconds, + fixture.finishFrameDuration.inSeconds); + }); + + test('returns the correct manual end time', () async { + sut.markAsManual(); + Future.delayed(fixture.finishFrameDuration, () { + sut.completeTracking(); + }); + + final endTime = await sut.determineEndTime(); + + expect(endTime?.difference(fixture.startTimestamp).inSeconds, + fixture.finishFrameDuration.inSeconds); + }); + }); +} + +class Fixture { + final startTimestamp = getUtcDateTime(); + final hub = Hub(SentryFlutterOptions(dsn: fakeDsn)..tracesSampleRate = 1.0); + late final fakeFrameCallbackHandler = FakeFrameCallbackHandler(); + + ISentrySpan getTransaction({String? name = "Regular route"}) { + return hub.startTransaction(name!, 'ui.load', + bindToScope: true, startTimestamp: startTimestamp); + } + + /// The time it takes until a fake frame has been triggered + Duration get finishFrameDuration => + fakeFrameCallbackHandler.finishAfterDuration; + + TimeToInitialDisplayTracker getSut( + {bool triggerApproximationTimeout = false}) { + return TimeToInitialDisplayTracker( + frameCallbackHandler: triggerApproximationTimeout + ? DefaultFrameCallbackHandler() + : FakeFrameCallbackHandler()); + } +} diff --git a/flutter/test/profiling_test.dart b/flutter/test/profiling_test.dart index eddb391313..adf88e0f2e 100644 --- a/flutter/test/profiling_test.dart +++ b/flutter/test/profiling_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; diff --git a/flutter/test/screenshot/sentry_screenshot_widget_test.dart b/flutter/test/screenshot/sentry_screenshot_widget_test.dart new file mode 100644 index 0000000000..57379387d0 --- /dev/null +++ b/flutter/test/screenshot/sentry_screenshot_widget_test.dart @@ -0,0 +1,80 @@ +@TestOn('vm') +library flutter_test; +// ignore_for_file: invalid_use_of_internal_member + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + +import '../mocks.dart'; + +void main() { + late Fixture fixture; + setUp(() { + fixture = Fixture(); + TestWidgetsFlutterBinding.ensureInitialized(); + }); + + testWidgets( + '$SentryScreenshotWidget does not apply when attachScreenshot is false', + (tester) async { + await tester.pumpWidget( + fixture.getSut( + attachScreenshot: false, + ), + ); + + final widget = find.byType(MyApp); + final repaintBoundaryFinder = find.descendant( + of: widget, + matching: find.byType(RepaintBoundary), + ); + expect(repaintBoundaryFinder, findsNothing); + }, + ); + + testWidgets( + '$SentryScreenshotWidget applies when attachScreenshot is true', + (tester) async { + await tester.pumpWidget( + fixture.getSut( + attachScreenshot: true, + ), + ); + + final widget = find.byType(MyApp); + final repaintBoundaryFinder = find.ancestor( + of: widget, + matching: find.byKey(sentryScreenshotWidgetGlobalKey), + ); + expect(repaintBoundaryFinder, findsOneWidget); + }, + ); +} + +class Fixture { + final _options = SentryFlutterOptions(dsn: fakeDsn); + late Hub hub; + + SentryScreenshotWidget getSut({ + bool attachScreenshot = false, + }) { + _options.attachScreenshot = attachScreenshot; + + hub = Hub(_options); + + return SentryScreenshotWidget( + hub: hub, + child: MaterialApp(home: MyApp()), + ); + } +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return const Text('test'); + } +} diff --git a/flutter/test/sentry_flutter_options_test.dart b/flutter/test/sentry_flutter_options_test.dart index a6d871318b..ed4a3ea7f7 100644 --- a/flutter/test/sentry_flutter_options_test.dart +++ b/flutter/test/sentry_flutter_options_test.dart @@ -32,7 +32,7 @@ void main() { expect(options.enableAutoNativeBreadcrumbs, isFalse); }); - testWidgets('useFlutterBreadcrumbTracking', (WidgetTester tester) async { + testWidgets('useNativeBreadcrumbTracking', (WidgetTester tester) async { final options = SentryFlutterOptions(); options.useNativeBreadcrumbTracking(); diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index 87e4f46e84..e06938da90 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -3,6 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/integrations/connectivity/connectivity_integration.dart'; import 'package:sentry_flutter/src/integrations/integrations.dart'; import 'package:sentry_flutter/src/integrations/screenshot_integration.dart'; import 'package:sentry_flutter/src/profiling.dart'; @@ -23,13 +24,18 @@ final platformAgnosticIntegrations = [ SentryViewHierarchyIntegration, ]; +final webIntegrations = [ + ConnectivityIntegration, +]; + final nonWebIntegrations = [ OnErrorIntegration, ]; -// These should only be added to Android +// These should be added to Android final androidIntegrations = [ LoadImageListIntegration, + LoadContextsIntegration, ]; // These should be added to iOS and macOS @@ -81,14 +87,18 @@ void main() { options: sentryFlutterOptions!, expectedHasNativeScopeObserver: true); testConfiguration( - integrations: integrations, - shouldHaveIntegrations: [ - ...androidIntegrations, - ...nativeIntegrations, - ...platformAgnosticIntegrations, - ...nonWebIntegrations, - ], - shouldNotHaveIntegrations: iOsAndMacOsIntegrations); + integrations: integrations, + shouldHaveIntegrations: [ + ...androidIntegrations, + ...nativeIntegrations, + ...platformAgnosticIntegrations, + ...nonWebIntegrations, + ], + shouldNotHaveIntegrations: [ + ...iOsAndMacOsIntegrations, + ...nonWebIntegrations, + ], + ); integrations .indexWhere((element) => element is WidgetsFlutterBindingIntegration); @@ -138,7 +148,10 @@ void main() { ...platformAgnosticIntegrations, ...nonWebIntegrations, ], - shouldNotHaveIntegrations: androidIntegrations, + shouldNotHaveIntegrations: [ + ...androidIntegrations, + ...nonWebIntegrations, + ], ); testBefore( @@ -179,16 +192,15 @@ void main() { testScopeObserver( options: sentryFlutterOptions!, expectedHasNativeScopeObserver: true); - testConfiguration( - integrations: integrations, - shouldHaveIntegrations: [ - ...iOsAndMacOsIntegrations, - ...nativeIntegrations, - ...platformAgnosticIntegrations, - ...nonWebIntegrations, - ], - shouldNotHaveIntegrations: androidIntegrations, - ); + testConfiguration(integrations: integrations, shouldHaveIntegrations: [ + ...iOsAndMacOsIntegrations, + ...nativeIntegrations, + ...platformAgnosticIntegrations, + ...nonWebIntegrations, + ], shouldNotHaveIntegrations: [ + ...androidIntegrations, + ...nonWebIntegrations, + ]); testBefore( integrations: integrations, @@ -239,6 +251,7 @@ void main() { ...androidIntegrations, ...iOsAndMacOsIntegrations, ...nativeIntegrations, + ...webIntegrations, ], ); @@ -290,6 +303,7 @@ void main() { ...androidIntegrations, ...iOsAndMacOsIntegrations, ...nativeIntegrations, + ...webIntegrations, ], ); @@ -336,7 +350,10 @@ void main() { testConfiguration( integrations: integrations, - shouldHaveIntegrations: platformAgnosticIntegrations, + shouldHaveIntegrations: [ + ...platformAgnosticIntegrations, + ...webIntegrations, + ], shouldNotHaveIntegrations: [ ...androidIntegrations, ...iOsAndMacOsIntegrations, @@ -383,7 +400,10 @@ void main() { testConfiguration( integrations: integrations, - shouldHaveIntegrations: platformAgnosticIntegrations, + shouldHaveIntegrations: [ + ...platformAgnosticIntegrations, + ...webIntegrations, + ], shouldNotHaveIntegrations: [ ...androidIntegrations, ...iOsAndMacOsIntegrations, @@ -427,7 +447,10 @@ void main() { testConfiguration( integrations: integrations, - shouldHaveIntegrations: platformAgnosticIntegrations, + shouldHaveIntegrations: [ + ...platformAgnosticIntegrations, + ...webIntegrations, + ], shouldNotHaveIntegrations: [ ...androidIntegrations, ...iOsAndMacOsIntegrations, @@ -472,7 +495,10 @@ void main() { testConfiguration( integrations: integrations, - shouldHaveIntegrations: platformAgnosticIntegrations, + shouldHaveIntegrations: [ + ...platformAgnosticIntegrations, + ...webIntegrations, + ], shouldNotHaveIntegrations: [ ...androidIntegrations, ...iOsAndMacOsIntegrations, diff --git a/flutter/test/sentry_native_channel_test.dart b/flutter/test/sentry_native_channel_test.dart index 04ec723feb..050693cc8a 100644 --- a/flutter/test/sentry_native_channel_test.dart +++ b/flutter/test/sentry_native_channel_test.dart @@ -1,6 +1,7 @@ // ignore_for_file: inference_failure_on_function_invocation @TestOn('vm') +library flutter_test; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; @@ -20,8 +21,11 @@ void main() { test('fetchNativeAppStart', () async { final map = { + 'pluginRegistrationTime': 1, 'appStartTime': 0.1, 'isColdStart': true, + // ignore: inference_failure_on_collection_literal + 'nativeSpanTimes': {}, }; final future = Future.value(map); diff --git a/flutter/test/sentry_native_test.dart b/flutter/test/sentry_native_test.dart index 68dc16fdfa..8d30312f6f 100644 --- a/flutter/test/sentry_native_test.dart +++ b/flutter/test/sentry_native_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -16,7 +17,11 @@ void main() { }); test('fetchNativeAppStart sets didFetchAppStart', () async { - final nativeAppStart = NativeAppStart(0.0, true); + final nativeAppStart = NativeAppStart( + appStartTime: 0.0, + pluginRegistrationTime: 10, + isColdStart: true, + nativeSpanTimes: {}); channel.nativeAppStart = nativeAppStart; expect(sut.didFetchAppStart, false); diff --git a/flutter/test/sentry_navigator_observer_test.dart b/flutter/test/sentry_navigator_observer_test.dart index c49588ab85..e2b1488cca 100644 --- a/flutter/test/sentry_navigator_observer_test.dart +++ b/flutter/test/sentry_navigator_observer_test.dart @@ -1,3 +1,5 @@ +// ignore_for_file: invalid_use_of_internal_member + import 'dart:async'; import 'package:flutter/material.dart'; @@ -5,9 +7,13 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/integrations/integrations.dart'; import 'package:sentry_flutter/src/native/sentry_native.dart'; import 'package:sentry/src/sentry_tracer.dart'; +import 'package:sentry_flutter/src/navigation/time_to_display_tracker.dart'; +import 'package:sentry_flutter/src/navigation/time_to_initial_display_tracker.dart'; +import 'fake_frame_callback_handler.dart'; import 'mocks.dart'; import 'mocks.mocks.dart'; @@ -30,10 +36,12 @@ void main() { customSamplingContext: anyNamed('customSamplingContext'), startTimestamp: anyNamed('startTimestamp'), )).thenReturn(thenReturnSpan); + when(mockHub.getSpan()).thenReturn(thenReturnSpan); } setUp(() { fixture = Fixture(); + WidgetsFlutterBinding.ensureInitialized(); }); group('NativeFrames', () { @@ -55,10 +63,17 @@ void main() { final tracer = getMockSentryTracer(); _whenAnyStart(mockHub, tracer); + when(tracer.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); + when(tracer.finished).thenReturn(false); + when(tracer.status).thenReturn(SpanStatus.ok()); final sut = fixture.getSut(hub: mockHub); sut.didPush(currentRoute, null); + await sut.completedDisplayTracking?.future; // Handle internal async method calls. await Future.delayed(const Duration(milliseconds: 10), () { @@ -73,31 +88,32 @@ void main() { options.tracesSampleRate = 1; final hub = Hub(options); + mockNativeChannel = MockNativeChannel(); + SentryFlutter.native = + SentryNative(SentryFlutterOptions(dsn: fakeDsn), mockNativeChannel); + final nativeFrames = NativeFrames(3, 2, 1); mockNativeChannel.nativeFrames = nativeFrames; - final sut = fixture.getSut( - hub: hub, - autoFinishAfter: Duration(milliseconds: 50), - ); + final sut = fixture.getSut(hub: hub); sut.didPush(currentRoute, null); + await sut.completedDisplayTracking?.future; // Get ref to created transaction - // ignore: invalid_use_of_internal_member SentryTracer? actualTransaction; hub.configureScope((scope) { - // ignore: invalid_use_of_internal_member actualTransaction = scope.span as SentryTracer; }); - await Future.delayed(Duration(milliseconds: 500)); + // Wait for the transaction to finish the async native frame fetching + await Future.delayed(Duration(milliseconds: 1500)); expect(mockNativeChannel.numberOfEndNativeFramesCalls, 1); final measurements = actualTransaction?.measurements ?? {}; - expect(measurements.length, 3); + expect(measurements.length, 4); final expectedTotal = SentryMeasurement.totalFrames(3); final expectedSlow = SentryMeasurement.slowFrames(2); @@ -117,15 +133,21 @@ void main() { }); group('$SentryNavigatorObserver', () { - test('didPush starts transaction', () { + test('didPush starts transaction', () async { const name = 'Current Route'; final currentRoute = route(RouteSettings(name: name)); - const op = 'navigation'; + const op = 'ui.load'; final hub = _MockHub(); final span = getMockSentryTracer(name: name); when(span.context).thenReturn(SentrySpanContext(operation: op)); _whenAnyStart(hub, span); + when(span.finished).thenReturn(false); + when(span.status).thenReturn(SpanStatus.ok()); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); final sut = fixture.getSut( hub: hub, @@ -133,9 +155,11 @@ void main() { ); sut.didPush(currentRoute, null); + await sut.completedDisplayTracking?.future; final context = verify(hub.startTransactionWithContext( captureAny, + startTimestamp: anyNamed('startTimestamp'), waitForChildren: true, autoFinishAfter: anyNamed('autoFinishAfter'), trimEnd: true, @@ -150,13 +174,14 @@ void main() { }); }); - test('do not bind transaction to scope if no op', () { + test('do not bind transaction to scope if no op', () async { final currentRoute = route(RouteSettings(name: 'Current Route')); final hub = _MockHub(); final span = NoOpSentrySpan(); _whenAnyStart(hub, span); + when(hub.getSpan()).thenReturn(null); final sut = fixture.getSut( hub: hub, @@ -164,9 +189,11 @@ void main() { ); sut.didPush(currentRoute, null); + await sut.completedDisplayTracking?.future; verify(hub.startTransactionWithContext( any, + startTimestamp: anyNamed('startTimestamp'), waitForChildren: true, autoFinishAfter: Duration(seconds: 5), trimEnd: true, @@ -179,20 +206,24 @@ void main() { }); }); - test('route with empty name does not start transaction', () { + test('route with empty name does not start transaction', () async { final currentRoute = route(null); final hub = _MockHub(); final span = getMockSentryTracer(); when(span.context).thenReturn(SentrySpanContext(operation: 'op')); + when(span.finished).thenReturn(false); + when(span.status).thenReturn(SpanStatus.ok()); _whenAnyStart(hub, span); final sut = fixture.getSut(hub: hub); sut.didPush(currentRoute, null); + await Future.delayed(const Duration(milliseconds: 100)); verifyNever(hub.startTransactionWithContext( any, + startTimestamp: anyNamed('startTimestamp'), waitForChildren: true, autoFinishAfter: anyNamed('autoFinishAfter'), trimEnd: true, @@ -204,13 +235,15 @@ void main() { }); }); - test('no transaction on opt-out', () { + test('no transaction on opt-out', () async { final currentRoute = route(RouteSettings(name: 'Current Route')); final hub = _MockHub(); final span = getMockSentryTracer(); when(span.context).thenReturn(SentrySpanContext(operation: 'op')); _whenAnyStart(hub, span); + when(span.finished).thenReturn(false); + when(span.status).thenReturn(SpanStatus.ok()); final sut = fixture.getSut(hub: hub, enableAutoTransactions: false); @@ -218,6 +251,7 @@ void main() { verifyNever(hub.startTransactionWithContext( any, + startTimestamp: anyNamed('startTimestamp'), waitForChildren: true, autoFinishAfter: anyNamed('autoFinishAfter'), trimEnd: true, @@ -237,6 +271,12 @@ void main() { final span = getMockSentryTracer(); when(span.context).thenReturn(SentrySpanContext(operation: 'op')); + when(span.finished).thenReturn(false); + when(span.status).thenReturn(SpanStatus.ok()); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); _whenAnyStart(hub, span); final sut = fixture.getSut(hub: hub); @@ -245,6 +285,7 @@ void main() { verify(hub.startTransactionWithContext( any, + startTimestamp: anyNamed('startTimestamp'), waitForChildren: true, autoFinishAfter: anyNamed('autoFinishAfter'), trimEnd: true, @@ -256,72 +297,178 @@ void main() { }); }); - test('didPush finishes previous transaction', () { + test('didPush finishes previous transaction', () async { final firstRoute = route(RouteSettings(name: 'First Route')); final secondRoute = route(RouteSettings(name: 'Second Route')); final hub = _MockHub(); - final span = getMockSentryTracer(); + final span = getMockSentryTracer(finished: false) as SentryTracer; when(span.context).thenReturn(SentrySpanContext(operation: 'op')); when(span.status).thenReturn(null); + when(span.finished).thenReturn(false); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); + when(span.children).thenReturn([]); _whenAnyStart(hub, span); final sut = fixture.getSut(hub: hub); sut.didPush(firstRoute, null); sut.didPush(secondRoute, firstRoute); + sut.didPop(secondRoute, null); - verify(span.status = SpanStatus.ok()); - verify(span.finish()); + hub.configureScope((scope) { + expect(scope.span, null); + }); + + verify(span.finish()).called(2); }); test('didPop finishes transaction', () async { final currentRoute = route(RouteSettings(name: 'Current Route')); final hub = _MockHub(); - final span = getMockSentryTracer(); + final span = getMockSentryTracer(finished: false) as SentryTracer; when(span.context).thenReturn(SentrySpanContext(operation: 'op')); when(span.status).thenReturn(null); + when(span.finished).thenReturn(false); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); _whenAnyStart(hub, span); + when(span.children).thenReturn([]); final sut = fixture.getSut(hub: hub); sut.didPush(currentRoute, null); sut.didPop(currentRoute, null); - verify(span.status = SpanStatus.ok()); - verify(span.finish()); + hub.configureScope((scope) { + expect(scope.span, null); + }); + + verify(span.finish()).called(1); }); - test('didPop re-starts previous', () { - final previousRoute = route(RouteSettings(name: 'Previous Route')); + test('multiple didPop only finish transaction once', () async { final currentRoute = route(RouteSettings(name: 'Current Route')); final hub = _MockHub(); - final previousSpan = getMockSentryTracer(); - when(previousSpan.context).thenReturn(SentrySpanContext(operation: 'op')); - when(previousSpan.status).thenReturn(null); - - _whenAnyStart(hub, previousSpan); + final span = getMockSentryTracer(finished: false) as SentryTracer; + when(span.context).thenReturn(SentrySpanContext(operation: 'op')); + when(span.status).thenReturn(null); + when(span.children).thenReturn([]); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); + _whenAnyStart(hub, span); final sut = fixture.getSut(hub: hub); - sut.didPop(currentRoute, previousRoute); + sut.didPush(currentRoute, null); + await sut.completedDisplayTracking?.future; - verify(hub.startTransactionWithContext( - any, - waitForChildren: true, - autoFinishAfter: anyNamed('autoFinishAfter'), - trimEnd: true, - onFinish: anyNamed('onFinish'), - )); + sut.didPop(currentRoute, null); + sut.didPop(currentRoute, null); hub.configureScope((scope) { - expect(scope.span, previousSpan); + expect(scope.span, null); }); + + verify(span.finish()).called(1); }); - test('route arguments are set on transaction', () { + test( + 'unfinished children will be finished with deadline_exceeded on didPush', + () async { + final currentRoute = route(RouteSettings(name: 'Current Route')); + + final hub = _MockHub(); + final span = getMockSentryTracer(finished: false) as SentryTracer; + final mockChildA = MockSentrySpan(); + final mockChildB = MockSentrySpan(); + when(span.children).thenReturn([ + mockChildB, + mockChildA, + ]); + when(mockChildA.finished).thenReturn(false); + when(mockChildB.finished).thenReturn(false); + when(mockChildA.context).thenReturn(SentrySpanContext( + operation: SentrySpanOperations.uiTimeToInitialDisplay)); + when(mockChildB.context).thenReturn(SentrySpanContext( + operation: SentrySpanOperations.uiTimeToFullDisplay)); + when(span.context).thenReturn(SentrySpanContext(operation: 'op')); + when(span.status).thenReturn(null); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); + _whenAnyStart(hub, span); + + final sut = fixture.getSut(hub: hub); + + // Push to new screen, e.g app start / root screen + sut.didPush(currentRoute, null); + + // Push to screen e.g root to user screen + sut.didPush(currentRoute, null); + + await Future.delayed(const Duration(milliseconds: 100)); + + verify(mockChildA.finish(status: SpanStatus.deadlineExceeded())) + .called(1); + verify(mockChildB.finish(status: SpanStatus.deadlineExceeded())) + .called(1); + }); + + test( + 'unfinished children will be finished with deadline_exceeded on didPop', + () async { + final currentRoute = route(RouteSettings(name: 'Current Route')); + + final hub = _MockHub(); + final span = getMockSentryTracer(finished: false) as SentryTracer; + final mockChildA = MockSentrySpan(); + final mockChildB = MockSentrySpan(); + when(span.children).thenReturn([ + mockChildB, + mockChildA, + ]); + when(mockChildA.finished).thenReturn(false); + when(mockChildB.finished).thenReturn(false); + when(mockChildA.context).thenReturn(SentrySpanContext( + operation: SentrySpanOperations.uiTimeToInitialDisplay)); + when(mockChildB.context).thenReturn(SentrySpanContext( + operation: SentrySpanOperations.uiTimeToFullDisplay)); + when(span.context).thenReturn(SentrySpanContext(operation: 'op')); + when(span.status).thenReturn(null); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); + _whenAnyStart(hub, span); + + final sut = fixture.getSut(hub: hub); + + // Push to new screen, e.g root to user screen + sut.didPush(currentRoute, null); + + // Pop back e.g user to root screen + sut.didPop(currentRoute, null); + + await Future.delayed(const Duration(milliseconds: 100)); + + verify(mockChildA.finish(status: SpanStatus.deadlineExceeded())) + .called(1); + verify(mockChildB.finish(status: SpanStatus.deadlineExceeded())) + .called(1); + }); + + test('route arguments are set on transaction', () async { final arguments = {'foo': 'bar'}; final currentRoute = route(RouteSettings( name: 'Current Route', @@ -332,43 +479,68 @@ void main() { final span = getMockSentryTracer(); when(span.context).thenReturn(SentrySpanContext(operation: 'op')); when(span.status).thenReturn(null); + when(span.finished).thenReturn(false); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); _whenAnyStart(hub, span); final sut = fixture.getSut(hub: hub); sut.didPush(currentRoute, null); + await sut.completedDisplayTracking?.future; verify(span.setData('route_settings_arguments', arguments)); }); - test('flutter root name is replaced', () { + test('flutter root name is replaced', () async { final rootRoute = route(RouteSettings(name: '/')); + NativeAppStartIntegration.setAppStartInfo( + AppStartInfo( + AppStartType.cold, + start: DateTime.now().add(const Duration(seconds: 1)), + end: DateTime.now().add(const Duration(seconds: 2)), + pluginRegistration: DateTime.now().add(const Duration(seconds: 3)), + sentrySetupStart: DateTime.now().add(const Duration(seconds: 4)), + nativeSpanTimes: [], + ), + ); final hub = _MockHub(); final span = getMockSentryTracer(name: '/'); when(span.context).thenReturn(SentrySpanContext(operation: 'op')); + when(span.finished).thenReturn(false); + when(span.status).thenReturn(SpanStatus.ok()); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); _whenAnyStart(hub, span); final sut = fixture.getSut(hub: hub); sut.didPush(rootRoute, null); + await Future.delayed(const Duration(milliseconds: 100)); + final context = verify(hub.startTransactionWithContext( captureAny, waitForChildren: true, + startTimestamp: anyNamed('startTimestamp'), autoFinishAfter: anyNamed('autoFinishAfter'), trimEnd: true, onFinish: anyNamed('onFinish'), )).captured.single as SentryTransactionContext; - expect(context.name, 'root ("/")'); + expect(context.name, 'root /'); hub.configureScope((scope) { expect(scope.span, span); }); }); - test('didPush sets current route name', () { + test('didPush sets current route name', () async { const name = 'Current Route'; final currentRoute = route(RouteSettings(name: name)); @@ -376,6 +548,12 @@ void main() { final hub = _MockHub(); final span = getMockSentryTracer(name: name); when(span.context).thenReturn(SentrySpanContext(operation: op)); + when(span.finished).thenReturn(false); + when(span.status).thenReturn(SpanStatus.ok()); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); _whenAnyStart(hub, span); final sut = fixture.getSut( @@ -384,6 +562,7 @@ void main() { ); sut.didPush(currentRoute, null); + await sut.completedDisplayTracking?.future; expect(SentryNavigatorObserver.currentRouteName, 'Current Route'); }); @@ -398,6 +577,12 @@ void main() { final hub = _MockHub(); final span = getMockSentryTracer(name: oldRouteName); when(span.context).thenReturn(SentrySpanContext(operation: op)); + when(span.finished).thenReturn(false); + when(span.status).thenReturn(SpanStatus.ok()); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); _whenAnyStart(hub, span); final sut = fixture.getSut( @@ -422,6 +607,11 @@ void main() { final span = getMockSentryTracer(name: oldRouteName); when(span.context).thenReturn(SentrySpanContext(operation: op)); when(span.status).thenReturn(null); + when(span.finished).thenReturn(false); + when(span.startChild('ui.load.initial_display', + description: anyNamed('description'), + startTimestamp: anyNamed('startTimestamp'))) + .thenReturn(NoOpSentrySpan()); _whenAnyStart(hub, span); final sut = fixture.getSut( @@ -641,6 +831,7 @@ void main() { final hub = _MockHub(); final observer = fixture.getSut(hub: hub); + when(hub.getSpan()).thenReturn(NoOpSentrySpan()); final to = route(); final previous = route(); @@ -800,11 +991,19 @@ class Fixture { SentryNavigatorObserver getSut({ required Hub hub, bool enableAutoTransactions = true, - Duration autoFinishAfter = const Duration(seconds: 3), + Duration autoFinishAfter = const Duration(seconds: 1), bool setRouteNameAsTransaction = false, RouteNameExtractor? routeNameExtractor, AdditionalInfoExtractor? additionalInfoProvider, + bool enableTimeToFullDisplayTracing = false, }) { + final frameCallbackHandler = FakeFrameCallbackHandler(); + final timeToInitialDisplayTracker = + TimeToInitialDisplayTracker(frameCallbackHandler: frameCallbackHandler); + final timeToDisplayTracker = TimeToDisplayTracker( + ttidTracker: timeToInitialDisplayTracker, + enableTimeToFullDisplayTracing: enableTimeToFullDisplayTracing, + ); return SentryNavigatorObserver( hub: hub, enableAutoTransactions: enableAutoTransactions, @@ -812,6 +1011,7 @@ class Fixture { setRouteNameAsTransaction: setRouteNameAsTransaction, routeNameExtractor: routeNameExtractor, additionalInfoProvider: additionalInfoProvider, + timeToDisplayTracker: timeToDisplayTracker, ); } @@ -833,9 +1033,10 @@ class _MockHub extends MockHub { } } -ISentrySpan getMockSentryTracer({String? name}) { +ISentrySpan getMockSentryTracer({String? name, bool? finished}) { final tracer = MockSentryTracer(); when(tracer.name).thenReturn(name ?? 'name'); + when(tracer.finished).thenReturn(finished ?? true); return tracer; } diff --git a/flutter/test/sentry_widget_test.dart b/flutter/test/sentry_widget_test.dart new file mode 100644 index 0000000000..a64fded42f --- /dev/null +++ b/flutter/test/sentry_widget_test.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + +void main() { + group('SentryWidget', () { + const testChild = Text('Test Child'); + + setUp(() async { + TestWidgetsFlutterBinding.ensureInitialized(); + }); + + testWidgets('SentryWidget wraps child with SentryUserInteractionWidget', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: SentryWidget(child: testChild), + ), + ); + + expect(find.byType(SentryUserInteractionWidget), findsOneWidget); + expect(find.byWidget(testChild), findsOneWidget); + }); + + testWidgets('SentryWidget wraps child with SentryScreenshotWidget', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: SentryWidget(child: testChild), + ), + ); + + expect(find.byType(SentryScreenshotWidget), findsOneWidget); + expect(find.byWidget(testChild), findsOneWidget); + }); + }); +} diff --git a/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart b/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart index 02d1022157..8f326579f4 100644 --- a/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart +++ b/flutter/test/user_interaction/sentry_user_interaction_widget_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; // ignore_for_file: invalid_use_of_internal_member import 'dart:async'; @@ -32,6 +33,75 @@ void main() { }, ); + testWidgets( + '$SentryUserInteractionWidget does not apply when enableUserInteractionTracing and enableUserInteractionBreadcrumbs is false', + (tester) async { + await tester.runAsync(() async { + await tester.pumpWidget( + fixture.getSut( + enableUserInteractionTracing: false, + enableUserInteractionBreadcrumbs: false, + ), + ); + final specificChildFinder = find.byType(MyApp); + + expect( + find.ancestor( + of: specificChildFinder, + matching: find.byType(Listener), + ), + findsNothing, + ); + }); + }, + ); + + testWidgets( + '$SentryUserInteractionWidget does apply when enableUserInteractionTracing is true', + (tester) async { + await tester.runAsync(() async { + await tester.pumpWidget( + fixture.getSut( + enableUserInteractionTracing: true, + enableUserInteractionBreadcrumbs: false, + ), + ); + final specificChildFinder = find.byType(MyApp); + + expect( + find.ancestor( + of: specificChildFinder, + matching: find.byType(Listener), + ), + findsOne, + ); + }); + }, + ); + + testWidgets( + '$SentryUserInteractionWidget does apply when enableUserInteractionBreadcrumbs is true', + (tester) async { + await tester.runAsync(() async { + await tester.pumpWidget( + fixture.getSut( + enableUserInteractionTracing: false, + enableUserInteractionBreadcrumbs: true, + ), + ); + final specificChildFinder = find.byType(MyApp); + + expect( + find.ancestor( + of: specificChildFinder, + matching: find.byType(Listener), + ), + findsOne, + ); + }); + }, + ); + group('$SentryUserInteractionWidget crumbs', () { testWidgets('Add crumb for MaterialButton', (tester) async { await tester.runAsync(() async { @@ -327,7 +397,7 @@ class Fixture { } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { @@ -340,7 +410,7 @@ class MyApp extends StatelessWidget { } class Page1 extends StatelessWidget { - const Page1({Key? key}) : super(key: key); + const Page1({super.key}); @override Widget build(BuildContext context) { @@ -416,7 +486,7 @@ class Page1 extends StatelessWidget { } class Page2 extends StatelessWidget { - const Page2({Key? key}) : super(key: key); + const Page2({super.key}); @override Widget build(BuildContext context) { diff --git a/flutter/test/version_test.dart b/flutter/test/version_test.dart index 5beaf24622..b97fd250b4 100644 --- a/flutter/test/version_test.dart +++ b/flutter/test/version_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. @TestOn('vm') +library flutter_test; import 'dart:io'; diff --git a/flutter/test/view_hierarchy/sentry_tree_walker_test.dart b/flutter/test/view_hierarchy/sentry_tree_walker_test.dart index c2048c3492..52d775529b 100644 --- a/flutter/test/view_hierarchy/sentry_tree_walker_test.dart +++ b/flutter/test/view_hierarchy/sentry_tree_walker_test.dart @@ -172,7 +172,7 @@ bool _findWidget( } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { diff --git a/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart b/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart index 537b2cd9c4..7743e8ebc6 100644 --- a/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart +++ b/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart @@ -26,7 +26,7 @@ void main() { exceptions: [SentryException(type: 'type', value: 'value')]); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNotNull); }); @@ -42,7 +42,7 @@ void main() { final event = SentryEvent(throwable: StateError('error')); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNotNull); }); @@ -58,7 +58,7 @@ void main() { final event = SentryEvent(); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNull); }); @@ -74,7 +74,7 @@ void main() { final event = SentryEvent(); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNull); }); @@ -107,7 +107,7 @@ class Fixture { } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { diff --git a/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart b/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart index 580d2672ca..bef4050c6e 100644 --- a/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart +++ b/flutter/test/view_hierarchy/view_hierarchy_integration_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library flutter_test; import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; diff --git a/hive/README.md b/hive/README.md index 593d367100..b67e9e4f7b 100644 --- a/hive/README.md +++ b/hive/README.md @@ -8,9 +8,9 @@ Sentry integration for `hive` package =========== -| package | build | pub | likes | popularity | pub points | -|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| ------- | -| sentry_hive | [![build](https://github.com/getsentry/sentry-dart/workflows/sentry-hive/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-hive) | [![pub package](https://img.shields.io/pub/v/sentry_hive.svg)](https://pub.dev/packages/sentry_hive) | [![likes](https://img.shields.io/pub/likes/sentry_hive)](https://pub.dev/packages/sentry_hive/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_hive)](https://pub.dev/packages/sentry_hive/score) | [![pub points](https://img.shields.io/pub/points/sentry_hive)](https://pub.dev/packages/sentry_hive/score) +| package | build | pub | likes | popularity | pub points | +|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| ------- | +| sentry_hive | [![build](https://github.com/getsentry/sentry-dart/actions/workflows/hive.yml/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-hive) | [![pub package](https://img.shields.io/pub/v/sentry_hive.svg)](https://pub.dev/packages/sentry_hive) | [![likes](https://img.shields.io/pub/likes/sentry_hive)](https://pub.dev/packages/sentry_hive/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_hive)](https://pub.dev/packages/sentry_hive/score) | [![pub points](https://img.shields.io/pub/points/sentry_hive)](https://pub.dev/packages/sentry_hive/score) Integration for the [`hive`](https://pub.dev/packages/hive) package. @@ -78,8 +78,9 @@ class Person { #### Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) -* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) -* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) * [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) diff --git a/hive/lib/src/sentry_span_helper.dart b/hive/lib/src/sentry_span_helper.dart index a1c780ef08..38a67501a4 100644 --- a/hive/lib/src/sentry_span_helper.dart +++ b/hive/lib/src/sentry_span_helper.dart @@ -35,24 +35,44 @@ class SentrySpanHelper { // ignore: invalid_use_of_internal_member span?.origin = _origin; - span?.setData(SentryHiveImpl.dbSystemKey, SentryHiveImpl.dbSystem); + var breadcrumb = Breadcrumb( + message: description, + data: {}, + type: 'query', + ); + span?.setData(SentryHiveImpl.dbSystemKey, SentryHiveImpl.dbSystem); if (dbName != null) { span?.setData(SentryHiveImpl.dbNameKey, dbName); } + breadcrumb.data?[SentryHiveImpl.dbSystemKey] = SentryHiveImpl.dbSystem; + if (dbName != null) { + breadcrumb.data?[SentryHiveImpl.dbNameKey] = dbName; + } + try { final result = await execute(); + span?.status = SpanStatus.ok(); + breadcrumb.data?['status'] = 'ok'; return result; } catch (exception) { span?.throwable = exception; span?.status = SpanStatus.internalError(); + breadcrumb.data?['status'] = 'internal_error'; + breadcrumb = breadcrumb.copyWith( + level: SentryLevel.warning, + ); + rethrow; } finally { await span?.finish(); + + // ignore: invalid_use_of_internal_member + await _hub.scope.addBreadcrumb(breadcrumb); } } } diff --git a/hive/lib/src/version.dart b/hive/lib/src/version.dart index 00e8950582..18932a8818 100644 --- a/hive/lib/src/version.dart +++ b/hive/lib/src/version.dart @@ -1,5 +1,5 @@ /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; /// The package name reported to Sentry.io in the submitted events. const String packageName = 'pub:sentry_hive'; diff --git a/hive/pubspec.yaml b/hive/pubspec.yaml index 0a53ab3f16..a065329ce4 100644 --- a/hive/pubspec.yaml +++ b/hive/pubspec.yaml @@ -1,6 +1,6 @@ name: sentry_hive description: An integration which adds support for performance tracing for the hive package. -version: 7.13.1 +version: 8.3.0 homepage: https://docs.sentry.io/platforms/flutter/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues @@ -8,8 +8,16 @@ issue_tracker: https://github.com/getsentry/sentry-dart/issues environment: sdk: '>=2.17.0 <4.0.0' +platforms: + android: + ios: + macos: + linux: + windows: + web: + dependencies: - sentry: 7.13.1 + sentry: 8.3.0 hive: ^2.2.3 meta: ^1.3.0 diff --git a/hive/test/sentry_box_base_test.dart b/hive/test/sentry_box_base_test.dart index 3caf5e06e5..3821b8b341 100644 --- a/hive/test/sentry_box_base_test.dart +++ b/hive/test/sentry_box_base_test.dart @@ -40,6 +40,23 @@ void main() { expect(span?.throwable, exception); } + void verifyBreadcrumb( + String message, + Breadcrumb? crumb, { + bool checkName = false, + String status = 'ok', + }) { + expect( + crumb?.message, + message, + ); + expect(crumb?.type, 'query'); + if (checkName) { + expect(crumb?.data?[SentryHiveImpl.dbNameKey], Fixture.dbName); + } + expect(crumb?.data?['status'], status); + } + group('adds span', () { late Fixture fixture; @@ -49,6 +66,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); }); tearDown(() async { @@ -131,6 +149,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); when(fixture.mockBox.name).thenReturn(Fixture.dbName); + when(fixture.hub.scope).thenReturn(fixture.scope); }); tearDown(() async { @@ -253,6 +272,254 @@ void main() { verifyErrorSpan('deleteAt', fixture.exception, fixture.getCreatedSpan()); }); }); + + group('adds breadcrumb', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + await fixture.setUp(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('add adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.add(Person('Joe Dirt')); + + verifyBreadcrumb('add', fixture.getCreatedBreadcrumb()); + }); + + test('addAll adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.addAll([Person('Joe Dirt')]); + + verifyBreadcrumb('addAll', fixture.getCreatedBreadcrumb()); + }); + + test('clear adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.clear(); + + verifyBreadcrumb('clear', fixture.getCreatedBreadcrumb()); + }); + + test('close adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.close(); + + verifyBreadcrumb('close', fixture.getCreatedBreadcrumb()); + }); + + test('compact adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.compact(); + + verifyBreadcrumb('compact', fixture.getCreatedBreadcrumb()); + }); + + test('delete adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.delete('fixture-key'); + + verifyBreadcrumb('delete', fixture.getCreatedBreadcrumb()); + }); + + test('deleteAll adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.deleteAll(['fixture-key']); + + verifyBreadcrumb('deleteAll', fixture.getCreatedBreadcrumb()); + }); + + test('deleteAt adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.add(Person('Joe Dirt')); + await sut.deleteAt(0); + + verifyBreadcrumb('deleteAt', fixture.getCreatedBreadcrumb()); + }); + }); + + group('adds error breadcrumb', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + await fixture.setUp(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.mockBox.name).thenReturn(Fixture.dbName); + when(fixture.hub.scope).thenReturn(fixture.scope); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('throwing add adds error breadcrumb', () async { + when(fixture.mockBox.add(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + try { + await sut.add(Person('Joe Dirt')); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'add', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing addAll adds error breadcrumb', () async { + when(fixture.mockBox.addAll(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + try { + await sut.addAll([Person('Joe Dirt')]); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'addAll', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing clear adds error breadcrumb', () async { + when(fixture.mockBox.clear()).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + try { + await sut.clear(); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'clear', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing close adds error breadcrumb', () async { + when(fixture.mockBox.close()).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + try { + await sut.close(); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'close', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing compact adds error breadcrumb', () async { + when(fixture.mockBox.compact()).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + try { + await sut.compact(); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'compact', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing delete adds error breadcrumb', () async { + when(fixture.mockBox.delete(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + try { + await sut.delete('fixture-key'); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'delete', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteAll adds error breadcrumb', () async { + when(fixture.mockBox.deleteAll(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + try { + await sut.deleteAll(['fixture-key']); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'deleteAll', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteAt adds error breadcrumb', () async { + when(fixture.mockBox.add(any)).thenAnswer((_) async { + return 1; + }); + when(fixture.mockBox.deleteAt(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + await sut.add(Person('Joe Dirt')); + try { + await sut.deleteAt(0); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'deleteAt', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + }); } class Fixture { @@ -266,6 +533,7 @@ class Fixture { final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); + late final scope = Scope(options); Future setUp() async { Hive.init(Directory.systemTemp.path); @@ -294,4 +562,8 @@ class Fixture { SentrySpan? getCreatedSpan() { return tracer.children.last; } + + Breadcrumb? getCreatedBreadcrumb() { + return hub.scope.breadcrumbs.last; + } } diff --git a/hive/test/sentry_box_collection_test.dart b/hive/test/sentry_box_collection_test.dart index 4965896611..f13b95e1c8 100644 --- a/hive/test/sentry_box_collection_test.dart +++ b/hive/test/sentry_box_collection_test.dart @@ -42,6 +42,23 @@ void main() { expect(span?.throwable, exception); } + void verifyBreadcrumb( + String message, + Breadcrumb? crumb, { + bool checkName = false, + String status = 'ok', + }) { + expect( + crumb?.message, + message, + ); + expect(crumb?.type, 'query'); + if (checkName) { + expect(crumb?.data?[SentryHiveImpl.dbNameKey], Fixture.dbName); + } + expect(crumb?.data?['status'], status); + } + group('adds span when calling', () { late Fixture fixture; @@ -51,6 +68,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); }); tearDown(() async { @@ -111,6 +129,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); when(fixture.mockBoxCollection.name).thenReturn(Fixture.dbName); + when(fixture.hub.scope).thenReturn(fixture.scope); }); tearDown(() async { @@ -184,6 +203,155 @@ void main() { ); }); }); + + group('adds breadcrumb when calling', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + await fixture.setUp(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('open', () async { + await SentryBoxCollection.open( + Fixture.dbName, + {'people'}, + hub: fixture.hub, + ); + + final span = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('open', span); + }); + + test('openBox', () async { + final sut = await fixture.getSut(); + + await sut.openBox('people'); + + final span = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('openBox', span); + }); + + test('transaction', () async { + final sut = await fixture.getSut(); + + final people = await sut.openBox('people'); + await sut.transaction( + () async { + print(people.name); + }, + boxNames: ['people'], + ); + final span = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('transaction', span); + }); + + test('deleteFromDisk', () async { + final sut = await fixture.getSut(); + + await sut.deleteFromDisk(); + + final span = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('deleteFromDisk', span); + }); + }); + + group('adds error breadcrumb when calling', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + await fixture.setUp(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.mockBoxCollection.name).thenReturn(Fixture.dbName); + when(fixture.hub.scope).thenReturn(fixture.scope); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + // open is static and cannot be mocked + + test('throwing openBox', () async { + when( + // ignore: inference_failure_on_function_invocation + fixture.mockBoxCollection.openBox( + any, + preload: anyNamed('preload'), + boxCreator: anyNamed('boxCreator'), + ), + ).thenThrow(fixture.exception); + + final sut = await fixture.getSut(injectMock: true); + + try { + // ignore: inference_failure_on_function_invocation + await sut.openBox('people'); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'openBox', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing transaction', () async { + when( + fixture.mockBoxCollection.transaction( + any, + boxNames: anyNamed('boxNames'), + readOnly: anyNamed('readOnly'), + ), + ).thenThrow(fixture.exception); + + final sut = await fixture.getSut(injectMock: true); + + try { + await sut.transaction(() async {}); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'transaction', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteFromDisk', () async { + when(fixture.mockBoxCollection.deleteFromDisk()) + .thenThrow(fixture.exception); + + final sut = await fixture.getSut(injectMock: true); + + try { + await sut.deleteFromDisk(); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'deleteFromDisk', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + }); } class Fixture { @@ -197,6 +365,7 @@ class Fixture { final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); + late final scope = Scope(options); Future setUp() async { SentryHive.init(Directory.systemTemp.path); @@ -222,4 +391,8 @@ class Fixture { SentrySpan? getCreatedSpan() { return tracer.children.last; } + + Breadcrumb? getCreatedBreadcrumb() { + return hub.scope.breadcrumbs.last; + } } diff --git a/hive/test/sentry_hive_impl_test.dart b/hive/test/sentry_hive_impl_test.dart index df5c8502f9..521415d1ed 100644 --- a/hive/test/sentry_hive_impl_test.dart +++ b/hive/test/sentry_hive_impl_test.dart @@ -41,6 +41,23 @@ void main() { expect(span?.throwable, error); } + void verifyBreadcrumb( + String message, + Breadcrumb? crumb, { + bool checkName = false, + String status = 'ok', + }) { + expect( + crumb?.message, + message, + ); + expect(crumb?.type, 'query'); + if (checkName) { + expect(crumb?.data?[SentryHiveImpl.dbNameKey], Fixture.dbName); + } + expect(crumb?.data?['status'], status); + } + group('adds span', () { late Fixture fixture; @@ -49,6 +66,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); await fixture.setUp(); }); @@ -119,6 +137,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); when(fixture.mockHive.close()).thenAnswer((_) async => {}); + when(fixture.hub.scope).thenReturn(fixture.scope); await fixture.setUp(injectMockHive: true); }); @@ -274,6 +293,259 @@ void main() { }); }); + group('adds breadcrumbs', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('boxExists adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.openBox(Fixture.dbName); + await sut.boxExists(Fixture.dbName); + + verifyBreadcrumb('boxExists', fixture.getCreatedBreadcrumb()); + }); + + test('close adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.close(); + + verifyBreadcrumb('close', fixture.getCreatedBreadcrumb()); + }); + + test('deleteBoxFromDisk adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.openBox(Fixture.dbName); + await sut.deleteBoxFromDisk(Fixture.dbName); + + verifyBreadcrumb('deleteBoxFromDisk', fixture.getCreatedBreadcrumb()); + }); + + test('deleteFromDisk adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.deleteFromDisk(); + + verifyBreadcrumb('deleteFromDisk', fixture.getCreatedBreadcrumb()); + }); + + test('openBox adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.openBox(Fixture.dbName); + + verifyBreadcrumb( + 'openBox', + fixture.getCreatedBreadcrumb(), + checkName: true, + ); + }); + + test('openLazyBox adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.openLazyBox(Fixture.dbName); + + verifyBreadcrumb( + 'openLazyBox', + fixture.getCreatedBreadcrumb(), + checkName: true, + ); + }); + }); + + group('adds error breadcrumb', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.mockHive.close()).thenAnswer((_) async => {}); + when(fixture.hub.scope).thenReturn(fixture.scope); + + await fixture.setUp(injectMockHive: true); + }); + + test('throwing boxExists adds error span', () async { + final Box box = MockBox(); + when( + fixture.mockHive.openBox( + any, + encryptionCipher: anyNamed('encryptionCipher'), + keyComparator: anyNamed('keyComparator'), + compactionStrategy: anyNamed('compactionStrategy'), + crashRecovery: anyNamed('crashRecovery'), + path: anyNamed('path'), + bytes: anyNamed('bytes'), + collection: anyNamed('collection'), + encryptionKey: anyNamed('encryptionKey'), + ), + ).thenAnswer((_) => Future(() => box)); + when(fixture.mockHive.boxExists(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(); + + await sut.openBox(Fixture.dbName); + try { + await sut.boxExists(Fixture.dbName); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'boxExists', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing close adds error span', () async { + when(fixture.mockHive.close()).thenThrow(fixture.exception); + + final sut = fixture.getSut(); + + try { + await sut.close(); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'close', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteBoxFromDisk adds error span', () async { + final Box box = MockBox(); + when( + fixture.mockHive.openBox( + any, + encryptionCipher: anyNamed('encryptionCipher'), + keyComparator: anyNamed('keyComparator'), + compactionStrategy: anyNamed('compactionStrategy'), + crashRecovery: anyNamed('crashRecovery'), + path: anyNamed('path'), + bytes: anyNamed('bytes'), + collection: anyNamed('collection'), + encryptionKey: anyNamed('encryptionKey'), + ), + ).thenAnswer((_) => Future(() => box)); + when(fixture.mockHive.deleteBoxFromDisk(any)) + .thenThrow(fixture.exception); + + final sut = fixture.getSut(); + + await sut.openBox(Fixture.dbName); + try { + await sut.deleteBoxFromDisk(Fixture.dbName); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'deleteBoxFromDisk', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteFromDisk adds error span', () async { + when(fixture.mockHive.deleteFromDisk()).thenThrow(fixture.exception); + + final sut = fixture.getSut(); + + try { + await sut.deleteFromDisk(); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'deleteFromDisk', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing openBox adds error span', () async { + when( + fixture.mockHive.openBox( + any, + encryptionCipher: anyNamed('encryptionCipher'), + keyComparator: anyNamed('keyComparator'), + compactionStrategy: anyNamed('compactionStrategy'), + crashRecovery: anyNamed('crashRecovery'), + path: anyNamed('path'), + bytes: anyNamed('bytes'), + collection: anyNamed('collection'), + encryptionKey: anyNamed('encryptionKey'), + ), + ).thenThrow(fixture.exception); + + final sut = fixture.getSut(); + + try { + await sut.openBox(Fixture.dbName); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'openBox', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing openLazyBox adds error span', () async { + when( + fixture.mockHive.openLazyBox( + any, + encryptionCipher: anyNamed('encryptionCipher'), + keyComparator: anyNamed('keyComparator'), + compactionStrategy: anyNamed('compactionStrategy'), + crashRecovery: anyNamed('crashRecovery'), + path: anyNamed('path'), + collection: anyNamed('collection'), + encryptionKey: anyNamed('encryptionKey'), + ), + ).thenThrow(fixture.exception); + + final sut = fixture.getSut(); + + try { + await sut.openLazyBox(Fixture.dbName); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'openLazyBox', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + }); + group('integrations', () { late Fixture fixture; @@ -282,6 +554,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); await fixture.setUp(); }); @@ -319,6 +592,7 @@ class Fixture { final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); late SentryHiveImpl sut; + late final scope = Scope(options); Future setUp({bool injectMockHive = false}) async { if (injectMockHive) { @@ -344,4 +618,8 @@ class Fixture { SentrySpan? getCreatedSpan() { return tracer.children.last; } + + Breadcrumb? getCreatedBreadcrumb() { + return hub.scope.breadcrumbs.last; + } } diff --git a/hive/test/sentry_lazy_box_test.dart b/hive/test/sentry_lazy_box_test.dart index 263658af8d..291dc3fc20 100644 --- a/hive/test/sentry_lazy_box_test.dart +++ b/hive/test/sentry_lazy_box_test.dart @@ -40,6 +40,23 @@ void main() { expect(span?.throwable, exception); } + void verifyBreadcrumb( + String message, + Breadcrumb? crumb, { + bool checkName = false, + String status = 'ok', + }) { + expect( + crumb?.message, + message, + ); + expect(crumb?.type, 'query'); + if (checkName) { + expect(crumb?.data?[SentryHiveImpl.dbNameKey], Fixture.dbName); + } + expect(crumb?.data?['status'], status); + } + group('adds span', () { late Fixture fixture; @@ -49,6 +66,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); }); tearDown(() async { @@ -84,6 +102,7 @@ void main() { when(fixture.hub.options).thenReturn(fixture.options); when(fixture.hub.getSpan()).thenReturn(fixture.tracer); when(fixture.mockBox.name).thenReturn(Fixture.dbName); + when(fixture.hub.scope).thenReturn(fixture.scope); }); tearDown(() async { @@ -126,6 +145,103 @@ void main() { verifyErrorSpan('getAt', fixture.exception, fixture.getCreatedSpan()); }); }); + + group('adds breadcrumb', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + await fixture.setUp(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('get adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.put('fixture-key', Person('John Malkovich')); + await sut.get('fixture-key'); + + verifyBreadcrumb('get', fixture.getCreatedBreadcrumb()); + }); + + test('getAt adds breadcrumb', () async { + final sut = fixture.getSut(); + + await sut.add(Person('John Malkovich')); + await sut.getAt(0); + + verifyBreadcrumb('getAt', fixture.getCreatedBreadcrumb()); + }); + }); + + group('adds error breadcrumbs', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + await fixture.setUp(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.mockBox.name).thenReturn(Fixture.dbName); + when(fixture.hub.scope).thenReturn(fixture.scope); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('throwing get adds error breadcrumbs', () async { + when(fixture.mockBox.add(any)).thenAnswer((_) async { + return 1; + }); + when(fixture.mockBox.get(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + await sut.put('fixture-key', Person('John Malkovich')); + try { + await sut.get('fixture-key'); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'get', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing getAt adds error breadcrumbs', () async { + when(fixture.mockBox.add(any)).thenAnswer((_) async { + return 1; + }); + when(fixture.mockBox.getAt(any)).thenThrow(fixture.exception); + + final sut = fixture.getSut(injectMockBox: true); + + await sut.add(Person('John Malkovich')); + try { + await sut.getAt(0); + } catch (error) { + expect(error, fixture.exception); + } + + verifyBreadcrumb( + 'getAt', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + }); } class Fixture { @@ -139,6 +255,7 @@ class Fixture { final _context = SentryTransactionContext('name', 'operation'); late final tracer = SentryTracer(_context, hub); + late final scope = Scope(options); Future setUp() async { Hive.init(Directory.systemTemp.path); @@ -167,4 +284,8 @@ class Fixture { SentrySpan? getCreatedSpan() { return tracer.children.last; } + + Breadcrumb? getCreatedBreadcrumb() { + return hub.scope.breadcrumbs.last; + } } diff --git a/isar/.gitignore b/isar/.gitignore new file mode 100644 index 0000000000..fdd96ceb43 --- /dev/null +++ b/isar/.gitignore @@ -0,0 +1,17 @@ +# Omit committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Downloaded on demand by tests for correct architecture. +libisar.dylib diff --git a/isar/.metadata b/isar/.metadata new file mode 100644 index 0000000000..eea17bc4a0 --- /dev/null +++ b/isar/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2f708eb8396e362e280fac22cf171c2cb467343c" + channel: "stable" + +project_type: package diff --git a/isar/CHANGELOG.md b/isar/CHANGELOG.md new file mode 120000 index 0000000000..04c99a55ca --- /dev/null +++ b/isar/CHANGELOG.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/isar/LICENSE b/isar/LICENSE new file mode 100644 index 0000000000..2a6964d84d --- /dev/null +++ b/isar/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Sentry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/isar/README.md b/isar/README.md new file mode 100644 index 0000000000..011e8e834f --- /dev/null +++ b/isar/README.md @@ -0,0 +1,84 @@ +

+ + + +
+

+ +Sentry integration for `isar` package +=========== + +| package | build | pub | likes | popularity | pub points | +| ------- | ------- | ------- | ------- | ------- | ------- | +| sentry_isar | [![build](https://github.com/getsentry/sentry-dart/actions/workflows/isar.yml/badge.svg?branch=main)](https://github.com/getsentry/sentry-dart/actions?query=workflow%3Asentry-isar) | [![pub package](https://img.shields.io/pub/v/sentry_isar.svg)](https://pub.dev/packages/sentry_isar) | [![likes](https://img.shields.io/pub/likes/sentry_isar)](https://pub.dev/packages/sentry_isar/score) | [![popularity](https://img.shields.io/pub/popularity/sentry_isar)](https://pub.dev/packages/sentry_isar/score) | [![pub points](https://img.shields.io/pub/points/sentry_isar)](https://pub.dev/packages/sentry_isar/score) + +Integration for the [`isar`](https://pub.dev/packages/isar) package. + +#### Usage + +- Sign up for a Sentry.io account and get a DSN at https://sentry.io. + +- Follow the installing instructions on [pub.dev](https://pub.dev/packages/sentry/install). + +- Initialize the Sentry SDK using the DSN issued by Sentry.io. + +- Call... + +```dart +import 'package:path_provider/path_provider.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_isar/sentry_isar.dart'; + +import 'user.dart'; + +Future main() async { + await SentryFlutter.init( + (options) { + options.dsn = 'https://example@sentry.io/add-your-dsn-here'; + options.tracesSampleRate = 1.0; + }, + // Init your App. + appRunner: () => runApp(MyApp()), + ); +} + +Future runApp() async { + final tr = Sentry.startTransaction( + 'isarTest', + 'db', + bindToScope: true, + ); + + final dir = await getApplicationDocumentsDirectory(); + + final isar = await SentryIsar.open( + [UserSchema], + directory: dir.path, + ); + + final newUser = User() + ..name = 'Joe Dirt' + ..age = 36; + + await isar.writeTxn(() async { + await isar.users.put(newUser); // insert & update + }); + + final existingUser = await isar.users.get(newUser.id); // get + + await isar.writeTxn(() async { + await isar.users.delete(existingUser!.id); // delete + }); + + await tr.finish(status: const SpanStatus.ok()); +} +``` + +#### Resources + +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) +* [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) +* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) diff --git a/isar/analysis_options.yaml b/isar/analysis_options.yaml new file mode 100644 index 0000000000..92c8931384 --- /dev/null +++ b/isar/analysis_options.yaml @@ -0,0 +1,33 @@ +include: package:lints/recommended.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + errors: + # treat missing required parameters as a warning (not a hint) + missing_required_param: error + # treat missing returns as a warning (not a hint) + missing_return: error + # allow having TODOs in the code + todo: ignore + # allow self-reference to deprecated members (we do this because otherwise we have + # to annotate every member in every test, assert, etc, when we deprecate something) + deprecated_member_use_from_same_package: warning + # ignore sentry/path on pubspec as we change it on deployment + invalid_dependency: ignore + unnecessary_import: ignore + exclude: + - example/** + +linter: + rules: + - prefer_final_locals + - public_member_api_docs + - prefer_single_quotes + - prefer_relative_imports + - unnecessary_brace_in_string_interps + - implementation_imports + - require_trailing_commas + - unawaited_futures diff --git a/isar/dartdoc_options.yaml b/isar/dartdoc_options.yaml new file mode 120000 index 0000000000..7cbb8c0d74 --- /dev/null +++ b/isar/dartdoc_options.yaml @@ -0,0 +1 @@ +../dart/dartdoc_options.yaml \ No newline at end of file diff --git a/isar/example/main.dart b/isar/example/main.dart new file mode 100644 index 0000000000..7c9972b50d --- /dev/null +++ b/isar/example/main.dart @@ -0,0 +1,47 @@ +import 'package:path_provider/path_provider.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_isar/sentry_isar.dart'; + +import 'user.dart'; + +Future main() async { + // ATTENTION: Change the DSN below with your own to see the events in Sentry. Get one at sentry.io + const dsn = + 'https://e85b375ffb9f43cf8bdf9787768149e0@o447951.ingest.sentry.io/5428562'; + + await SentryFlutter.init( + (options) { + options.dsn = dsn; + options.tracesSampleRate = 1.0; + options.debug = true; + }, + appRunner: runApp, // Init your App. + ); +} + +Future runApp() async { + final tr = Sentry.startTransaction('isar', 'db', bindToScope: true); + + final dir = await getApplicationDocumentsDirectory(); + + final isar = await SentryIsar.open( + [UserSchema], + directory: dir.path, + ); + + final newUser = User() + ..name = 'Joe Dirt' + ..age = 36; + + await isar.writeTxn(() async { + await isar.users.put(newUser); // insert & update + }); + + final existingUser = await isar.users.get(newUser.id); // get + + await isar.writeTxn(() async { + await isar.users.delete(existingUser!.id); // delete + }); + + await tr.finish(status: const SpanStatus.ok()); +} diff --git a/isar/example/user.dart b/isar/example/user.dart new file mode 100644 index 0000000000..f255d2389d --- /dev/null +++ b/isar/example/user.dart @@ -0,0 +1,12 @@ +import 'package:isar/isar.dart'; + +part 'user.g.dart'; + +@collection +class User { + Id id = Isar.autoIncrement; + + String? name; + + int? age; +} diff --git a/isar/example/user.g.dart b/isar/example/user.g.dart new file mode 100644 index 0000000000..370c40860f --- /dev/null +++ b/isar/example/user.g.dart @@ -0,0 +1,553 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user.dart'; + +// ************************************************************************** +// IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types + +extension GetUserCollection on Isar { + IsarCollection get users => this.collection(); +} + +const UserSchema = CollectionSchema( + name: r'User', + id: -7838171048429979076, + properties: { + r'age': PropertySchema( + id: 0, + name: r'age', + type: IsarType.long, + ), + r'name': PropertySchema( + id: 1, + name: r'name', + type: IsarType.string, + ) + }, + estimateSize: _userEstimateSize, + serialize: _userSerialize, + deserialize: _userDeserialize, + deserializeProp: _userDeserializeProp, + idName: r'id', + indexes: {}, + links: {}, + embeddedSchemas: {}, + getId: _userGetId, + getLinks: _userGetLinks, + attach: _userAttach, + version: '3.1.0+1', +); + +int _userEstimateSize( + User object, + List offsets, + Map> allOffsets, +) { + var bytesCount = offsets.last; + { + final value = object.name; + if (value != null) { + bytesCount += 3 + value.length * 3; + } + } + return bytesCount; +} + +void _userSerialize( + User object, + IsarWriter writer, + List offsets, + Map> allOffsets, +) { + writer.writeLong(offsets[0], object.age); + writer.writeString(offsets[1], object.name); +} + +User _userDeserialize( + Id id, + IsarReader reader, + List offsets, + Map> allOffsets, +) { + final object = User(); + object.age = reader.readLongOrNull(offsets[0]); + object.id = id; + object.name = reader.readStringOrNull(offsets[1]); + return object; +} + +P _userDeserializeProp

( + IsarReader reader, + int propertyId, + int offset, + Map> allOffsets, +) { + switch (propertyId) { + case 0: + return (reader.readLongOrNull(offset)) as P; + case 1: + return (reader.readStringOrNull(offset)) as P; + default: + throw IsarError('Unknown property with id $propertyId'); + } +} + +Id _userGetId(User object) { + return object.id; +} + +List> _userGetLinks(User object) { + return []; +} + +void _userAttach(IsarCollection col, Id id, User object) { + object.id = id; +} + +extension UserQueryWhereSort on QueryBuilder { + QueryBuilder anyId() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(const IdWhereClause.any()); + }); + } +} + +extension UserQueryWhere on QueryBuilder { + QueryBuilder idEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: id, + upper: id, + )); + }); + } + + QueryBuilder idNotEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ) + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ); + } else { + return query + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ) + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ); + } + }); + } + + QueryBuilder idGreaterThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: include), + ); + }); + } + + QueryBuilder idLessThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: include), + ); + }); + } + + QueryBuilder idBetween( + Id lowerId, + Id upperId, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + )); + }); + } +} + +extension UserQueryFilter on QueryBuilder { + QueryBuilder ageIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'age', + )); + }); + } + + QueryBuilder ageIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'age', + )); + }); + } + + QueryBuilder ageEqualTo(int? value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'age', + value: value, + )); + }); + } + + QueryBuilder ageGreaterThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'age', + value: value, + )); + }); + } + + QueryBuilder ageLessThan( + int? value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'age', + value: value, + )); + }); + } + + QueryBuilder ageBetween( + int? lower, + int? upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'age', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder idEqualTo(Id value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idGreaterThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idLessThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idBetween( + Id lower, + Id upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder nameIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'name', + )); + }); + } + + QueryBuilder nameIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'name', + )); + }); + } + + QueryBuilder nameEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameGreaterThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameLessThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameBetween( + String? lower, + String? upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'name', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameContains(String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameMatches(String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'name', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: '', + )); + }); + } + + QueryBuilder nameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'name', + value: '', + )); + }); + } +} + +extension UserQueryObject on QueryBuilder {} + +extension UserQueryLinks on QueryBuilder {} + +extension UserQuerySortBy on QueryBuilder { + QueryBuilder sortByAge() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.asc); + }); + } + + QueryBuilder sortByAgeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.desc); + }); + } + + QueryBuilder sortByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder sortByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension UserQuerySortThenBy on QueryBuilder { + QueryBuilder thenByAge() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.asc); + }); + } + + QueryBuilder thenByAgeDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'age', Sort.desc); + }); + } + + QueryBuilder thenById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.asc); + }); + } + + QueryBuilder thenByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.desc); + }); + } + + QueryBuilder thenByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder thenByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension UserQueryWhereDistinct on QueryBuilder { + QueryBuilder distinctByAge() { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'age'); + }); + } + + QueryBuilder distinctByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'name', caseSensitive: caseSensitive); + }); + } +} + +extension UserQueryProperty on QueryBuilder { + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'id'); + }); + } + + QueryBuilder ageProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'age'); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'name'); + }); + } +} diff --git a/isar/lib/sentry_isar.dart b/isar/lib/sentry_isar.dart new file mode 100644 index 0000000000..75e63c47ea --- /dev/null +++ b/isar/lib/sentry_isar.dart @@ -0,0 +1,4 @@ +library sentry_isar; + +export 'src/sentry_isar.dart'; +export 'src/sentry_isar_collection.dart'; diff --git a/isar/lib/src/sentry_isar.dart b/isar/lib/src/sentry_isar.dart new file mode 100644 index 0000000000..e6e174a8eb --- /dev/null +++ b/isar/lib/src/sentry_isar.dart @@ -0,0 +1,253 @@ +import 'package:isar/isar.dart'; +import 'package:meta/meta.dart'; +import 'package:sentry/sentry.dart'; +import 'version.dart'; + +import 'sentry_isar_collection.dart'; +import 'sentry_span_helper.dart'; + +/// A sentry wrapper around the Isar Database +@experimental +class SentryIsar implements Isar { + @internal + // ignore: public_member_api_docs + static const dbOp = 'db'; + + @internal + // ignore: public_member_api_docs + static const dbSystemKey = 'db.system'; + @internal + // ignore: public_member_api_docs + static const dbSystem = 'isar'; + + @internal + // ignore: public_member_api_docs + static const dbNameKey = 'db.name'; + + @internal + // ignore: public_member_api_docs + static const dbCollectionKey = 'db.collection'; + + final Isar _isar; + final Hub _hub; + final _spanHelper = SentrySpanHelper( + // ignore: invalid_use_of_internal_member + SentryTraceOrigins.autoDbIsar, + ); + + /// ctor of SentryIsar + SentryIsar(this._isar, this._hub) { + _spanHelper.setHub(_hub); + + // ignore: invalid_use_of_internal_member + final options = _hub.options; + options.sdk.addIntegration('SentryIsarTracing'); + options.sdk.addPackage(packageName, sdkVersion); + } + + /// Open a new Isar instance, wrapped by SentryIsar + static Future open( + List> schemas, { + required String directory, + String name = Isar.defaultName, + int maxSizeMiB = Isar.defaultMaxSizeMiB, + bool relaxedDurability = true, + CompactCondition? compactOnLaunch, + bool inspector = true, + Hub? hub, + }) async { + final spanHelper = SentrySpanHelper( + // ignore: invalid_use_of_internal_member + SentryTraceOrigins.autoDbIsar, + ); + final hubToUse = hub ?? HubAdapter(); + spanHelper.setHub(hubToUse); + + final isar = await spanHelper.asyncWrapInSpan( + 'open', + () async { + return await Isar.open( + schemas, + directory: directory, + name: name, + maxSizeMiB: maxSizeMiB, + relaxedDurability: relaxedDurability, + compactOnLaunch: compactOnLaunch, + inspector: inspector, + ); + }, + dbName: name, + ); + + return SentryIsar(isar, hubToUse); + } + + /// Open a new Isar instance, wrapped by SentryIsar + static Isar openSync( + List> schemas, { + required String directory, + String name = Isar.defaultName, + int maxSizeMiB = Isar.defaultMaxSizeMiB, + bool relaxedDurability = true, + CompactCondition? compactOnLaunch, + bool inspector = true, + Hub? hub, + }) { + final isar = Isar.openSync( + schemas, + directory: directory, + name: name, + maxSizeMiB: maxSizeMiB, + relaxedDurability: relaxedDurability, + compactOnLaunch: compactOnLaunch, + inspector: inspector, + ); + return SentryIsar(isar, hub ?? HubAdapter()); + } + + @override + void attachCollections(Map> collections) { + _isar.attachCollections(collections); + } + + @override + Future clear() { + return _spanHelper.asyncWrapInSpan( + 'clear', + () { + return _isar.clear(); + }, + dbName: name, + ); + } + + @override + void clearSync() { + _isar.clearSync(); + } + + @override + Future close({bool deleteFromDisk = false}) { + return _spanHelper.asyncWrapInSpan( + 'close', + () { + return _isar.close(deleteFromDisk: deleteFromDisk); + }, + dbName: name, + ); + } + + @override + IsarCollection collection() { + return SentryIsarCollection(_isar.collection(), _hub, name); + } + + @override + Future copyToFile(String targetPath) { + return _spanHelper.asyncWrapInSpan( + 'copyToFile', + () { + return _isar.copyToFile(targetPath); + }, + dbName: name, + ); + } + + @override + String? get directory => _isar.directory; + + @override + IsarCollection? getCollectionByNameInternal(String name) { + final collection = _isar.getCollectionByNameInternal(name); + if (collection != null) { + return SentryIsarCollection(collection, _hub, name); + } else { + return null; + } + } + + @override + Future getSize({ + bool includeIndexes = false, + bool includeLinks = false, + }) { + return _spanHelper.asyncWrapInSpan( + 'getSize', + () { + return _isar.getSize( + includeIndexes: includeIndexes, + includeLinks: includeLinks, + ); + }, + dbName: name, + ); + } + + @override + int getSizeSync({bool includeIndexes = false, bool includeLinks = false}) { + return _isar.getSizeSync( + includeIndexes: includeIndexes, + includeLinks: includeLinks, + ); + } + + @override + bool get isOpen => _isar.isOpen; + + @override + String get name => _isar.name; + + @override + String? get path => _isar.path; + + @override + void requireOpen() { + _isar.requireOpen(); + } + + @override + Future txn(Future Function() callback) { + return _spanHelper.asyncWrapInSpan( + 'txn', + () { + return _isar.txn(callback); + }, + dbName: name, + ); + } + + @override + T txnSync(T Function() callback) { + return _isar.txnSync(callback); + } + + @override + @visibleForTesting + @experimental + Future verify() { + return _spanHelper.asyncWrapInSpan( + 'verify', + () { + // ignore: invalid_use_of_visible_for_testing_member + return _isar.verify(); + }, + dbName: name, + ); + } + + @override + Future writeTxn(Future Function() callback, {bool silent = false}) { + return _spanHelper.asyncWrapInSpan( + 'writeTxn', + () { + return _isar.writeTxn(callback, silent: silent); + }, + dbName: name, + ); + } + + @override + T writeTxnSync(T Function() callback, {bool silent = false}) { + return _isar.writeTxnSync(callback, silent: silent); + } +} diff --git a/isar/lib/src/sentry_isar_collection.dart b/isar/lib/src/sentry_isar_collection.dart new file mode 100644 index 0000000000..3f85242bbe --- /dev/null +++ b/isar/lib/src/sentry_isar_collection.dart @@ -0,0 +1,433 @@ +import 'dart:typed_data'; +import 'package:isar/isar.dart'; +import 'package:meta/meta.dart'; +import 'package:sentry/sentry.dart'; + +import 'sentry_span_helper.dart'; + +/// Sentry wrapper around IsarCollection +@experimental +class SentryIsarCollection implements IsarCollection { + final IsarCollection _isarCollection; + final Hub _hub; + final String _dbName; + + final _spanHelper = SentrySpanHelper( + // ignore: invalid_use_of_internal_member + SentryTraceOrigins.autoDbIsarCollection, + ); + + /// ctor of SentryIsarCollection + SentryIsarCollection(this._isarCollection, this._hub, this._dbName) { + _spanHelper.setHub(_hub); + } + + @override + Query buildQuery({ + List whereClauses = const [], + bool whereDistinct = false, + Sort whereSort = Sort.asc, + FilterOperation? filter, + List sortBy = const [], + List distinctBy = const [], + int? offset, + int? limit, + String? property, + }) { + return _isarCollection.buildQuery( + whereClauses: whereClauses, + whereDistinct: whereDistinct, + whereSort: whereSort, + filter: filter, + sortBy: sortBy, + distinctBy: distinctBy, + offset: offset, + limit: limit, + property: property, + ); + } + + @override + Future clear() { + return _spanHelper.asyncWrapInSpan( + 'clear', + () { + return _isarCollection.clear(); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + void clearSync() { + _isarCollection.clearSync(); + } + + @override + Future count() { + return _spanHelper.asyncWrapInSpan( + 'count', + () { + return _isarCollection.count(); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + int countSync() { + return _isarCollection.countSync(); + } + + @override + Future delete(Id id) { + return _spanHelper.asyncWrapInSpan( + 'delete', + () { + return _isarCollection.delete(id); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Future deleteAll(List ids) { + return _spanHelper.asyncWrapInSpan( + 'deleteAll', + () { + return _isarCollection.deleteAll(ids); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Future deleteAllByIndex(String indexName, List keys) { + return _spanHelper.asyncWrapInSpan( + 'deleteAllByIndex', + () { + return _isarCollection.deleteAllByIndex(indexName, keys); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + int deleteAllByIndexSync(String indexName, List keys) { + return _isarCollection.deleteAllByIndexSync(indexName, keys); + } + + @override + int deleteAllSync(List ids) { + return _isarCollection.deleteAllSync(ids); + } + + @override + Future deleteByIndex(String indexName, IndexKey key) { + return _spanHelper.asyncWrapInSpan( + 'deleteByIndex', + () { + return _isarCollection.deleteByIndex(indexName, key); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + bool deleteByIndexSync(String indexName, IndexKey key) { + return _isarCollection.deleteByIndexSync(indexName, key); + } + + @override + bool deleteSync(Id id) { + return _isarCollection.deleteSync(id); + } + + @override + QueryBuilder filter() { + return _isarCollection.filter(); + } + + @override + Future get(Id id) { + return _spanHelper.asyncWrapInSpan( + 'get', + () { + return _isarCollection.get(id); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Future> getAll(List ids) { + return _spanHelper.asyncWrapInSpan( + 'getAll', + () { + return _isarCollection.getAll(ids); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Future> getAllByIndex(String indexName, List keys) { + return _spanHelper.asyncWrapInSpan( + 'getAllByIndex', + () { + return _isarCollection.getAllByIndex(indexName, keys); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + List getAllByIndexSync(String indexName, List keys) { + return _isarCollection.getAllByIndexSync(indexName, keys); + } + + @override + List getAllSync(List ids) { + return _isarCollection.getAllSync(ids); + } + + @override + Future getByIndex(String indexName, IndexKey key) { + return _spanHelper.asyncWrapInSpan( + 'getByIndex', + () { + return _isarCollection.getByIndex(indexName, key); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + OBJ? getByIndexSync(String indexName, IndexKey key) { + return _isarCollection.getByIndexSync(indexName, key); + } + + @override + Future getSize({ + bool includeIndexes = false, + bool includeLinks = false, + }) { + return _spanHelper.asyncWrapInSpan( + 'getSize', + () { + return _isarCollection.getSize( + includeIndexes: includeIndexes, + includeLinks: includeLinks, + ); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + int getSizeSync({bool includeIndexes = false, bool includeLinks = false}) { + return _isarCollection.getSizeSync( + includeIndexes: includeIndexes, + includeLinks: includeLinks, + ); + } + + @override + OBJ? getSync(Id id) { + return _isarCollection.getSync(id); + } + + @override + Future importJson(List> json) { + return _spanHelper.asyncWrapInSpan( + 'importJson', + () { + return _isarCollection.importJson(json); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Future importJsonRaw(Uint8List jsonBytes) { + return _spanHelper.asyncWrapInSpan( + 'importJsonRaw', + () { + return _isarCollection.importJsonRaw(jsonBytes); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + void importJsonRawSync(Uint8List jsonBytes) { + _isarCollection.importJsonRawSync(jsonBytes); + } + + @override + void importJsonSync(List> json) { + _isarCollection.importJsonSync(json); + } + + @override + Isar get isar => _isarCollection.isar; + + @override + String get name => _isarCollection.name; + + @override + Future put(OBJ object) { + return _spanHelper.asyncWrapInSpan( + 'put', + () { + return _isarCollection.put(object); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Future> putAll(List objects) { + return _spanHelper.asyncWrapInSpan( + 'putAll', + () { + return _isarCollection.putAll(objects); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Future> putAllByIndex(String indexName, List objects) { + return _spanHelper.asyncWrapInSpan( + 'putAllByIndex', + () { + return _isarCollection.putAllByIndex(indexName, objects); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + List putAllByIndexSync( + String indexName, + List objects, { + bool saveLinks = true, + }) { + return _isarCollection.putAllByIndexSync( + indexName, + objects, + saveLinks: saveLinks, + ); + } + + @override + List putAllSync(List objects, {bool saveLinks = true}) { + return _isarCollection.putAllSync(objects, saveLinks: saveLinks); + } + + @override + Future putByIndex(String indexName, OBJ object) { + return _spanHelper.asyncWrapInSpan( + 'putByIndex', + () { + return _isarCollection.putByIndex(indexName, object); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Id putByIndexSync(String indexName, OBJ object, {bool saveLinks = true}) { + return _isarCollection.putByIndexSync( + indexName, + object, + saveLinks: saveLinks, + ); + } + + @override + Id putSync(OBJ object, {bool saveLinks = true}) { + return _isarCollection.putSync(object, saveLinks: saveLinks); + } + + @override + CollectionSchema get schema => _isarCollection.schema; + + @override + @visibleForTesting + @experimental + Future verify(List objects) { + return _spanHelper.asyncWrapInSpan( + 'verify', + () { + // ignore: invalid_use_of_visible_for_testing_member + return _isarCollection.verify(objects); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + @visibleForTesting + @experimental + Future verifyLink( + String linkName, + List sourceIds, + List targetIds, + ) { + return _spanHelper.asyncWrapInSpan( + 'verifyLink', + () { + // ignore: invalid_use_of_visible_for_testing_member + return _isarCollection.verifyLink(linkName, sourceIds, targetIds); + }, + dbName: _dbName, + collectionName: name, + ); + } + + @override + Stream watchLazy({bool fireImmediately = false}) { + return _isarCollection.watchLazy(fireImmediately: fireImmediately); + } + + @override + Stream watchObject(Id id, {bool fireImmediately = false}) { + return _isarCollection.watchObject(id, fireImmediately: fireImmediately); + } + + @override + Stream watchObjectLazy(Id id, {bool fireImmediately = false}) { + return _isarCollection.watchObjectLazy( + id, + fireImmediately: fireImmediately, + ); + } + + @override + QueryBuilder where({ + bool distinct = false, + Sort sort = Sort.asc, + }) { + return _isarCollection.where(distinct: distinct, sort: sort); + } +} diff --git a/isar/lib/src/sentry_span_helper.dart b/isar/lib/src/sentry_span_helper.dart new file mode 100644 index 0000000000..ec1823c7ca --- /dev/null +++ b/isar/lib/src/sentry_span_helper.dart @@ -0,0 +1,83 @@ +// ignore_for_file: invalid_internal_annotation + +import 'package:meta/meta.dart'; +import 'package:sentry/sentry.dart'; +import 'sentry_isar.dart'; + +/// @nodoc +@internal +class SentrySpanHelper { + /// @nodoc + Hub _hub = HubAdapter(); + + /// @nodoc + final String _origin; + + /// @nodoc + SentrySpanHelper(this._origin); + + /// @nodoc + void setHub(Hub hub) { + _hub = hub; + } + + /// @nodoc + @internal + Future asyncWrapInSpan( + String description, + Future Function() execute, { + String? dbName, + String? collectionName, + }) async { + final currentSpan = _hub.getSpan(); + final span = currentSpan?.startChild( + SentryIsar.dbOp, + description: description, + ); + + // ignore: invalid_use_of_internal_member + span?.origin = _origin; + + var breadcrumb = Breadcrumb( + message: description, + data: {}, + type: 'query', + ); + + span?.setData(SentryIsar.dbSystemKey, SentryIsar.dbSystem); + + if (dbName != null) { + span?.setData(SentryIsar.dbNameKey, dbName); + breadcrumb.data?[SentryIsar.dbNameKey] = dbName; + } + + if (collectionName != null) { + span?.setData(SentryIsar.dbCollectionKey, collectionName); + breadcrumb.data?[SentryIsar.dbCollectionKey] = collectionName; + } + + try { + final result = await execute(); + + span?.status = SpanStatus.ok(); + breadcrumb.data?['status'] = 'ok'; + + return result; + } catch (exception) { + span?.throwable = exception; + span?.status = SpanStatus.internalError(); + + breadcrumb.data?['status'] = 'internal_error'; + breadcrumb = breadcrumb.copyWith( + level: SentryLevel.warning, + ); + + rethrow; + } finally { + await span?.finish(); + + // ignore: invalid_use_of_internal_member + await _hub.scope.addBreadcrumb(breadcrumb); + } + } +} diff --git a/isar/lib/src/version.dart b/isar/lib/src/version.dart new file mode 100644 index 0000000000..c215620372 --- /dev/null +++ b/isar/lib/src/version.dart @@ -0,0 +1,5 @@ +/// The SDK version reported to Sentry.io in the submitted events. +const String sdkVersion = '8.3.0'; + +/// The package name reported to Sentry.io in the submitted events. +const String packageName = 'pub:sentry_isar'; diff --git a/isar/pubspec.yaml b/isar/pubspec.yaml new file mode 100644 index 0000000000..cbafa2af80 --- /dev/null +++ b/isar/pubspec.yaml @@ -0,0 +1,36 @@ +name: sentry_isar +description: An integration which adds support for performance tracing for the isar package. +version: 8.3.0 +homepage: https://docs.sentry.io/platforms/flutter/ +repository: https://github.com/getsentry/sentry-dart +issue_tracker: https://github.com/getsentry/sentry-dart/issues + +environment: + sdk: '>=2.17.0 <4.0.0' + flutter: '>=3.3.0' + +platforms: + android: + ios: + macos: + linux: + windows: + web: + +dependencies: + isar: ^3.1.0 + isar_flutter_libs: ^3.1.0 # contains Isar Core + sentry: 8.3.0 + meta: ^1.3.0 + path: ^1.8.3 + +dev_dependencies: + isar_generator: ^3.1.0 + build_runner: ^2.4.6 + lints: ^3.0.0 + flutter_test: + sdk: flutter + coverage: ^1.3.0 + mockito: ^5.1.0 + yaml: ^3.1.0 # needed for version match (code and pubspec) + path_provider: ^2.1.1 diff --git a/isar/pubspec_overrides.yaml b/isar/pubspec_overrides.yaml new file mode 100644 index 0000000000..16e71d16f0 --- /dev/null +++ b/isar/pubspec_overrides.yaml @@ -0,0 +1,3 @@ +dependency_overrides: + sentry: + path: ../dart diff --git a/isar/test/mocks/mocks.dart b/isar/test/mocks/mocks.dart new file mode 100644 index 0000000000..55f59b6de3 --- /dev/null +++ b/isar/test/mocks/mocks.dart @@ -0,0 +1,10 @@ +import 'package:isar/isar.dart'; +import 'package:mockito/annotations.dart'; +import 'package:sentry/sentry.dart'; + +@GenerateMocks([ + Hub, + Isar, + IsarCollection, +]) +void main() {} diff --git a/isar/test/mocks/mocks.mocks.dart b/isar/test/mocks/mocks.mocks.dart new file mode 100644 index 0000000000..4f7adfed86 --- /dev/null +++ b/isar/test/mocks/mocks.mocks.dart @@ -0,0 +1,1340 @@ +// Mocks generated by Mockito 5.4.2 from annotations +// in sentry_isar/test/mocks/mocks.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes, invalid_use_of_internal_member +import 'dart:async' as _i3; +import 'dart:typed_data' as _i7; + +import 'package:isar/isar.dart' as _i4; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i6; +import 'package:sentry/sentry.dart' as _i2; +import 'package:sentry/src/profiling.dart' as _i5; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeSentryOptions_0 extends _i1.SmartFake implements _i2.SentryOptions { + _FakeSentryOptions_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSentryId_1 extends _i1.SmartFake implements _i2.SentryId { + _FakeSentryId_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeScope_2 extends _i1.SmartFake implements _i2.Scope { + _FakeScope_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeHub_3 extends _i1.SmartFake implements _i2.Hub { + _FakeHub_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeISentrySpan_4 extends _i1.SmartFake implements _i2.ISentrySpan { + _FakeISentrySpan_4( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeFuture_5 extends _i1.SmartFake implements _i3.Future { + _FakeFuture_5( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeIsarCollection_6 extends _i1.SmartFake + implements _i4.IsarCollection { + _FakeIsarCollection_6( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeIsar_7 extends _i1.SmartFake implements _i4.Isar { + _FakeIsar_7( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeCollectionSchema_8 extends _i1.SmartFake + implements _i4.CollectionSchema { + _FakeCollectionSchema_8( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeQueryBuilder_9 extends _i1.SmartFake + implements _i4.QueryBuilder { + _FakeQueryBuilder_9( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeQuery_10 extends _i1.SmartFake implements _i4.Query { + _FakeQuery_10( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [Hub]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockHub extends _i1.Mock implements _i2.Hub { + MockHub() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.SentryOptions get options => (super.noSuchMethod( + Invocation.getter(#options), + returnValue: _FakeSentryOptions_0( + this, + Invocation.getter(#options), + ), + ) as _i2.SentryOptions); + + @override + bool get isEnabled => (super.noSuchMethod( + Invocation.getter(#isEnabled), + returnValue: false, + ) as bool); + + @override + _i2.SentryId get lastEventId => (super.noSuchMethod( + Invocation.getter(#lastEventId), + returnValue: _FakeSentryId_1( + this, + Invocation.getter(#lastEventId), + ), + ) as _i2.SentryId); + + @override + _i2.Scope get scope => (super.noSuchMethod( + Invocation.getter(#scope), + returnValue: _FakeScope_2( + this, + Invocation.getter(#scope), + ), + ) as _i2.Scope); + + @override + set profilerFactory(_i5.SentryProfilerFactory? value) => super.noSuchMethod( + Invocation.setter( + #profilerFactory, + value, + ), + returnValueForMissingStub: null, + ); + + @override + _i3.Future<_i2.SentryId> captureEvent( + _i2.SentryEvent? event, { + dynamic stackTrace, + _i2.Hint? hint, + _i2.ScopeCallback? withScope, + }) => + (super.noSuchMethod( + Invocation.method( + #captureEvent, + [event], + { + #stackTrace: stackTrace, + #hint: hint, + #withScope: withScope, + }, + ), + returnValue: _i3.Future<_i2.SentryId>.value(_FakeSentryId_1( + this, + Invocation.method( + #captureEvent, + [event], + { + #stackTrace: stackTrace, + #hint: hint, + #withScope: withScope, + }, + ), + )), + ) as _i3.Future<_i2.SentryId>); + + @override + _i3.Future<_i2.SentryId> captureException( + dynamic throwable, { + dynamic stackTrace, + _i2.Hint? hint, + _i2.ScopeCallback? withScope, + }) => + (super.noSuchMethod( + Invocation.method( + #captureException, + [throwable], + { + #stackTrace: stackTrace, + #hint: hint, + #withScope: withScope, + }, + ), + returnValue: _i3.Future<_i2.SentryId>.value(_FakeSentryId_1( + this, + Invocation.method( + #captureException, + [throwable], + { + #stackTrace: stackTrace, + #hint: hint, + #withScope: withScope, + }, + ), + )), + ) as _i3.Future<_i2.SentryId>); + + @override + _i3.Future<_i2.SentryId> captureMessage( + String? message, { + _i2.SentryLevel? level, + String? template, + List? params, + _i2.Hint? hint, + _i2.ScopeCallback? withScope, + }) => + (super.noSuchMethod( + Invocation.method( + #captureMessage, + [message], + { + #level: level, + #template: template, + #params: params, + #hint: hint, + #withScope: withScope, + }, + ), + returnValue: _i3.Future<_i2.SentryId>.value(_FakeSentryId_1( + this, + Invocation.method( + #captureMessage, + [message], + { + #level: level, + #template: template, + #params: params, + #hint: hint, + #withScope: withScope, + }, + ), + )), + ) as _i3.Future<_i2.SentryId>); + + @override + _i3.Future captureUserFeedback(_i2.SentryUserFeedback? userFeedback) => + (super.noSuchMethod( + Invocation.method( + #captureUserFeedback, + [userFeedback], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future addBreadcrumb( + _i2.Breadcrumb? crumb, { + _i2.Hint? hint, + }) => + (super.noSuchMethod( + Invocation.method( + #addBreadcrumb, + [crumb], + {#hint: hint}, + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + void bindClient(_i2.SentryClient? client) => super.noSuchMethod( + Invocation.method( + #bindClient, + [client], + ), + returnValueForMissingStub: null, + ); + + @override + _i2.Hub clone() => (super.noSuchMethod( + Invocation.method( + #clone, + [], + ), + returnValue: _FakeHub_3( + this, + Invocation.method( + #clone, + [], + ), + ), + ) as _i2.Hub); + + @override + _i3.Future close() => (super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.FutureOr configureScope(_i2.ScopeCallback? callback) => + (super.noSuchMethod(Invocation.method( + #configureScope, + [callback], + )) as _i3.FutureOr); + + @override + _i2.ISentrySpan startTransaction( + String? name, + String? operation, { + String? description, + DateTime? startTimestamp, + bool? bindToScope, + bool? waitForChildren, + Duration? autoFinishAfter, + bool? trimEnd, + _i2.OnTransactionFinish? onFinish, + Map? customSamplingContext, + }) => + (super.noSuchMethod( + Invocation.method( + #startTransaction, + [ + name, + operation, + ], + { + #description: description, + #startTimestamp: startTimestamp, + #bindToScope: bindToScope, + #waitForChildren: waitForChildren, + #autoFinishAfter: autoFinishAfter, + #trimEnd: trimEnd, + #onFinish: onFinish, + #customSamplingContext: customSamplingContext, + }, + ), + returnValue: _FakeISentrySpan_4( + this, + Invocation.method( + #startTransaction, + [ + name, + operation, + ], + { + #description: description, + #startTimestamp: startTimestamp, + #bindToScope: bindToScope, + #waitForChildren: waitForChildren, + #autoFinishAfter: autoFinishAfter, + #trimEnd: trimEnd, + #onFinish: onFinish, + #customSamplingContext: customSamplingContext, + }, + ), + ), + ) as _i2.ISentrySpan); + + @override + _i2.ISentrySpan startTransactionWithContext( + _i2.SentryTransactionContext? transactionContext, { + Map? customSamplingContext, + DateTime? startTimestamp, + bool? bindToScope, + bool? waitForChildren, + Duration? autoFinishAfter, + bool? trimEnd, + _i2.OnTransactionFinish? onFinish, + }) => + (super.noSuchMethod( + Invocation.method( + #startTransactionWithContext, + [transactionContext], + { + #customSamplingContext: customSamplingContext, + #startTimestamp: startTimestamp, + #bindToScope: bindToScope, + #waitForChildren: waitForChildren, + #autoFinishAfter: autoFinishAfter, + #trimEnd: trimEnd, + #onFinish: onFinish, + }, + ), + returnValue: _FakeISentrySpan_4( + this, + Invocation.method( + #startTransactionWithContext, + [transactionContext], + { + #customSamplingContext: customSamplingContext, + #startTimestamp: startTimestamp, + #bindToScope: bindToScope, + #waitForChildren: waitForChildren, + #autoFinishAfter: autoFinishAfter, + #trimEnd: trimEnd, + #onFinish: onFinish, + }, + ), + ), + ) as _i2.ISentrySpan); + + @override + _i3.Future<_i2.SentryId> captureTransaction( + _i2.SentryTransaction? transaction, { + _i2.SentryTraceContextHeader? traceContext, + }) => + (super.noSuchMethod( + Invocation.method( + #captureTransaction, + [transaction], + {#traceContext: traceContext}, + ), + returnValue: _i3.Future<_i2.SentryId>.value(_FakeSentryId_1( + this, + Invocation.method( + #captureTransaction, + [transaction], + {#traceContext: traceContext}, + ), + )), + ) as _i3.Future<_i2.SentryId>); + + @override + void setSpanContext( + dynamic throwable, + _i2.ISentrySpan? span, + String? transaction, + ) => + super.noSuchMethod( + Invocation.method( + #setSpanContext, + [ + throwable, + span, + transaction, + ], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [Isar]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockIsar extends _i1.Mock implements _i4.Isar { + MockIsar() { + _i1.throwOnMissingStub(this); + } + + @override + String get name => (super.noSuchMethod( + Invocation.getter(#name), + returnValue: '', + ) as String); + + @override + bool get isOpen => (super.noSuchMethod( + Invocation.getter(#isOpen), + returnValue: false, + ) as bool); + + @override + void requireOpen() => super.noSuchMethod( + Invocation.method( + #requireOpen, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i3.Future txn(_i3.Future Function()? callback) => + (super.noSuchMethod( + Invocation.method( + #txn, + [callback], + ), + returnValue: _i6.ifNotNull( + _i6.dummyValueOrNull( + this, + Invocation.method( + #txn, + [callback], + ), + ), + (T v) => _i3.Future.value(v), + ) ?? + _FakeFuture_5( + this, + Invocation.method( + #txn, + [callback], + ), + ), + ) as _i3.Future); + + @override + _i3.Future writeTxn( + _i3.Future Function()? callback, { + bool? silent = false, + }) => + (super.noSuchMethod( + Invocation.method( + #writeTxn, + [callback], + {#silent: silent}, + ), + returnValue: _i6.ifNotNull( + _i6.dummyValueOrNull( + this, + Invocation.method( + #writeTxn, + [callback], + {#silent: silent}, + ), + ), + (T v) => _i3.Future.value(v), + ) ?? + _FakeFuture_5( + this, + Invocation.method( + #writeTxn, + [callback], + {#silent: silent}, + ), + ), + ) as _i3.Future); + + @override + T txnSync(T Function()? callback) => (super.noSuchMethod( + Invocation.method( + #txnSync, + [callback], + ), + returnValue: _i6.dummyValue( + this, + Invocation.method( + #txnSync, + [callback], + ), + ), + ) as T); + + @override + T writeTxnSync( + T Function()? callback, { + bool? silent = false, + }) => + (super.noSuchMethod( + Invocation.method( + #writeTxnSync, + [callback], + {#silent: silent}, + ), + returnValue: _i6.dummyValue( + this, + Invocation.method( + #writeTxnSync, + [callback], + {#silent: silent}, + ), + ), + ) as T); + + @override + void attachCollections(Map>? collections) => + super.noSuchMethod( + Invocation.method( + #attachCollections, + [collections], + ), + returnValueForMissingStub: null, + ); + + @override + _i4.IsarCollection collection() => (super.noSuchMethod( + Invocation.method( + #collection, + [], + ), + returnValue: _FakeIsarCollection_6( + this, + Invocation.method( + #collection, + [], + ), + ), + ) as _i4.IsarCollection); + + @override + _i4.IsarCollection? getCollectionByNameInternal(String? name) => + (super.noSuchMethod(Invocation.method( + #getCollectionByNameInternal, + [name], + )) as _i4.IsarCollection?); + + @override + _i3.Future clear() => (super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + void clearSync() => super.noSuchMethod( + Invocation.method( + #clearSync, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i3.Future getSize({ + bool? includeIndexes = false, + bool? includeLinks = false, + }) => + (super.noSuchMethod( + Invocation.method( + #getSize, + [], + { + #includeIndexes: includeIndexes, + #includeLinks: includeLinks, + }, + ), + returnValue: _i3.Future.value(0), + ) as _i3.Future); + + @override + int getSizeSync({ + bool? includeIndexes = false, + bool? includeLinks = false, + }) => + (super.noSuchMethod( + Invocation.method( + #getSizeSync, + [], + { + #includeIndexes: includeIndexes, + #includeLinks: includeLinks, + }, + ), + returnValue: 0, + ) as int); + + @override + _i3.Future copyToFile(String? targetPath) => (super.noSuchMethod( + Invocation.method( + #copyToFile, + [targetPath], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future close({bool? deleteFromDisk = false}) => (super.noSuchMethod( + Invocation.method( + #close, + [], + {#deleteFromDisk: deleteFromDisk}, + ), + returnValue: _i3.Future.value(false), + ) as _i3.Future); + + @override + _i3.Future verify() => (super.noSuchMethod( + Invocation.method( + #verify, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); +} + +/// A class which mocks [IsarCollection]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockIsarCollection extends _i1.Mock + implements _i4.IsarCollection { + MockIsarCollection() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Isar get isar => (super.noSuchMethod( + Invocation.getter(#isar), + returnValue: _FakeIsar_7( + this, + Invocation.getter(#isar), + ), + ) as _i4.Isar); + + @override + _i4.CollectionSchema get schema => (super.noSuchMethod( + Invocation.getter(#schema), + returnValue: _FakeCollectionSchema_8( + this, + Invocation.getter(#schema), + ), + ) as _i4.CollectionSchema); + + @override + String get name => (super.noSuchMethod( + Invocation.getter(#name), + returnValue: '', + ) as String); + + @override + _i3.Future get(int? id) => (super.noSuchMethod( + Invocation.method( + #get, + [id], + ), + returnValue: _i3.Future.value(), + ) as _i3.Future); + + @override + OBJ? getSync(int? id) => (super.noSuchMethod(Invocation.method( + #getSync, + [id], + )) as OBJ?); + + @override + _i3.Future> getAll(List? ids) => (super.noSuchMethod( + Invocation.method( + #getAll, + [ids], + ), + returnValue: _i3.Future>.value([]), + ) as _i3.Future>); + + @override + List getAllSync(List? ids) => (super.noSuchMethod( + Invocation.method( + #getAllSync, + [ids], + ), + returnValue: [], + ) as List); + + @override + _i3.Future getByIndex( + String? indexName, + List? key, + ) => + (super.noSuchMethod( + Invocation.method( + #getByIndex, + [ + indexName, + key, + ], + ), + returnValue: _i3.Future.value(), + ) as _i3.Future); + + @override + OBJ? getByIndexSync( + String? indexName, + List? key, + ) => + (super.noSuchMethod(Invocation.method( + #getByIndexSync, + [ + indexName, + key, + ], + )) as OBJ?); + + @override + _i3.Future> getAllByIndex( + String? indexName, + List>? keys, + ) => + (super.noSuchMethod( + Invocation.method( + #getAllByIndex, + [ + indexName, + keys, + ], + ), + returnValue: _i3.Future>.value([]), + ) as _i3.Future>); + + @override + List getAllByIndexSync( + String? indexName, + List>? keys, + ) => + (super.noSuchMethod( + Invocation.method( + #getAllByIndexSync, + [ + indexName, + keys, + ], + ), + returnValue: [], + ) as List); + + @override + _i3.Future put(OBJ? object) => (super.noSuchMethod( + Invocation.method( + #put, + [object], + ), + returnValue: _i3.Future.value(0), + ) as _i3.Future); + + @override + int putSync( + OBJ? object, { + bool? saveLinks = true, + }) => + (super.noSuchMethod( + Invocation.method( + #putSync, + [object], + {#saveLinks: saveLinks}, + ), + returnValue: 0, + ) as int); + + @override + _i3.Future> putAll(List? objects) => (super.noSuchMethod( + Invocation.method( + #putAll, + [objects], + ), + returnValue: _i3.Future>.value([]), + ) as _i3.Future>); + + @override + List putAllSync( + List? objects, { + bool? saveLinks = true, + }) => + (super.noSuchMethod( + Invocation.method( + #putAllSync, + [objects], + {#saveLinks: saveLinks}, + ), + returnValue: [], + ) as List); + + @override + _i3.Future putByIndex( + String? indexName, + OBJ? object, + ) => + (super.noSuchMethod( + Invocation.method( + #putByIndex, + [ + indexName, + object, + ], + ), + returnValue: _i3.Future.value(0), + ) as _i3.Future); + + @override + int putByIndexSync( + String? indexName, + OBJ? object, { + bool? saveLinks = true, + }) => + (super.noSuchMethod( + Invocation.method( + #putByIndexSync, + [ + indexName, + object, + ], + {#saveLinks: saveLinks}, + ), + returnValue: 0, + ) as int); + + @override + _i3.Future> putAllByIndex( + String? indexName, + List? objects, + ) => + (super.noSuchMethod( + Invocation.method( + #putAllByIndex, + [ + indexName, + objects, + ], + ), + returnValue: _i3.Future>.value([]), + ) as _i3.Future>); + + @override + List putAllByIndexSync( + String? indexName, + List? objects, { + bool? saveLinks = true, + }) => + (super.noSuchMethod( + Invocation.method( + #putAllByIndexSync, + [ + indexName, + objects, + ], + {#saveLinks: saveLinks}, + ), + returnValue: [], + ) as List); + + @override + _i3.Future delete(int? id) => (super.noSuchMethod( + Invocation.method( + #delete, + [id], + ), + returnValue: _i3.Future.value(false), + ) as _i3.Future); + + @override + bool deleteSync(int? id) => (super.noSuchMethod( + Invocation.method( + #deleteSync, + [id], + ), + returnValue: false, + ) as bool); + + @override + _i3.Future deleteAll(List? ids) => (super.noSuchMethod( + Invocation.method( + #deleteAll, + [ids], + ), + returnValue: _i3.Future.value(0), + ) as _i3.Future); + + @override + int deleteAllSync(List? ids) => (super.noSuchMethod( + Invocation.method( + #deleteAllSync, + [ids], + ), + returnValue: 0, + ) as int); + + @override + _i3.Future deleteByIndex( + String? indexName, + List? key, + ) => + (super.noSuchMethod( + Invocation.method( + #deleteByIndex, + [ + indexName, + key, + ], + ), + returnValue: _i3.Future.value(false), + ) as _i3.Future); + + @override + bool deleteByIndexSync( + String? indexName, + List? key, + ) => + (super.noSuchMethod( + Invocation.method( + #deleteByIndexSync, + [ + indexName, + key, + ], + ), + returnValue: false, + ) as bool); + + @override + _i3.Future deleteAllByIndex( + String? indexName, + List>? keys, + ) => + (super.noSuchMethod( + Invocation.method( + #deleteAllByIndex, + [ + indexName, + keys, + ], + ), + returnValue: _i3.Future.value(0), + ) as _i3.Future); + + @override + int deleteAllByIndexSync( + String? indexName, + List>? keys, + ) => + (super.noSuchMethod( + Invocation.method( + #deleteAllByIndexSync, + [ + indexName, + keys, + ], + ), + returnValue: 0, + ) as int); + + @override + _i3.Future clear() => (super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + void clearSync() => super.noSuchMethod( + Invocation.method( + #clearSync, + [], + ), + returnValueForMissingStub: null, + ); + + @override + _i3.Future importJsonRaw(_i7.Uint8List? jsonBytes) => + (super.noSuchMethod( + Invocation.method( + #importJsonRaw, + [jsonBytes], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + void importJsonRawSync(_i7.Uint8List? jsonBytes) => super.noSuchMethod( + Invocation.method( + #importJsonRawSync, + [jsonBytes], + ), + returnValueForMissingStub: null, + ); + + @override + _i3.Future importJson(List>? json) => + (super.noSuchMethod( + Invocation.method( + #importJson, + [json], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + void importJsonSync(List>? json) => super.noSuchMethod( + Invocation.method( + #importJsonSync, + [json], + ), + returnValueForMissingStub: null, + ); + + @override + _i4.QueryBuilder where({ + bool? distinct = false, + _i4.Sort? sort = _i4.Sort.asc, + }) => + (super.noSuchMethod( + Invocation.method( + #where, + [], + { + #distinct: distinct, + #sort: sort, + }, + ), + returnValue: _FakeQueryBuilder_9( + this, + Invocation.method( + #where, + [], + { + #distinct: distinct, + #sort: sort, + }, + ), + ), + ) as _i4.QueryBuilder); + + @override + _i4.QueryBuilder filter() => + (super.noSuchMethod( + Invocation.method( + #filter, + [], + ), + returnValue: _FakeQueryBuilder_9( + this, + Invocation.method( + #filter, + [], + ), + ), + ) as _i4.QueryBuilder); + + @override + _i4.Query buildQuery({ + List<_i4.WhereClause>? whereClauses = const [], + bool? whereDistinct = false, + _i4.Sort? whereSort = _i4.Sort.asc, + _i4.FilterOperation? filter, + List<_i4.SortProperty>? sortBy = const [], + List<_i4.DistinctProperty>? distinctBy = const [], + int? offset, + int? limit, + String? property, + }) => + (super.noSuchMethod( + Invocation.method( + #buildQuery, + [], + { + #whereClauses: whereClauses, + #whereDistinct: whereDistinct, + #whereSort: whereSort, + #filter: filter, + #sortBy: sortBy, + #distinctBy: distinctBy, + #offset: offset, + #limit: limit, + #property: property, + }, + ), + returnValue: _FakeQuery_10( + this, + Invocation.method( + #buildQuery, + [], + { + #whereClauses: whereClauses, + #whereDistinct: whereDistinct, + #whereSort: whereSort, + #filter: filter, + #sortBy: sortBy, + #distinctBy: distinctBy, + #offset: offset, + #limit: limit, + #property: property, + }, + ), + ), + ) as _i4.Query); + + @override + _i3.Future count() => (super.noSuchMethod( + Invocation.method( + #count, + [], + ), + returnValue: _i3.Future.value(0), + ) as _i3.Future); + + @override + int countSync() => (super.noSuchMethod( + Invocation.method( + #countSync, + [], + ), + returnValue: 0, + ) as int); + + @override + _i3.Future getSize({ + bool? includeIndexes = false, + bool? includeLinks = false, + }) => + (super.noSuchMethod( + Invocation.method( + #getSize, + [], + { + #includeIndexes: includeIndexes, + #includeLinks: includeLinks, + }, + ), + returnValue: _i3.Future.value(0), + ) as _i3.Future); + + @override + int getSizeSync({ + bool? includeIndexes = false, + bool? includeLinks = false, + }) => + (super.noSuchMethod( + Invocation.method( + #getSizeSync, + [], + { + #includeIndexes: includeIndexes, + #includeLinks: includeLinks, + }, + ), + returnValue: 0, + ) as int); + + @override + _i3.Stream watchLazy({bool? fireImmediately = false}) => + (super.noSuchMethod( + Invocation.method( + #watchLazy, + [], + {#fireImmediately: fireImmediately}, + ), + returnValue: _i3.Stream.empty(), + ) as _i3.Stream); + + @override + _i3.Stream watchObject( + int? id, { + bool? fireImmediately = false, + }) => + (super.noSuchMethod( + Invocation.method( + #watchObject, + [id], + {#fireImmediately: fireImmediately}, + ), + returnValue: _i3.Stream.empty(), + ) as _i3.Stream); + + @override + _i3.Stream watchObjectLazy( + int? id, { + bool? fireImmediately = false, + }) => + (super.noSuchMethod( + Invocation.method( + #watchObjectLazy, + [id], + {#fireImmediately: fireImmediately}, + ), + returnValue: _i3.Stream.empty(), + ) as _i3.Stream); + + @override + _i3.Future verify(List? objects) => (super.noSuchMethod( + Invocation.method( + #verify, + [objects], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future verifyLink( + String? linkName, + List? sourceIds, + List? targetIds, + ) => + (super.noSuchMethod( + Invocation.method( + #verifyLink, + [ + linkName, + sourceIds, + targetIds, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); +} diff --git a/isar/test/person.dart b/isar/test/person.dart new file mode 100644 index 0000000000..385ae69e04 --- /dev/null +++ b/isar/test/person.dart @@ -0,0 +1,11 @@ +import 'package:isar/isar.dart'; + +part 'person.g.dart'; + +@collection +class Person { + Id id = Isar.autoIncrement; + + @Index() + String? name; +} diff --git a/isar/test/person.g.dart b/isar/test/person.g.dart new file mode 100644 index 0000000000..cbd85e6fe5 --- /dev/null +++ b/isar/test/person.g.dart @@ -0,0 +1,518 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'person.dart'; + +// ************************************************************************** +// IsarCollectionGenerator +// ************************************************************************** + +// coverage:ignore-file +// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types + +extension GetPersonCollection on Isar { + IsarCollection get persons => this.collection(); +} + +const PersonSchema = CollectionSchema( + name: r'Person', + id: 7854610480646705599, + properties: { + r'name': PropertySchema( + id: 0, + name: r'name', + type: IsarType.string, + ) + }, + estimateSize: _personEstimateSize, + serialize: _personSerialize, + deserialize: _personDeserialize, + deserializeProp: _personDeserializeProp, + idName: r'id', + indexes: { + r'name': IndexSchema( + id: 879695947855722453, + name: r'name', + unique: false, + replace: false, + properties: [ + IndexPropertySchema( + name: r'name', + type: IndexType.hash, + caseSensitive: true, + ) + ], + ) + }, + links: {}, + embeddedSchemas: {}, + getId: _personGetId, + getLinks: _personGetLinks, + attach: _personAttach, + version: '3.1.0+1', +); + +int _personEstimateSize( + Person object, + List offsets, + Map> allOffsets, +) { + var bytesCount = offsets.last; + { + final value = object.name; + if (value != null) { + bytesCount += 3 + value.length * 3; + } + } + return bytesCount; +} + +void _personSerialize( + Person object, + IsarWriter writer, + List offsets, + Map> allOffsets, +) { + writer.writeString(offsets[0], object.name); +} + +Person _personDeserialize( + Id id, + IsarReader reader, + List offsets, + Map> allOffsets, +) { + final object = Person(); + object.id = id; + object.name = reader.readStringOrNull(offsets[0]); + return object; +} + +P _personDeserializeProp

( + IsarReader reader, + int propertyId, + int offset, + Map> allOffsets, +) { + switch (propertyId) { + case 0: + return (reader.readStringOrNull(offset)) as P; + default: + throw IsarError('Unknown property with id $propertyId'); + } +} + +Id _personGetId(Person object) { + return object.id; +} + +List> _personGetLinks(Person object) { + return []; +} + +void _personAttach(IsarCollection col, Id id, Person object) { + object.id = id; +} + +extension PersonQueryWhereSort on QueryBuilder { + QueryBuilder anyId() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(const IdWhereClause.any()); + }); + } +} + +extension PersonQueryWhere on QueryBuilder { + QueryBuilder idEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: id, + upper: id, + )); + }); + } + + QueryBuilder idNotEqualTo(Id id) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ) + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ); + } else { + return query + .addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: false), + ) + .addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: false), + ); + } + }); + } + + QueryBuilder idGreaterThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.greaterThan(lower: id, includeLower: include), + ); + }); + } + + QueryBuilder idLessThan(Id id, + {bool include = false}) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause( + IdWhereClause.lessThan(upper: id, includeUpper: include), + ); + }); + } + + QueryBuilder idBetween( + Id lowerId, + Id upperId, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IdWhereClause.between( + lower: lowerId, + includeLower: includeLower, + upper: upperId, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder nameIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IndexWhereClause.equalTo( + indexName: r'name', + value: [null], + )); + }); + } + + QueryBuilder nameIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IndexWhereClause.between( + indexName: r'name', + lower: [null], + includeLower: false, + upper: [], + )); + }); + } + + QueryBuilder nameEqualTo(String? name) { + return QueryBuilder.apply(this, (query) { + return query.addWhereClause(IndexWhereClause.equalTo( + indexName: r'name', + value: [name], + )); + }); + } + + QueryBuilder nameNotEqualTo(String? name) { + return QueryBuilder.apply(this, (query) { + if (query.whereSort == Sort.asc) { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'name', + lower: [], + upper: [name], + includeUpper: false, + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'name', + lower: [name], + includeLower: false, + upper: [], + )); + } else { + return query + .addWhereClause(IndexWhereClause.between( + indexName: r'name', + lower: [name], + includeLower: false, + upper: [], + )) + .addWhereClause(IndexWhereClause.between( + indexName: r'name', + lower: [], + upper: [name], + includeUpper: false, + )); + } + }); + } +} + +extension PersonQueryFilter on QueryBuilder { + QueryBuilder idEqualTo(Id value) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idGreaterThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idLessThan( + Id value, { + bool include = false, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'id', + value: value, + )); + }); + } + + QueryBuilder idBetween( + Id lower, + Id upper, { + bool includeLower = true, + bool includeUpper = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'id', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + )); + }); + } + + QueryBuilder nameIsNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNull( + property: r'name', + )); + }); + } + + QueryBuilder nameIsNotNull() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(const FilterCondition.isNotNull( + property: r'name', + )); + }); + } + + QueryBuilder nameEqualTo( + String? value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameGreaterThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameLessThan( + String? value, { + bool include = false, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.lessThan( + include: include, + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameBetween( + String? lower, + String? upper, { + bool includeLower = true, + bool includeUpper = true, + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.between( + property: r'name', + lower: lower, + includeLower: includeLower, + upper: upper, + includeUpper: includeUpper, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameStartsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.startsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameEndsWith( + String value, { + bool caseSensitive = true, + }) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.endsWith( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameContains(String value, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.contains( + property: r'name', + value: value, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameMatches( + String pattern, + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.matches( + property: r'name', + wildcard: pattern, + caseSensitive: caseSensitive, + )); + }); + } + + QueryBuilder nameIsEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.equalTo( + property: r'name', + value: '', + )); + }); + } + + QueryBuilder nameIsNotEmpty() { + return QueryBuilder.apply(this, (query) { + return query.addFilterCondition(FilterCondition.greaterThan( + property: r'name', + value: '', + )); + }); + } +} + +extension PersonQueryObject on QueryBuilder {} + +extension PersonQueryLinks on QueryBuilder {} + +extension PersonQuerySortBy on QueryBuilder { + QueryBuilder sortByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder sortByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension PersonQuerySortThenBy on QueryBuilder { + QueryBuilder thenById() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.asc); + }); + } + + QueryBuilder thenByIdDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'id', Sort.desc); + }); + } + + QueryBuilder thenByName() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.asc); + }); + } + + QueryBuilder thenByNameDesc() { + return QueryBuilder.apply(this, (query) { + return query.addSortBy(r'name', Sort.desc); + }); + } +} + +extension PersonQueryWhereDistinct on QueryBuilder { + QueryBuilder distinctByName( + {bool caseSensitive = true}) { + return QueryBuilder.apply(this, (query) { + return query.addDistinctBy(r'name', caseSensitive: caseSensitive); + }); + } +} + +extension PersonQueryProperty on QueryBuilder { + QueryBuilder idProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'id'); + }); + } + + QueryBuilder nameProperty() { + return QueryBuilder.apply(this, (query) { + return query.addPropertyName(r'name'); + }); + } +} diff --git a/isar/test/sentry_isar_collection_test.dart b/isar/test/sentry_isar_collection_test.dart new file mode 100644 index 0000000000..de55ac5989 --- /dev/null +++ b/isar/test/sentry_isar_collection_test.dart @@ -0,0 +1,928 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:isar/isar.dart'; +import 'package:mockito/mockito.dart'; +import 'package:sentry/sentry.dart'; +import 'package:sentry_isar/sentry_isar.dart'; +import 'package:sentry_isar/src/sentry_isar.dart'; + +import 'package:sentry/src/sentry_tracer.dart'; + +import 'mocks/mocks.mocks.dart'; +import 'person.dart'; + +void main() { + void verifySpan( + String description, + SentrySpan? span, + ) { + expect(span?.context.operation, SentryIsar.dbOp); + expect(span?.context.description, description); + expect(span?.status, SpanStatus.ok()); + // ignore: invalid_use_of_internal_member + expect(span?.origin, SentryTraceOrigins.autoDbIsarCollection); + expect(span?.data[SentryIsar.dbNameKey], Fixture.dbName); + expect(span?.data[SentryIsar.dbCollectionKey], 'Person'); + } + + void verifyErrorSpan(String description, SentrySpan? span, Exception error) { + expect(span?.context.operation, SentryIsar.dbOp); + expect(span?.context.description, description); + expect(span?.status, SpanStatus.internalError()); + // ignore: invalid_use_of_internal_member + expect(span?.origin, SentryTraceOrigins.autoDbIsarCollection); + expect(span?.throwable, error); + } + + void verifyBreadcrumb( + String message, + Breadcrumb? crumb, { + String status = 'ok', + }) { + expect( + crumb?.message, + message, + ); + expect(crumb?.type, 'query'); + expect(crumb?.data?['status'], status); + if (status != 'ok') { + expect(crumb?.level, SentryLevel.warning); + } + } + + group('add spans', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('clear adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().clear(); + }); + final span = fixture.getCreatedSpan(); + verifySpan('clear', span); + }); + + test('count adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().count(); + }); + final span = fixture.getCreatedSpan(); + verifySpan('count', span); + }); + + test('delete adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().delete(0); + }); + final span = fixture.getCreatedSpan(); + verifySpan('delete', span); + }); + + test('deleteAll adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().deleteAll([0]); + }); + final span = fixture.getCreatedSpan(); + verifySpan('deleteAll', span); + }); + + test('deleteAllByIndex adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putByIndex('name', Person()..name = 'Joe'); + await fixture.getSut().deleteAllByIndex('name', []); + }); + final span = fixture.getCreatedSpan(); + verifySpan('deleteAllByIndex', span); + }); + + test('deleteByIndex adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putByIndex('name', Person()..name = 'Joe'); + await fixture.getSut().deleteByIndex('name', []); + }); + final span = fixture.getCreatedSpan(); + verifySpan('deleteByIndex', span); + }); + + test('get adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().get(1); + }); + final span = fixture.getCreatedSpan(); + verifySpan('get', span); + }); + + test('getAll adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getAll([1]); + }); + final span = fixture.getCreatedSpan(); + verifySpan('getAll', span); + }); + + test('getAllByIndex adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getAllByIndex('name', []); + }); + final span = fixture.getCreatedSpan(); + verifySpan('getAllByIndex', span); + }); + + test('getByIndex adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getByIndex('name', []); + }); + final span = fixture.getCreatedSpan(); + verifySpan('getByIndex', span); + }); + + test('getSize adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getSize(); + }); + final span = fixture.getCreatedSpan(); + verifySpan('getSize', span); + }); + + test('importJson adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().importJson([]); + }); + final span = fixture.getCreatedSpan(); + verifySpan('importJson', span); + }); + + test('importJsonRaw adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + final query = fixture.getSut().buildQuery(); + Uint8List jsonRaw = Uint8List.fromList([]); + await query.exportJsonRaw((raw) { + jsonRaw = Uint8List.fromList(raw); + }); + await fixture.getSut().importJsonRaw(jsonRaw); + }); + final span = fixture.getCreatedSpan(); + verifySpan('importJsonRaw', span); + }); + + test('put adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().put(Person()); + }); + final span = fixture.getCreatedSpan(); + verifySpan('put', span); + }); + + test('putAll adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putAll([Person()]); + }); + final span = fixture.getCreatedSpan(); + verifySpan('putAll', span); + }); + + test('putAllByIndex adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putAllByIndex('name', [Person()]); + }); + final span = fixture.getCreatedSpan(); + verifySpan('putAllByIndex', span); + }); + + test('putByIndex adds span', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putByIndex('name', Person()); + }); + final span = fixture.getCreatedSpan(); + verifySpan('putByIndex', span); + }); + }); + + group('add error spans', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + when(fixture.isarCollection.name).thenReturn(Fixture.dbCollection); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('throwing clear adds error span', () async { + when(fixture.isarCollection.clear()).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).clear(); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('clear', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing count adds error span', () async { + when(fixture.isarCollection.count()).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).count(); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('count', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing delete adds error span', () async { + when(fixture.isarCollection.delete(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).delete(0); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('delete', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing deleteAll adds error span', () async { + when(fixture.isarCollection.deleteAll(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).deleteAll([0]); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('deleteAll', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing deleteAllByIndex adds error span', () async { + when(fixture.isarCollection.deleteAllByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).deleteAllByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'deleteAllByIndex', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing deleteByIndex adds error span', () async { + when(fixture.isarCollection.deleteByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).deleteByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'deleteByIndex', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing get adds error span', () async { + when(fixture.isarCollection.get(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).get(1); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('get', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing getAll adds error span', () async { + when(fixture.isarCollection.getAll(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getAll([1]); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('getAll', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing getAllByIndex adds error span', () async { + when(fixture.isarCollection.getAllByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getAllByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'getAllByIndex', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing getByIndex adds error span', () async { + when(fixture.isarCollection.getByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'getByIndex', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing getSize adds error span', () async { + when(fixture.isarCollection.getSize()).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getSize(); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('getSize', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing importJson adds error span', () async { + when(fixture.isarCollection.importJson(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).importJson([]); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'importJson', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing importJsonRaw adds error span', () async { + when(fixture.isarCollection.importJsonRaw(any)) + .thenThrow(fixture.exception); + try { + await fixture + .getSut(injectMock: true) + .importJsonRaw(Uint8List.fromList([])); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'importJsonRaw', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing put adds error span', () async { + when(fixture.isarCollection.put(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).put(Person()); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('put', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing putAll adds error span', () async { + when(fixture.isarCollection.putAll(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).putAll([Person()]); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('putAll', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing putAllByIndex adds error span', () async { + when(fixture.isarCollection.putAllByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture + .getSut(injectMock: true) + .putAllByIndex('name', [Person()]); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'putAllByIndex', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing putByIndex adds error span', () async { + when(fixture.isarCollection.putByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).putByIndex('name', Person()); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'putByIndex', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + }); + + group('add breadcrumbs', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('clear adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().clear(); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('clear', breadcrumb); + }); + + test('count adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().count(); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('count', breadcrumb); + }); + + test('delete adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().delete(0); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('delete', breadcrumb); + }); + + test('deleteAll adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().deleteAll([0]); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('deleteAll', breadcrumb); + }); + + test('deleteAllByIndex adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putByIndex('name', Person()..name = 'Joe'); + await fixture.getSut().deleteAllByIndex('name', []); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[2]; + verifyBreadcrumb('deleteAllByIndex', breadcrumb); + }); + + test('deleteByIndex adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putByIndex('name', Person()..name = 'Joe'); + await fixture.getSut().deleteByIndex('name', []); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[2]; + verifyBreadcrumb('deleteByIndex', breadcrumb); + }); + + test('get adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().get(1); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('get', breadcrumb); + }); + + test('getAll adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getAll([1]); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('getAll', breadcrumb); + }); + + test('getAllByIndex adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getAllByIndex('name', []); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('getAllByIndex', breadcrumb); + }); + + test('getByIndex adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getByIndex('name', []); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('getByIndex', breadcrumb); + }); + + test('getSize adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().getSize(); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('getSize', breadcrumb); + }); + + test('importJson adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().importJson([]); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('importJson', breadcrumb); + }); + + test('importJsonRaw adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + final query = fixture.getSut().buildQuery(); + Uint8List jsonRaw = Uint8List.fromList([]); + await query.exportJsonRaw((raw) { + jsonRaw = Uint8List.fromList(raw); + }); + await fixture.getSut().importJsonRaw(jsonRaw); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('importJsonRaw', breadcrumb); + }); + + test('put adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().put(Person()); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('put', breadcrumb); + }); + + test('putAll adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putAll([Person()]); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('putAll', breadcrumb); + }); + + test('putAllByIndex adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putAllByIndex('name', [Person()]); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('putAllByIndex', breadcrumb); + }); + + test('putByIndex adds breadcrumb', () async { + await fixture.sentryIsar.writeTxn(() async { + await fixture.getSut().putByIndex('name', Person()); + }); + final breadcrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('putByIndex', breadcrumb); + }); + }); + + group('add error breadcrumbs', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + when(fixture.isarCollection.name).thenReturn(Fixture.dbCollection); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('throwing clear adds error breadcrumb', () async { + when(fixture.isarCollection.clear()).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).clear(); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'clear', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing count adds error breadcrumb', () async { + when(fixture.isarCollection.count()).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).count(); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'count', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing delete adds error breadcrumb', () async { + when(fixture.isarCollection.delete(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).delete(0); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'delete', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteAll adds error breadcrumb', () async { + when(fixture.isarCollection.deleteAll(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).deleteAll([0]); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'deleteAll', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteAllByIndex adds error breadcrumb', () async { + when(fixture.isarCollection.deleteAllByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).deleteAllByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'deleteAllByIndex', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing deleteByIndex adds error breadcrumb', () async { + when(fixture.isarCollection.deleteByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).deleteByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'deleteByIndex', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing get adds error breadcrumb', () async { + when(fixture.isarCollection.get(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).get(1); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'get', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing getAll adds error breadcrumb', () async { + when(fixture.isarCollection.getAll(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getAll([1]); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'getAll', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing getAllByIndex adds error breadcrumb', () async { + when(fixture.isarCollection.getAllByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getAllByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'getAllByIndex', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing getByIndex adds error breadcrumb', () async { + when(fixture.isarCollection.getByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getByIndex('name', []); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'getByIndex', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing getSize adds error breadcrumb', () async { + when(fixture.isarCollection.getSize()).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).getSize(); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'getSize', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing importJson adds error breadcrumb', () async { + when(fixture.isarCollection.importJson(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).importJson([]); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'importJson', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing importJsonRaw adds error breadcrumb', () async { + when(fixture.isarCollection.importJsonRaw(any)) + .thenThrow(fixture.exception); + try { + await fixture + .getSut(injectMock: true) + .importJsonRaw(Uint8List.fromList([])); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'importJsonRaw', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing put adds error breadcrumb', () async { + when(fixture.isarCollection.put(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).put(Person()); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'put', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing putAll adds error breadcrumb', () async { + when(fixture.isarCollection.putAll(any)).thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).putAll([Person()]); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'putAll', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing putAllByIndex adds error breadcrumb', () async { + when(fixture.isarCollection.putAllByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture + .getSut(injectMock: true) + .putAllByIndex('name', [Person()]); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'putAllByIndex', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing putByIndex adds error breadcrumb', () async { + when(fixture.isarCollection.putByIndex(any, any)) + .thenThrow(fixture.exception); + try { + await fixture.getSut(injectMock: true).putByIndex('name', Person()); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'putByIndex', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + }); +} + +class Fixture { + final options = SentryOptions(); + final hub = MockHub(); + final isarCollection = MockIsarCollection(); + + static final dbName = 'people-isar'; + static final dbCollection = 'Person'; + final exception = Exception('fixture-exception'); + + final _context = SentryTransactionContext('name', 'operation'); + late final tracer = SentryTracer(_context, hub); + late Isar sentryIsar; + late final scope = Scope(options); + + Future setUp() async { + // Make sure to use flutter test -j 1 to avoid tests running in parallel. This would break the automatic download. + await Isar.initializeIsarCore(download: true); + sentryIsar = await SentryIsar.open( + [PersonSchema], + directory: Directory.systemTemp.path, + name: dbName, + hub: hub, + ); + } + + Future tearDown() async { + try { + // ignore: invalid_use_of_protected_member + sentryIsar.requireOpen(); + await sentryIsar.close(); + } catch (_) { + // Don't close multiple times + } + } + + IsarCollection getSut({bool injectMock = false}) { + if (injectMock) { + return SentryIsarCollection(isarCollection, hub, sentryIsar.name); + } else { + return sentryIsar.collection(); + } + } + + SentrySpan? getCreatedSpan() { + return tracer.children.last; + } + + Breadcrumb? getCreatedBreadcrumb() { + return hub.scope.breadcrumbs.last; + } +} diff --git a/isar/test/sentry_isar_test.dart b/isar/test/sentry_isar_test.dart new file mode 100644 index 0000000000..222226fa53 --- /dev/null +++ b/isar/test/sentry_isar_test.dart @@ -0,0 +1,476 @@ +@TestOn('vm') + +import 'dart:io'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:isar/isar.dart'; +import 'package:mockito/mockito.dart'; +import 'package:sentry/sentry.dart'; +import 'package:sentry_isar/src/sentry_isar.dart'; + +import 'package:sentry/src/sentry_tracer.dart'; +import 'package:sentry_isar/src/version.dart'; + +import 'mocks/mocks.mocks.dart'; +import 'person.dart'; + +void main() { + void verifySpan(String description, SentrySpan? span) { + expect(span?.context.operation, SentryIsar.dbOp); + expect(span?.context.description, description); + expect(span?.status, SpanStatus.ok()); + // ignore: invalid_use_of_internal_member + expect(span?.origin, SentryTraceOrigins.autoDbIsar); + expect(span?.data[SentryIsar.dbNameKey], Fixture.dbName); + } + + void verifyErrorSpan(String description, SentrySpan? span, Exception error) { + expect(span?.context.operation, SentryIsar.dbOp); + expect(span?.context.description, description); + expect(span?.status, SpanStatus.internalError()); + // ignore: invalid_use_of_internal_member + expect(span?.origin, SentryTraceOrigins.autoDbIsar); + expect(span?.throwable, error); + } + + void verifyBreadcrumb( + String message, + Breadcrumb? crumb, { + String status = 'ok', + }) { + expect( + crumb?.message, + message, + ); + expect(crumb?.type, 'query'); + expect(crumb?.data?[SentryIsar.dbNameKey], Fixture.dbName); + expect(crumb?.data?['status'], status); + if (status != 'ok') { + expect(crumb?.level, SentryLevel.warning); + } + } + + group('add spans', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('open adds span', () async { + final span = fixture.getCreatedSpan(); + verifySpan('open', span); + }); + + test('clear adds span', () async { + await fixture.sut.writeTxn(() async { + await fixture.sut.clear(); + }); + final span = fixture.getCreatedSpan(); + verifySpan('clear', span); + }); + + test('close adds span', () async { + await fixture.sut.close(); + final span = fixture.getCreatedSpan(); + verifySpan('close', span); + }); + + test('copyToFile adds span', () async { + await fixture.sut.copyToFile(fixture.copyPath); + final span = fixture.getCreatedSpan(); + verifySpan('copyToFile', span); + }); + + test('getSize adds span', () async { + await fixture.sut.getSize(); + final span = fixture.getCreatedSpan(); + verifySpan('getSize', span); + }); + + test('txn adds span', () async { + await fixture.sut.txn(() async {}); + final span = fixture.getCreatedSpan(); + verifySpan('txn', span); + }); + + test('writeTxn adds span', () async { + await fixture.sut.writeTxn(() async {}); + final span = fixture.getCreatedSpan(); + verifySpan('writeTxn', span); + }); + }); + + group('add error spans', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + when(fixture.isar.close()).thenAnswer((_) async { + return true; + }); + when(fixture.isar.name).thenReturn(Fixture.dbName); + + await fixture.setUp(injectMock: true); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('throwing close adds error span', () async { + when(fixture.isar.close()).thenThrow(fixture.exception); + try { + await fixture.sut.close(); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('close', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing clear adds error span', () async { + when(fixture.isar.clear()).thenThrow(fixture.exception); + try { + await fixture.sut.clear(); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('clear', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing copyToFile adds error span', () async { + when(fixture.isar.copyToFile(any)).thenThrow(fixture.exception); + try { + await fixture.sut.copyToFile(fixture.copyPath); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan( + 'copyToFile', + fixture.getCreatedSpan(), + fixture.exception, + ); + }); + + test('throwing getSize adds error span', () async { + when(fixture.isar.getSize()).thenThrow(fixture.exception); + try { + await fixture.sut.getSize(); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('getSize', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing txn adds error span', () async { + param() async {} + when(fixture.isar.txn(param)).thenThrow(fixture.exception); + try { + await fixture.sut.txn(param); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('txn', fixture.getCreatedSpan(), fixture.exception); + }); + + test('throwing writeTxn adds error span', () async { + param() async {} + when(fixture.isar.writeTxn(param)).thenThrow(fixture.exception); + try { + await fixture.sut.writeTxn(param); + } catch (error) { + expect(error, fixture.exception); + } + verifyErrorSpan('writeTxn', fixture.getCreatedSpan(), fixture.exception); + }); + }); + + group('adds breadcrumbs', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('open adds breadcrumb', () async { + final breadcrumb = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('open', breadcrumb); + }); + + test('clear adds breadcrumb', () async { + await fixture.sut.writeTxn(() async { + await fixture.sut.clear(); + }); + + // order: open, clear, writeTxn + + final openCrumb = fixture.hub.scope.breadcrumbs[0]; + verifyBreadcrumb('open', openCrumb); + + final clearCrumb = fixture.hub.scope.breadcrumbs[1]; + verifyBreadcrumb('clear', clearCrumb); + + final writeTxnCrumb = fixture.hub.scope.breadcrumbs[2]; + verifyBreadcrumb('writeTxn', writeTxnCrumb); + }); + + test('close adds breadcrumb', () async { + await fixture.sut.close(); + final breadcrumb = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('close', breadcrumb); + }); + + test('copyToFile adds breadcrumb', () async { + await fixture.sut.copyToFile(fixture.copyPath); + final breadcrumb = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('copyToFile', breadcrumb); + }); + + test('getSize adds breadcrumb', () async { + await fixture.sut.getSize(); + final breadcrumb = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('getSize', breadcrumb); + }); + + test('txn adds breadcrumb', () async { + await fixture.sut.txn(() async {}); + final breadcrumb = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('txn', breadcrumb); + }); + + test('writeTxn adds breadcrumb', () async { + await fixture.sut.writeTxn(() async {}); + final breadcrumb = fixture.getCreatedBreadcrumb(); + verifyBreadcrumb('writeTxn', breadcrumb); + }); + }); + + group('add error breadcrumbs', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + when(fixture.isar.close()).thenAnswer((_) async { + return true; + }); + when(fixture.isar.name).thenReturn(Fixture.dbName); + + await fixture.setUp(injectMock: true); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('throwing close adds error breadcrumb', () async { + when(fixture.isar.close()).thenThrow(fixture.exception); + try { + await fixture.sut.close(); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'close', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing clear adds error breadcrumb', () async { + when(fixture.isar.clear()).thenThrow(fixture.exception); + try { + await fixture.sut.clear(); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'clear', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing copyToFile adds error breadcrumb', () async { + when(fixture.isar.copyToFile(any)).thenThrow(fixture.exception); + try { + await fixture.sut.copyToFile(fixture.copyPath); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'copyToFile', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing getSize adds error breadcrumb', () async { + when(fixture.isar.getSize()).thenThrow(fixture.exception); + try { + await fixture.sut.getSize(); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'getSize', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing txn adds error breadcrumb', () async { + param() async {} + when(fixture.isar.txn(param)).thenThrow(fixture.exception); + try { + await fixture.sut.txn(param); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'txn', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + + test('throwing writeTxn adds error breadcrumb', () async { + param() async {} + when(fixture.isar.writeTxn(param)).thenThrow(fixture.exception); + try { + await fixture.sut.writeTxn(param); + } catch (error) { + expect(error, fixture.exception); + } + verifyBreadcrumb( + 'writeTxn', + fixture.getCreatedBreadcrumb(), + status: 'internal_error', + ); + }); + }); + + group('integrations', () { + late Fixture fixture; + + setUp(() async { + fixture = Fixture(); + + when(fixture.hub.options).thenReturn(fixture.options); + when(fixture.hub.getSpan()).thenReturn(fixture.tracer); + when(fixture.hub.scope).thenReturn(fixture.scope); + + await fixture.setUp(); + }); + + tearDown(() async { + await fixture.tearDown(); + }); + + test('adds integration', () { + expect( + fixture.options.sdk.integrations.contains('SentryIsarTracing'), + true, + ); + }); + + test('adds package', () { + expect( + fixture.options.sdk.packages.any( + (element) => + element.name == packageName && element.version == sdkVersion, + ), + true, + ); + }); + }); +} + +class Fixture { + final options = SentryOptions(); + final hub = MockHub(); + final isar = MockIsar(); + + static final dbName = 'people-isar'; + final exception = Exception('fixture-exception'); + final copyPath = '${Directory.systemTemp.path}/copy'; + + final _context = SentryTransactionContext('name', 'operation'); + late final tracer = SentryTracer(_context, hub); + late Isar sut; + late final scope = Scope(options); + + Future setUp({bool injectMock = false}) async { + if (injectMock) { + sut = SentryIsar(isar, hub); + } else { + // Make sure to use flutter test -j 1 to avoid tests running in parallel. This would break the automatic download. + await Isar.initializeIsarCore(download: true); + sut = await SentryIsar.open( + [PersonSchema], + directory: Directory.systemTemp.path, + name: dbName, + hub: hub, + ); + } + await deleteCopyPath(); + } + + Future tearDown() async { + try { + // ignore: invalid_use_of_protected_member + sut.requireOpen(); + await sut.close(); + } catch (_) { + // Don't close multiple times + } + } + + Isar getSut() { + return sut; + } + + SentrySpan? getCreatedSpan() { + return tracer.children.last; + } + + Breadcrumb? getCreatedBreadcrumb() { + return hub.scope.breadcrumbs.last; + } + + Future deleteCopyPath() async { + final file = File(copyPath); + if (await file.exists()) { + await file.delete(recursive: true); + } + } +} diff --git a/logging/README.md b/logging/README.md index 0b4b4fcfef..488ebb8adf 100644 --- a/logging/README.md +++ b/logging/README.md @@ -43,8 +43,9 @@ void initApp() { #### Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) -* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) -* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) -* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) +* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) \ No newline at end of file diff --git a/logging/lib/src/version.dart b/logging/lib/src/version.dart index 9e5b7e8364..58dbea03c7 100644 --- a/logging/lib/src/version.dart +++ b/logging/lib/src/version.dart @@ -1,5 +1,5 @@ /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; /// The package name reported to Sentry.io in the submitted events. const String packageName = 'pub:sentry_logging'; diff --git a/logging/pubspec.yaml b/logging/pubspec.yaml index e8254560c7..80b484da48 100644 --- a/logging/pubspec.yaml +++ b/logging/pubspec.yaml @@ -1,6 +1,6 @@ name: sentry_logging description: An integration which adds support for recording log from the logging package. -version: 7.13.1 +version: 8.3.0 homepage: https://docs.sentry.io/platforms/dart/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues @@ -9,12 +9,20 @@ documentation: https://docs.sentry.io/platforms/dart/integrations/logging/ environment: sdk: '>=2.17.0 <4.0.0' +platforms: + android: + ios: + macos: + linux: + windows: + web: + dependencies: logging: ^1.0.0 - sentry: 7.13.1 + sentry: 8.3.0 dev_dependencies: - lints: ^3.0.0 + lints: ^4.0.0 test: ^1.21.1 yaml: ^3.1.0 # needed for version match (code and pubspec) coverage: ^1.3.0 diff --git a/logging/test/version_test.dart b/logging/test/version_test.dart index f27d675c7d..316a1caaff 100644 --- a/logging/test/version_test.dart +++ b/logging/test/version_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library dart_test; import 'dart:io'; diff --git a/metrics/flutter.properties b/metrics/flutter.properties index 46cc19edb4..a218c6f206 100644 --- a/metrics/flutter.properties +++ b/metrics/flutter.properties @@ -1,2 +1,2 @@ -version = 3.13.9 +version = 3.22.2 repo = https://github.com/flutter/flutter diff --git a/metrics/metrics-ios.yml b/metrics/metrics-ios.yml index e4263a6560..57177c0899 100644 --- a/metrics/metrics-ios.yml +++ b/metrics/metrics-ios.yml @@ -11,4 +11,4 @@ startupTimeTest: binarySizeTest: diffMin: 900 KiB - diffMax: 1200 KiB + diffMax: 1300 KiB diff --git a/min_version_test/ios/Podfile b/min_version_test/ios/Podfile index 88359b225f..2c068c404b 100644 --- a/min_version_test/ios/Podfile +++ b/min_version_test/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index d3e8fae081..dedd3e1b66 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -10,7 +10,7 @@ NEW_VERSION="${2}" echo "Current version: ${OLD_VERSION}" echo "Bumping version: ${NEW_VERSION}" -for pkg in {dart,flutter,logging,dio,file,sqflite,drift,hive}; do +for pkg in {dart,flutter,logging,dio,file,sqflite,drift,hive,isar}; do # Bump version in pubspec.yaml perl -pi -e "s/^version: .*/version: $NEW_VERSION/" $pkg/pubspec.yaml # Bump sentry dependency version in pubspec.yaml diff --git a/scripts/flutter_symbol_collector/lib/src/symbol_collector_cli.dart b/scripts/flutter_symbol_collector/lib/src/symbol_collector_cli.dart index 0f4c97d6a6..c67b0208bc 100644 --- a/scripts/flutter_symbol_collector/lib/src/symbol_collector_cli.dart +++ b/scripts/flutter_symbol_collector/lib/src/symbol_collector_cli.dart @@ -19,7 +19,7 @@ class SymbolCollectorCli { // https://github.com/getsentry/symbol-collector/releases @internal - static const version = '1.12.1'; + static const version = '1.18.0'; @internal late final String cli; diff --git a/sqflite/README.md b/sqflite/README.md index ed2b3c4f9d..ff5774ba74 100644 --- a/sqflite/README.md +++ b/sqflite/README.md @@ -62,8 +62,9 @@ Future insertProducts() async { #### Resources -* [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dart/) -* [![Forum](https://img.shields.io/badge/forum-sentry-green.svg)](https://forum.sentry.io/c/sdks) -* [![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr) +* [![Flutter docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=flutter%20docs)](https://docs.sentry.io/platforms/flutter/) +* [![Dart docs](https://img.shields.io/badge/documentation-sentry.io-green.svg?label=dart%20docs)](https://docs.sentry.io/platforms/dart/) +* [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-dart.svg)](https://github.com/getsentry/sentry-dart/discussions) +* [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) * [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-sentry-green.svg)](https://stackoverflow.com/questions/tagged/sentry) -* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) +* [![Twitter Follow](https://img.shields.io/twitter/follow/getsentry?label=getsentry&style=social)](https://twitter.com/intent/follow?screen_name=getsentry) \ No newline at end of file diff --git a/sqflite/lib/src/sentry_database.dart b/sqflite/lib/src/sentry_database.dart index fafcad06d9..23ac1dae63 100644 --- a/sqflite/lib/src/sentry_database.dart +++ b/sqflite/lib/src/sentry_database.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; import 'package:sqflite/sqflite.dart'; @@ -32,7 +34,10 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database { // ignore: public_member_api_docs static const dbSqlQueryOp = 'db.sql.query'; - static const _dbSqlOp = 'db.sql.transaction'; + static const _dbSqlTransactionOp = 'db.sql.transaction'; + + static const _dbSqlReadTransactionOp = 'db.sql.read_transaction'; + @internal // ignore: public_member_api_docs static const dbSystemKey = 'db.system'; @@ -143,7 +148,7 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database { final currentSpan = _hub.getSpan(); final description = 'Transaction DB: ${_database.path}'; final span = currentSpan?.startChild( - _dbSqlOp, + _dbSqlTransactionOp, description: description, ); // ignore: invalid_use_of_internal_member @@ -152,7 +157,7 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database { var breadcrumb = Breadcrumb( message: description, - category: _dbSqlOp, + category: _dbSqlTransactionOp, data: {}, type: 'query', ); @@ -196,4 +201,86 @@ class SentryDatabase extends SentryDatabaseExecutor implements Database { } }); } + + @override + // ignore: override_on_non_overriding_member, public_member_api_docs + Future readTransaction(Future Function(Transaction txn) action) { + return Future(() async { + final currentSpan = _hub.getSpan(); + final description = 'Transaction DB: ${_database.path}'; + final span = currentSpan?.startChild( + _dbSqlReadTransactionOp, + description: description, + ); + // ignore: invalid_use_of_internal_member + span?.origin = SentryTraceOrigins.autoDbSqfliteDatabase; + setDatabaseAttributeData(span, dbName); + + var breadcrumb = Breadcrumb( + message: description, + category: _dbSqlReadTransactionOp, + data: {}, + type: 'query', + ); + setDatabaseAttributeOnBreadcrumb(breadcrumb, dbName); + + Future newAction(Transaction txn) async { + final executor = SentryDatabaseExecutor( + txn, + parentSpan: span, + hub: _hub, + dbName: dbName, + ); + final sentrySqfliteTransaction = + SentrySqfliteTransaction(executor, hub: _hub, dbName: dbName); + + return await action(sentrySqfliteTransaction); + } + + try { + final futureOrResult = _resolvedReadTransaction(newAction); + T result; + + if (futureOrResult is Future) { + result = await futureOrResult; + } else { + result = futureOrResult; + } + + span?.status = SpanStatus.ok(); + breadcrumb.data?['status'] = 'ok'; + + return result; + } catch (exception) { + span?.throwable = exception; + span?.status = SpanStatus.internalError(); + breadcrumb.data?['status'] = 'internal_error'; + breadcrumb = breadcrumb.copyWith( + level: SentryLevel.warning, + ); + + rethrow; + } finally { + await span?.finish(); + + // ignore: invalid_use_of_internal_member + await _hub.scope.addBreadcrumb(breadcrumb); + } + }); + } + + FutureOr _resolvedReadTransaction( + Future Function(Transaction txn) action, + ) async { + try { + // ignore: return_of_invalid_type + final result = await (_database as dynamic).readTransaction(action); + // Await and cast, as directly returning the future resulted in a runtime error. + return result as T; + } on NoSuchMethodError catch (_) { + // The `readTransaction` does not exists on sqflite version < 2.5.0+2. + // Fallback to transaction instead. + return _database.transaction(action); + } + } } diff --git a/sqflite/lib/src/sentry_sqflite_transaction.dart b/sqflite/lib/src/sentry_sqflite_transaction.dart index 78c41b487d..c51bfe1c53 100644 --- a/sqflite/lib/src/sentry_sqflite_transaction.dart +++ b/sqflite/lib/src/sentry_sqflite_transaction.dart @@ -23,8 +23,8 @@ class SentrySqfliteTransaction extends Transaction implements DatabaseExecutor { final Hub _hub; final String? _dbName; - // ignore: public_member_api_docs @internal + // ignore: public_member_api_docs SentrySqfliteTransaction( this._executor, { @internal Hub? hub, diff --git a/sqflite/lib/src/version.dart b/sqflite/lib/src/version.dart index 912423e889..a74f25cdbd 100644 --- a/sqflite/lib/src/version.dart +++ b/sqflite/lib/src/version.dart @@ -1,5 +1,5 @@ /// The SDK version reported to Sentry.io in the submitted events. -const String sdkVersion = '7.13.1'; +const String sdkVersion = '8.3.0'; /// The package name reported to Sentry.io in the submitted events. const String packageName = 'pub:sentry_sqflite'; diff --git a/sqflite/pubspec.yaml b/sqflite/pubspec.yaml index e7ca891fec..b8449f13f7 100644 --- a/sqflite/pubspec.yaml +++ b/sqflite/pubspec.yaml @@ -1,6 +1,6 @@ name: sentry_sqflite description: An integration which adds support for performance tracing for the sqflite package. -version: 7.13.1 +version: 8.3.0 homepage: https://docs.sentry.io/platforms/flutter/ repository: https://github.com/getsentry/sentry-dart issue_tracker: https://github.com/getsentry/sentry-dart/issues @@ -9,15 +9,20 @@ environment: sdk: '>=2.17.0 <4.0.0' flutter: '>=3.3.0' # matching sqflite +platforms: + android: + ios: + macos: + dependencies: - sentry: 7.13.1 - sqflite: ^2.0.0 + sentry: 8.3.0 + sqflite: ^2.2.8 sqflite_common: ^2.0.0 meta: ^1.3.0 path: ^1.8.3 dev_dependencies: - lints: ^3.0.0 + lints: ^4.0.0 flutter_test: sdk: flutter coverage: ^1.3.0 diff --git a/sqflite/test/sentry_batch_test.dart b/sqflite/test/sentry_batch_test.dart index b9c53b8762..4a5062f2a2 100644 --- a/sqflite/test/sentry_batch_test.dart +++ b/sqflite/test/sentry_batch_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library sqflite_test; import 'package:sentry/sentry.dart'; import 'package:sentry_sqflite/sentry_sqflite.dart'; diff --git a/sqflite/test/sentry_database_test.dart b/sqflite/test/sentry_database_test.dart index ad1a07b360..93b258b20f 100644 --- a/sqflite/test/sentry_database_test.dart +++ b/sqflite/test/sentry_database_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library sqflite_test; import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; @@ -107,6 +108,27 @@ void main() { await db.close(); }); + test('creates readTransaction span', () async { + final db = await fixture.getSut(); + + await db.readTransaction((txn) async { + expect(txn is SentrySqfliteTransaction, true); + }); + final span = fixture.tracer.children.last; + expect(span.context.operation, 'db.sql.read_transaction'); + expect(span.context.description, 'Transaction DB: $inMemoryDatabasePath'); + expect(span.status, SpanStatus.ok()); + expect(span.data[SentryDatabase.dbSystemKey], SentryDatabase.dbSystem); + expect(span.data[SentryDatabase.dbNameKey], inMemoryDatabasePath); + expect( + span.origin, + // ignore: invalid_use_of_internal_member + SentryTraceOrigins.autoDbSqfliteDatabase, + ); + + await db.close(); + }); + test('creates transaction breadcrumb', () async { final db = await fixture.getSut(); @@ -128,6 +150,27 @@ void main() { await db.close(); }); + test('creates readTransaction breadcrumb', () async { + final db = await fixture.getSut(); + + await db.readTransaction((txn) async { + expect(txn is SentrySqfliteTransaction, true); + }); + + final breadcrumb = fixture.hub.scope.breadcrumbs.first; + expect(breadcrumb.message, 'Transaction DB: $inMemoryDatabasePath'); + expect(breadcrumb.category, 'db.sql.read_transaction'); + expect(breadcrumb.data?['status'], 'ok'); + expect( + breadcrumb.data?[SentryDatabase.dbSystemKey], + SentryDatabase.dbSystem, + ); + expect(breadcrumb.data?[SentryDatabase.dbNameKey], inMemoryDatabasePath); + expect(breadcrumb.type, 'query'); + + await db.close(); + }); + test('creates transaction children run by the transaction', () async { final db = await fixture.getSut(); diff --git a/sqflite/test/sentry_sqflite_database_factory_dart_test.dart b/sqflite/test/sentry_sqflite_database_factory_dart_test.dart index 9eeac66734..061660884f 100644 --- a/sqflite/test/sentry_sqflite_database_factory_dart_test.dart +++ b/sqflite/test/sentry_sqflite_database_factory_dart_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library sqflite_test; import 'package:sentry/sentry.dart'; import 'package:sentry/src/sentry_tracer.dart'; diff --git a/sqflite/test/sentry_sqflite_test.dart b/sqflite/test/sentry_sqflite_test.dart index 27851881b0..41aa3277b9 100644 --- a/sqflite/test/sentry_sqflite_test.dart +++ b/sqflite/test/sentry_sqflite_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library sqflite_test; import 'package:sentry/sentry.dart'; import 'package:sentry_sqflite/sentry_sqflite.dart'; diff --git a/sqflite/test/version_test.dart b/sqflite/test/version_test.dart index fbe3aa0a93..98e02ca499 100644 --- a/sqflite/test/version_test.dart +++ b/sqflite/test/version_test.dart @@ -1,4 +1,5 @@ @TestOn('vm') +library sqflite_test; import 'dart:io';