Skip to content

Commit

Permalink
Merge branch 'next' into robert/plat-11577_view_load_instrumentation_…
Browse files Browse the repository at this point in the history
…updates
  • Loading branch information
tomlongridge authored Jul 8, 2024
2 parents f2e0dba + 7860560 commit 058cabd
Show file tree
Hide file tree
Showing 23 changed files with 333 additions and 25 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Changelog

* View load instrumentation
[65](https://github.com/bugsnag/bugsnag-flutter-performance/pull/65)

* Auto-inject traceparent headers into HTTP requests [73](https://github.com/bugsnag/bugsnag-flutter-performance/pull/73)

## 1.0.0 (2024-04-11)

Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ gem 'cocoapods'

# A reference to Maze Runner is only needed for running tests locally and if committed it must be
# portable for CI, e.g. a specific release. However, leaving it commented out would mean quicker CI.
gem 'bugsnag-maze-runner', '~> 8.13.2'
gem 'bugsnag-maze-runner', '~> 9.9.1'

# Use a specific branch
#gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', branch: 'master'
Expand Down
30 changes: 13 additions & 17 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ GEM
atomos (0.1.3)
base64 (0.2.0)
bigdecimal (3.1.7)
bugsnag (6.26.0)
bugsnag (6.27.1)
concurrent-ruby (~> 1.0)
bugsnag-maze-runner (8.13.2)
bugsnag-maze-runner (9.9.1)
appium_lib (~> 12.0.0)
appium_lib_core (~> 5.4.0)
bugsnag (~> 6.24)
Expand All @@ -49,7 +49,7 @@ GEM
selenium-webdriver (~> 4.0)
test-unit (~> 3.5.2)
webrick (~> 1.7.0)
builder (3.2.4)
builder (3.3.0)
childprocess (4.1.0)
claide (1.1.0)
cocoapods (1.15.2)
Expand Down Expand Up @@ -124,7 +124,7 @@ GEM
cucumber-core (~> 10.1, >= 10.1.0)
cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
curb (0.9.11)
diff-lcs (1.5.0)
diff-lcs (1.5.1)
dogstatsd-ruby (5.5.0)
drb (2.2.1)
ecma-re-validator (0.4.0)
Expand All @@ -151,9 +151,9 @@ GEM
regexp_parser (~> 2.0)
simpleidn (~> 0.2)
uri_template (~> 0.7)
mime-types (3.5.1)
mime-types (3.5.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.1003)
mime-types-data (3.2024.0604)
minitest (5.22.3)
molinillo (0.8.0)
multi_test (0.1.2)
Expand All @@ -162,18 +162,18 @@ GEM
nap (1.1.0)
netrc (0.11.0)
nkf (0.2.0)
nokogiri (1.15.6-arm64-darwin)
nokogiri (1.16.6-arm64-darwin)
racc (~> 1.4)
nokogiri (1.15.6-x86_64-darwin)
nokogiri (1.16.6-x86_64-darwin)
racc (~> 1.4)
optimist (3.0.1)
os (1.0.1)
power_assert (2.0.3)
public_suffix (4.0.7)
racc (1.7.3)
racc (1.8.0)
rack (2.2.9)
rake (12.3.3)
regexp_parser (2.8.2)
regexp_parser (2.9.2)
rexml (3.2.6)
ruby-macho (2.5.1)
rubyzip (2.3.2)
Expand All @@ -182,9 +182,8 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
simpleidn (0.2.1)
unf (~> 0.1.4)
sys-uname (1.2.3)
simpleidn (0.2.3)
sys-uname (1.3.0)
ffi (~> 1.1)
test-unit (3.5.9)
power_assert
Expand All @@ -193,9 +192,6 @@ GEM
ethon (>= 0.9.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.9.1)
uri_template (0.7.0)
webrick (1.7.0)
websocket (1.2.10)
Expand All @@ -217,7 +213,7 @@ PLATFORMS
x86_64-darwin-23

DEPENDENCIES
bugsnag-maze-runner (~> 8.13.2)
bugsnag-maze-runner (~> 9.9.1)
cocoapods

BUNDLED WITH
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3.6'
services:

maze-runner:
image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v8-cli
image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v9-cli
environment:
DEBUG:
BITBAR_USERNAME:
Expand Down
45 changes: 44 additions & 1 deletion features/automatic_spans.feature
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,47 @@ Feature: Automatic instrumentation spans
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentViewLoadNestedScenarioWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentViewLoadNestedScenarioWidget/loading content"
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget/building"
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget/appearing"
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget/loading content"
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentViewLoadNestedScenarioChildWidget/loading content"

Scenario: AutoInstrumentNavigationWithViewLoadScenario
Given I run "AutoInstrumentNavigationWithViewLoadScenario"
And I wait for 3 seconds
* no span named "[Navigation]navigation_view_load_scenario" exists
* no span named "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget" exists
Then I invoke "step2"
And I wait for 3 seconds
* no span named "[Navigation]navigation_view_load_scenario" exists
* no span named "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget" exists
Then I invoke "step3"
And I wait for 3 seconds
* no span named "[Navigation]navigation_view_load_scenario" exists
* no span named "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget" exists
Then I invoke "step4"
And I wait for 5 spans
Then the trace "Content-Type" header equals "application/json"
* the trace "Bugsnag-Span-Sampling" header equals "1:1"
* the trace "Bugsnag-Sent-At" header matches the regex "^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\dZ$"
* a span field "name" equals "[Navigation]navigation_view_load_scenario"
* a span string attribute "bugsnag.navigation.route" equals "navigation_view_load_scenario"
* a span string attribute "bugsnag.navigation.triggered_by" equals "push"
* a span string attribute "bugsnag.navigation.ended_by" equals "loading_indicator"
* a span string attribute "bugsnag.navigation.previous_route" equals "/"
* a span field "name" equals "[ViewLoadPhase]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget/building"
* a span string attribute "bugsnag.phase" equals "building"
* a span field "name" equals "[ViewLoadPhase]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget/appearing"
* a span string attribute "bugsnag.phase" equals "appearing"
* a span field "name" equals "[ViewLoadPhase]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget/loading"
* a span string attribute "bugsnag.phase" equals "loading content"
* a span string attribute "bugsnag.span.category" equals "view_load_phase"
* a span field "name" equals "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget"
* a span string attribute "bugsnag.span.category" equals "view_load"
* every span field "spanId" matches the regex "^[A-Fa-f0-9]{16}$"
* every span field "traceId" matches the regex "^[A-Fa-f0-9]{32}$"
* every span field "startTimeUnixNano" matches the regex "^[0-9]+$"
* every span field "endTimeUnixNano" matches the regex "^[0-9]+$"
* every span bool attribute "bugsnag.span.first_class" does not exist
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget/building"
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget/appearing"
* the span named "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget" is the parent of the span named "[ViewLoadPhase]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget/loading content"
* the span named "[Navigation]navigation_view_load_scenario" is the parent of the span named "[ViewLoad]FlutterWidget/AutoInstrumentNavigationWithViewLoadWidget"

Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import 'package:bugsnag_flutter_performance/bugsnag_flutter_performance.dart';
import 'package:flutter/material.dart';
import 'package:mazerunner/main.dart';

import 'scenario.dart';

class AutoInstrumentNavigationWithViewLoadScenario extends Scenario {
final _key =
GlobalKey<_AutoInstrumentNavigationWithViewLoadScenarioScreenState>();

@override
Future<void> run() async {
setInstrumentsNavigation(true);
setInstrumentsViewLoad(true);
await startBugsnag();
setMaxBatchSize(1);
}

@override
Widget? createWidget() {
return AutoInstrumentNavigationWithViewLoadScenarioScreen(
key: _key,
runCommandCallback: () => runCommandCallback!(),
);
}

@override
RouteSettings? routeSettings() {
return const RouteSettings(name: 'navigation_view_load_scenario');
}

void step2() {
_key.currentState!.setStage(2);
}

void step3() {
_key.currentState!.setStage(3);
}

void step4() {
_key.currentState!.setStage(4);
}

@override
void invokeMethod(String name) {
switch (name) {
case 'step2':
step2();
break;
case 'step3':
step3();
break;
case 'step4':
step4();
break;
default:
break;
}
}
}

class AutoInstrumentNavigationWithViewLoadScenarioScreen
extends StatefulWidget {
const AutoInstrumentNavigationWithViewLoadScenarioScreen({
super.key,
required this.runCommandCallback,
});
final void Function() runCommandCallback;

@override
State<AutoInstrumentNavigationWithViewLoadScenarioScreen> createState() =>
_AutoInstrumentNavigationWithViewLoadScenarioScreenState();
}

class _AutoInstrumentNavigationWithViewLoadScenarioScreenState
extends State<AutoInstrumentNavigationWithViewLoadScenarioScreen> {
var _stage = 1;

@override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
color: Colors.white,
child: MeasuredWidget(
name: 'AutoInstrumentNavigationWithViewLoadWidget',
builder: (context) => Row(
children: [
if (_stage < 4)
BugsnagLoadingIndicator(
child: Column(children: [
if (_stage < 3)
const BugsnagLoadingIndicator(
child: Text('Still loading...'),
),
if (_stage < 2)
const BugsnagLoadingIndicator(
child: CircularProgressIndicator(),
)
]),
),
const Text(
'AutoInstrumentNavigationWithViewLoadScenarioScreen')
],
),
)),
onTap: () => widget.runCommandCallback());
}

