AppDynamics Xamarin SDK  2023.2.0
Real user monitoring for your Xamarin app.
AppDynamics Xamarin SDK Documentation

Table of Contents

About the AppDynamics Xamarin SDK

The AppDynamics Xamarin SDK is a package that allows you to monitor the performance and activities of a Xamarin.Android, Xamarin.iOS and/or a Xamarin.Forms app.

The SDK includes APIs to instrument specific methods in your own code, to measure durations of operations in your application (like application start up, for example), or to report an arbitrary metric.

Xamarin.Forms on Windows or .NET

NOTE: The SDK only targets Android and iOS deployments. All other targets will build and run. However, at runtime, the SDK calls are "stubbed" out and will actually do no work.

Instrument Xamarin Applications

Follow the steps below to manually instrument your Xamarin iOS, Android, and Forms apps.

Get Your Application Key

Complete the Getting Started Wizard to get an EUM App Key. You will need this key when you modify the source code. In some cases, multiple mobile applications can share the same key.

Because there is no Xamarin platform option, you will need to choose either Android or iOS. For Android, you will need to select Manual.

Add the Xamarin Agent Package

  1. Get the Xamarin Agent from the NuGet Gallery. Follow the instructions given in Adding a Package to add the package AppDynamics Xamarin Agent from nuget.org. Note that there are three diferent packages:
    • AppDynamics.Agent - Used for Xamarin.Forms / Xamarin.Native instrumentation
    • AppDynamics.Agent.Forms - Based on AppDynamics.Agent but including some Xamarin-Forms specific instrumentation
    • AppDynamics.Agent.AutoInstrument.Fody - Enables automatic instrumentation. Should be used alongside one of the previous two. Check the automatic instrumentation features below.
  2. In the Xamarin.Android project, add the following to MainActivity.cs under OnCreate:
AppDynamics.Droid.Agent.Init(this, bundle);
Example
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle); //existing code
global::Xamarin.Forms.Forms.Init(this, bundle);
AppDynamics.Droid.Agent.Init(this, bundle); //initialize the agent on the Android Platform
LoadApplication(new App());
}

Initialize the Agent

To initialize the Xamarin Agent, all you have to do is:

Note: See the AppDynamics.Agent.AgentConfiguration object for more configuration options

Where to best place this code snippet depends on the desgin of the application. It is usually best to place it as early as possible in the runtime lifecycle.

For Xamarin.Forms

It's recommended to add the initialization code in the App.xaml.cs file:

public App()
{
InitializeComponent();
// This initialization code is used by both iOS and Android apps.
var config = AppDynamics.Agent.AgentConfiguration.Create(<EUM_APP_KEY>);
MainPage = new FormsExamplePage();
}

For Xamarin.Android

It's recommended to add the initialization code in the MainActivity.cs file under the OnCreate method:

class MainActivity {
protected override void OnCreate(Bundle savedInstanceState) {
...
var config = AppDynamics.Agent.AgentConfiguration.Create(<EUM_APP_KEY>);
...
}
}

For Xamarin.iOS

It's recommended to add the initialization code in the AppDelegate.cs file under the FinishedLaunching method:

public class AppDelegate : UIApplicationDelegate
{
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
...
var config = AppDynamics.Agent.AgentConfiguration.Create(<EUM_APP_KEY>);
...
}
}

Add the Required Permissions (Andriod)

Although these are usually on by default, it is important to make sure that the following permissions are enabled in the Properties/AndroidManifest.xml file:

Build the Application

Run and build your application from Visual Studio. From the Getting Started Wizard, you should see that the application has connected and the instrumentation has been verified.

To be able to run on iOS Simulator without issues, for iOS projects with the Xamarin Agent >= 21.6.0, you must add the additional MtouchExtraArgs argument --registrar:static for each simulator build configuration, such as the debug and release builds. This does not apply for physical device configurations, since the static registrar is already the default in that case. More on that: https://docs.microsoft.com/en-us/xamarin/ios/internals/registrar

If the iOS project file is edited directly, the build configuration should contain the MtouchExtraArgs element:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
...
<MtouchExtraArgs>--registrar:static</MtouchExtraArgs>
</PropertyGroup>

Point to an On-Premises EUM Server (Optional)

To use an on-premises EUM Server, you pass the URL to the on-premises EUM Server when you initialize the instrumentation with the EUM App Key from Get Your Application Key:

