Grouping with Action Names
When AppSignal receives data from your application, traces/transactions are grouped by their namespace and action name combination.
By default, these action names are automatically determined based on your framework (e.g., Controller#action_name
, BackgroundWorker#perform
, etc.).
When the automatically determined action name is not good enough, you can customize the action name.
This guide explains how to customize action names in different language integrations.
Why Customize Action Names?
- Improved clarity: Provide more descriptive names for complex operations.
- Customized grouping: Control how application data is organized in the AppSignal.
When Automatic Action Names Fall Short
Here are some examples where automatically generated action names may not be good enough:
- Catch-all routes: In applications that use catch-all routes or dynamic routing (like
/api/:entity/:action
), the default action name might be something generic likeApiController#dispatch
. - Multi-purpose tasks: Background workers and scripts that handle different types of work based on parameters that would all be grouped under the same action name (e.g.,
GenericWorker#perform
). - GraphQL resolvers: These might all be grouped under a single action name (e.g.
POST /graphql
) despite handling many different types of operations.
Customizing Actions Per Language
Ruby
In Ruby applications, you can use the Appsignal.set_action
helper to customize the action name:
# In a Rails controller class PaymentsController < ApplicationController def process_payment provider = params[:payment][:provider] # GOOD: Change the action name from "PaymentsController#process_payment" # to something more specific about the operation if provider == "creditcard" Appsignal.set_action("PaymentsController#process_payment (creditcard)") end # BAD: Don't use a dynamic value, it creates too many action names # Appsignal.set_action("PaymentsController#process_#{provider}") # Rest of your code end end
For background jobs, tasks and scripts, you can set the action name in the same way with the Appsignal.set_action
helper.
It's also possible to configure the action name when creating a transaction using the Appsignal.monitor
helper. It accepts the action name as a keyword argument.
# When creating a new transaction Appsignal.monitor(action: "script/custom_script") do # Your code to instrument end
Elixir
In Elixir applications, you can use the Appsignal.Span.set_name/2
function to customize the action name on the root span:
# In a Phoenix controller defmodule MyAppWeb.PaymentController do use MyAppWeb, :controller def process(conn, params) do # GOOD: Set a custom static action name based on payment type payment_type = Map.get(params, "type", "unknown") if payment_type == "creditcard" do Appsignal.Span.set_name( Appsignal.Tracer.root_span(), "PaymentController#process_payment (creditcard)" ) end # BAD: Don't use a dynamic value, it creates too many action names # Appsignal.Span.set_name( # Appsignal.Tracer.root_span(), # "PaymentController#process_#{payment_type}" # ) # Rest of your code render(conn, "success.html") end end
For background jobs, tasks and scripts, you can set the action name in the same way with the Appsignal.Span.set_name/2
function.
Node.js
In Node.js applications, you can use the setRootName
helper from the AppSignal package to customize action names:
import { setRootName } from "@appsignal/nodejs"; // In an Express.js route handler app.post("/payments", (req, res) => { const paymentType = req.body.type || "unknown"; // GOOD: Set a custom action name based on payment type if (paymentType === "creditcard") { setRootName("PaymentsController#process_payment (creditcard)"); } // BAD: Don't use a dynamic value, it creates too many action names // setRootName(`PaymentsController#process_${paymentType}`); // Rest of your code res.send("Payment processed"); });
For background jobs, tasks and scripts, you can set the action name in the same way with the setRootName
helper.
Python
In Python applications, you can use the set_root_name
helper from the AppSignal package to customize action names:
from appsignal import set_root_name # In a Django view def process_payment(request): payment_type = request.POST.get('type', 'unknown') # GOOD: Set a custom action name based on payment type if payment_type == "creditcard": set_root_name("PaymentsView#process_payment (creditcard)") # BAD: Don't use a dynamic value, it creates too many action names # set_root_name(f"PaymentsView#process_{payment_type}") # Rest of your code return HttpResponse("Payment processed")
For background jobs, tasks and scripts, you can set the action name in the same way with the set_root_name
helper.
Front-end JavaScript
In Front-end JavaScript applications, you can use the setAction
helper from the AppSignal package to customize action names:
const span = appsignal.createSpan((span) => { const formType = getFormType(); // GOOD: Set a custom action name based on form type if (formType === "checkout") { span.setAction("CheckoutPage#submit_form (checkout)"); } // BAD: Don't use a dynamic value, it creates too many action names // span.setAction(`CheckoutPage#submit_${formType}_form`); // Rest of your code });
Alternatively, you can update an existing span's action name:
// Get the current active span const span = appsignal.getActiveSpan(); function handlePaymentMethodSelection(method) { // GOOD: Set a custom action name based on payment method if (method === "creditcard") { span.setAction("PaymentForm#select_method (creditcard)"); } // BAD: Don't do this - using a variable creates too many action names // span.setAction(`PaymentForm#select_${method}`); // Rest of your code }
Best Practices
When customizing action names, follow these guidelines:
- Be consistent: Use a consistent naming pattern across your application.
- Be specific: Include relevant information that helps identify the operation.
- Avoid high cardinality: Don't include unique IDs or values that would create unique action names per execution.
- Use static strings: Never interpolate variables or dynamic data into action names.
- Follow the codebase naming: Use naming patterns like
Controller#action
that match your application structure so the location in the code can be found. - Use tags or metadata instead: For tracking variable information like payment providers or user types, use tags and metadata rather than incorporating them into action names.
How to Handle Different Operations with the Same Action Name
Instead of creating dynamic action names, use a combination of:
- Static action names: Use descriptive but static action names.
- Tags: Add tags with the variable information (e.g.,
provider: stripe
,operation_type: refund
). - Custom attributes: Add additional metadata to the trace/transaction.
Example:
# Instead of this: # Appsignal.set_action("PaymentController#process_#{provider}") # Do this: Appsignal.set_action("PaymentController#process_payment") Appsignal.add_tags( provider: provider, operation: operation )
This approach allows you to:
- Group related operations under a single action name.
- Filter and search based on tags.
- Maintain a clean incident overview.
Deploy
After you've implemented custom action names, deploy your application. New traces/transactions will use your custom action names in the AppSignal dashboards.
Are your custom action names not appearing correctly? Don't hesitate to contact our support team for help!