Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass the applicationName to the platform #8

Open
wants to merge 57 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
fcb03b7
httpClientIssue
aleksandr-denisov-epam Sep 9, 2022
049963c
Created TrackingInterceptor as an alternative to TrackedDioClient
lohnn Jun 14, 2022
32f6501
Review PR: rename classes; comment failing test
teodor-appd Jun 16, 2022
b897604
Use skip:true instead of comment out test
lohnn Jun 16, 2022
87cc9b1
Fix misaligned docs
teodor-appd Jun 16, 2022
a0c461c
Report stauts codes outside of OK range as expected
lohnn Jun 17, 2022
2a2311c
Fix unit tests
teodor-appd Sep 22, 2022
e915ce0
Merge pull request #2 from DenisovAV/master
teodor-appd Sep 22, 2022
e80a8bd
Merge branch 'master' of github.com:Appdynamics/appdynamics_flutter_a…
teodor-appd Sep 27, 2022
2e04e4b
Merge branch 'master' of ssh://bitbucket.corp.appdynamics.com:7999/eu…
teodor-appd Oct 21, 2022
1f98ec9
Merge branch 'Appdynamics:master' into tracking_interceptor
lohnn Oct 31, 2022
06b045e
Merge branch 'Appdynamics:master' into tracking_interceptor
lohnn Dec 12, 2022
1eb6fef
Android uses same logic for mapping logging levels as iOS. (None was …
lohnn Feb 1, 2023
2829220
Android uses same logic for mapping logging levels as iOS. (None was …
lohnn Feb 1, 2023
dd4eb46
Merge pull request #3 from lohnn/fix/logging_level_none_android
teodor-appd Feb 10, 2023
a0ec85b
Merge branch 'Appdynamics:master' into tracking_interceptor
lohnn Feb 10, 2023
4d7dce8
Import UniqueKey from Cupertino
teodor-appd Feb 13, 2023
24fc732
Disable auto webview instrumentation
teodor-appd Feb 13, 2023
78c11b9
Fix empty space in comment
teodor-appd Feb 13, 2023
33af0a8
Upgrade example dependencies
teodor-appd Feb 13, 2023
8f548b9
Misc changes
teodor-appd Feb 13, 2023
57fad13
Bump version
teodor-appd Feb 13, 2023
ec8c637
Update changelog
teodor-appd Feb 13, 2023
754ca3f
Merge branch 'master' of ssh://bitbucket.corp.appdynamics.com:7999/eu…
teodor-appd Mar 1, 2023
b1fa8a1
Merge branch 'master' of github.com:Appdynamics/appdynamics_flutter_a…
teodor-appd Mar 1, 2023
270c838
chore: Bump Dio to 5.0.1
spydon Mar 6, 2023
5afe74c
Create dart.yml
teodor-appd Mar 6, 2023
01d6d5e
Add basic Flutter pipeline
spydon Mar 6, 2023
61b0467
main -> master
spydon Mar 6, 2023
583ef89
Revert "chore: Bump Dio to 5.0.1"
spydon Mar 6, 2023
9c9283b
Add pub get
spydon Mar 6, 2023
d1b277d
Fix updated import
spydon Mar 6, 2023
71130bb
Remove unnecessary comments
spydon Mar 6, 2023
9dc3a5c
Remove proxy from pubspec
spydon Mar 7, 2023
5af8881
Fix formatting
spydon Mar 7, 2023
285b522
Merge pull request #5 from spydon/add-github-ci
teodor-appd Mar 7, 2023
d73b391
Merge branch 'Appdynamics:master' into master
spydon Mar 7, 2023
8574109
Bring back the Dio bump to 5.0.1
spydon Mar 7, 2023
1ca6631
Merge pull request #4 from spydon/master
teodor-appd Mar 7, 2023
2428ca5
Merge branch 'master' of github.com:Appdynamics/appdynamics_flutter_a…
teodor-appd Mar 8, 2023
eda770d
Merge branch 'master' of ssh://bitbucket.corp.appdynamics.com:7999/eu…
teodor-appd Mar 17, 2023
4221155
Merge origin/master into tracking_interceptor
lohnn Mar 27, 2023
4219431
Updated Dio version to 5.1.0 to get proper stack traces
lohnn Mar 27, 2023
0e3f089
Formatted tracked_dio_interceptor_test
lohnn Mar 27, 2023
33d8bf6
Updated test
lohnn Mar 27, 2023
84c635c
Merge branch 'master' of github.com:Appdynamics/appdynamics_flutter_a…
teodor-appd Mar 29, 2023
73ae832
Add new version of interceptor
teodor-appd Mar 29, 2023
9de56b2
Extracted trackerId key to a constant field
lohnn Mar 30, 2023
9e905ce
Reformatted some code in the test to adhere to formatting standards b…
lohnn Mar 30, 2023
bae3560
Add e2e test for Dio interceptor
teodor-appd Mar 30, 2023
966a8fb
Merge branch 'tracking_interceptor' of github.com:lohnn/appdynamics_f…
teodor-appd Mar 30, 2023
cc2a4d0
Fix flaky Dio client tests
teodor-appd Mar 30, 2023
95a02d6
Wait for happyPathTestLogic to finish
teodor-appd Mar 30, 2023
e5f1426
Revert "Fix flaky Dio client tests"
teodor-appd Mar 30, 2023
756e01f
Small format change
lohnn Mar 30, 2023
a76ca20
Merge pull request #1 from lohnn/tracking_interceptor
teodor-appd Mar 30, 2023
3c68158
Pass the applicationName to the platform
nivisi Mar 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Dart

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

# Note: This workflow uses the latest stable version of the Dart SDK.
# You can specify other versions if desired, see documentation here:
# https://github.com/dart-lang/setup-dart/blob/main/README.md
# - uses: dart-lang/setup-dart@v1
- uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603

- name: Install dependencies
run: dart pub get

# Uncomment this step to verify the use of 'dart format' on each commit.
# - name: Verify formatting
# run: dart format --output=none --set-exit-if-changed .

# Consider passing '--fatal-infos' for slightly stricter analysis.
- name: Analyze project source
run: dart analyze

# Your project will need to have tests in test/ and a dependency on
# package:test for this step to succeed. Note that Flutter projects will
# want to change this to 'flutter test'.
- name: Run tests
run: dart test
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Fixed native errors not being reported correctly.
* Fixed incorrect LoggingLevel values on Android.


# 22.12.0-beta.1
* Improved crash reporting by grouping exceptions and errors into different categories in the UI
* controller.
Expand Down
28 changes: 28 additions & 0 deletions example/integration_test/features/request_tracker_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,31 @@ extension on WidgetTester {
expect(actualHeaders[key.toLowerCase()], value.first);
});
}