var config = AppDynamics.Agent.AgentConfiguration.Create(<EUM_APP_KEY>);
config.CollectorURL = <COLLECTOR_URL:PORT>;

Instrumentation

Track Calls

You can instrument methods to see how often the instrumented a method is invoked and how long it takes to run. To do this, add a call at the beginning and end of the method you'd like to instrument.

In the example below, the code executed in the constructor for the class ShoppingCart will be tracked and reported. In your own code, start tracking calls by specifying the class and method in BeginCall and then complete the tracking and report the data by calling ReportCallEnded.

...
public class ShoppingCart {
void CheckOut(int custId, int transactionId) {
var tracker = Instrumentation.BeginCall("ShoppingCart", "CheckOut", custId, transactionId);
// The code placed here will be tracked and reported.
..
tracker.ReportCallEnded();
}
}

Timing Events

Sometimes you want to time an event in your application that spans multiple methods. You can do this by calling StartTimerWithName when the event starts, and then StopTimerWithName when it ends. For example, to track the time a user spends viewing a screen, the instrumentation might look something like the following:

...
async private void StartCapturePreview_Click(object sender, RoutedEventArgs e) {
capturePreview.Source = captureManager;
Instrumentation.StartTimerWithName("CapturePreview");
await captureManager.StartPreviewAsync();
}
async private void StopCapturePreview_Click(object sender, RoutedEventArgs e) {
await captureManager.StopPreviewAsync();
Instrumentation.StopTimerWithName("CapturePreview");
}

Report Metrics

To report other types of data, you can use a metric. The metric name should only contain alphanumeric characters and spaces. Illegal characters are replaced by their ASCII hex value. The metric value must be a long integer.

The snippet below shows how you might report a metric.

...
Instrumentation.ReportMetricWithName("Database Rows", 5123);

Add Tracking to HTTP Requests

Simplified HTTP Tracking

The HttpRequestTrackerHandler handles all the tracking and error handling. It can also include other inner handlers if you are already using a custom HttpMessageHandler for other purposes, such as for logging.

To add http tracking, instantiate an HttpClient and pass the HttpRequestTrackerHandler:

var client = new HttpClient(new HttpRequestTrackerHandler());

Then, all the requests sent using the client will be already instrumented:

response = await client.GetAsync(uri);

If you already have HttpMessageHandler passed to the HttpClient (for example, adding a logging handler), you must instantiate HttpRequestTrackerHandler and pass the existing handler to the constructor:

var loggingHandler = new MyLoggingHandler();
var client = new HttpClient(new HttpRequestTrackerHandler(loggingHandler));

Manual HTTP Tracking

You can manually report a network request using the AppDynamics.Agent.HTTPRequestTracker.

The example below uses HTTPRequestTracker with the System.Net.Http.HttpClient class. The tracker object synchronously captures and reports the network request as well as any network errors.

...
public async Task<string> Fetch(Uri uri) {
var client = new HttpClient();
// Create AppDynamics Tracker
var tracker = HTTPRequestTracker.Create(uri);
// Add AppDynamics Server Correlation Headers
foreach (var header in ServerCorrelationHeaders.Generate) {
// Each header could have multiple values
foreach (var value in header.Value) {
client.DefaultRequestHeaders.Add(header.Key, value);
}
}
HttpResponseMessage response = null;
try {
response = await client.GetAsync(uri);
} catch (Exception ex) {
// Capture any network errors.
tracker.Exception = ex;
tracker.ReportDone();
throw ex; //you decide to throw it or not
}
if (!response.Equals(null)) {
// Capture request information such as the
// status code, status message, and headers.
tracker.ResponseCode = (int)response.StatusCode;
tracker.StatusLine = response.ReasonPhrase;
tracker.ResponseHeaderFields = response.Headers;
tracker.ReportDone();
return await response.Content.ReadAsStringAsync();
}
return null;
}

Attach a Custom User Data Property to a Network Request

You can attach a custom user data property to a specific network request by adding user data to HttpRequestTracker.

void SetUserData(string key, string value);
void SetUserDataLong(string key, long value);
void SetUserDataBoolean(string key, bool value);
void SetUserDataDouble(string key, double value);
void SetUserDataDate(string key, DateTime value);

Example:

