• /
  • EnglishEspañol日本語한국어Português
  • Log inStart now

Send metrics from your product

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.

Each procedure in this course builds on top of the last one, so make sure you 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. In this lesson, you send metrics from your product using our telemetry software development kit (SDK).

Use our SDK

We offer an open source telemetry SDK 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 to send metrics to New Relic.

Change to the send-metrics/flashDB direcrory of the course repository.

bash
$
cd ../send-metrics/flashDB

Use pip to install the newrelic-telemetry-sdk package.

bash
$
pip install newrelic-telemetry-sdk

Store your New Relic license key in an environment variable called $NEW_RELIC_LICENSE_KEY.

bash
$
export NEW_RELIC_LICENSE_KEY=<YOUR_USER_KEY>

Tip

You can find your New Relic license key in your account settings.

Next, you familiarize yourself with the app logic.

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()
db.py

Familiarize yourself with the application

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.

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()
db.py

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

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.

In db.py, configure the MetricClient.

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()
db.py

Instrument your app to send the folloiwng metrics to New Relic:

  • keys

  • db_size

  • errors

  • cache_hits

  • response_times

    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()
    db.py

    Here, you configure your platform to use GaugeMetric, CountMetric, and SummaryMetric to report metrics to New Relic.

Amend the try_send module to send these metrics every 2 second.

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()
db.py

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

Navigate to the root of your application at build-a-quickstart-lab/send-metrics/flashDB.

Run your services to verify that it is reporting metrics.

bash
$
python simulator.py
Writing...
try_send
Writing...
try_send
Reading...
try_send
Reading...
try_send
Writing...
try_send
Writing...
try_send
Reading...
sending metrics...
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.

Copyright © 2024 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.