---
title: Send metrics from your product
source: https://docs.newrelic.com/docs/new-relic-solutions/build-nr-ui/contribute-nr-io/send-metrics
---

> #### 💡 TIP
>
> This procedure is a part of course that teaches you how to build a quickstart. If you haven't already, checkout the [course introduction](https://docs.newrelic.com/docs/new-relic-solutions/build-nr-ui/contribute-nr-io/contribute-quickstart).
>
> Each procedure in this course builds on top of the last one, so make sure you [deploy your application](https://docs.newrelic.com/docs/new-relic-solutions/build-nr-ui/contribute-nr-io/deploy-your-application) before proceeding with this one.

Metrics are aggregated measurements derived from the system's performance and behaviors. If your product is a database, you might send metrics like CPU utilization, memory utilization, and query throughput. Note that metrics are generally only used if you want to limit the amount of Data sent to New Relic.
Note that many metrics, such as error rates and throughput, can be computed by aggregating events.

New Relic provides you a variety of ways to instrument your application to send metrics to our [metric API](https://docs.newrelic.com/docs/data-apis/ingest-apis/metric-api/introduction-metric-api).
In this lesson, you send metrics from your product using our telemetry software development kit (SDK).

## Use our SDK [#use-sdk]

We offer an open source [telemetry SDK](https://docs.newrelic.com/docs/data-apis/ingest-apis/telemetry-sdks-report-custom-telemetry-data) in several of the most popular programming languages. These send data to our data ingest APIs, including our Metric API. Of these language SDKs, Python, Java, Node/TypeScript, and Go work with the Metric API.

In this lesson, you learn how to install and use the [Python telemetry SDK](https://github.com/newrelic/newrelic-telemetry-sdk-python) to send metrics to New Relic.

1.  Change to the `send-metrics/flashDB` direcrory of the [course repository](https://github.com/newrelic-experimental/build-a-quickstart-lab).
    ````bash
    cd ../send-metrics/flashDB
    ```

    ````
2.  Use `pip` to install the `newrelic-telemetry-sdk` package.
    ````bash
    pip install newrelic-telemetry-sdk
    ```

    ````
3.  Store your New Relic license key in an environment variable called `$NEW_RELIC_LICENSE_KEY`.
    ````bash
    export NEW_RELIC_LICENSE_KEY=<YOUR_USER_KEY>
    ```

    <Callout variant="tip">
      You can find your New Relic license key in your [account settings](/docs/apis/intro-apis/new-relic-api-keys).
    </Callout>

    ````

Next, you familiarize yourself with the app logic.

```python fileName=db.py
import os
import random
import datetime

db = {}
stats = {
    "read_response_times": [],
    "read_errors": 0,
    "read_count": 0,
    "create_response_times": [],
    "create_errors": 0,
    "create_count": 0,
    "update_response_times": [],
    "update_errors": 0,
    "update_count": 0,
    "delete_response_times": [],
    "delete_errors": 0,
    "delete_count": 0,
    "cache_hit": 0,
}
last_push = {
    "read": datetime.datetime.now(),
    "create": datetime.datetime.now(),
    "update": datetime.datetime.now(),
    "delete": datetime.datetime.now(),
}

def read(key):

    print(f"Reading...")

    if random.randint(0, 30) > 10:
        stats["cache_hit"] += 1

    stats["read_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["read_errors"] += 1
    stats["read_count"] += 1
    try_send("read")

def create(key, value):

    print(f"Writing...")

    db[key] = value
    stats["create_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["create_errors"] += 1
    stats["create_count"] += 1
    try_send("create")

def update(key, value):

    print(f"Updating...")

    db[key] = value
    stats["update_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["update_errors"] += 1
    stats["update_count"] += 1
    try_send("update")

def delete(key):

    print(f"Deleting...")

    db.pop(key, None)
    stats["delete_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["delete_errors"] += 1
    stats["delete_count"] += 1
    try_send("delete")

def try_send(type_):

    print("try_send")

def clear(type_):
    stats[f"{type_}_response_times"] = []
    stats[f"{type_}_errors"] = 0
    stats["cache_hit"] = 0
    stats[f"{type_}_count"] = 0
    last_push[type_] = datetime.datetime.now()

```

## Familiarize yourself with the application [#familiarize-with-app]

Open `db.py` file in the IDE of your choice and familiarize yourself with the app logic.

This demo uses a dummy Python application that mimics the Create, Read, Update, and Delete (CRUD) operations.

```python fileName=db.py
import os
import random
import datetime

db = {}
stats = {
    "read_response_times": [],
    "read_errors": 0,
    "read_count": 0,
    "create_response_times": [],
    "create_errors": 0,
    "create_count": 0,
    "update_response_times": [],
    "update_errors": 0,
    "update_count": 0,
    "delete_response_times": [],
    "delete_errors": 0,
    "delete_count": 0,
    "cache_hit": 0,
}
last_push = {
    "read": datetime.datetime.now(),
    "create": datetime.datetime.now(),
    "update": datetime.datetime.now(),
    "delete": datetime.datetime.now(),
}

def read(key):

    print(f"Reading...")

    if random.randint(0, 30) > 10:
        stats["cache_hit"] += 1

    stats["read_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["read_errors"] += 1
    stats["read_count"] += 1
    try_send("read")

def create(key, value):

    print(f"Writing...")

    db[key] = value
    stats["create_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["create_errors"] += 1
    stats["create_count"] += 1
    try_send("create")

def update(key, value):

    print(f"Updating...")

    db[key] = value
    stats["update_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["update_errors"] += 1
    stats["update_count"] += 1
    try_send("update")

def delete(key):

    print(f"Deleting...")

    db.pop(key, None)
    stats["delete_response_times"].append(random.uniform(0.5, 1.0))
    if random.choice([True, False]):
        stats["delete_errors"] += 1
    stats["delete_count"] += 1
    try_send("delete")

def try_send(type_):

    print("try_send")

def clear(type_):
    stats[f"{type_}_response_times"] = []
    stats[f"{type_}_errors"] = 0
    stats["cache_hit"] = 0
    stats[f"{type_}_count"] = 0
    last_push[type_] = datetime.datetime.now()

```

The `read`, `create`, `update`, and `delete` are the dummy methods to mimic CRUD operations. For every CRUD operations, respective `stat` is incremented to reflect that the operation has been performed. Next, you send this `stats` data to New Relic.

## Send metrics to New Relic [#send-metrics]

There are 3 different types of metrics:

-   **GaugeMetric**: sends a single value at a single point in time.
-   **CountMetric**: tracks the total number of occurrences of an event.
-   **SummaryMetric**: tracks count, sum, min, and max values over time.

Next, instrument your application to send these metrics.

1.  In `db.py`, configure the `MetricClient`.
    ````python fileName=db.py
    import os
    import random
    import datetime

    from newrelic_telemetry_sdk import MetricClient

    metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])

    db = {}
    stats = {
        "read_response_times": [],
        "read_errors": 0,
        "read_count": 0,
        "create_response_times": [],
        "create_errors": 0,
        "create_count": 0,
        "update_response_times": [],
        "update_errors": 0,
        "update_count": 0,
        "delete_response_times": [],
        "delete_errors": 0,
        "delete_count": 0,
        "cache_hit": 0,
    }
    last_push = {
        "read": datetime.datetime.now(),
        "create": datetime.datetime.now(),
        "update": datetime.datetime.now(),
        "delete": datetime.datetime.now(),
    }

    def read(key):

        print(f"Reading...")

        if random.randint(0, 30) > 10:
            stats["cache_hit"] += 1

        stats["read_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["read_errors"] += 1
        stats["read_count"] += 1
        try_send("read")

    def create(key, value):

        print(f"Writing...")

        db[key] = value
        stats["create_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["create_errors"] += 1
        stats["create_count"] += 1
        try_send("create")

    def update(key, value):

        print(f"Updating...")

        db[key] = value
        stats["update_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["update_errors"] += 1
        stats["update_count"] += 1
        try_send("update")

    def delete(key):

        print(f"Deleting...")

        db.pop(key, None)
        stats["delete_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["delete_errors"] += 1
        stats["delete_count"] += 1
        try_send("delete")

    def try_send(type_):

        print("try_send")

    def clear(type_):
        stats[f"{type_}_response_times"] = []
        stats[f"{type_}_errors"] = 0
        stats["cache_hit"] = 0
        stats[f"{type_}_count"] = 0
        last_push[type_] = datetime.datetime.now()

    ```

    ````
2.  Instrument your app to send the folloiwng metrics to New Relic:
    -   `keys`
    -   `db_size`
    -   `errors`
    -   `cache_hits`
    -   `response_times`

        ```python fileName=db.py

        import os
        import random
        import datetime
        from sys import getsizeof

        from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric

        metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])

        db = {}
        stats = {
            "read_response_times": [],
            "read_errors": 0,
            "read_count": 0,
            "create_response_times": [],
            "create_errors": 0,
            "create_count": 0,
            "update_response_times": [],
            "update_errors": 0,
            "update_count": 0,
            "delete_response_times": [],
            "delete_errors": 0,
            "delete_count": 0,
            "cache_hit": 0,
        }
        last_push = {
            "read": datetime.datetime.now(),
            "create": datetime.datetime.now(),
            "update": datetime.datetime.now(),
            "delete": datetime.datetime.now(),
        }

        def read(key):

            print(f"Reading...")

            if random.randint(0, 30) > 10:
                stats["cache_hit"] += 1

            stats["read_response_times"].append(random.uniform(0.5, 1.0))
            if random.choice([True, False]):
                stats["read_errors"] += 1
            stats["read_count"] += 1
            try_send("read")

        def create(key, value):

            print(f"Writing...")

            db[key] = value
            stats["create_response_times"].append(random.uniform(0.5, 1.0))
            if random.choice([True, False]):
                stats["create_errors"] += 1
            stats["create_count"] += 1
            try_send("create")

        def update(key, value):

            print(f"Updating...")

            db[key] = value
            stats["update_response_times"].append(random.uniform(0.5, 1.0))
            if random.choice([True, False]):
                stats["update_errors"] += 1
            stats["update_count"] += 1
            try_send("update")

        def delete(key):

            print(f"Deleting...")

            db.pop(key, None)
            stats["delete_response_times"].append(random.uniform(0.5, 1.0))
            if random.choice([True, False]):
                stats["delete_errors"] += 1
            stats["delete_count"] += 1
            try_send("delete")

        def try_send(type_):

            print("try_send")

        def send_metrics(type_, interval_ms):

            print("sending metrics...")

            keys = GaugeMetric("fdb_keys", len(db))
            db_size = GaugeMetric("fdb_size", getsizeof(db))

            errors = CountMetric(
                name=f"fdb_{type_}_errors",
                value=stats[f"{type_}_errors"],
                interval_ms=interval_ms
            )

            cache_hits = CountMetric(
                name=f"fdb_cache_hits",
                value=stats["cache_hit"],
                interval_ms=interval_ms
            )

            response_times = stats[f"{type_}_response_times"]
            response_time_summary = SummaryMetric(
                f"fdb_{type_}_responses",
                count=len(response_times),
                min=min(response_times),
                max=max(response_times),
                sum=sum(response_times),
                interval_ms=interval_ms,
            )

            batch = [keys, db_size, errors, cache_hits, response_time_summary]
            response = metric_client.send_batch(batch)
            response.raise_for_status()
            print("Sent metrics successfully!")
            clear(type_)

        def clear(type_):
            stats[f"{type_}_response_times"] = []
            stats[f"{type_}_errors"] = 0
            stats["cache_hit"] = 0
            stats[f"{type_}_count"] = 0
            last_push[type_] = datetime.datetime.now()

        ```

        Here, you configure your platform to use `GaugeMetric`, `CountMetric`, and `SummaryMetric` to report metrics to New Relic.
3.  Amend the `try_send` module to send these metrics every 2 second.
    ````python fileName=db.py
    import os
    import random
    import datetime
    from sys import getsizeof

    from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric

    metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])

    db = {}
    stats = {
        "read_response_times": [],
        "read_errors": 0,
        "read_count": 0,
        "create_response_times": [],
        "create_errors": 0,
        "create_count": 0,
        "update_response_times": [],
        "update_errors": 0,
        "update_count": 0,
        "delete_response_times": [],
        "delete_errors": 0,
        "delete_count": 0,
        "cache_hit": 0,
    }
    last_push = {
        "read": datetime.datetime.now(),
        "create": datetime.datetime.now(),
        "update": datetime.datetime.now(),
        "delete": datetime.datetime.now(),
    }

    def read(key):

        print(f"Reading...")

        if random.randint(0, 30) > 10:
            stats["cache_hit"] += 1

        stats["read_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["read_errors"] += 1
        stats["read_count"] += 1
        try_send("read")

    def create(key, value):

        print(f"Writing...")

        db[key] = value
        stats["create_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["create_errors"] += 1
        stats["create_count"] += 1
        try_send("create")

    def update(key, value):

        print(f"Updating...")

        db[key] = value
        stats["update_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["update_errors"] += 1
        stats["update_count"] += 1
        try_send("update")

    def delete(key):

        print(f"Deleting...")

        db.pop(key, None)
        stats["delete_response_times"].append(random.uniform(0.5, 1.0))
        if random.choice([True, False]):
            stats["delete_errors"] += 1
        stats["delete_count"] += 1
        try_send("delete")

    def try_send(type_):

        print("try_send")

        now = datetime.datetime.now()
        interval_ms = (now - last_push[type_]).total_seconds() * 1000
        if interval_ms >= 2000:
            send_metrics(type_, interval_ms)

    def send_metrics(type_, interval_ms):

        print("sending metrics...")

        keys = GaugeMetric("fdb_keys", len(db))
        db_size = GaugeMetric("fdb_size", getsizeof(db))

        errors = CountMetric(
            name=f"fdb_{type_}_errors",
            value=stats[f"{type_}_errors"],
            interval_ms=interval_ms
        )

        cache_hits = CountMetric(
            name=f"fdb_cache_hits",
            value=stats["cache_hit"],
            interval_ms=interval_ms
        )

        response_times = stats[f"{type_}_response_times"]
        response_time_summary = SummaryMetric(
            f"fdb_{type_}_responses",
            count=len(response_times),
            min=min(response_times),
            max=max(response_times),
            sum=sum(response_times),
            interval_ms=interval_ms,
        )

        batch = [keys, db_size, errors, cache_hits, response_time_summary]
        response = metric_client.send_batch(batch)
        response.raise_for_status()
        print("Sent metrics successfully!")
        clear(type_)

    def clear(type_):
        stats[f"{type_}_response_times"] = []
        stats[f"{type_}_errors"] = 0
        stats["cache_hit"] = 0
        stats[f"{type_}_count"] = 0
        last_push[type_] = datetime.datetime.now()

    ```

    Your platform will now report all the configured metrics every 2 seconds.

    ````
4.  Navigate to the root of your application at `build-a-quickstart-lab/send-metrics/flashDB`.
5.  Run your services to verify that it is reporting metrics.
    ````bash animate
    python simulator.py
    [output] Writing...
    [output] try_send
    [output] Writing...
    [output] try_send
    [output] Reading...
    [output] try_send
    [output] Reading...
    [output] try_send
    [output] Writing...
    [output] try_send
    [output] Writing...
    [output] try_send
    [output] Reading...
    [output] sending metrics...
    [output] {green}Sent metrics successfully!
    ```

    ````

## Alternative Options

If the language SDK doesn't fit your needs or you'd like something more customized to send metrics to New Relic, try out one of our other options:

-   **Manual Implementation**: If our SDK in your preferred language doesn't support metrics, you can always manually instrument your own library to make a POST request to the New Relic Metric API.
-   **Prometheus Data**: Prometheus data can be sent to New Relic in two ways, remote write and OpenMetrics. At a very high level, you should use remote write if you manage your own Prometheus servers and OpenMetrics if you don't.

In this procedure, you instrumented your service to send metrics to New Relic. Next, instrument it to send events.

> #### 💡 TIP
>
> This procedure is a part of course that teaches you how to build a quickstart. Continue to next lesson, [send events from your product](https://docs.newrelic.com/docs/new-relic-solutions/build-nr-ui/contribute-nr-io/send-events).
