Structuring Monitoring Data in Monolithic Applications With Namespaces
Tomas Fernandez
Posted on December 15, 2020
What Are Namespaces?
Everything that happens in an AppSignal-monitored application is logged under a namespace. Namespaces work like folders, grouping events, issues, and monitoring data into manageable chunks.
By default, every application starts with three default namespaces: web
, background
, and frontend
.
- The web namespace holds all your HTTP requests. In MVC-oriented frameworks such as Rails or Sinatra, this includes controller actions.
- The background namespace holds activity from background jobs, libraries, and tasks.
- The frontend namespace logs the events sent by the AppSignal for JavaScript integration.
AppSignal maps incoming events using built-in per-application and per-integration rules. However, you can change these mappings at any time and even create new namespaces to model your application structure.
Trying Out Namespaces in Ruby
Let’s try out namespaces on a Ruby on Rails (ROR) application. After creating a fresh Rails project with rails new
and setting up the rails integration, you’ll find the web
namespace in your dashboard.
AppSignal shows the namespace as soon as it receives transactions from any of the controllers.
The rest of the default namespaces won’t appear until there is some activity in them. Let’s add something in the background namespace to make things more interesting. This is how the dashboard looks after adding Sidekiq to the project (check the code in examples repository).
AppSignal assigns the action to the background namespace because it recognizes Sidekiq as a job processor. AppSignal integrates with most of the popular background processors out there, but if yours is omitted, you can always add instrumentation to your jobs manually.
Creating Custom Namespaces
On large monolithic applications, the default namespaces can feel too generic. A big website typically serves static content, dynamic pages, API endpoints, among other web services. Most of this would all end up on the web
namespace.
Also, every part of the application has a different priority. A login page problem is a lot more urgent than one in the internal administration panel. Yet AppSignal treats all issues within a namespace as equal. When there is a lot of activity, it can be hard to identify the most critical issues.
So, we should organize namespaces by priority and areas of responsibility. Then we can attach separate notification policies and alert only the interested parties. Following this reasoning, we could create custom namespaces for the login_page
, api_endpoints
, and admin_panel
.
To create a new namespace in Ruby, we’ll use Appsignal.set_namespace
. Take a look at the following code, which creates a job in a namespace called urgent_background
:
class FetchPricesWorker
include Sidekiq::Worker
def perform
Appsignal.set_namespace("urgent_background")
# worker code ...
end
end
Once we made this change and restarted the app, these new jobs will appear in the newly-created namespace:
We can confirm that the actual job has been logged by checking the action name in the dashboard:
Custom namespaces also work in all integrations.
Ignoring Namespaces
Another benefit of custom namespaces is that they let us disregard events from parts of the application we don’t care about. For instance, we may choose to ignore events from the admin_panel
completely.
Ignoring a namespace takes three steps:
- Assign the parts we don’t want to monitor to a custom namespace.
- Configure the integration to ignore the namespace.
- Restart your app.
For Ruby, add the ignore_namespaces option in the AppSignal config file:
production:
ignore_namespaces:
- "admin_panel"
Ignoring a namespace skips all the transaction and span data at the source. Custom metric data is still reported.
The Elixir and JavaScript integrations have similar options. For more details check the ignoring namespaces guide.
Namespaces for Monolithic Applications
Now that we know how namespaces work, let’s examine a few ways we can use them to partition a monolithic application.
While there are no set rules, partitioning boils down to two strategies. You may choose one of them or a mix of both as a starting point:
-
By role: we assign namespaces to functional or logical units within the project. Thus, we may find it sensible to define namespaces such as
billing
,sign_in
orsign_up
,admin_panel
, andhomepage
. One glance at the AppSigal dashboard and you will understand what’s going on in each part of the application. This approach works well when the code can be nicely broken up by clear boundaries. -
By severity: here we use namespaces as a prioritizing device. It’s up to you to establish which parts of the code are
critical
,important
,medium
, orlow
. This approach lets you immediately sort out what problems you want to address first.
Suppose that we have a controllers that handle user sign in and registration. When choosing to partition by role, we could map them to the user_login
namespace.
# in Rails we use before_action callback to change
# the namespace before the request starts
class LoginController < ApplicationController
before_action :set_appsignal_namespace
def set_appsignal_namespace
# Sets the namespace
Appsignal.set_namespace("user_login")
end
# controller actions ...
end
But if you prefer using priority namespaces, a controller in charge of billing would probably go in the critical
namespace.
class BillingPageController < ApplicationController
before_action :set_appsignal_namespace
def set_appsignal_namespace
Appsignal.set_namespace("critical")
end
end
Controllers that inherit from these share the same namespace as their parents:
# any controllers that inherit from LoginController
# are also part of the "user_login" namespace
class RegistrationController < LoginController
# there’s no need for before_action here
# this controller already reports to the parent’s namespace
end
As we’ve seen, jobs and tasks are automatically assigned to the background
namespace. Whenever possible, we should assign them into more specific ones. For instance, a database cleanup job could go into the database
namespace, like this:
class ActiveJobDatabaseCleanupJob < ActiveJob::Base
queue_as :default
def perform(argument = nil, options = {})
Appsignal.set_namespace("database")
Priorities also work for jobs. We could assign unimportant tasks to low
for instance, as in this Rake task:
task :unimportant_job do
# Run this rake job in the low namespace
Appsignal.set_namespace("low")
# job code ...
end
In some cases, you will want to log actions using a manual transaction. You can define the namespace while creating it, like in the following example, which codes a custom mailer job:
class Job
def perform
# Create a transaction for this job and set the namespace
transaction = Appsignal::Transaction.create(
SecureRandom.uuid,
"mailer",
Appsignal::Transaction::GenericRequest.new(ENV.to_hash)
)
# job code ...
end
end
Namespaces and Notifications
Not everyone in the team needs to be notified about every problem. Frontend specialists don’t care about background jobs as much as backend developers. Still, they may want to know when there’s a problem in the backend. Backend developers will surely like to be notified of performance issues on the web
namespace. Namespaces let us route notifications to the right people.
Setting Up Per-Namespace Notifiers
We can create notification groups that are only active for specific namespaces. For instance, we could send emails for errors in the web
namespace, or send a message into the #frontend Slack channel for issues in the frontend
namespace.
To create per-namespace notification groups, go to App Settings > Notifications > Notifiers and click on Add Integration.
Select one of the integrations and type its name. Choose which type of messages to send and for which namespace. For example, let’s create a Slack notification for the #frontend
channel.
While we’re still here, create a second notification for the backend developers:
You can configure as many notifiers as you need to keep the team up to date with everything that’s happening.
Changing Per-Namespace Notifications
When an incident is created, AppSignal will apply a notification policy. This policy is based on the namespace the error comes from. We can define separate policies for each namespace.
To see the namespace defaults for your application, go to App Settings > Notifications > Namespace defaults.
Here, you’ll find options to customize error and performance notifications for every namespace:
- Every occurrence: sends notifications every time an incident is triggered, with a 5-minute cooldown.
- First on deploy: notifies you of the first error after deploying the application.
- First after close: sends a notification the first time a closed issue is reopened.
- Never notify: disables notifications altogether.
Creating Per-Namespace Triggers
Triggers tell AppSignal to create an incident and send notifications when a metric goes over or below a predefined value. Since different parts of an application may have different thresholds, we should create separate triggers for each namespace. The classic example is a trigger that alerts us when throughput is too low in the web
namespace.
To create a trigger, go to Anomaly Detection > Triggers, and click on Add your first trigger.
Select an Actions trigger type on the left menu and choose the relevant namespace. Then, set the thresholds that trigger the alert.
Here you can also define which groups should be notified. To finalize, click on Save Trigger.
Conclusion
Namespaces let make sense of your application’s monitoring data. They are also indispensable for firing notifications and incidents on a fine-grained level, limiting noise, and avoiding false positives.
After checking how custom namespaces work on Ruby, Node.js, and Elixir, read these next to continue learning how to use namespaces:
- Namespaces in AppSignal
- Grouping with namespaces
- What's The Difference Between Monitoring Webhooks and Background Jobs
- Gem 2.2 - Custom namespaces!
Our guest author Tomas spent 10 years working at IBM, where he did a bit of everything: development, service delivery, database administration, and cloud engineering. He's now an independent consultant and a technical writer.
Posted on December 15, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.