public async Task Fetch(Uri uri) {
// Create AppDynamics Tracker
var tracker = HTTPRequestTracker.Create(uri);
//set user data
tracker.SetUserData("key", "value");
tracker.SetUserDataLong("number", 100);
tracker.SetUserDataBoolean("boolean", true);
tracker.SetUserDataDouble("double", 1.1234);
tracker.SetUserDataDate("date", DateTime.Now);
//rest of the implementation omitted
tracker.ReportDone();
}

Leave Breadcrumbs

You can leave breadcrumbs to mark interesting events. For example, if your application crashes, the breadcrumbs you left with be displayed in the crash report and could provide context. You can also configure the breadcrumb to appear in sessions.

The following is the method signature for leaving breadcrumbs:

static void AppDynamics.Agent.Instrumentation.LeaveBreadcrumb(string breadcrumb, BreadcrumbVisibility mode)

You use the mode to set the visibility of the breadcrumb. The visibility defines where you will see the breadcrumb in the Controller UI. The value of mode can be one of the following:

Thus, you would use the method below to set breadcrumbs that are only reported in crash reports:

If you would like to see the breadcrumb in crash reports and sessions:

...
Instrumentation.LeaveBreadcrumb("GetUserInfo", BreadcrumbVisibility.CrashesAndSessions);

Disable the Agent to Stop Sending User Data to the Collector

You can disable the agent to stop sending all data to the collector while the agent is initialized and running. For example, you can disable the agent if your app has an option for users to opt-out of monitoring for privacy reasons.

shutdownAgent

The shutdownAgent call stops outgoing data to the collector, and does not persist data on the device.

...
Instrumentation.shutdownAgent();

restartAgent

To re-enable the agent and reverse shutdownAgent, use restartAgent.

...
Instrumentation.restartAgent();

Report Errors and Exceptions

You can report exceptions using the method reportError from the Instrumentation class. Reported exceptions will appear in session details.

You can also set one of the severity levels below for an issue. With the severity level, you can filter errors in the Code Issues Dashboard or Code Issues Analyze.

The example below uses the API to report possible exceptions and sets the severity level to ErrorSeverityLevel.CRITICAL (critical) when writing to a file

...
try {
// possible exception //
}
catch (Exception e){
Instrumentation.ReportError(exception, ErrorSeverityLevel.CRITICAL);
}

Report Aggregate Exceptions as Crashes

You can configure the Xamarin Agent to report aggregate exceptions (handled and unhandled) as crashes by setting the boolean property EnableAggregateExceptionHandling to true. When the property is set to false, only unhandled exceptions are reported. The default value is false.

The following code example configures the Xamarin Agent to report aggregate exceptions (handled and unhandled) as crashes.

...
var config = AppDynamics.Agent.AgentConfiguration.Create(<EUM_APP_KEY>);
AppDynamics.Agent.Instrumentation.EnableAggregateExceptionHandling = true;
...

Disable Crash Reporting

Crash reporting is enabled by default, but you can manually disable crash reporting through the instrumentation configuration. If you are using other crash reporting tools, you might disable crash reporting to minimize conflicts and optimize the crash report results.

You can disable crash reporting by configuring the instrumentation with the crashReportingEnabled property as shown in the following code snippet:

...
var config = AgentConfiguration.Create(<EUM_APP_KEY>);
config.CrashReportingEnabled = false;
Instrumentation.InitWithConfiguration(config);
...

Programmatically Control Sessions

By default, a mobile session ends after a period of user inactivity. For example, when a user opens your application, the session begins and only ends after the user stops using the app for a set period of time. When the user begins to use the application again, a new session begins.

Instead of having a period of inactivity to define the duration of a session, however, you can use the following API to programmatically control when sessions begin and end:

When you call the method StartNextSession, the current session ends and a new session begins. The API enables you to define and frame your sessions so that they align more closely with business goals and expected user flows. For example, you could use the API to define a session that tracks a purchase of a product or registers a new user.

Excessive use of this API will cause sessions to be throttled (excessive use is > 10 calls per minute per Xamarin Agent, but is subject to change). When not using the API, sessions will fall back to the default of ending after a period of user inactivity.

Example of a Programmatically Controlled Session

In the example below, the current session ends and a new one begins when an item is bought.

