• Log inStart now

Send metrics from your product

Course

This procedure is a part of a 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.

Step 1 of 3

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

bash
$
cd ../send-metrics/flashDB
Step 2 of 3

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

bash
$
pip install newrelic-telemetry-sdk
Step 3 of 3

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

bash
$
export NEW_RELIC_LICENSE_KEY=<USER'S LICENSE KEY>

Tip

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

Next, you familiarize yourself with the app logic.

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.

1
import os
2
import random
3
import datetime
4
5
db = {}
6
stats = {
7
"read_response_times": [],
8
"read_errors": 0,
9
"read_count": 0,
10
"create_response_times": [],
11
"create_errors": 0,
12
"create_count": 0,
13
"update_response_times": [],
14
"update_errors": 0,
15
"update_count": 0,
16
"delete_response_times": [],
17
"delete_errors": 0,
18
"delete_count": 0,
19
"cache_hit": 0,
20
}
21
last_push = {
22
"read": datetime.datetime.now(),
23
"create": datetime.datetime.now(),
24
"update": datetime.datetime.now(),
25
"delete": datetime.datetime.now(),
26
}
27
28
def read(key):
29
30
print(f"Reading...")
31
32
if random.randint(0, 30) > 10:
33
stats["cache_hit"] += 1
34
35
stats["read_response_times"].append(random.uniform(0.5, 1.0))
36
if random.choice([True, False]):
37
stats["read_errors"] += 1
38
stats["read_count"] += 1
39
try_send("read")
40
41
def create(key, value):
42
43
print(f"Writing...")
44
45
db[key] = value
46
stats["create_response_times"].append(random.uniform(0.5, 1.0))
47
if random.choice([True, False]):
48
stats["create_errors"] += 1
49
stats["create_count"] += 1
50
try_send("create")
51
52
def update(key, value):
53
54
print(f"Updating...")
55
56
db[key] = value
57
stats["update_response_times"].append(random.uniform(0.5, 1.0))
58
if random.choice([True, False]):
59
stats["update_errors"] += 1
60
stats["update_count"] += 1
61
try_send("update")
62
63
def delete(key):
64
65
print(f"Deleting...")
66
67
db.pop(key, None)
68
stats["delete_response_times"].append(random.uniform(0.5, 1.0))
69
if random.choice([True, False]):
70
stats["delete_errors"] += 1
71
stats["delete_count"] += 1
72
try_send("delete")
73
74
def try_send(type_):
75
76
print("try_send")
77
78
def clear(type_):
79
stats[f"{type_}_response_times"] = []
80
stats[f"{type_}_errors"] = 0
81
stats["cache_hit"] = 0
82
stats[f"{type_}_count"] = 0
83
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.

Step 1 of 5

In db.py, configure the MetricClient.

1
import os
2
import random
3
import datetime
4
5
from newrelic_telemetry_sdk import MetricClient
6
7
metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])
8
9
db = {}
10
stats = {
11
"read_response_times": [],
12
"read_errors": 0,
13
"read_count": 0,
14
"create_response_times": [],
15
"create_errors": 0,
16
"create_count": 0,
17
"update_response_times": [],
18
"update_errors": 0,
19
"update_count": 0,
20
"delete_response_times": [],
21
"delete_errors": 0,
22
"delete_count": 0,
23
"cache_hit": 0,
24
}
25
last_push = {
26
"read": datetime.datetime.now(),
27
"create": datetime.datetime.now(),
28
"update": datetime.datetime.now(),
29
"delete": datetime.datetime.now(),
30
}
31
32
def read(key):
33
34
print(f"Reading...")
35
36
if random.randint(0, 30) > 10:
37
stats["cache_hit"] += 1
38
39
stats["read_response_times"].append(random.uniform(0.5, 1.0))
40
if random.choice([True, False]):
41
stats["read_errors"] += 1
42
stats["read_count"] += 1
43
try_send("read")
44
45
def create(key, value):
46
47
print(f"Writing...")
48
49
db[key] = value
50
stats["create_response_times"].append(random.uniform(0.5, 1.0))
51
if random.choice([True, False]):
52
stats["create_errors"] += 1
53
stats["create_count"] += 1
54
try_send("create")
55
56
def update(key, value):
57
58
print(f"Updating...")
59
60
db[key] = value
61
stats["update_response_times"].append(random.uniform(0.5, 1.0))
62
if random.choice([True, False]):
63
stats["update_errors"] += 1
64
stats["update_count"] += 1
65
try_send("update")
66
67
def delete(key):
68
69
print(f"Deleting...")
70
71
db.pop(key, None)
72
stats["delete_response_times"].append(random.uniform(0.5, 1.0))
73
if random.choice([True, False]):
74
stats["delete_errors"] += 1
75
stats["delete_count"] += 1
76
try_send("delete")
77
78
def try_send(type_):
79
80
print("try_send")
81
82
def clear(type_):
83
stats[f"{type_}_response_times"] = []
84
stats[f"{type_}_errors"] = 0
85
stats["cache_hit"] = 0
86
stats[f"{type_}_count"] = 0
87
last_push[type_] = datetime.datetime.now()
db.py
Step 2 of 5

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

  • keys
  • db_size
  • errors
  • cache_hits
  • response_times