void setStage(int stage) {
setState(() {
_stage = stage;
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'dart:io';

import 'package:bugsnag_flutter_dart_io_http_client/bugsnag_flutter_dart_io_http_client.dart'
as dartIo;
import 'package:bugsnag_flutter_performance/bugsnag_flutter_performance.dart';
import '../main.dart';
import 'scenario.dart';

class DartIoTraceparentScenario extends Scenario {
@override
Future<void> run() async {
await startBugsnag();
setMaxBatchSize(1);
dartIo.addSubscriber(bugsnag_performance.networkInstrumentation);
final client = dartIo.HttpClient();
HttpClientRequest request = await client
.getUrl(Uri.parse('${FixtureConfig.MAZE_HOST.toString()}/reflect'));
await request.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:bugsnag_flutter_performance/bugsnag_flutter_performance.dart';
import 'package:bugsnag_http_client/bugsnag_http_client.dart' as http;
import '../main.dart';
import 'scenario.dart';

class HttpClientTracePropagationUrlsScenario extends Scenario {
@override
Future<void> run() async {
await startBugsnag(tracePropagationUrls: [RegExp('dosend')]);
setMaxBatchSize(1);
http.addSubscriber(bugsnag_performance.networkInstrumentation);
http.get(
Uri.parse('${FixtureConfig.MAZE_HOST.toString()}/reflect?dontsend'));
await Future.delayed(Duration(seconds: 1));
http.get(Uri.parse('${FixtureConfig.MAZE_HOST.toString()}/reflect?dosend'));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:bugsnag_flutter_performance/bugsnag_flutter_performance.dart';
import 'package:bugsnag_http_client/bugsnag_http_client.dart' as http;
import '../main.dart';
import 'scenario.dart';

class HttpClientTraceparentScenario extends Scenario {
@override
Future<void> run() async {
await startBugsnag();
setMaxBatchSize(1);
http.addSubscriber(bugsnag_performance.networkInstrumentation);
http.get(Uri.parse('${FixtureConfig.MAZE_HOST.toString()}/reflect'));
}
}
2 changes: 2 additions & 0 deletions features/fixture_resources/lib/scenarios/scenario.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ abstract class Scenario {
Future<void> startBugsnag({
String? releaseStage,
List<String>? enabledReleaseStages,
List<RegExp>? tracePropagationUrls,
String? appVersion,
}) async {
bugsnag_performance.setExtraConfig("instrumentAppStart", false);
Expand All @@ -51,6 +52,7 @@ abstract class Scenario {
endpoint: Uri.parse('${FixtureConfig.MAZE_HOST}/traces'),
releaseStage: releaseStage,
enabledReleaseStages: enabledReleaseStages,
tracePropagationUrls: tracePropagationUrls,
appVersion: appVersion,
);
}
Expand Down
11 changes: 11 additions & 0 deletions features/fixture_resources/lib/scenarios/scenarios.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import 'package:mazerunner/scenarios/auto_instrument_navigation_push_and_pop_sce
import 'package:mazerunner/scenarios/auto_instrument_view_load_basic_defer_scenario.dart';
import 'package:mazerunner/scenarios/auto_instrument_view_load_basic_scenario.dart';
import 'package:mazerunner/scenarios/auto_instrument_view_load_nested_scenario.dart';
import 'package:mazerunner/scenarios/dart_io_traceparent_scenario.dart';
import 'package:mazerunner/scenarios/http_client_trace_propagation_urls_scenario.dart';
import 'package:mazerunner/scenarios/http_client_traceparent_scenario.dart';

import 'auto_instrument_app_starts_scenario.dart';
import 'auto_instrument_navigation_with_view_load_scenario.dart';
import 'dio_callback_cancel_span.dart';
import 'dio_callback_edit_scenario.dart';
import 'initial_p_scenario.dart';
Expand Down Expand Up @@ -104,4 +108,11 @@ final List<ScenarioInfo<Scenario>> scenarios = [
() => AutoInstrumentViewLoadBasicDeferScenario()),
ScenarioInfo('AutoInstrumentViewLoadNestedScenario',
() => AutoInstrumentViewLoadNestedScenario()),
ScenarioInfo('AutoInstrumentNavigationWithViewLoadScenario',
() => AutoInstrumentNavigationWithViewLoadScenario()),
ScenarioInfo(
'HttpClientTraceparentScenario', () => HttpClientTraceparentScenario()),
ScenarioInfo('DartIoTraceparentScenario', () => DartIoTraceparentScenario()),
ScenarioInfo('HttpClientTracePropagationUrlsScenario',
() => HttpClientTracePropagationUrlsScenario()),
];
1 change: 1 addition & 0 deletions features/manual_span.feature
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Feature: Manual Spans
* the span named "part 2: not null" exists
* the span named "context" is the parent of the span named "part 2: not null"

@skip
Scenario: Custom timings
When I run "CustomSpanTimeScenario"
And I wait for 1 span
Expand Down
Loading

0 comments on commit 058cabd

Please sign in to comment.