...
public async Task BuySaleItemAsync(SaleItem item)
{
try
{
bool buySucceeded = await this.MobileService.InvokeApiAsync<SaleItem, bool>("buy", item);
if (buySucceeded)
{
await UserDialogs.Instance.AlertAsync("Thanks for buying this item");
Instrumentation.StartNextSession();
}
}
catch (Exception e)
{
Debug.WriteLine(@"Unexpected error {0}", e.Message);
}
}

Start and End Session Frames

You can use the Session Frame API to create session frames that will appear in the session activity. Session frames provide context for what the user is doing during a session. With the API, you can improve the names of user screens and chronicle user flows within a business context.

Use Cases

The following are common use cases for the ISessionFrame API:

ISessionFrame API

The table below lists the two methods and one property you can use with session frames. In short, you start a session frame with StartSessionFrame and then use the returned ISessionFrame object to rename and end the session frame.

Class Method / Property Description
Instrument Method:
static ISessionFrame StartSessionFrame(string sessionFrameName)
Use this to start and name your session frame.
Naming session frames enables you to easily identify and track the frames in the Sessions Details dialog.
ISessionFrame Property:
string Name
Rename the session frame name.
You assign the updated session frame name with this property from the ISessionFrame object returned from StartSessionFrame.
ISessionFrame Method:
static void End()
End the session frame.
You call this method from the ISessionFrame object returned from StartSessionFrame.

Session Frame Example

In the following example, the ISessionFrame API is used to track user activity during the checkout process.

...
namespace ShoppingApp {
public partial class ShoppingCart : ContentPage {
private ISessionFrame sessionFrame;
private string orderId;
...
void checkoutCartButtonClicked(object sender, EventArgs e) {
// The checkout starts when the user clicks the checkout button.
// This may be after they have updated quantities of items in their cart, etc.
sessionFrame = Instrumentation.StartSessionFrame("Checkout");
}
void confirmOrderButtonClicked(object sender, EventArgs e) {
// Once they have confirmed payment info and shipping information, and they
// are clicking the "Confirm" button to start the backend process of checking out,
// we may know more information about the order itself, such as an order ID.
sessionFrame.Name = $"Checkout: Order ID {this.orderId}";
}
void processOrderCompleted(object sender, EventArgs e) {
// Once the order is processed, the user is done "checking out" so we end
// the session frame.
sessionFrame.End();
}
void checkoutCancelled(object sender, EventArgs e) {
// If they cancel or go back, you'll want to end the session frame also, or else
// it will be left open and appear to have never ended.
sessionFrame.End();
}
}
}

Add User Data

You can set a key/value pair of strings to record important events or information. Below is the method signature for setting user data:

static void AppDynamics.Agent.Instrumentation.SetUserData(string key, string value)

For example, you might want to log the user ID when the method for logging in the user is called:

...
void LogInUser(UserCredentials) {
// Log in user
...
// Set user data with the user name.
Instrumentation.SetUserData("user_id", UserCredentials.ID);
}

This information is available in Network Request Analyze and is added to any crash snapshots that may be taken. Keys and values are limited to 2048 characters each.

You can also set user data with values of other types (long, boolean, double, DateTime) using the following methods:

To remove user data, use the following methods:

Set the Logging Level (Optional)

You can set the logging level with the configuration LoggingLevel as part of the class AgentConfiguration.

You can set LoggingLevel to one of the levels listed in the table below:

Level Description
Off Agent will emit no messages at all.
Error Default Value.
Only show errors and initial banner.
Warn Warning level messages and above.
Info Information level messages and above.
May be useful to the developer.
Debug Debug level messages and above.
Useful for support personnel and developers.
Verbose Verbose level messages and above.
Use verbose logging only for troubleshooting. Be sure to disable for production.
All All messages.

For example:

var config = AppDynamics.Agent.AgentConfiguration.Create("<#Your App Key#>");
config.LoggingLevel = AppDynamics.Agent.LoggingLevel.All;

Transform URLs for Network Requests

Implement the Network Request Callback

The callback that modifies or ignore specific URLs should be assigned to the Func delegate below.

public Func<IHttpRequestTracker, bool> OnNetworkRequest { get; set; }

Transforming URLs

To transform URLs, the OnNetworkRequest method should:

  1. Identify specific URLs using techniques such as regex or pattern matching. This first step is optional because you can choose to transform the URLs of all network requests.
  2. Modify the URL property of the IHttpRequestTracker object.
  3. Assign a valid URL to the url property. Modifying other properties of the IHttpRequestTracker object will be ignored.
  4. Return true.

