# Initializing

Glean needs to be initialized in order to be able to send pings,
record metrics and perform maintenance tasks. Thus it is advised that Glean be initialized as
soon as possible in an application's lifetime and importantly, before any other libraries in the
application start using Glean.

{{#include ../../../shared/blockquote-info.html}}

## Libraries are not required to initialize Glean

> Libraries rely on the same Glean singleton as the application in which they are
> embedded. Hence, they are not expected to initialize Glean
> as the application should already do that.

## Behavior when uninitialized

Any API called before Glean is initialized is queued and applied at initialization.
To avoid unbounded memory growth the queue is bounded (currently to a maximum of 100 tasks),
and further calls are dropped.

The number of calls dropped, if any,
is recorded in the `glean.error.preinit_tasks_overflow` metric.

## Behavior once initialized

### When upload is enabled

Once initialized, if upload is enabled,
Glean applies all metric recordings and ping submissions,
for both user-defined and builtin metrics and pings.

This always happens asynchronously.

### When upload is disabled

If upload is disabled, any persisted metrics, events and pings (other than `first_run_date` and `first_run_hour`) are cleared.
Pending `deletion-request` pings are sent.
Subsequent calls to record metrics and submit pings will be no-ops.
Because Glean does that as part of its initialization, users are _required_ to always initialize Glean.

**Glean must be initialized even if upload is disabled.**

This does not apply to special builds where telemetry is disabled at build time.
In that case, it is acceptable to not call initialize at all.

## API

### `Glean.initialize(configuration)`

Initializes Glean.

May only be called once. Subsequent calls to `initialize` are no-op.

#### Configuration

The available `initialize` configuration options may vary depending on the SDK.
Below are listed the configuration options available on most SDKs.

- `applicationId`: Application identifier. For Android and iOS applications, this is the id used on the platform's respective app store and is extracted automatically from the application context.
- `uploadEnabled`: The user preference on whether or not data upload is enabled.
- `appChannel`: The application's release channel. When present, the `app_channel` will be reported in all ping's [`client_info`](../../user/pings/index.html#the-client_info-section) section.
- `appBuild`: A build identifier e.g. the build identifier generated by a CI system (e.g. "1234/A"). If not present, `app_build` will be reported as "Unknown" on all pings [`client_info`](../../user/pings/index.html#the-client_info-section) section.
- `appDisplayVersion`: The user visible version string for the application running Glean. If not present, `app_display_version` will be reported as "Unknown" on all pings [`client_info`](../../user/pings/index.html#the-client_info-section) section.
- `serverEndpoint`: The server pings are sent to. Defaults to `https://incoming.telemetry.mozilla.org`.
- `maxEvents`: The maximum number of events the Glean storage will hold on to before submitting the 'events' ping. Defaults to 500. Refer to the [`events` ping documentation](../../user/pings/events.md) for more information on its scheduling.
- `httpUploader`: A custom HTTP uploader instance, that will overwrite Glean's provided uploader. Useful
for users that wish to use specific uploader implementations. See [Custom Uploaders](#custom-uploaders)
for more information on how and when the use this feature.

To learn about SDK specific configuration options available, refer to the [Reference](#reference) section.

{{#include ../../../shared/blockquote-stop.html}}

##### Always initialize Glean with the correct upload preference

> Glean must **always** be initialized with real values.
>
> Always pass the user preference, e.g. `Glean.initialize(upload=userSettings.telemetry_enabled)` or the equivalent for your application.
> Never call `Glean.initialize(upload=true)` if `true` is a placeholder value that later gets reset by `Glean.setUploadEnabled(false)` and vice-versa.
>
> Depending on the provided placeholder value, this might trigger the generation of new client ids or the submission of bogus [`deletion-request` pings](../../user/pings/deletion-request.md).

{{#include ../../../shared/tab_header.md}}

<div data-lang="Kotlin" class="tab">

An excellent place to initialize Glean is within the `onCreate` method of the class that extends Android's `Application` class.

```Kotlin
import org.mozilla.yourApplication.GleanMetrics.GleanBuildInfo
import org.mozilla.yourApplication.GleanMetrics.Pings

class SampleApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        // If you have custom pings in your application, you must register them
        // using the following command. This command should be omitted for
        // applications not using custom pings.
        Glean.registerPings(Pings)

        // Initialize the Glean library.
        Glean.initialize(
            applicationContext,
            // Here, `settings()` is a method to get user preferences, specific to
            // your application and not part of the Glean API.
            uploadEnabled = settings().isTelemetryEnabled,
            buildInfo = GleanBuildInfo.buildInfo
        )
    }
}
```

The Glean Kotlin SDK does not support use across multiple processes, and must only be initialized on the application's main process. Initializing in other processes is a no-op.

Additionally, Glean must be initialized on the main (UI) thread of the applications main process. Failure to do so will throw an `IllegalThreadStateException`.

### Consuming Glean through Android Components

When the Glean Kotlin SDK is consumed through Android Components,
it is required to configure an HTTP client to be used for upload.

For example:

```Kotlin
// Requires `org.mozilla.components:concept-fetch`
import mozilla.components.concept.fetch.Client

// Requires `org.mozilla.components:lib-fetch-httpurlconnection`.
// This can be replaced by other implementations, e.g. `lib-fetch-okhttp`
// or an implementation from `browser-engine-gecko`.
import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient
import mozilla.components.service.glean.config.Configuration
import mozilla.components.service.glean.net.ConceptFetchHttpUploader

val httpClient = ConceptFetchHttpUploader(lazy { HttpURLConnectionClient() as Client })
val config = Configuration(httpClient = httpClient)
Glean.initialize(
   context,
   uploadEnabled = true,
   configuration = config,
   buildInfo = GleanBuildInfo.buildInfo
)
```

</div>

<div data-lang="Swift" class="tab">

An excellent place to initialize Glean is within the `application(_:)` method of the class that extends the `UIApplicationDelegate` class.

```Swift
import Glean
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // If you have custom pings in your application, you must register them
        // using the following command. This command should be omitted for
        // applications not using custom pings.
        Glean.shared.registerPings(GleanMetrics.Pings)

        // Initialize the Glean library.
        Glean.shared.initialize(
            // Here, `Settings` is a method to get user preferences specific to
            // your application, and not part of the Glean API.
            uploadEnabled = Settings.isTelemetryEnabled,
            buildInfo = GleanMetrics.GleanBuild.info
        )
    }
}
```

The Glean Swift SDK does not support use across multiple processes,
and must only be initialized on the application's main process.

</div>

<div data-lang="Python" class="tab">

The main control for the Glean Python SDK is on the `glean.Glean` singleton.


```python
from glean import Glean

Glean.initialize(
    application_id="my-app-id",
    application_version="0.1.0",
    # Here, `is_telemetry_enabled` is a method to get user preferences specific to
    # your application, and not part of the Glean API.
    upload_enabled=is_telemetry_enabled(),
)
```

Unlike in other implementations, the Python SDK does not automatically send any pings.
See the [custom pings documentation](../../user/pings/custom.md) about adding custom pings and sending them.

</div>

<div data-lang="Rust" class="tab">

The Glean Rust SDK should be initialized as soon as possible.

```Rust
use glean::{ClientInfoMetrics, Configuration};
let cfg = Configuration {
    data_path,
    application_id: "my-app-id".into(),
    // Here, `is_telemetry_enabled` is a method to get user preferences specific to
    // your application, and not part of the Glean API.
    upload_enabled: is_telemetry_enabled(),
    max_events: None,
    delay_ping_lifetime_io: false,
    channel: None,
    server_endpoint: Some("https://incoming.telemetry.mozilla.org".into()),
    uploader: None,
    use_core_mps: true,
};

let client_info = ClientInfoMetrics {
    app_build: env!("CARGO_PKG_VERSION").to_string(),
    app_display_version: env!("CARGO_PKG_VERSION").to_string(),
};

glean::initialize(cfg, client_info);
```

The Glean Rust SDK does not support use across multiple processes, and must only be initialized on the application's main process.

Unlike in other implementations, the Rust SDK does not provide a default uploader.
See [`PingUploader`](../../../docs/glean/net/trait.PingUploader.html) for details.

</div>

<div data-lang="JavaScript" class="tab">

```js
import Glean from "@mozilla/glean/<platform>";

Glean.initialize(
    "my-app-id",
    // Here, `isTelemetryEnabled` is a method to get user preferences specific to
    // your application, and not part of the Glean API.
    isTelemetryEnabled(),
    {
      appDisplayVersion: "0.1.0"
    }
);
```
</div>

<div data-lang="Firefox Desktop" class="tab" data-info="On Firefox Desktop Glean initialization is handled internally."></div>

{{#include ../../../shared/tab_footer.md}}

### Custom Uploaders

A custom HTTP uploader may be provided at initialization time in order to overwrite Glean's
native ping uploader implementation. Each SDK exposes a base class for Glean users to extend
into their own custom uploaders.

{{#include ../../../shared/tab_header.md}}

<div data-lang="Kotlin" class="tab">

See [`BaseUploader`](https://github.com/mozilla/glean/blob/main/glean-core/android/src/main/java/mozilla/telemetry/glean/net/BaseUploader.kt)
for details on how to implement a custom upload on Kotlin.

</div>
<div data-lang="Swift" class="tab">

See [`HttpPingUploader`](../../../swift/Classes/HttpPingUploader.html)
for details on how to implement a custom upload on Swift.

</div>
<div data-lang="Python" class="tab">

See [`BaseUploader`](../../../python/glean/net/base_uploader.html#glean.net.base_uploader.BaseUploader)
for details on how to implement a custom upload on Python.

</div>
<div data-lang="Rust" class="tab">

See [`PingUploader`](../../../docs/glean/net/trait.PingUploader.html)
for details on how to implement a custom upload on Rust.

</div>
<div data-lang="JavaScript" class="tab">

```ts
import { Uploader, UploadResult, UploadResultStatus } from "@mozilla/glean/uploader";
import Glean from "@mozilla/glean/<platform>";

/**
 * My custom uploader implementation
 */
export class MyCustomUploader extends Uploader {
  async post(url: string, body: string, headers): Promise<UploadResult> {
    // My custom POST request code
  }
}

Glean.initialize(
    "my-app-id",
    // Here, `isTelemetryEnabled` is a method to get user preferences specific to
    // your application, and not part of the Glean API.
    isTelemetryEnabled(),
    {
      httpClient: new MyCustomUploader()
    }
);
```

</div>

<div data-lang="Firefox Desktop" class="tab"></div>

{{#include ../../../shared/tab_footer.md}}

## Testing API

When unit testing metrics and pings, Glean needs to be put in testing mode. Initializing
Glean for tests is referred to as "resetting". It is advised that Glean is reset before each unit test
to prevent side effects of one unit test impacting others.

How to do that and the definition of "testing mode" varies per Glean SDK. Refer to the information
below for SDK specific information.

{{#include ../../../shared/tab_header.md}}

<div data-lang="Kotlin" class="tab">

Using the Glean Kotlin SDK's unit testing API requires adding
[Robolectric 4.0 or later](http://robolectric.org/) as a testing dependency.
In Gradle, this can be done by declaring a `testImplementation` dependency:

```groovy
dependencies {
    testImplementation "org.robolectric:robolectric:4.3.1"
}
```

In order to put the Glean Kotlin SDK into testing mode apply the JUnit `GleanTestRule` to your test class.
Testing mode will prevent issues with async calls when unit testing the Glean SDK on Kotlin. It also
enables uploading and clears the recorded metrics at the beginning of each test run.

The rule can be used as shown:

```kotlin
@RunWith(AndroidJUnit4::class)
class ActivityCollectingDataTest {
    // Apply the GleanTestRule to set up a disposable Glean instance.
    // Please note that this clears the Glean data across tests.
    @get:Rule
    val gleanRule = GleanTestRule(ApplicationProvider.getApplicationContext())

    @Test
    fun checkCollectedData() {
      // The Glean Kotlin SDK testing APIs can be called here.
    }
}
```

This will ensure that metrics are done recording when the other test functions are used.

</div>

<div data-lang="Swift" class="tab">

**Note**: There's no automatic test rule for Glean tests implemented in Swift.

In order to prevent issues with async calls when unit testing the Glean SDK, it is important to put
the Glean Swift SDK into testing mode. When the Glean Swift SDK is in testing mode,
it enables uploading and clears the recorded metrics at the beginning of each test run.

Activate it by resetting Glean in your test's setup:

```swift
// All pings and metrics testing APIs are marked as `internal`
// so you need to import `Glean` explicitly in test mode.
import XCTest

class GleanUsageTests: XCTestCase {
    override func setUp() {
        Glean.shared.resetGlean(clearStores: true)
    }

    // ...
}
```

This will ensure that metrics are done recording when the other test functions are used.

</div>

<div data-lang="Python" class="tab">

The Glean Python SDK contains a helper function `glean.testing.reset_glean()` for resetting Glean for tests.
It has two required arguments: the application ID, and the application version.

Each reset of the Glean Python SDK will create a new temporary directory for Glean to store its data in.
This temporary directory is automatically cleaned up the next time the Glean Python SDK is reset or when the testing framework finishes.

The instructions below assume you are using [pytest](https://pypi.org/project/pytest/) as the test runner.
Other test-running libraries have similar features, but are different in the details.

Create a file `conftest.py` at the root of your test directory, and add the following to reset Glean at the start of every test in your suite:

```python
import pytest
from glean import testing

@pytest.fixture(name="reset_glean", scope="function", autouse=True)
def fixture_reset_glean():
    testing.reset_glean(application_id="my-app-id", application_version="0.1.0")
```

</div>

<div data-lang="Rust" class="tab"></div>
<div data-lang="JavaScript" class="tab">

The Glean JavaScript SDK contains a helper function `testResetGlean()` for resetting Glean for tests.
It expects the same list of arguments as `Glean.initialize`.

Each reset of the Glean JavaScript SDK will clear stores. Calling `testResetGlean` will also make
metrics and pings testing APIs available and replace ping uploading with a mock implementation that
does not make real HTTP requests.

```js
import { testResetGlean } from "@mozilla/glean/testing"

describe("myTestSuite", () => {
    beforeEach(async () => {
        await testResetGlean("my-test-id");
    });
});

```

</div>
<div data-lang="Firefox Desktop" class="tab" data-info='Documentation on how to reset Glean in Firefox Desktop tests can be found at <a href="https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/instrumentation_tests.html" target="_blank">"Writing Instrumentation Tests"</a>'></div>

{{#include ../../../shared/tab_footer.md}}

## Reference

- [Swift API docs](../../../swift/Classes/Glean.html#/s:5GleanAAC10initialize13uploadEnabled13configuration9buildInfoySb_AA13ConfigurationVAA05BuildG0VtF)
- [Python API docs](../../../python/glean/index.html#glean.Glean.initialize)
- [Rust API docs](../../../docs/glean/fn.initialize.html)
- [JavaScript API docs](https://mozilla.github.io/glean.js/modules/core_glean.default.html#initialize)
