Subscribe to
Ruby Magic
Magicians never share their secrets. But we do. Sign up for our Ruby Magic email series and receive deep insights about garbage collection, memory allocation, concurrency and much more.
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
.
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.
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.
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
:
1 2 3 4 5 6 7 8 9 10 | 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.
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:
For Ruby, add the ignore_namespaces option in the AppSignal config file:
1 2 3 | 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.
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:
billing
, sign_in
or sign_up
, admin_panel
, and homepage
. 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.critical
, important
, medium
, or low
. 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.
1 2 3 4 5 6 7 8 9 10 11 12 | # 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.
1 2 3 4 5 6 7 | 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:
1 2 3 4 5 6 7 8 | # 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:
1 2 3 4 5 | 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:
1 2 3 4 5 6 7 8 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
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.
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.
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:
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.
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:
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.