New Relic: Monitoring your Go database with New Relic

Object-Relational Mapping (ORM) tools provide a convenient layer of abstraction between your database and your programming language. You use them to represent database transactions as code, rather than as explicit queries, which greatly improves the readability and footprint of your code. In the Go community, one of the most popular ORM tools is GORM, due to its developer-friendly design and wide range of features.

Using GORM can help you develop the database layer of your application more easily, but how will you know if it meets your performance expectations? This is where Agent New Relic Go comes into play. The Go Agent is an SDK that allows you to instrument and observe a Go application in New Relic.

This article will show you how to use the SDK to manually instrument a Go application with a GORM guides quickstart example and how to use New Relic One to monitor your database transaction cost and code execution time. If you are not yet a New Relic user, you can register for free. A free account includes 100GB/month of free data ingestion, one free full access user, and unlimited free basic users. After creating your account, you can follow this example.

Here is a fully instrumented version of the GORM quickstart. This example uses SQLite, but this article will also discuss using PostgreSQL and MySQL.

New Relic Go Agent Setup

Let’s walk through a savvy code example and explain the decisions you make at each step. Note that the Go agent has several configuration options you can set when it initializes, which we won’t cover here. For details, see the Go Agent documentation.

The agent is initialized by calling the function. Within this function, you can call a number of configuration functions to set various options for running and operating the Go Agent.

1. First, give the app a name. This name will be used to identify your app’s data and dashboards in New Relic, so it’s important that you make it something distinct and clear.

2. Go Agent requires a license key to work. Without one, it will return an error. To keep things simple, this example retrieves the key from an environment variable named .

3. The Go Agent produces its own logs to track events such as data collection cycles and communication with the New Relic backend. For your convenience, it also tells you the exact web address where your app data is hosted in New Relic. Since this is a simple single application intended to serve as sample code, the sample simply logs to stdout and does nothing more to manage the logs.

4. Finally, enable the distributed tracing feature. Distributed tracing is a feature that allows agents to track service requests across distributed systems and then create a visualization of those requests in your New Relic dashboard. Enabling distributed tracing is not required to trace an application like this, but it is particularly useful for obtaining more accurate information about the execution flow of a process in a distributed system. More on that later in this blog post.

Because this single application runs so quickly, it’s possible that the application will finish running before the agent can send the data it has collected to New Relic. The following lines of code ensure that all collected data is sent to New Relic before the application closes. This code would not be needed to monitor a production application with a lot of data.

Using New Relic Instrumented DB Drivers with GORM

The New Relic Go Agent includes several instrumented database drivers for some of the most popular database vendors. With a few simple steps, you can import these drivers from the Go Agent Integrations Library and use them instead of GORM’s default database drivers.

1. First, import a New Relic database driver from the Go Agent Integrations Library. By importing it with a preceding underscore, the driver is implicitly registered as a driver database that will be used to communicate with SQLite.

2. For most databases, you must create a custom GORM dialect object to configure GORM to use the New Relic database driver. The dialector object is passed to the function to configure how GORM opens a database connection. In the dialector object, the should be the name of the New Relic database driver you are using, and the should be the name or address of the database you are connecting to.

If you are using GORM with MySQL or PostgreSQL, you do not need to create a dialector object. Instead, the function will implicitly use the database driver you import, and you specify how to use it in an object specific to that database. The following example is for MySQL, but the code would be exactly the same for PostgreSQL.

Go app instrumentation

Once your application is configured to use the Go agent, the last step is to start instrumenting your code.

1. Since the Go agent is an SDK, you must explicitly start and stop tracing in your application. The easiest way to do this is to start a transaction trace.

When a transaction starts, trace data collection begins immediately. The name of a transaction identifies it in New Relic.

2. After starting a transaction, you must explicitly create a context from that transaction. In Go, contexts pass timeouts, cancellation signals, and other request scope values ​​across APIs and processes. A background context is an empty but non-nil context that does not communicate any timeout or cancellation policy, and for this reason it is often used by default. A context object is generated in the row. It is a background context with additional metadata associating it with the transaction trace. This context is used to keep track of service calls belonging to this transaction trace, therefore a new GORM database object is generated from the context in the line. Here’s what it looks like with an example of hard-coded database operations.

You must repeat these steps for each separate transaction you want to trace in your code. More nuanced and advanced ways to trace and instrument your code are covered in the Instrument Go Transactions documentation. If you’re looking for a more in-depth look at some of these concepts, we’ll be posting a Go Agent Masterclass soon.

Data collection and analysis

To run the application, you need to ensure that the necessary go modules are installed, then run them as shown in the following snippet.

The New Relic Go agent automatically connects to New Relic, captures your transaction data, and then sends it to New Relic. The app will show a URL in the app logs on your command line that will take you directly to your app data in New Relic. You can see your app data in this web UI.

The summary page is quite sparse for this sample application as it only recorded one very short transaction, but if you scroll down you can see summary statistics on the trace. Statistics such as response time and throughput are useful for getting an overview of the average transaction performance of your application, and statistics such as CPU utilization and memory utilization are useful for monitoring hardware performance. In the previous example, you can see that the average response time was 7.84 milliseconds. To determine what factors led to this average response time, select Left Pane Databases.

the Data base view visualizes your database transactions. In this example, the majority of database transactions were SQLite update operations, and on average updates took 0.341 milliseconds. By comparison, selects took 0.108 milliseconds and insertions took 0.155 milliseconds. Based on this data, it is clear that update queries are almost three times more expensive than insert and select operations. This is valuable information, but it doesn’t show us what these average runtime costs mean in our application flow. This is where distributed tracing comes in.

Distributed tracing helps put your data in context by breaking out the cost of executing each subsection of a transaction, called a scope, and displaying it in the order in which it was executed. This creates a holistic view of a transaction that shows when a segment occurred in the execution order, what happened in that range, and the cost of events that occurred during that segment. Our application’s transaction trace contains scopes for one insert, two selects, and four updates that are executed sequentially. The cost of executing these ranges is 7.84 milliseconds, which is the total execution time of our transaction. Scope tracking update operations consumed an inordinate amount of this execution time compared to other captured scopes, both because they took longer to execute and because they are more numerous.

Next steps

Interested in monitoring your Go application? Install the New Relic Go agent. And if you haven’t already, sign up for New Relic. Your free account includes 100GB/month of free data acquisition, one full platform user, and unlimited free basic users.