1
import os
2
import random
3
import datetime
4
from sys import getsizeof
5
6
from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric
7
8
metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])
9
10
db = {}
11
stats = {
12
"read_response_times": [],
13
"read_errors": 0,
14
"read_count": 0,
15
"create_response_times": [],
16
"create_errors": 0,
17
"create_count": 0,
18
"update_response_times": [],
19
"update_errors": 0,
20
"update_count": 0,
21
"delete_response_times": [],
22
"delete_errors": 0,
23
"delete_count": 0,
24
"cache_hit": 0,
25
}
26
last_push = {
27
"read": datetime.datetime.now(),
28
"create": datetime.datetime.now(),
29
"update": datetime.datetime.now(),
30
"delete": datetime.datetime.now(),
31
}
32
33
def read(key):
34
35
print(f"Reading...")
36
37
if random.randint(0, 30) > 10:
38
stats["cache_hit"] += 1
39
40
stats["read_response_times"].append(random.uniform(0.5, 1.0))
41
if random.choice([True, False]):
42
stats["read_errors"] += 1
43
stats["read_count"] += 1
44
try_send("read")
45
46
def create(key, value):
47
48
print(f"Writing...")
49
50
db[key] = value
51
stats["create_response_times"].append(random.uniform(0.5, 1.0))
52
if random.choice([True, False]):
53
stats["create_errors"] += 1
54
stats["create_count"] += 1
55
try_send("create")
56
57
def update(key, value):
58
59
print(f"Updating...")
60
61
db[key] = value
62
stats["update_response_times"].append(random.uniform(0.5, 1.0))
63
if random.choice([True, False]):
64
stats["update_errors"] += 1
65
stats["update_count"] += 1
66
try_send("update")
67
68
def delete(key):
69
70
print(f"Deleting...")
71
72
db.pop(key, None)
73
stats["delete_response_times"].append(random.uniform(0.5, 1.0))
74
if random.choice([True, False]):
75
stats["delete_errors"] += 1
76
stats["delete_count"] += 1
77
try_send("delete")
78
79
def try_send(type_):
80
81
print("try_send")
82
83
def send_metrics(type_, interval_ms):
84
85
print("sending metrics...")
86
87
keys = GaugeMetric("fdb_keys", len(db))
88
db_size = GaugeMetric("fdb_size", getsizeof(db))
89
90
errors = CountMetric(
91
name=f"fdb_{type_}_errors",
92
value=stats[f"{type_}_errors"],
93
interval_ms=interval_ms
94
)
95
96
cache_hits = CountMetric(
97
name=f"fdb_cache_hits",
98
value=stats["cache_hit"],
99
interval_ms=interval_ms
100
)
101
102
response_times = stats[f"{type_}_response_times"]
103
response_time_summary = SummaryMetric(
104
f"fdb_{type_}_responses",
105
count=len(response_times),
106
min=min(response_times),
107
max=max(response_times),
108
sum=sum(response_times),
109
interval_ms=interval_ms,
110
)
111
112
batch = [keys, db_size, errors, cache_hits, response_time_summary]
113
response = metric_client.send_batch(batch)
114
response.raise_for_status()
115
print("Sent metrics successfully!")
116
clear(type_)
117
118
def clear(type_):
119
stats[f"{type_}_response_times"] = []
120
stats[f"{type_}_errors"] = 0
121
stats["cache_hit"] = 0
122
stats[f"{type_}_count"] = 0
123
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.

