Structuring Monitoring Data in Monolithic Applications With Namespaces

tomfern

Tomas Fernandez

Posted on December 15, 2020

Structuring Monitoring Data in Monolithic Applications With Namespaces

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.

Dashboard showing web namespace

AppSignal shows the namespace as soon as it receives transactions from any of the controllers.

Most recent actions. Shows controller events.

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).

Dashboard showing the background namespace

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.

Last events in the background namespace

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.

Custom namespaces let us create fine-grained zones for the application

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
Enter fullscreen mode Exit fullscreen mode

Once we made this change and restarted the app, these new jobs will appear in the newly-created namespace:

Dashboard showing the urgent\_background namespace

We can confirm that the actual job has been logged by checking the action name in the dashboard:

Last events in the urgent\_background namespace

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:

  1. Assign the parts we don’t want to monitor to a custom namespace.
  2. Configure the integration to ignore the namespace.
  3. Restart your app.

For Ruby, add the ignore_namespaces option in the AppSignal config file:

production:
  ignore_namespaces:
    - "admin_panel"
Enter fullscreen mode Exit fullscreen mode

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 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.
  • 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, 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.

# 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Adding an 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.

slack integration

While we’re still here, create a second notification for the backend developers:

New notification group for web

You can configure as many notifiers as you need to keep the team up to date with everything that’s happening.

Notifiers for different parts of the application

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.

Namespace defaults for web, background and urgent\_background

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.

Creating a new trigger for the web namespace

Here you can also define which groups should be notified. To finalize, click on Save Trigger.

This alert will send a notification to backend developers

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:

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.

💖 💪 🙅 🚩
tomfern
Tomas Fernandez

Posted on December 15, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related