> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Grouping with Action Names

When AppSignal receives data from your application, traces/transactions are grouped by their [namespace](/guides/namespaces) 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.

<Warning>
  Actions names are not meant to be unique!
  Do not use variables to customize the action names, as this will create a new incident per occurrence.
  This makes the incident overview difficult to use and prevents proper grouping and trend analysis.

  **Always use static strings** for action names. Never interpolate variables, user input, or dynamic data into action names.
</Warning>

## 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:

1. **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 like `ApiController#dispatch`.
2. **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`).
3. **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](#ruby)
* [Elixir](#elixir)
* [Python](#python)
* [Node.js](#nodejs)
* [Front-end JavaScript](#front-end-javascript)
* [Go](#go)
* [Java](#java)
* [PHP](#php)

### Ruby

In Ruby applications, you can use the `Appsignal.set_action` helper to customize the action name:

<CodeGroup>
  ```ruby Ruby theme={null}
  # 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
  ```
</CodeGroup>

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`](https://rubydoc.info/gems/appsignal/Appsignal/Helpers/Instrumentation#monitor-instance_method) helper. It accepts the action name as a keyword argument.

<CodeGroup>
  ```ruby Ruby theme={null}
  # When creating a new transaction
  Appsignal.monitor(action: "script/custom_script") do
    # Your code to instrument
  end
  ```
</CodeGroup>

### Elixir

In Elixir applications, you can use the `Appsignal.Span.set_name/2` function to customize the action name on the **root span**:

<CodeGroup>
  ```elixir Elixir theme={null}
  # 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
  ```
</CodeGroup>

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:

<CodeGroup>
  ```javascript Node.js theme={null}
  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");
  });
  ```
</CodeGroup>

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:

<CodeGroup>
  ```python Python theme={null}
  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")
  ```
</CodeGroup>

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:

<CodeGroup>
  ```javascript JavaScript theme={null}
  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
  });
  ```
</CodeGroup>

Alternatively, you can update an existing span's action name:

<CodeGroup>
  ```javascript JavaScript theme={null}
  // 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
  }
  ```
</CodeGroup>

### Go

In Go applications, AppSignal works with OpenTelemetry, which uses spans to track metadata, such as the action name. On any span in the trace, set an `appsignal.action_name` attribute with a String value to customize the action name:

<CodeGroup>
  ```go Go theme={null}
  package main

  import (
  	"context"
  	"net/http"

  	"go.opentelemetry.io/otel/attribute"
  	"go.opentelemetry.io/otel/trace"
  )

  func processPaymentHandler(w http.ResponseWriter, r *http.Request) {
  	ctx := r.Context()
  	span := trace.SpanFromContext(ctx)

  	paymentType := r.FormValue("type")

  	// GOOD: Set a custom action name based on payment type
  	if paymentType == "creditcard" {
  		span.SetAttributes(attribute.String("appsignal.action_name", "PaymentHandler#process_payment (creditcard)"))
  	}

  	// BAD: Don't use a dynamic value, it creates too many action names
  	// span.SetAttributes(attribute.String("appsignal.action_name", fmt.Sprintf("PaymentHandler#process_%s", paymentType)))

  	// Rest of your code

  	w.WriteHeader(http.StatusOK)
  	w.Write([]byte("Payment processed"))
  }
  ```
</CodeGroup>

For background jobs, tasks and scripts, you can set the action name in the same way by setting the `appsignal.action_name` attribute on the active span.

### Java

In Java applications, AppSignal works with OpenTelemetry, which uses spans to track metadata, such as the action name. On any span in the trace, set an `appsignal.action_name` attribute with a String value to customize the action name:

<CodeGroup>
  ```java Java theme={null}
  import io.opentelemetry.api.trace.Span;
  import org.springframework.web.bind.annotation.PostMapping;
  import org.springframework.web.bind.annotation.RequestParam;
  import org.springframework.web.bind.annotation.RestController;

  @RestController
  public class PaymentController {

      @PostMapping("/payments")
      public String processPayment(@RequestParam String type) {
          Span span = Span.current();

          // GOOD: Set a custom action name based on payment type
          if ("creditcard".equals(type)) {
              span.setAttribute("appsignal.action_name", "PaymentController#processPayment (creditcard)");
          }

          // BAD: Don't use a dynamic value, it creates too many action names
          // span.setAttribute("appsignal.action_name", "PaymentController#process_" + type);

          // Rest of your code

          return "Payment processed";
      }
  }
  ```
</CodeGroup>

For background jobs, tasks and scripts, you can set the action name in the same way by setting the `appsignal.action_name` attribute on the active span.

### PHP

In PHP applications, you can use the `Appsignal::setAction()` helper method from the AppSignal package to customize action names:

<CodeGroup>
  ```php PHP theme={null}
  <?php

  use Appsignal\Appsignal;

  class PaymentController
  {
      public function processPayment()
      {
          $paymentType = $_POST['type'] ?? 'unknown';

          // GOOD: Set a custom action name based on payment type
          if ($paymentType === 'creditcard') {
              Appsignal::setAction('PaymentController::processPayment (creditcard)');
          }

          // BAD: Don't use a dynamic value, it creates too many action names
          // Appsignal::setAction("PaymentController::process_{$paymentType}");

          // Rest of your code

          return 'Payment processed';
      }
  }
  ```
</CodeGroup>

For background jobs, tasks and scripts, you can set the action name in the same way by setting the `appsignal.action_name` attribute on the active span.

## Best Practices

When customizing action names, follow these guidelines:

1. **Be consistent**: Use a consistent naming pattern across your application.
2. **Be specific**: Include relevant information that helps identify the operation.
3. **Avoid high cardinality**: Don't include unique IDs or values that would create unique action names per execution.
4. **Use static strings**: Never interpolate variables or dynamic data into action names.
5. **Follow the codebase naming**: Use naming patterns like `Controller#action` that match your application structure so the location in the code can be found.
6. **Use tags or metadata instead**: For tracking variable information like payment providers or user types, use [tags](/guides/tagging) and [metadata](/guides/custom-data) 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:

1. **Static action names**: Use descriptive but static action names.
2. **Tags**: [Add tags](/guides/tagging) with the variable information (e.g., `provider: stripe`, `operation_type: refund`).
3. **Custom attributes**: [Add additional metadata](/guides/custom-data) to the trace/transaction.

Example:

<CodeGroup>
  ```ruby Ruby theme={null}
  # Instead of this:
  # Appsignal.set_action("PaymentController#process_#{provider}")

  # Do this:
  Appsignal.set_action("PaymentController#process_payment")
  Appsignal.add_tags(
    provider: provider,
    operation: operation
  )
  ```
</CodeGroup>

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.

<Tip>
  Historical data will still use the original action names. Only newly reported actions will use the custom names you've defined.
</Tip>

Are your custom action names not appearing correctly? Don't hesitate to [contact our support team](mailto:support@appsignal.com) for help!

## Further Reading

* [Grouping with Namespaces](/guides/namespaces)
* [Add Tags](/guides/tagging)
* [Add Metadata](/guides/custom-data)
* [Ignore Specific Actions](/guides/filter-data/ignore-actions)