For example:

public static bool NetworkRequestCallback(IHttpRequestTracker tracker)
{
var maskUrl = new Uri("http://networkrequest-mask.com/");
tracker.Uri = maskUrl;
return true;
}

Transforming Sensitive URLs

You may want to identify and transform URLs that contain sensitive information.

For example:

public static bool NetworkRequestCallback(IHttpRequestTracker tracker)
{
var urlString = tracker.Uri.ToString();
if (urlString.Contains("accountInfo"))
{
tracker.Uri = new Uri("http://customer-account.com/");
}
return true;
}

Ignoring URLs

If the onNetworkRequest method returns false, the beacon is dropped. Generally, the process for ignoring beacons is:

  1. Identify specific URLs using techniques such as regex or pattern matching.
  2. Return false.

To ignore specific URLs, you would identify network requests that you didn't want to monitor and return false to ignore the network request.

For example:

public static bool NetworkRequestCallback(IHttpRequestTracker tracker)
{
if (tracker.Uri.ToString().Contains("avatar"))
{
//ignore calls for avatars
return false;
}
return true;
}

To ignore all network requests, implement the following:

public static bool NetworkRequestCallback(IHttpRequestTracker tracker)
{
return false;
}

Register a Network Request Callback

To register a network request callback:

  1. Define your own method to handle the callback:
public static bool NetworkRequestCallback(IHttpRequestTracker tracker)
{
return true;
}
  1. Pass it during the AgentConfiguration initialization phase:
IAgentConfiguration config = AgentConfiguration.Create(appKey);
config.OnNetworkRequest += NetworkRequestCallback; //Register the Callback
Instrumentation.InitWithConfiguration(config);
  1. Or you can use an anonymous function:
IAgentConfiguration config = AgentConfiguration.Create(appKey);
config.OnNetworkRequest += (IHttpRequestTracker tracker) =>
{
return true;
};
Instrumentation.InitWithConfiguration(config);

Configure and Take Screenshots

Mobile screenshots are enabled by default, but you can configure the Controller UI to automatically take screenshots or use the Xamarin SDK to manually take a screenshot:

Instrumentation.TakeScreenshot();

Note: The takeScreenshot() function limits screenshots to a maximum of 1 screenshot per 10 seconds.

Disable Screenshots

You can disable screenshots from the Controller UI or with the Xamarin SDK. To disable screenshots with the Xamarin SDK, set the property ScreenshotsEnabled of the IAgentConfiguration object to false:

IAgentConfiguration config = AgentConfiguration.Create(appKey); config.ScreenshotsEnabled = false; Instrumentation.InitWithConfiguration(config);

Block and Unblock Screenshots

You can also use the Xamarin SDK to block screenshots from being taken during the execution of a code block. This just temporarily blocks screenshots from being taken until you unblock screenshots. This enables you to stop taking screenshots in situations where users are entering personal data, such as on login and account screens.

The Instrumentation class provides the methods blockScreenshots() and unblockScreenshots() to block and unblock screenshots.

Note: If screenshots are disabled through the property ScreenshotsEnabled of the IAgentConfiguration object or through the Controller UI, these methods have no effect. You can also check the Instrumentation.ScreenshotsBlocked property to check if screenshots are being blocked.

public void LoginUser()
{
if (!Instrumentation.ScreenshotsBlocked)
{
Instrumentation.BlockScreenshots();
}
LoginCredentials credentials = UserLogin.GetCredentials();
if (credentials.Authorized)
{
RedirectToProfile(credentials.user);
Instrumentation.UnblockScreenshots();
}
}

Add a Crash Reporting Callback

You may want to make crash report information (that the Xamarin Agent collects) available to other parts of your code, for example, to Google Analytics. To enable passing on summary crash information, you can set up a crash report runtime callback. To get a callback when the Xamarin Agent detects and then reports a crash, subscribe to the following event, that's part of the IAgentConfiguration interface.

event EventHandler<IEnumerable<CrashReportSummary>> OnCrash;

The Xamarin Agent sends a collection of crash report summaries instead of an individual callback in the event that there is more than one crash, producing multiple crash report summaries.

The OnCrash event is raised during the next initialization of the Xamarin Agent after a crash has occurred.