Step 3 of 5

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

1
import os
2
import random
3
import datetime
4
from sys import getsizeof
5
6
from newrelic_telemetry_sdk import MetricClient, GaugeMetric, CountMetric, SummaryMetric
7
8
metric_client = MetricClient(os.environ["NEW_RELIC_LICENSE_KEY"])
9
10
db = {}
11
stats = {
12
"read_response_times": [],
13
"read_errors": 0,
14
"read_count": 0,
15
"create_response_times": [],
16
"create_errors": 0,
17
"create_count": 0,
18
"update_response_times": [],
19
"update_errors": 0,
20
"update_count": 0,
21
"delete_response_times": [],
22
"delete_errors": 0,
23
"delete_count": 0,
24
"cache_hit": 0,
25
}
26
last_push = {
27
"read": datetime.datetime.now(),
28
"create": datetime.datetime.now(),
29
"update": datetime.datetime.now(),
30
"delete": datetime.datetime.now(),
31
}
32
33
def read(key):
34
35
print(f"Reading...")
36
37
if random.randint(0, 30) > 10:
38
stats["cache_hit"] += 1
39
40
stats["read_response_times"].append(random.uniform(0.5, 1.0))
41
if random.choice([True, False]):
42
stats["read_errors"] += 1
43
stats["read_count"] += 1
44
try_send("read")
45
46
def create(key, value):
47
48
print(f"Writing...")
49
50
db[key] = value
51
stats["create_response_times"].append(random.uniform(0.5, 1.0))
52
if random.choice([True, False]):
53
stats["create_errors"] += 1
54
stats["create_count"] += 1
55
try_send("create")
56
57
def update(key, value):
58
59
print(f"Updating...")
60
61
db[key] = value
62
stats["update_response_times"].append(random.uniform(0.5, 1.0))
63
if random.choice([True, False]):
64
stats["update_errors"] += 1
65
stats["update_count"] += 1
66
try_send("update")
67
68
def delete(key):
69
70
print(f"Deleting...")
71
72
db.pop(key, None)
73
stats["delete_response_times"].append(random.uniform(0.5, 1.0))
74
if random.choice([True, False]):
75
stats["delete_errors"] += 1
76
stats["delete_count"] += 1
77
try_send("delete")
78
79
def try_send(type_):
80
81
print("try_send")
82
83
now = datetime.datetime.now()
84
interval_ms = (now - last_push[type_]).total_seconds() * 1000
85
if interval_ms >= 2000:
86
send_metrics(type_, interval_ms)
87
88
def send_metrics(type_, interval_ms):
89
90
print("sending metrics...")
91
92
keys = GaugeMetric("fdb_keys", len(db))
93
db_size = GaugeMetric("fdb_size", getsizeof(db))
94
95
errors = CountMetric(
96
name=f"fdb_{type_}_errors",
97
value=stats[f"{type_}_errors"],
98
interval_ms=interval_ms
99
)
100
101
cache_hits = CountMetric(
102
name=f"fdb_cache_hits",
103
value=stats["cache_hit"],
104
interval_ms=interval_ms
105
)
106
107
response_times = stats[f"{type_}_response_times"]
108
response_time_summary = SummaryMetric(
109
f"fdb_{type_}_responses",
110
count=len(response_times),
111
min=min(response_times),
112
max=max(response_times),
113
sum=sum(response_times),
114
interval_ms=interval_ms,
115
)
116
117
batch = [keys, db_size, errors, cache_hits, response_time_summary]
118
response = metric_client.send_batch(batch)
119
response.raise_for_status()
120
print("Sent metrics successfully!")
121
clear(type_)
122
123
def clear(type_):
124
stats[f"{type_}_response_times"] = []
125
stats[f"{type_}_errors"] = 0
126
stats["cache_hit"] = 0
127
stats[f"{type_}_count"] = 0
128
last_push[type_] = datetime.datetime.now()
db.py

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

Step 4 of 5

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

Step 5 of 5

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.

Course

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 © 2022 New Relic Inc.

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