assertDioInterceptorBeaconSent() async {
final requestSentLabel = find.text("Success with 200.");
await ensureVisible(requestSentLabel);
expect(requestSentLabel, findsOneWidget);

final trackerRequests = await findRequestsBy(
url: successURL,
type: "network-request",
hrc: "200",
$is: "Manual HttpTracker",
);
expect(trackerRequests.length, 3);

final actualRequests = await findRequestsBy(type: "trackeddiointerceptor");
expect(actualRequests.length, 1);

// Also assert correlation headers are added
final Map<String, dynamic> actualHeaders =
actualRequests[0]["request"]["headers"];
final btHeaders = await RequestTracker.getServerCorrelationHeaders();
btHeaders.forEach((key, value) {
expect(actualHeaders[key.toLowerCase()], value.first);
});
}
}

void main() {
Expand Down Expand Up @@ -147,6 +172,9 @@ void main() {
await tester.tapAndSettle("manualDioClientGetRequestButton");
await tester.flushBeacons();
await tester.assertDioTrackerBeaconSent();
await tester.tapAndSettle("manualDioInterceptorGetRequestButton");
await tester.flushBeacons();
await tester.assertDioInterceptorBeaconSent();
});

tearDown(() async {
Expand Down
2 changes: 1 addition & 1 deletion example/integration_test/tests.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

// Configure these based on the system's emulator/simulator names.
def android_device = "Android SDK built for x86"
def iOS_device = "iPhone 13"
def iOS_device = "iPhone 14"

def test_driver_path = "integration_test/test_driver/integration_test.dart"
def integration_tests_path = "integration_test/features/"
Expand Down
39 changes: 33 additions & 6 deletions example/lib/feature_list/features/manual_network_requests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,32 @@ class _ManualNetworkRequestsState extends State<ManualNetworkRequests> {
}
}

Future<void> _sendDioInterceptorRequestButtonPressed() async {
var urlString = urlFieldController.text;
if (urlString.trim().isEmpty) {
return;
}

try {
setState(() {
responseText = "Loading...";
});

final dioClient = Dio();
dioClient.interceptors.add(TrackedDioInterceptor());

final response = await dioClient.post(urlString,
data: "[{\"type\": \"trackeddiointerceptor\"}]");
setState(() {
responseText = "Success with ${response.statusCode}.";
});
} catch (e) {
setState(() {
responseText = "Failed with ${e.toString()}.";
});
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
Expand Down Expand Up @@ -218,18 +244,19 @@ class _ManualNetworkRequestsState extends State<ManualNetworkRequests> {
onPressed: _sendPostRequestButtonPressed),
ElevatedButton(
key: const Key("manualHttpClientGetRequestButton"),
child: const Text(
'TrackedHttpClient GET request\n'
'(has custom header: "foo")',
child: const Text('TrackedHttpClient GET request',
textAlign: TextAlign.center),
onPressed: _sendHttpClientRequestButtonPressed),
ElevatedButton(
key: const Key("manualDioClientGetRequestButton"),
child: const Text(
'TrackedDioClient GET request\n'
'(has custom header: "foo")',
child: const Text('TrackedDioClient GET request',
textAlign: TextAlign.center),
onPressed: _sendDioClientRequestButtonPressed),
ElevatedButton(
key: const Key("manualDioInterceptorGetRequestButton"),
child: const Text('TrackedDioInterceptor GET request',
textAlign: TextAlign.center),
onPressed: _sendDioInterceptorRequestButtonPressed),
const SizedBox(
height: 30,
),
Expand Down
1 change: 1 addition & 0 deletions lib/appdynamics_agent.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export 'src/instrumentation.dart';
export 'src/request_tracker.dart';
export 'src/tracked_clients/tracked_http_client.dart';
export 'src/tracked_clients/tracked_dio_client.dart';
export 'src/tracked_clients/tracked_dio_interceptor.dart';
export 'src/session_frame.dart' hide createSessionFrame;
export 'src/activity_tracking/widget_tracker.dart' hide TrackedWidget;
export 'src/activity_tracking/navigation_observer.dart';
1 change: 1 addition & 0 deletions lib/src/instrumentation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class Instrumentation {

Map<String, dynamic> arguments = {
"appKey": config.appKey,
"applicationName": config.applicationName,
"loggingLevel": config.loggingLevel.index,
"collectorURL": config.collectorURL,
"screenshotURL": config.screenshotURL,
Expand Down
3 changes: 2 additions & 1 deletion lib/src/request_tracker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ class RequestTracker {
/// Sets a dictionary representing the keys and values from the server
/// response's headers.
///
/// If an error occurred and a response was not received, this not be called.
/// If an error occurred and a response was not received, this should not be
/// called.
///
/// Method might throw [Exception].
Future<RequestTracker> setResponseHeaders(
Expand Down
3 changes: 2 additions & 1 deletion lib/src/tracked_clients/tracked_dio_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
*/

import 'package:dio/dio.dart';
import 'package:dio/native_imp.dart';
import 'package:dio/io.dart';

import '../../appdynamics_agent.dart';

/// Use this client to track requests made via the `dio` package (version <5).
/// For Dio version 5 and above, see [TrackedDioInterceptor].
///
/// ```dart
/// import 'package:dio/dio.dart';
Expand Down
103 changes: 103 additions & 0 deletions lib/src/tracked_clients/tracked_dio_interceptor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import 'package:appdynamics_agent/appdynamics_agent.dart';
import 'package:dio/dio.dart';

/// Use this class to create a custom Dio [Interceptor] that tracks requests
/// automatically. Alternative to [TrackedDioClient].
///
/// ```dart
/// import 'package:dio/dio.dart';
///
/// try {
/// final dio = Dio();
/// dio.interceptors.add(TrackedDioInterceptor());
/// final response = await dio.post(urlString, data: {"foo": "bar"});
/// // handle response
/// } catch (e) {
/// // handle error
/// }
/// ```
class TrackedDioInterceptor implements Interceptor {
final bool addCorrelationHeaders;

final Map<String, RequestTracker> _activeTrackers = {};

TrackedDioInterceptor({this.addCorrelationHeaders = true});

static const _trackerId = 'trackerId';

@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
try {
if (addCorrelationHeaders) {
final correlationHeaders =
await RequestTracker.getServerCorrelationHeaders();
final headers = correlationHeaders.map(
(key, value) => MapEntry(key, value.first),
);
options.headers.addAll(headers);
}

var url = options.uri.toString();
final tracker = await RequestTracker.create(url);
_activeTrackers[tracker.id] = tracker;
options.extra[_trackerId] = tracker.id;
} finally {
handler.next(options);
}
}

@override
void onResponse(
Response<dynamic> response,
ResponseInterceptorHandler handler,
) async {
try {
final tracker = _activeTrackers.remove(
response.requestOptions.extra[_trackerId],
);
if (tracker != null) {
await tracker.setResponseStatusCode(response.statusCode ?? 404);
await _logResponse(response, tracker);
await tracker.reportDone();
}
} finally {
handler.next(response);
}
}

@override
void onError(DioError err, ErrorInterceptorHandler handler) async {
try {
final tracker = _activeTrackers.remove(
err.requestOptions.extra[_trackerId],
);
if (tracker != null) {
final statusCode = err.response?.statusCode;
if (statusCode != null) {
// TODO: Find a way to test this (coverage).
// Errors for when status code is not in accepted range should be recorded as normal
await tracker.setResponseStatusCode(statusCode);
await _logResponse(err.response, tracker);
} else {
// If status code is null, it means that the error is not a response, but rather a network error
await tracker.setError(err.toString(), err.stackTrace.toString());
}
await tracker.reportDone();
}
} finally {
handler.next(err);
}
}

Future _logResponse(Response? response, RequestTracker tracker) async {
if (response != null) {
await tracker.setRequestHeaders(
response.requestOptions.headers.map((k, v) => MapEntry(k, <String>[v])),
);
await tracker.setResponseHeaders(response.headers.map);
}
}
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
flutter:
sdk: flutter
http: ^0.13.3
dio: ^4.0.6
dio: ^5.1.0

dev_dependencies:
flutter_test:
Expand Down
10 changes: 5 additions & 5 deletions test/tracked_dio_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void main() {

// Used to not duplicate logic that has same results but only one different
// parameter (i.e. request options).
void happyPathTestLogic(
Future happyPathTestLogic(
Options? options, Map<String, List<String>> expectedHeaders) async {
final dio = Dio();
dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
Expand Down Expand Up @@ -91,28 +91,28 @@ void main() {
final headers = await RequestTracker.getServerCorrelationHeaders();
headers.addAll(
customHeaders.map((key, value) => MapEntry(key, <String>[value])));
happyPathTestLogic(Options(headers: customHeaders), headers);
await happyPathTestLogic(Options(headers: customHeaders), headers);
});

test('TrackedDioClient happy path works with `null` options', () async {
log = [];
final headers = await RequestTracker.getServerCorrelationHeaders();
happyPathTestLogic(null, headers);
await happyPathTestLogic(null, headers);
});

test('TrackedDioClient happy path works with `null` option headers',
() async {
log = [];
final headers = await RequestTracker.getServerCorrelationHeaders();
happyPathTestLogic(Options(headers: null), headers);
await happyPathTestLogic(Options(headers: null), headers);
});

test('TrackedDioClient error-path methods are called correctly', () async {
log = [];

const urlString = "https://www.foo.com";
final error = DioError(
type: DioErrorType.other,
type: DioErrorType.unknown,
error: Error(),
requestOptions: RequestOptions(path: urlString));

Expand Down
Loading