This event is raised on your app's UI thread, so any work should be done on a separate work thread.

Each CrashReportSummary has the following properties:

public class CrashReportSummary
{
public string ExceptionId { get; }
public string ExceptionName { get; }
public string ExceptionReason { get; }
}

If you are sending the information to another analytics tool, such as Google Analytics, we recommend to include all three properties: ExceptionName and ExceptionReason are useful for quick identification of the crash, and ExceptionId is useful to look up the crash in the Controller UI.

For example, to print the crash information to the console, you could subscribe to the OnCrash event like this:

IAgentConfiguration config = AgentConfiguration.Create(appKey);
config.OnCrash += (sender, crashReportSummaries) =>
{
foreach (var crashReportSummary in crashReportSummaries) {
Console.WriteLine($"Crash Detected: {crashReportSummary.ExceptionName}: {crashReportSummary.ExceptionReason} ({crashReportSummary.ExceptionId})");
}
};
Instrumentation.InitWithConfiguration(config);

Xamarin.Forms Specific Instrumentation

You can now instrument Xamarin.Forms elements using AppDynamics.Agent.Forms. Make sure you included the right nuget package before proceeding.

Page Tracking

Track page usage and see the how the user interacts with the application in the session timeline.

In order to track pages, all you need to do is call TrackPage from the constructor on every page you want to monitor:

public partial class MyPage : ContentPage
{
public MyPage()
{
InitializeComponent();
}
}

UI Tracking

Track user interaction with UI elements. You can now instrument Buttons, Entries and ListViews.

All you have to do is attach a property to your views:

appd:UiInstrumentation.IsInstrumented="True"

And make sure to also include the namespace:

xmlns:appd="clr-namespace:AppDynamics.Agent.Forms;assembly=AppDynamics.Agent.Forms"

Example (xaml file):

<ContentPage
xmlns:appd="clr-namespace:AppDynamics.Agent.Forms;assembly=AppDynamics.Agent.Forms" >
<StackLayout>
<Button
appd:UiInstrumentation.IsInstrumented="True"
Clicked="OnButtonClicked" />
<Entry
appd:UiInstrumentation.IsInstrumented="True" />
<ListView
appd:UiInstrumentation.IsInstrumented="True">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Item 1</x:String>
<x:String>Item 2</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</ContentPage>

You can also instrument properties from code behind:

...
var button = new Button();
button.SetValue(UiInstrumentation.IsInstrumentedProperty, true);

The IsInstrumented property will track the following events:

  1. Button - Button Clicked
  2. ListView - Item Selected
  3. Entry - Entry Focused & Entry Unfocused

Automatic instrumentation with AppDynamics.Agent.AutoInstrument.Fody

Since the release of AppDynamics.Agent 22.2.0, we added automatic instrumentation capabilities to the Xamarin Agent. This is handled via a stand alone library, called AppDynamics.Agent.AutoInstrument.Fody

AppDynamics.Agent.AutoInstrument.Fody

The Xamarin Agent can automatically inject Xamarin-specific instrumentation code into your project. You can:

  1. Automtically Track Network Requests using either the classic HttpClient or Refit
  2. Automatically add Page Tracking (link to Intrument Xamarin.Forms - Page Tracking section)
  3. Automatically add UI Tracking (link to Instrument Xamarin.Forms - UI Tracking section)

This can be achieved using a different nuget package (currently in Beta), called AppDynamics.Agent.AutoInstrument.Fody. To install the package while in Beta, make sure the **"Include prereleases"** option is checked under Manage Nuget Packages.

How to use

  1. Make sure you already have the AppDynamics.Agent package set up and initialised. See Add the Xamarin Agent Package and Initialize the Agent.
  2. Add the new AppDynamics.Agent.AutoInstrument.Fody package.
  3. Build the solution

Normally, after you build the solution, two files will be generated automatically:

  1. FodyWeavers.xml
  2. FodyWeavers.xsd

These files should be checked into source control.

Note1: If the above files are not generated automatically, a new file called FodyWeavers.xml should be created manually having the content as below:

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<AppDynamics.Agent.AutoInstrument />
</Weavers>

Note2: If the project is already using Fody, these files will already be there and only the FodyWeavers.xml file has to be updated to include the AppDynamics.Agent.AutoInstrument weaver. Example:

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
... Existing weavers ...
<AppDynamics.Agent.AutoInstrument />
</Weavers>

Customize automatic instrumentation

Customize Automatic Network Requests Instrumentation

There are two ways of enabling or disabling Automatic Http instrumentation:

1. Global Switch

You can enable or disable HttpInstrumentation using the FodyWeavers.xml file, via the NetworkInstrumentationEnabled flag. Example:

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
... Existing weavers ...
<AppDynamics.Agent.AutoInstrument NetworkInstrumentationEnabled="true"/>
</Weavers>

2. Per class switch

You can enable or disable network instrumentation per class using two different attributes.

[EnableNetworkInstrumentation]

[EnableNetworkInstrumentation]
public class MyClass
{
...
}

[DisableNetworkInstrumentation]

[DisableNetworkInstrumentation]
public class MyClass
{
...
}

This means that you can either:

  1. Enable the automatic instrumentation at a project level from the FodyWeavers.xml file, but exclude some files using the DisableNetworkInstrumentation attribute.
  2. Disable the automatic instrumentation at a project level from the FodyWeavers.xml file, but include some files using the EnableNetworkInstrumentation attribute.

How Automatic Http Instrumentation works

The weaver will search the project for all new instances of HttpClient or Refit usages. If any are found found, our instrumentation code will be injected to the HttpClient or Refit request.

Note1: If you are using Manual Http Tracking, you will see duplicate entries for the same network request. To avoid that, you can either remove the manual instrumentation, or use the DisableNetworkInstrumentation attribute on that class.

Note2: If you are using the Simplified Http Tracking with the HttpRequestTrackerHandler, the request will not be reported twice.

Known Limitations

Http Requests are handled in a different project.

Answer: You should add both the AppDynamics.Agent and AppDynamics.Agent.AutoInstrument.Fody to that project as well, and instrumentation should work.

Using a HttpClient instance generated in another library.

Answer: Automatic instrumentation works by targeting new HttpClient instances within the project. Only creating and using the instance within the same project will work.

Customize Automatic Page Tracking

When automatic page tracking instrumentation is enabled, the weaver will search the project for all Xamarin Forms Pages in the project and inject the instrumentation code.

Enable/Disable at the Project Level

You can enable or disable automatic Page Tracking instrumentation at the project level using the PageTrackingInstrumentationEnabled flag in the FodyWeavers.xml file. For example:

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
... Existing weavers ...
<AppDynamics.Agent.AutoInstrument PageTrackingInstrumentationEnabled="true"/>
</Weavers>

Enable/Disable at the Class Level

You can enable or disable automatic Page Tracking instrumentation per class using two different attributes: EnablePageTracking and DisablePageTracking

[EnablePageTracking]
public class MyPage : Xamarin.Forms.ContentPage
{
...
}
[DisablePageTracking] public class MyPage : Xamarin.Forms.ContentPage
{ ... }

Customize Automatic UI Tracking

When automatic UI Tracking instrumentation is enabled, the weaver will search the project for all Xamarin Forms Buttons, Entries and Lists in the project and inject the instrumentation code.

Enable/Disable at the Project Level

You can enable or disable automatic UI Tracking Instrumentation at the project level using the UITrackingInstrumentationEnabled flag in the FodyWeavers.xml file.

For example:

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
... Existing weavers ...
<AppDynamics.Agent.AutoInstrument UITrackingInstrumentationEnabled="true"/>
</Weavers>

Enable/Disable at the Class Level

You can enable or disable automatic UI Tracking instrumentation per class using two different attributes: EnableUITracking and DisableUITracking.

[EnableUITracking]
public class MyPage : Xamarin.Forms.ContentPage
{
...
}
[DisableUITracking]
public class MyPage : Xamarin.Forms.ContentPage
{
...
}

UI Tracking and XAML

UI Tracking works with both XAML and Code Behind UI elements. While code-behind UIs are automatically instrumented, there's a required extra step to auto instrument XAML. Please include this in the .csproj.

<PropertyGroup>
<FodyDependsOnTargets>
XamlC
</FodyDependsOnTargets>
</PropertyGroup>

It's also worth mentioning what it will only work with pre-compiled XAML. So you need to use XamlCompilationOptions.Compile. By default, a project created with a Visual Studio Xamarin.Forms template will already include this. More info: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xamlc

[XamlCompilation(XamlCompilationOptions.Compile)]