# Alerting in AppSignal Source: https://docs.appsignal.com/alerting Learn which AppSignal alerting feature to use, which alerts teams commonly start with, and how to avoid noisy alerts. Alerts help your team notice behavior that needs attention before customers need to tell you about it. In AppSignal, the most useful alerts are specific, routed to the right people, and urgent only when a human needs to act. AppSignal has five alerting systems: | System | Use it for | Example | | - | - | - | | [Uptime monitoring](/uptime-monitoring/setup) | An external check that your public endpoints still respond | Alert when a health-check endpoint stops returning a `2xx` from any region | | [Incident notifications](/application/notification-settings) | Errors AppSignal already detects in your app | Notify the team the first time an error appears after a deploy, or when a closed incident starts happening again | | [Anomaly detection triggers](/anomaly-detection) | Threshold alerts on built-in and [custom metrics](/metrics/custom) | Alert when error rate stays above `5%`, `p95` response time rises, throughput drops, or disk usage crosses `85%` | | [Log triggers](/logging/triggers) | Patterns in logs that should alert even when they never become an incident or metric | Alert when one payment provider starts logging repeated timeouts | | [Check-in triggers](/check-ins) | Cron jobs, heartbeats, and other processes that should report on time | Alert when a nightly job does not finish, or a worker stops sending heartbeats | Uptime monitoring checks your endpoints from AppSignal's servers in multiple regions over the public internet; the other four alert on data your app already sends to AppSignal. Many teams set it up first, because it catches an outage even when the app can send nothing at all. Five companion pages go deeper than this overview: * [Common alert questions](/alerting/common-questions) answers frequent support questions about alert emails, Kubernetes metrics, process memory alerts, and alert noise. * [Alerting in production](/alerting/production) covers setup order, coverage gaps, and how fast you need to know about each kind of failure. * [Alert recipes](/alerting/recipes) gives a starting configuration for each alert most production apps need. * [Tune your alerts](/alerting/tuning) covers thresholds, warm-up, cooldown, scope, and routing when your alerts are too noisy. * [Reduce alerting noise](/alerting/reduce-noise) is the production tuning pass, ordered by how many notifications each step removes, with the configuration we run on AppSignal itself. ## What alerts are Alerts turn telemetry into action. They help you answer questions such as: * Is the app down? * Are users seeing more errors than usual? * Did traffic drop because something upstream failed before requests reached the app? * Is a background queue backing up? * Did a scheduled job stop running? A good rule of thumb is to alert on the symptoms users feel, not every internal cause. That is the idea behind the SRE ["four golden signals"](https://sre.google/sre-book/monitoring-distributed-systems/): latency, traffic, errors, and saturation. In AppSignal, those map to response time, throughput, error rate, and host metrics and queue growth. ## Choose the right alerting system Use incident notifications when AppSignal already has an incident and you want to control who gets notified and how often. This is a strong default for exceptions and slow actions you already know you care about. Use anomaly detection triggers when you want threshold-based alerting on metrics. This is the most flexible option for SRE-style coverage, including error rate, response time percentiles, throughput, queue time, host metrics, and custom metrics. Use log triggers when the signal exists in logs but not yet as a dedicated incident or metric. They work well for integration-specific failures, such as one bank or provider timing out while the rest of the system looks healthy. Use check-in triggers when success means "this process reported on time." They are the right tool for cron jobs, heartbeats, workers, and scheduled tasks. ## A practical starter set For most production apps, a useful starter set looks like this: 1. An uptime check for your public health-check endpoint. 2. An anomaly trigger for `web` error rate. 3. An anomaly trigger for `p90` or `p95` response time on critical user-facing traffic. 4. An anomaly trigger for throughput drops. 5. An anomaly trigger for queue time, queue depth, or background job backlog. 6. Host metric triggers for CPU, memory, and disk. 7. Check-ins for cron jobs, scheduled tasks, and long-running workers. ## Popular alerts to start with These are common first alerts for teams that want broad coverage without too much noise: | Alert | Why it helps | AppSignal feature | | - | - | - | | Error rate in the `web` namespace | The fastest signal that users are hitting breakage | [Anomaly detection trigger](/anomaly-detection) | | `p90` or `p95` response time for critical actions | Averages hide a slow experience for part of your traffic | [Anomaly detection trigger](/anomaly-detection) | | Throughput drop | A sharp drop often means something upstream failed before requests reached your app | [Anomaly detection trigger](/anomaly-detection) | | Queue time or backlog growth | Early warning before users notice delays | [Anomaly detection trigger](/anomaly-detection) | | CPU, memory, and disk usage | Infrastructure heads-up for saturation and capacity problems | [Anomaly detection trigger](/anomaly-detection) | | Health-check endpoint failing | Confirms the app is unreachable from outside your infrastructure | [Uptime monitoring](/uptime-monitoring/setup) | | Cron job or worker heartbeat missing | Confirms expected background work still runs | [Check-in trigger](/check-ins) | ## What SREs commonly want coverage for If you are building out alert coverage from scratch, these are common priorities: * User-visible errors * Slow user requests, especially at `p90` or `p95` * Traffic drops and unusual throughput changes * Background queue growth and delayed jobs * Host saturation such as CPU, memory, and disk * Scheduled jobs that fail to start, finish, or report * External dependency problems such as slow bank APIs, timeouts, or retry storms This is also why deploy markers matter even though they are not an alert type on their own. They help you answer whether the alert started right after a release. ## Configure alerts successfully Good alerting is mostly about scope and routing: * Add notifiers first on the [Integrations](/application/integrations) and [Notifications](https://appsignal.com/redirect-to/app?to=notifiers) pages. Each trigger can use a different notifier, so you can route by severity. * Send urgent production alerts to an on-call tool such as [PagerDuty](/application/integrations/pagerduty), [Opsgenie](/application/integrations/opsgenie), or another webhook notifier. * Send warnings and degradations to chat or email, such as [Slack](/application/integrations/slack). Give staging its own channel or mute it. * Set [notification defaults per namespace](/application/notification-settings#organization-and-app-namespace-defaults) so `web`, `background`, and `admin` can notify different teams by default. * Start with alerts tied to user impact, then add narrower operational checks once you see what is useful. ## Avoid noisy alerts This is the part that separates a useful alert from one the team learns to ignore: * Set thresholds from real history, not guesswork. Review a few weeks of the metric's trend before choosing a threshold. * Use [warm-up windows](/anomaly-detection#warm-up-and-cooldown) so a condition must hold for several minutes before the alert opens. Three to five minutes is a common starting point, and most false alarms are single-minute blips. * Use at least a one-minute warm-up on uptime monitors to ride out brief network hiccups. * Add a [cooldown](/anomaly-detection#warm-up-and-cooldown) so a flapping signal becomes one longer alert instead of opening and closing repeatedly. * Prefer rates over absolute counts when traffic changes through the day. Error rate is usually more useful than raw error count. * Prefer `p90` or `p95` for latency-sensitive alerts instead of relying on averages. * Scope alerts by namespace, action, or tags so the notification says exactly what is affected. A trigger opens [one alert per matching series](/anomaly-detection#one-trigger-can-open-several-alerts), so a broad trigger can produce a burst of notifications from a single incident. * One good sustained alert beats five twitchy ones. Send only urgent, customer-facing alerts to on-call, and everything else to chat. [Tune your alerts](/alerting/tuning) works through each of these in detail, including which warm-up and cooldown values suit which signal. ## Set up uptime monitoring 1. Create a dedicated health-check endpoint if you do not already have one. 2. Add an [uptime monitor](/uptime-monitoring/setup) for that endpoint. 3. Choose a notifier for downtime notifications. 4. Set at least a one-minute warm-up so brief network hiccups do not open alerts. 5. [Ignore the health-check endpoint](/uptime-monitoring/setup#plans-and-requests) in your AppSignal app if you do not want those requests counted toward your monthly request volume. Use uptime monitoring for "is the app reachable from outside?" Use check-ins for "did this scheduled or background process report on time?" ## Examples ### Incident notification example Use incident notifications when AppSignal already created an error incident and you mainly need the right notification behavior. For slow actions, use an [anomaly detection trigger](/anomaly-detection) instead. For example: 1. Use **First in Deploy** for production errors that should only alert once per release. 2. Use **First After Close** for incidents caused by external systems that may recover without a deploy. 3. Use **Every Nth per Hour** or **Every Nth per Day** for noisy known errors where volume matters more than each individual occurrence. Pairing incident notifications with [deploy markers](/application/markers/deploy-markers) makes it much easier to answer, "Did this start after our last deploy?" ### Log trigger example Use log triggers when logs contain the signal you need. For example, a payment or signup flow may retry when a bank API is slow, so one failure may not deserve an urgent page, but a sustained pattern does. ```text Text theme={null} severity=error provider=bank-a message:timeout ``` A trigger like this can notify the team when one provider starts timing out. If retries are common, use **First After Close** or **Nth in an hour** instead of alerting on every matching log line. ### Custom metric alert example If you send custom metrics, you can alert on them with [anomaly detection](/anomaly-detection). For example, you might send: * A counter for successful payments or signups * A gauge for queue depth or active worker count * A measurement for provider response time After the metric appears in AppSignal: 1. Graph it first and review its recent history. 2. Choose the field that matches the question you are asking: `gauge`, `counter`, `count`, `mean`, `p90`, or `p95`. 3. Filter by tags such as `provider=bank-a` or `region=eu` when you need a narrower alert. 4. Add the right notifier for the severity of the problem. 5. Add warm-up and cooldown before you rely on the alert in production. ## Next steps * Pick a starting configuration from [alert recipes](/alerting/recipes). * Check [common alert questions](/alerting/common-questions) for support answers about alert emails, Kubernetes metrics, process memory alerts, and noisy notifications. * Cut notification volume with [tune your alerts](/alerting/tuning). * Review [notification settings](/application/notification-settings) for incident-based alerting. * Create [anomaly detection triggers](/anomaly-detection) for metrics and thresholds. * Set up [uptime monitoring](/uptime-monitoring/setup) for an external health check. * Create [process monitors and check-ins](/check-ins/create) for cron jobs and heartbeats. * Use [log triggers](/logging/triggers) for log-based alerting. # Common alert questions Source: https://docs.appsignal.com/alerting/common-questions Answers to common support questions about alert notifications, uptime monitors, Kubernetes metrics, process memory alerts, and alert noise. These answers cover common support questions about AppSignal alerts. For setup guidance, start with [Alerting in AppSignal](/alerting). For tuning noisy alerts, see [Tune your alerts](/alerting/tuning) and [Reduce alerting noise](/alerting/reduce-noise). ## Why am I still receiving alert emails after canceling my plan? Those emails are operational alert notifications, not marketing emails. They usually come from a monitor or trigger that is still configured for the app. For example, an uptime monitor can keep checking a URL and send an alert each time the URL cannot be reached. If your account is locked or canceled, the email may say that AppSignal is still monitoring the app but that you no longer have access to the data details. To stop the notifications: 1. If you can still access the app, remove the notifier from the trigger on the [triggers page](https://appsignal.com/redirect-to/app?to=triggers), or from the monitor on the [uptime monitoring page](https://appsignal.com/redirect-to/app?to=uptime_monitors). 2. Archive the trigger or delete the uptime monitor if you no longer need it. 3. If you cannot access the app because the account is locked or canceled, [contact support](mailto:support@appsignal.com). We can help identify and remove the monitor or trigger that is still sending alerts. ## How do I stop a trigger from sending notifications without deleting it? Remove the notifiers from the trigger on the [triggers page](https://appsignal.com/redirect-to/app?to=triggers). The trigger stays active and still records alerts, but it stops sending notifications. Archive the trigger only when you no longer want AppSignal to evaluate that condition. Archiving a trigger also closes its open alerts. For anomaly detection triggers, notification routing is controlled on the trigger itself. Incident notification frequency settings, such as **Never Notify** or **Every Nth per Hour**, do not apply to anomaly detection trigger alerts. ## Can I alert when Kubernetes containers are pending or stopped? AppSignal for Kubernetes reports node and pod metrics, and shows them on the [Cluster Metrics pages](https://appsignal.com/redirect-to/app?to=cluster). It does not provide a Kubernetes trigger for container states such as pending or stopped. Kubernetes metrics are not currently available for anomaly detection triggers, and the Kubernetes overview does not create alert rules. If you need alerts for Kubernetes container or pod states, [contact support](mailto:support@appsignal.com). We can help confirm what is possible for your setup and collect the use case if it needs product work. ## What metric powers the Process memory usage dashboard? The Process memory usage dashboard, one of your app's [dashboards](https://appsignal.com/redirect-to/app?to=dashboard), uses the `process_rss` metric. This metric is tagged with: * `hostname`, the host that emitted the metric. * `process_name`, the process name reported by the app process. To create an alert for a specific process, [create an anomaly detection trigger](https://appsignal.com/redirect-to/app?to=triggers) for `process_rss` and scope it with tags. For example, use `process_name=sidekiq*` or a specific process name if your app reports one, and use the relevant `hostname` when you want to alert on one host or dyno. To confirm the exact metric and tags behind a dashboard chart, open the chart menu and select **Edit chart**. Use the metric name, field, and tags from that chart as the starting point for the trigger. ## We receive alerts but rarely open AppSignal. Is that a problem? Not necessarily. Some teams use AppSignal mostly as an alerting system. That can work if the alerts are specific, routed to the right place, and acted on. It becomes a problem when notifications arrive but nobody investigates them. That usually means the alerts are too noisy, not clear enough, or routed to the wrong channel. Review the alert setup: 1. List the triggers that opened alerts in the last 90 days on the [triggers page](https://appsignal.com/redirect-to/app?to=triggers). 2. Check whether anyone acted on each alert in the [anomaly detection overview](https://appsignal.com/redirect-to/app?to=anomalies). 3. Remove notifiers from alerts that should not notify anyone. 4. Archive alerts for conditions nobody needs anymore. 5. Route urgent alerts to an on-call tool, and route lower-priority alerts to chat or email. 6. Add a clear trigger name, description, and dashboard link so the notification explains what to do next. If your team does not want to use the AppSignal UI often, use the [AppSignal CLI](/cli/triggers) or [AppSignal MCP server](/mcp-server) to review triggers and investigate alerts from your normal workflow\.z ## Which alerts should send email? Use email for alerts that should keep reminding someone while they stay open, or for lower-urgency alerts that do not need an immediate on-call response. For urgent production issues, use an on-call notifier such as [PagerDuty](/application/integrations/pagerduty), [Opsgenie](/application/integrations/opsgenie), or another webhook-based notifier. Email is easy to miss when a team receives many alerts. Connect notifiers on the [Notifications page](https://appsignal.com/redirect-to/app?to=notifiers), then select them on each trigger. Email can send reminders while an anomaly alert stays open. Other notifier types, including Slack, PagerDuty, Opsgenie, and webhooks, receive notifications when the alert opens and when it is resolved. ## How often should we review alert settings? Review triggers roughly every quarter, and any time a notification channel starts to feel noisy. Ask these questions for each trigger: * Did this trigger open an alert in the last 90 days? * Did someone act on it? * Did one incident create many alerts? * Is the notifier still right? * Does the trigger name and description explain the action to take? * Does the trigger still match current hosts, tags, queues, or process names? An alert nobody acts on should be retuned, rerouted, or archived. # Alerting in production Source: https://docs.appsignal.com/alerting/production Set up alerting for a production environment in layers, check your coverage for gaps, and decide how fast you need to know about each kind of failure. This page is about getting production alerting right the first time: what to set up, in what order, how to confirm it works, and how to check that nothing important is unmonitored. It assumes you know what you want to alert on. If you do not yet, start with [alert recipes](/alerting/recipes). If you already have alerts and they are too noisy, go to [tune your alerts](/alerting/tuning). ## Before you create a trigger Three setup steps make every alert that follows more useful, and all three are easier to do first than to retrofit. **Add your notifiers.** Triggers reference notifiers, so creating them first means you can route each alert as you build it rather than going back over everything later. Set up at least two destinations: somewhere urgent, such as an on-call tool, and somewhere non-urgent, such as a team chat channel. Notifiers are configured once for the organization and shared across apps. **Send [deploy markers](/application/markers/deploy-markers).** Most production incidents start with a release. A marker turns "when did this start?" into a question you can answer in seconds, and it is what makes the [**First in Deploy** notification setting](/application/notification-settings#first-in-deploy) work. **Split your app into [namespaces](/application/namespaces).** Namespaces are the main lever for alerting at different severities without configuring each alert individually. If `web`, `background`, and `admin` traffic all land in one namespace, every threshold you set has to suit all three at once, which usually means it suits none of them. ## Add alerts in layers Adding every alert at once produces too many notifications on day one and teaches the team to ignore them. Add a layer, live with it for a week, then add the next. 1. **Reachability.** An [uptime monitor](/uptime-monitoring/setup) on a health-check endpoint. This is the only alert that still works when your application cannot report anything at all. 2. **User-visible symptoms.** Error rate and response time on your user-facing namespace. These alerts correspond to errors or slow response times experienced by users. 3. **Scheduled and background work.** [Check-ins](/check-ins) for cron jobs and worker heartbeats, and an absence alert for any queue that should never be empty of activity. 4. **Saturation.** Host disk, memory, and swap. These are causes rather than symptoms, so route them to chat rather than on-call. 5. **Business metrics.** [Custom metrics](/metrics/custom) for the application-specific activity only you can measure, such as completed payments or signups per minute. Layers one and two cover most real incidents. Layer five detects application-specific failures that other alerts cannot detect. ## Keep staging and test noise out of production Production alerting only stays credible if non-production noise never reaches it. * Give each environment its own app in AppSignal, so thresholds and notifiers are set per environment rather than shared. * Give staging its own chat channel, or leave staging triggers with no notifier at all. A trigger with no notifier still records alerts you can review later, without notifying anyone. * Use different thresholds. Staging traffic is lower and changes more than production traffic, so a threshold tuned on production data may never open an alert or may open alerts too often. * Keep personal test channels out of production apps. A notifier can be shared by several apps, and trigger alerts are routed by the notifiers selected on each trigger. ## Check your coverage Too many notifications are the visible failure. The hidden failure is an outage nobody was alerted to. Work through the failure modes rather than the features, and check that each one has an alert: | If this happens | What detects it | | - | - | | The application is completely unreachable | [Uptime monitor](/uptime-monitoring/setup) | | The application responds but returns errors, so actions such as adding an item to a cart fail | Error rate trigger on the user-facing namespace | | The application responds slowly | p90 or p95 performance trigger | | Requests stop arriving at all, because something upstream broke before they reached the app | Throughput floor, or a trigger on throughput equal to `0` | | A background worker dies, so confirmation emails or invoices stop being sent | Absence alert on a job counter, or a heartbeat [check-in](/check-ins) | | A scheduled job does not run, so today's data is missing | Cron [check-in](/check-ins) | | A queue backs up, so work is accepted but takes hours to be processed | Queue depth or queue time trigger | | A host runs out of disk, memory, or swap, so the application stops abruptly | Host metric triggers | | A dependency fails intermittently but retries succeed, such as one payment provider or delivery partner | [Log trigger](/logging/triggers), or a metric extracted from those log lines | | A business process stops without errors appearing in AppSignal, such as orders, payments, or bookings no longer going through | Custom metric equal to `0`, or below a minimum threshold | | A TLS certificate is close to expiration, so browsers warn that the site is not secure | SSL expiration monitoring, available as an [AppSignal Labs](/labs) feature | | A metric stops being reported entirely | A trigger with **treat missing datapoints as 0** enabled | The last row is the one most often missing. Every other alert on this list needs data to arrive before it can open. Two questions are useful for reviewing the whole set. First, for each row you have covered, does the alert reach someone who can act at the time of day it is most likely to open? Second, of your last few production incidents, how many were first reported by a person rather than by an alert? That second number is a useful measure of coverage. ## Decide how fast you need to know Detection is not instant, and it is worth deciding deliberately how much delay each alert can carry. Three factors add up to the time between a problem starting and a notification arriving: * **Aggregation.** Metrics are evaluated once per minute, so there is always up to a minute before the offending value is even considered. * **[Processing](/anomaly-detection#data-processing).** AppSignal waits for the data for a minute to arrive from all of your servers before evaluating it. * **Warm-up.** The number of minutes AppSignal waits before opening the alert. Warm-up delays the alert. If a trigger has a 2-minute warm-up, the metric must stay above or below the threshold for 2 minutes before AppSignal opens the alert. These are reasonable targets for how quickly you need to know about each kind of failure: * **Checkout or payments broken, so customers cannot buy, book, or transfer money.** As fast as possible, so little or no warm-up. * **Site or app unreachable.** 1–2 minutes. * **Elevated error rate, so customers are hitting errors.** 1–2 minutes. * **Response time degradation, so requests take longer than usual.** 1–3 minutes. * **Queue backing up, so work is still being processed but arrives late.** 1–3 minutes. * **Disk usage approaching full capacity.** 10–60 minutes. If an alert is noisy but also needs to be fast, do not solve it with a longer warm-up. Narrow the scope or move the threshold instead, both of which reduce false alarms without costing detection time. > [!WARNING] > > Anomaly detection cannot tell you that something did not happen within a window shorter than the data it receives. Do not use a long warm-up as a substitute for [check-ins](/check-ins) when monitoring scheduled work. ## Verify an alert before you rely on it A trigger that matches nothing can look like a healthy system. Before you count an alert as coverage, confirm all of the following: 1. **The chart preview shows data.** An empty preview on the trigger form means the trigger currently matches nothing. 2. **The hostname resolves.** If the hostname field warns that the host was not found, the trigger is probably watching a machine that has been renamed or replaced. 3. **The tag combination is recognized.** AppSignal warns when a tag combination has not been seen in the last hour. Use one of the tag-key combinations listed in the trigger form, and set each value to an exact value or a wildcard. 4. **A notifier is attached.** A trigger with no notifier records alerts without sending notifications. 5. **The notifier works.** Send a test notification, and confirm it arrives in the channel you expect rather than one that looks similar. 6. **Absence alerts have missing data handled.** For any trigger whose threshold is zero or a minimum value, confirm **treat missing datapoints as 0** is enabled, or it will not open in exactly the case you built it for. ## Maintain alerting after setup Alerting is not finished when it is set up. * **Write the runbook into the trigger.** A name that says what is wrong, a description that says what to do, and a linked dashboard. Covered in [make the notification explain itself](/alerting/tuning#make-the-notification-explain-itself). * **Avoid retuning during an incident.** Changing trigger settings can affect the alert you are currently tracking, including closing or replacing active alert state. * **Review quarterly.** Alerting decays as hosts are replaced, services are renamed, and traffic grows. The [review checklist](/alerting/tuning#review-triggers-regularly) covers what to look for. * **Add an alert after each incident, and remove one too.** Post-incident review is the best time to notice both what was missing and what opened without requiring action. ## Next steps * Pick configurations from [alert recipes](/alerting/recipes). * Reduce volume with [tune your alerts](/alerting/tuning). * Set [notification defaults per namespace](/application/notification-settings#organization-and-app-namespace-defaults). * Set up [check-ins](/check-ins) for scheduled work. # Alert recipes Source: https://docs.appsignal.com/alerting/recipes Concrete starting configurations for the alerts most production apps need, and guidance on when each one is worth setting up. This page gives a starting configuration for each alert most production applications need. Every recipe lists what the trigger measures, when it is worth setting up, and values to start from. Treat the values as starting points. Graph the metric over at least two weeks before committing to a threshold, then adjust using the guidance in [tune your alerts](/alerting/tuning). Whichever recipe you start with, give the trigger a name that says what is wrong, a description that says what to do about it, and a linked dashboard. Those three fields are what turn the resulting notification into something a responder can act on, and they are covered in [make the notification explain itself](/alerting/tuning#make-the-notification-explain-itself). ## The four alerts to set up first If you are setting up alerting from scratch, these four cover most real incidents: 1. An [uptime monitor](#is-the-app-reachable) on a health-check endpoint. 2. An [error rate](#are-users-hitting-errors) trigger on your `web` namespace. 3. A [p95 response time](#are-requests-getting-slow) trigger on user-facing traffic. 4. [Check-ins](#did-scheduled-work-run) for scheduled jobs. Add host and saturation alerts once those are stable. Adding every recipe on this page at once is a reliable way to create alert fatigue. ## Is the app reachable? **Use:** [Uptime monitoring](/uptime-monitoring/setup) An external check that your endpoint still responds. It is the only alert that still works when your app cannot send anything to AppSignal at all, which is why most teams set it up first. | Setting | Starting value | | - | - | | URL | A dedicated health-check endpoint, including the scheme | | Warm-up | 1 minute or more | | Notifier | On-call | AppSignal requests the URL every minute from four regions and reports a failure when the response is not in the `2xx` range or does not arrive within 30 seconds. Each region is tracked separately, so a monitor opens one alert per failing region. A genuine outage opens up to four alerts, and a network problem between one region and your endpoint opens one alert while your application is fine. This is the main reason to set a warm-up on uptime monitors: a single-region failure that resolves within a minute does not send a notification. An uptime monitor also produces metrics tagged by region and monitor name, so you can add [anomaly detection triggers](/anomaly-detection) on response time per region if you need finer alerting than up or down. SSL certificate expiration monitoring is available as an [AppSignal Labs](/labs) feature. Once enabled, you turn it on for an individual `https://` monitor rather than building a trigger by hand, and AppSignal notifies you when the certificate has fewer than 14 days remaining, using the same notifiers as the monitor. Certificate expiry is a slow-moving problem, so route it to email or chat rather than on-call. ## Are users hitting errors? **Use:** An anomaly detection trigger on error rate, scoped to a namespace Error rate is the fastest indicator that users are experiencing errors, and it stays meaningful as traffic changes. | Setting | Starting value | | - | - | | Trigger kind | Error rate | | Namespace | `web` | | Threshold | Above 5% for a mature app, above 20% for a new one | | Warm-up | 3–5 minutes | | Cooldown | 5 minutes | | Notifier | On-call | The suggested trigger in AppSignal starts at 20%, which is deliberately conservative so a new app does not immediately produce alerts. Lower it once you know your baseline. Create a separate, more forgiving trigger for `background`. Job failures usually retry, so they rarely justify the same urgency as failing web requests. Running two error rate triggers at different thresholds works well, as long as each one has a different destination. A trigger at your normal degradation threshold goes to chat, and a second one at a much higher threshold, such as 50%, means there is a serious issue and should notify on-call. Two thresholds pointing at the same notifier only double the notifications. ### When to use error count instead Error count crosses a fixed threshold whenever traffic grows, so it notifies you on busy days regardless of whether anything is wrong. Use it only where any occurrence matters and volume is naturally low, such as a payment or signup namespace. Scope it tightly and set a low threshold. ## Are requests getting slow? **Use:** An anomaly detection trigger on performance, measured in milliseconds Averages hide slow requests for part of your traffic. If one request in 20 takes 8 seconds while the rest are quick, the average barely moves, but 5% of users experience a slow request. Percentiles fix this. A p95 of 400 ms means 95 out of every 100 requests finished within 400 ms, and the slowest five took longer. Alert on p90 or p95 rather than the average, so you notice a problem that affects part of your traffic. | Setting | Starting value | | - | - | | Trigger kind | Slow performance for a namespace | | Field | `p95` | | Threshold | Roughly twice your normal p95 | | Warm-up | 5 minutes | | Cooldown | 5 minutes | | Notifier | Team chat | AppSignal's suggested trigger uses a mean above 500 ms, which is a reasonable first alert but will miss partial degradation. Move to p95 once you have a baseline. To watch one critical path rather than a whole namespace, use an action-scoped performance trigger. Checkout, sign-in, and search are common candidates. Give each a threshold that fits it: a page that calls a third-party API may reasonably take 10 seconds, while a homepage should not. ## Did traffic disappear? **Use:** An anomaly detection trigger on throughput, measured in requests per minute A sharp drop in throughput usually means a failure happened before requests reached your app: an expired domain, a misconfigured load balancer, or a CDN outage. This failure is invisible to your other alerts, because an app receiving no traffic reports no errors and no slow requests. | Setting | Starting value | | - | - | | Trigger kind | Throughput for a namespace | | Comparison | Below | | Threshold | Well under your quietest normal hour | | Warm-up | 1–5 minutes | | Cooldown | 10 minutes | | Notifier | On-call | Set the threshold against your quietest period, not your average, or the trigger will notify you every night. If your traffic varies too much for a fixed floor to work, alert on traffic reaching exactly zero instead, as described in the following section. ### Alerting on traffic that is too high Traffic far above your normal peak can also need a trigger. It can come from expected growth, such as a successful campaign, or from a problem, such as a bot scraping your catalog or a client retrying in a loop. In both cases, the alert helps you respond before the traffic exhausts your capacity. Set the comparison to **More than**, with a threshold well over your busiest normal hour, and route it to chat. It is rarely urgent enough for on-call notification, but it explains many other alerts that arrive shortly afterwards. ## Did activity stop? **Use:** An anomaly detection trigger with a threshold of exactly zero Some of the most valuable alerts are about absence rather than excess. A queue consumer that stops consuming, a namespace that stops receiving traffic, or a pipeline stage that stops producing output can show no errors, no slow requests, and no saturation. The missing activity is the problem. | Setting | Starting value | | - | - | | Comparison | Equal to `0` | | Missing data | Enable **treat missing datapoints as 0** | | Warm-up | 3–5 minutes, based on how much the work varies minute to minute | | Notifier | On-call for anything customer-facing | Enabling **treat missing datapoints as 0** is what makes this work. Without it, a metric that stops reporting entirely sends no data points, so the trigger has nothing to evaluate and the alert never opens. With it, AppSignal treats missing data as zero and the alert opens as intended. Good candidates are throughput per namespace, a counter of successfully processed jobs, or a process count that should never drop to zero. This pattern is also the reliable way to notice a worker that has died rather than slowed down. > [!NOTE] > > Use this for continuous work that should always be happening. For work that runs on a schedule, use [check-ins](/check-ins) instead, which are built for it and do not need a warm-up long enough to span the gap between runs. ## Is work backing up? **Use:** An anomaly detection trigger on queue time, measured in milliseconds Queue time measures how long a request or job waited before your app started processing it. Rising queue time is an early warning that capacity is short, usually before response times or error rates react. Your app may report no errors and no slow requests while users are still waiting: an order confirmed hours after it was placed, or a report that arrives a day late. | Setting | Starting value | | - | - | | Trigger kind | Queue time for a namespace | | Field | `mean` or `p95` | | Threshold | Several times your normal queue time | | Warm-up | 5 minutes | | Cooldown | 5 minutes | | Notifier | Team chat, or on-call for user-facing queues | In practice, queue depth is often the easier signal to alert on. If you already track pending job count or unprocessed message count as a [custom metric](/metrics/custom), a depth threshold is concrete, easy to reason about, and easy to set from history. Tag it by queue name so a backlog in one queue does not read as a general outage. Use both where you can. Depth tells you the backlog is growing; queue time tells you it is already affecting someone. ## Are hosts running out of resources? **Use:** Host metric triggers Host alerts describe causes rather than user-visible symptoms, so route them to lower-urgency channels than user-facing alerts. A host at 95% CPU with healthy response times is not an incident. Host alerts are useful because they warn you before a resource runs out completely, which is when an app can stop abruptly and other alerts can start opening at once. Every host trigger accepts a hostname, and its default value of `*` matches every host. Set a specific name or a prefix such as `web-*` unless you genuinely want one alert per host in the fleet. ### Disk usage This is the clearest host alert to configure, because a full disk reliably causes failures and disk usage often increases predictably. | Setting | Starting value | | - | - | | Metric | `disk_usage`, in percent | | Mountpoint | `/`, plus any data volume | | Threshold | Above 80% generally, above 60% for hosts that fill quickly | | Warm-up | 0–10 minutes | | Notifier | Team chat | Set the threshold from how fast the disk fills, not from how full it is. A general-purpose host that gains a percentage point a week is fine at 80%. A database or queue host that can gain 20 points in an hour needs to warn you at 60%, because the remaining time matters more than the remaining space. That usually means several disk triggers rather than one, each scoped to a group of hosts with a wildcard, such as `db-*` at 60% and `web-*` at 80%. Set one trigger per mountpoint you care about too. A trigger without a mountpoint tag matches every mounted filesystem, including short-lived container mounts. ### Memory usage | Setting | Starting value | | - | - | | Metric | `memory` | | State | `used`, `free`, or `available` | | Threshold | Above 90% used, or a free-memory floor that suits the host | | Warm-up | 0–5 minutes | | Notifier | Team chat | Percentage is usually easier to reuse across differently sized hosts. Absolute values are better when you know how much free capacity a specific workload needs. ### Swap usage When a server runs low on memory it starts moving data to disk, which is far slower than memory. The application keeps working, so no error may occur, but requests can become slower. This is useful to alert on because the impact can be gradual and easy to miss. | Setting | Starting value | | - | - | | Metric | `swap` | | State | `used` or `total` | | Threshold | Above 20% used for an early warning, above 50% for action | | Warm-up | 0–5 minutes | | Notifier | Team chat | The suggested trigger in AppSignal notifies you when a host uses any swap at all, which is a reasonable way to discover whether your hosts swap. It is usually too sensitive to keep long term: many healthy hosts allocate a little swap and never touch it again. Once you know your baseline, move to a percentage threshold so the alert opens for real memory pressure rather than for a few megabytes allocated at boot. ### CPU usage and load average | Setting | Starting value | | - | - | | Metric | `cpu` in percent, or `load_avg` | | State | `user`, `nice`, `system`, `idle`, or `iowait`, each reported as a percentage | | Threshold | Above 90% CPU, or a load average around the host's core count | | Warm-up | 5 minutes | | Notifier | Team chat | The agent reports CPU per state rather than as a single total, so pick the state that describes the work you care about, and use `iowait` when you suspect the host is waiting on disk rather than computing. Short CPU increases are normal. Only sustained high CPU usage usually needs a notification, and even then it belongs in chat rather than on-call unless it is already affecting response times. Load average is often the more useful of the two on database and worker hosts, because it counts processes waiting on disk as well as on CPU. It is not comparable across machines, though: a load average of 60 is saturation on a 16-core host and healthy on a 128-core one. Scope a load average trigger to one class of host with a wildcard and set the threshold from that machine's core count, rather than running a single trigger across a mixed fleet. ### Disk and network throughput The disk I/O and network traffic triggers cover data read from and written to every disk, and data received and transmitted through every network interface. These make better dashboard graphs than alerts for most teams, because a meaningful threshold depends heavily on the workload. Alert on them when you have a known ceiling, such as a provisioned IOPS limit. ## Did scheduled work run? **Use:** [Check-ins](/check-ins) Anomaly detection cannot reliably tell you that scheduled work did not happen, because a trigger only evaluates data that arrives. Use check-ins for this. * **Cron check-in**, for jobs that run on a schedule. Its key setting is the cron expression, plus a timezone. * **Heartbeat check-in**, for workers and processes that should keep running. Its key setting is the maximum duration since the last heartbeat. Both use a **Maximum duration** in minutes rather than a warm-up. For a cron process monitor, AppSignal reports a failure when no event arrives between the start time set by the schedule and the end of that duration. For a heartbeat, it reports a failure when no event arrives within that duration of the last one. Set it longer than the job's normal variation in start time and run time, so a job that occasionally runs a few minutes late does not notify anyone. Good candidates are nightly billing runs, backups, data exports, cache warmers, and any long-running consumer. ## Is one dependency failing? **Use:** [Log triggers](/logging/triggers) Some failures never become an incident or a metric. A payment provider that times out and then succeeds on retry leaves no error and no latency spike large enough to notice, but a sustained pattern is worth knowing about. Start from the query that finds the lines. If you are already looking at them in the terminal, that query is the one you have: ```sh Shell theme={null} appsignal-cli logs search --app "MyApp" --environment production \ --query 'provider=bank-a message:timeout' --severities error --limit 20 ``` Once the query matches the expected lines only, create the trigger from it. The same query text is reused: ```sh Shell theme={null} appsignal-cli logs triggers create --app "MyApp" --environment production \ --name "Bank A timing out" \ --query 'provider=bank-a message:timeout' \ --severity ERROR \ --description "Bank A is timing out. Check their status page before investigating our own code." \ --notifier-id ``` To do the same in the interface, filter the Logs page to the lines you care about, select one to open **Log details**, and create the trigger from the **Actions** section, which carries your query, severity, and source across. See [log triggers](/logging/triggers) for the full flow. Log triggers work differently from metric triggers, and the difference matters for noise. A log trigger is evaluated against individual log lines as they arrive, so it does not have the anomaly trigger warm-up and cooldown settings. Control notification volume with the threshold setting instead: * **First After Close** for a problem that recovers on its own, so you get one notification each time the problem returns after closing. * **Nth in an hour** for a log pattern that matches intermittently by design, where the number of matching log lines is the important signal. * **Every Occurrence** only where a single line genuinely matters. Use **Never Notify** for patterns you want to track and count without notifying anyone. ### Getting warm-up and cooldown on log data When a log pattern is too noisy for any of those thresholds, convert it into a metric instead of alerting on the lines directly. Extract a [log-based metric](/logging/metrics) from the matching lines, then point an [anomaly detection trigger](/anomaly-detection) at that metric. That is two commands. First, count the matching lines into a metric. A `counter` needs no field, because it is counting lines rather than reading a value out of them: ```sh Shell theme={null} appsignal-cli logs metrics create --app "MyApp" --environment production \ --name "Bank A timeouts" \ --query 'provider=bank-a message:timeout' \ --metric 'name=bank_a_timeouts,type=counter' ``` Then alert on that metric, which is where warm-up and cooldown become available: ```sh Shell theme={null} appsignal-cli triggers create --app "MyApp" --environment production \ --name "Bank A timing out repeatedly" \ --metric-name bank_a_timeouts --kind Advanced --field counter \ --comparison-operator ">" --condition-value 10 \ --warmup-duration 5 --cooldown-duration 10 \ --description "Bank A has timed out more than 10 times in a minute for 5 minutes. Check their status page first." \ --notifier-ids ``` This gives log-derived data the full state machine: a threshold, a warm-up so a brief increase is ignored, and a cooldown so one recurring problem produces one alert. This is the recommended approach for a dependency that fails in short periods several times a day. ## Is a business metric wrong? **Use:** An anomaly detection trigger on a [custom metric](/metrics/custom) Custom metrics are the only way to alert on application-specific values AppSignal cannot infer, such as successful payments per minute, signups, or the size of a work queue. | Setting | Guidance | | - | - | | Field | `gauge` for a current value, `counter` for a rate of events, `mean` or a percentile for measurements | | Format | Set `duration`, `size`, `percent`, or `throughput` so thresholds and notifications show the right unit | | Tags | Filter to the series you care about, such as `provider=bank-a` | | Missing data | Enable **treat missing datapoints as 0** for counters that stop reporting when idle | This is the one failure no other alert on this page can detect. If a change at your payment provider starts rejecting every transaction, your app stays up, fast, and error-free while nothing is being sold, so only a metric you send yourself can detect it. Graph the metric first, then set the threshold from what you see. To verify a custom metric in the alerting UI, open **Anomaly detection**, go to **Triggers**, select **Add trigger**, then choose **Custom metrics** under **Other**. Enter the metric name and use the chart preview and tag combinations to confirm AppSignal has received the metric. ## Next steps * Tune what you have set up with [tune your alerts](/alerting/tuning). * Read how [anomaly detection](/anomaly-detection) evaluates triggers. * Send custom metrics with [custom metrics](/metrics/custom). * Review [notification settings](/application/notification-settings) for error incidents. * Check for coverage gaps with [alerting in production](/alerting/production). # Reduce alerting noise Source: https://docs.appsignal.com/alerting/reduce-noise Production guidance for cutting an alerting setup down to the notifications your team can act on, ordered by how much noise each step removes. A new application can send too many alerts. Thresholds are set before anyone knows the normal metric range, triggers watch every host and every tag value, and every notification goes to one channel. Within a few weeks the team starts ignoring that channel, and shortly after that somebody disables notifications for it. This page is the tuning pass that fixes it. The steps are ordered by how much noise each one removes, so working from the top down gets most of the benefit early. For the mechanics of each setting, see [tune your alerts](/alerting/tuning). The two steps that usually remove the most notifications are [using exact tag filters instead of broad wildcards](#use-exact-tag-filters-or-send-a-dedicated-alert-metric) and [keeping tag values to a small fixed set](#keep-tag-values-to-a-small-fixed-set). Both prevent one trigger from opening alerts for values you did not mean to monitor. ## Choose a destination by how fast someone must act Most notification noise comes from alerts being sent to a channel that implies more urgency than they have. Choose the destination based on how quickly someone needs to act. * **Customers lose money or access tonight:** On-call, such as [PagerDuty](/application/integrations/pagerduty) or [Opsgenie](/application/integrations/opsgenie). * **It gets worse, but nothing is lost yet:** Team chat, such as [Slack](/application/integrations/slack). * **Tomorrow is genuinely fine:** Email, or a low-traffic chat channel. * **Nothing, because it is already known:** No notifier at all. Each trigger selects its own notifiers. A trigger with no notifier still records its alerts, so you can monitor a metric without sending notifications. Give staging its own channel, or leave its triggers without a notifier. Staging alerts arriving in a production channel are the fastest way to teach a team to ignore that channel. ## Scope every trigger to the series you actually mean A trigger does not open one alert. It opens one alert per matching series. A host trigger left at its default hostname of `*` covers every host reporting to the app, so 30 hosts crossing a threshold together produce 30 notifications for one problem. Narrow the scope until the notification says exactly what is affected: * Replace `*` with a specific hostname, or a prefix such as `web-*`. Tag values accept wildcards, so `hostname=frontend*` scopes a trigger to one class of machine. * Scope error rate and response time triggers to a single [namespace](/application/namespaces), so `web`, `background`, and `admin` can carry different thresholds and different destinations. * Add a tag for the specific resource you care about, such as one mountpoint rather than every mounted filesystem. ## Use exact tag filters or send a dedicated alert metric This limitation causes many noisy-alerting support requests, and it is worth understanding before you design a metric. Suppose you send a counter named `api_request`, tagged with `status`, so you can break it down by `200`, `404`, and `500`. If you only care about one exact value, such as `status=500`, use that exact value in the trigger. The problem starts when you want a group of values: all `5xx` responses, anything except `200`, or every failed response. A tag filter cannot express exclusions or ranges, and `*` matches every value for that tag. A broad wildcard trigger can open alerts for successful statuses alongside failures, and most of what arrives describes an application working correctly. The solution is to make the condition you want to alert on its own series, at the point you send it. Keep the tagged metric when it is useful for charting, and send a second, narrower one for alerting: ```ruby Ruby theme={null} status_code = response.code.to_s # Useful for charts broken down by status. Appsignal.increment_counter("api_request", 1, :status => status_code) # Useful for alerting because it only increments for 5xx responses. Appsignal.increment_counter("api_request_failed", 1) if status_code.to_i >= 500 ``` ```elixir Elixir theme={null} status = response.status # Useful for charts broken down by status. Appsignal.increment_counter("api_request", 1, %{status: status}) if status >= 500 do # Useful for alerting because it only increments for 5xx responses. Appsignal.increment_counter("api_request_failed", 1) end ``` Then configure the trigger to use the narrower metric: ```sh Shell theme={null} appsignal-cli triggers create --app "MyApp" --environment production \ --name "Server errors from the payment API" \ --metric-name api_request_failed --kind Advanced --field counter \ --comparison-operator ">" --condition-value 10 \ --warmup-duration 3 --cooldown-duration 5 \ --notifier-ids ``` The alert now opens only for the condition that should send a notification. Decide this while you are writing the [custom metric](/metrics/custom), because it is easier than redesigning the metric after alerts start opening. ## Keep tag values to a small, fixed set Never use a value that is unique per event as a tag value. Request identifiers, order numbers, customer identifiers, and timestamps all look like useful context and all cause the same two problems. Every distinct value is a separate series. A trigger over that metric opens one alert per value, which can create an unbounded number of alerts. High-cardinality tags also make metric charts and alerting hard to manage. A tag value should have a handful of variations that you could list from memory. For example, tag by a bounded dimension such as `region`, not by a unique identifier: ```ruby Ruby theme={null} # A tag with a small set of values is safe to graph and alert on. Appsignal.increment_counter("order_processed", 1, :region => order.region) ``` ```elixir Elixir theme={null} # A tag with a small set of values is safe to graph and alert on. Appsignal.increment_counter("order_processed", 1, %{region: order.region}) ``` The order identifier still matters when you are investigating, so put it in a [log line](/logging), where high cardinality is expected. Use metric tags for dimensions you would want to group a chart by. The [custom metrics](/metrics/custom#metric-tags) reference has more on choosing tags, including keeping the same combination everywhere you report a metric. ## Alert on rates, not counts An error count crosses a fixed threshold whenever traffic grows, so it notifies you on your busiest day regardless of whether anything is wrong. Error rate stays meaningful at 4 a.m. and at peak. Switching from a count to a rate is often the single edit that turns a nightly alert into a useful one. Keep counts only where any occurrence matters and volume is naturally low, such as failures in a payment flow. ## Match warm-up to how much the metric changes Warm-up is how long AppSignal waits before opening an alert. During that wait, the metric must stay above or below the threshold, depending on the trigger. This filters out single-minute spikes, such as one slow deploy, one garbage collection pause, or one restarting host. Set warm-up based on how much the metric changes minute to minute, not how serious the metric is. Start with zero to two minutes for most production alerts. Use a longer warm-up only when a metric often spikes and recovers quickly. Memory and swap move gradually, so they often need little or no warm-up. If you need 30 or 60 minutes to reduce notifications, review the threshold or scope instead. ## Use cooldown when a metric stays near its threshold Cooldown keeps one incident from producing a stream of open and close notifications while a metric repeatedly crosses the threshold. Most triggers never need one. The exception is slow-moving resource metrics, which may need a longer cooldown: a disk close to 80% may cross that line several times before someone frees space, so without a long cooldown it can alert again every time the value moves above and below the threshold. Thirty to 60 minutes turns several notifications into one alert that stays open until it is fixed. ## Do not raise the cooldown on an uptime monitor Raising the cooldown is the standard fix for a trigger that opens and closes repeatedly, but it is the wrong fix here. An [uptime monitor](/uptime-monitoring/setup) failing means the endpoint did not respond. Suppressing the second notification does not make the first one less accurate. Reach for warm-up instead. AppSignal checks your endpoint every minute from four regions and tracks each region separately, so one outage can open up to four alerts, and a network problem between a single region and your endpoint opens one while your application is healthy. A warm-up of at least one minute filters out that case without hiding a real outage. ## Make every notification explain itself Alert fatigue is not only about how many notifications arrive. It is also about how much work each one takes to understand. Three fields provide that context: **Name.** Say what is wrong, not which metric moved. A custom metric trigger starts out named **Custom metric**, and a list of triggers all called that cannot be triaged. **Description.** Treat it as the runbook. Short is fine, but the field supports several paragraphs, commands, and links. The most useful descriptions include the information a responder would otherwise have to reconstruct: the number that matters ("the limit from the load balancer is 320"), the remedies in order, a diagnostic step, how long the fix takes, and what the cause was last time. **Dashboard.** Link the dashboard that shows the metric alongside related metrics, so the notification gives the responder a starting point for investigation. ## Review your triggers on a schedule Alert configuration becomes outdated. Triggers outlive the incidents that motivated them, thresholds set for last year's traffic no longer fit, and hosts named in a trigger get replaced. Roughly quarterly, ask of each trigger: has it opened in the last 90 days, did anyone act on it, did it open many alerts for one incident, and is its destination still right? An alert nobody acts on should be retuned, rerouted, or archived. Reviewing the whole set is faster from the terminal than by opening each trigger: ```sh Shell theme={null} # Every trigger, as JSON you can diff, grep, or hand to an agent appsignal-cli --output json triggers list --app "MyApp" --environment production # Narrow to one metric or one kind when you are hunting duplicates appsignal-cli triggers list --app "MyApp" --environment production --metric-name response_time ``` Retuning is a single command, but updates need the full trigger definition. Start from the current values in `triggers list`, change the fields you want to retune, and include optional values you want to keep, such as notifier IDs, tags, and the dashboard link: ```sh Shell theme={null} appsignal-cli triggers update --id --app "MyApp" --environment production \ --name "Slow web requests" \ --metric-name response_time --kind Advanced --field p95 \ --comparison-operator ">" --condition-value 750 \ --warmup-duration 5 --cooldown-duration 5 \ --notifier-ids ``` Changing trigger settings can affect active alert state, so avoid retuning a trigger while you are using an open alert for incident response. Archiving a trigger also closes its alerts and incidents, which is useful for a trigger nobody acts on: ```sh Shell theme={null} appsignal-cli triggers archive --id --app "MyApp" --environment production ``` The [MCP server](/mcp-server) exposes the same read and write access to triggers, so you can ask an agent to list every trigger that has not opened in 90 days and propose what to archive. See the [AppSignal CLI](/cli/triggers) reference for all flags. ## How AppSignal alerts on AppSignal We run AppSignal on AppSignal, and our operations team has been tuning that setup for years. The shape of it is a reasonable target to aim at: | What we watch | Condition | Warm-up | Cooldown | Destination | | - | - | - | - | - | | Disk usage on `/` | Above 80% | 10 minutes | 60 minutes | On-call | | Free memory | Below 100 MB | 0 | 0 | On-call | | Swap in use | Above 50% | 0 | 0 | On-call | | Items waiting in a queue, tagged by queue | More than 10,000 | 2 minutes | 0 | On-call | | Processing lag, at p95 | Above 2,000 ms | 0 | 0 | On-call | | Connections to one class of host | More than 800 | 2 minutes | 0 | Team chat only | | Throughput in a background namespace | 30,000 req/min or more | 2 minutes | 0 | On-call | | Replication lag | Above 60 seconds | 2 minutes | 0 | Email and on-call | Five patterns in that table are useful for production alerts: 1. **Warm-ups are short.** Most are zero to two minutes. The only long one is on disk usage, and it is paired with an hour of cooldown rather than used instead of it. 2. **Cooldown is used once, deliberately.** Only disk usage usually remains above the threshold until someone takes action, so only disk usage needs it. 3. **Not every alert notifies on-call.** The connection ceiling goes to team chat, because it predicts a capacity problem rather than describing an outage. 4. **Email is added, not substituted.** Replication lag reaches an on-call tool and email together, because email is the only channel that keeps reminding while an alert stays open. 5. **Every trigger carries a description.** The most useful ones name the relevant limit, give two remedies in order, and record what the cause turned out to be last time. The triggers that are hardest to review are the ones left named **Custom metric**. Naming is a small task, but it has a large effect on review and triage. ## Next steps * Work through the settings in detail with [tune your alerts](/alerting/tuning). * Check nothing important is unmonitored with [alerting in production](/alerting/production). * Find a starting configuration for a specific alert in [alert recipes](/alerting/recipes). * Shape a metric for alerting when you send it, with [custom metrics](/metrics/custom). # Tune your alerts Source: https://docs.appsignal.com/alerting/tuning Reduce alert fatigue by tuning thresholds, warm-up, cooldown, and scope so every notification is worth reading. An alert is only useful if someone acts on it. When a team receives more notifications than it can act on, it starts ignoring all of them, including the one that mattered. That is alert fatigue, and it is usually a configuration problem rather than a monitoring problem. This page covers how to tune an alert that already exists. If you are deciding what to alert on in the first place, start with [alert recipes](/alerting/recipes). If your problem is the whole set rather than one trigger, [reduce alerting noise](/alerting/reduce-noise) works through the changes that remove the most notifications first. ## Signs your alerting needs tuning * A channel receives alerts that nobody investigates. * The same alert opens and closes several times an hour. * One incident produces many notifications from many hosts or tag combinations. * On-call receives alerts that cannot be acted on until business hours. * Someone has disabled notifications for the alert channel. Each of these maps to a specific setting described in the following sections. ## Threshold, warm-up, and cooldown Every [anomaly detection trigger](/anomaly-detection) has three settings that control when alerts open and close. Tuning almost always means adjusting one of them. | Setting | Question it answers | Symptom when it is wrong | | - | - | - | | Threshold | How bad does it have to be? | Alerts open during normal operation | | Warm-up | How long does it have to stay bad? | Alerts open on single-minute spikes | | Cooldown | How long does it have to be better before we call it over? | The same alert opens and closes repeatedly | ### Set thresholds from metric history Before choosing a threshold, graph the metric over at least two weeks and look at its normal range, including its daily and weekly peaks. A threshold set below a routine Monday morning peak will notify you every Monday morning. A useful starting point is the value the metric reaches during a busy but healthy period, plus enough margin that normal variation does not cross it. If you cannot describe what you would do when the threshold is crossed, the threshold is probably not the right one. ### Use warm-up to filter out spikes Warm-up is how long AppSignal waits before opening an alert. During that wait, the metric must stay above or below the threshold, depending on the trigger. With a warm-up of `0`, AppSignal can open an alert as soon as the metric crosses the threshold. Use warm-up to avoid alerts for short metric spikes, such as one slow deploy, one garbage collection pause, or one restarting host. Start with zero to two minutes for most production alerts. Use a longer warm-up only when the metric often spikes and recovers quickly. Set warm-up based on how much the metric changes minute to minute. A metric that changes quickly often needs a warm-up. A metric that changes gradually often needs little or no warm-up. | Signal | Starting warm-up | Reasoning | | - | - | - | | Error rate | 1–2 minutes | Changes quickly. Filters out deploy-time spikes | | Response time percentiles | 1–3 minutes | Latency can change minute to minute | | Throughput, in either direction | 1–2 minutes | Short increases and decreases are common and usually recover | | Queue depth or backlog | 1–2 minutes | Can grow quickly as work arrives | | CPU and load average | 1–3 minutes | Short increases are normal; sustained high usage is not | | Memory and swap usage | 0–2 minutes | These move smoothly, so crossing the threshold is already meaningful | | Disk usage | 10–60 minutes | Usually changes slowly, so a longer warm-up can reduce noise without hiding a fast incident | | Uptime monitors | At least 1 minute | Ignores brief network problems between regions | Useful warm-ups are usually short. Beyond about 10 minutes you are mostly delaying the notification rather than improving it. If you need 30 or 60 minutes to reduce notifications, review the threshold or scope instead. > [!WARNING] > > Do not use a long warm-up to check whether a scheduled process is running. A trigger only evaluates data that arrives, so an absent job may never open an alert. AppSignal [recommends against](/anomaly-detection#warm-up) using anomaly detection this way. Use [check-ins](/check-ins) for cron jobs, workers, and heartbeats. ### Use cooldown when alerts open and close repeatedly Cooldown is the number of minutes the metric must stay recovered before the alert closes and a new alert can open. For "more than" triggers, this means the metric stays below the threshold. For "less than" triggers, this means the metric stays above the threshold. Without cooldown, a metric that repeatedly crosses its threshold produces a stream of open and close notifications for one incident. A short cooldown turns that stream into a single alert. Set it slightly longer than the period where the metric usually moves above and below the threshold. Cooldown is a targeted fix rather than a default. Most triggers never need one, because most metrics do not sit exactly on their threshold. Leave it at `0` until you see a trigger open and close repeatedly for what was clearly one incident, then set it from how long those gaps actually were. ## Scope: one trigger can open many alerts This is the most common cause of many notifications from one incident. A trigger does not open one alert. It opens one alert per matching series. For host triggers, that means one alert per host. The hostname field accepts a wildcard, and its default value of `*` matches every host reporting to the app. A fleet of 30 hosts crossing a CPU threshold at the same time produces 30 alerts. Narrow the scope so the notification says exactly what is affected: * Set a specific hostname, or a prefix such as `web-*`, instead of leaving the default `*`. * Add [tags](/anomaly-detection#tags) so the trigger only watches the series you care about, such as `mountpoint=/` for disk usage or `region=eu` for a custom metric. * Scope error rate and response time triggers to a single [namespace](/application/namespaces), so `web`, `background`, and `admin` can have different thresholds and different notifiers. When you add tags, AppSignal warns you if the tag combination has not been seen in the last hour. That warning usually means the trigger will never match data. Use one of the tag-key combinations listed in the trigger form, and set each value to an exact value or a wildcard. Uptime monitors behave the same way. Each of the four regions is tracked separately, so one monitor can open four alerts for a single outage, and one alert when a single region cannot reach an endpoint that is otherwise healthy. ## Choose a metric that reflects user impact Changing trigger settings cannot fix a trigger that watches the wrong metric. **Prefer rates over counts.** Error count crosses a fixed threshold whenever traffic grows, so it notifies you on your busiest days regardless of whether anything is wrong. Error rate stays stable as traffic changes. Use counts only for metrics where any occurrence matters, such as errors in a payment flow. **Prefer percentiles over means.** A mean response time hides a slow experience for part of your traffic. If 5% of requests take 8 seconds, the mean may barely move. Alert on p90 or p95 instead. **Prefer user-visible symptoms over causes.** Alert on errors, latency, traffic, or failed business actions, and use dashboards to find the cause. High CPU usage is not itself a problem if response times are fine. This keeps the number of alerts proportional to the number of real incidents. **Set missing data to zero deliberately.** A trigger assumes a data point arrives every minute. For metrics that only report when something happens, such as a counter, enable **treat missing datapoints as 0** so the alert closes when activity stops. Leave it off when a gap in data means "no information" rather than "zero". ## Route by severity, not by habit Sending everything to one channel causes alert fatigue. Each trigger can use its own notifier, so use that to separate urgent alerts from alerts that can wait. | Urgency | Example | Destination | | - | - | - | | Someone must act now | Error rate above threshold in `web`, health check failing | On-call tool such as [PagerDuty](/application/integrations/pagerduty) or [Opsgenie](/application/integrations/opsgenie) | | Someone should look today | Response time degradation, queue backlog growing | Team chat such as [Slack](/application/integrations/slack) | | Someone should notice this week | Disk usage approaching full capacity, SSL certificate expiring | Email or a low-traffic chat channel | | No notification needed | Known third-party errors already being tracked | No notifier for trigger alerts, or **Never Notify** for incident and log notifications | Give staging its own channel or leave its triggers without a notifier. Staging alerts arriving in a production channel are one of the fastest ways to teach a team to ignore that channel. Severity is not the only useful split. Once you have more than a handful of triggers, separate chat channels per domain, such as one for application errors and one for infrastructure, keep each channel small enough that the people who watch it recognize when something is unusual. A single channel receiving everything makes important notifications easier to miss. ### Route incidents and triggers differently Routing has two layers, and they behave differently. For anomaly detection triggers, choose the notifiers on the trigger itself. Removing all notifiers leaves the trigger active and still records alerts, but sends no notifications. For error incidents, set [notification defaults per namespace](/application/notification-settings#organization-and-app-namespace-defaults) rather than configuring each incident. An `admin` namespace set to [**Never Notify**](/application/notification-settings#never-notify) removes a whole category of low-value notifications at once. Namespace defaults are also where you route `web`, `background`, and `admin` incidents to different destinations. Notifiers are configured once for the organization and can be shared across apps, so a notifier used by many apps needs care. Check where a notifier is used before editing it. ## Make the notification explain itself Alert fatigue is not only about how many notifications arrive. It is also about how much work each one takes to understand. An alert that says a number crossed a threshold forces the responder to investigate what that threshold means. An alert that explains itself can be acted on immediately, or correctly ignored. Three fields provide this context, and all three are worth filling in on every trigger. **Name.** Say what is wrong, not which metric moved. A trigger list where many entries are called **Custom metric** cannot be reviewed or triaged. **Description.** Treat it as a one-line runbook. State what the condition means and what the responder should do about it. These are the two questions a responder has to answer, and the description is the best place to answer them: * "This host is swapping, so every request it serves is slower. Check what is using the memory and notify the operations channel." * "Less than 100 MB of free memory. Check what is using it and add capacity before the kernel starts killing processes." * "This service has a known memory leak. Memory grows until the kernel kills the process, so restart it and only escalate if it returns within the hour." The third example is worth noticing. Documenting a known cause on the trigger stops the same investigation being repeated by whoever is on call this time, and it tells the responder when not to act. **Dashboard.** Each trigger can link a dashboard, and the link is included in the notification. Link to the dashboard that shows the metric in context alongside related metrics. This gives the responder a starting point for investigation. ## What you cannot tune, and what should not alert Two things about trigger alerts cannot be tuned, and one category of metric should not alert in the first place. **Frequency options apply to incidents and log triggers, not to anomaly detection trigger alerts.** Error and performance notifications use [incident notification options](/application/notification-settings#notification-options), such as **Every Occurrence**, **First in Deploy**, **First After Close**, and **Never Notify**, set per namespace in [notification defaults](/application/notification-settings#organization-and-app-namespace-defaults). Log triggers have similar threshold options. Anomaly detection trigger alerts follow the alert state machine instead. **Only email repeats while an anomaly alert stays open.** Email notifiers have a **Reminder interval** of 15 minutes, 30 minutes, or 1 hour. Slack, PagerDuty, Opsgenie, and webhooks have no equivalent. **What to do instead.** To stop a trigger notifying anyone, remove its notifiers, or archive it. If an open alert must keep sending reminders until someone acts, pair email with an on-call tool that has its own escalation policy. If a long-running alert is filling a chat channel, the cause is repeated opening and closing rather than reminders, so the fix is a longer [cooldown](#use-cooldown-when-alerts-open-and-close-repeatedly). For other cases, decide whether the condition should send a notification at all. * Alert on an error rate above 5% in `web` for three minutes, not on every individual exception, however rare. * Alert on p95 response time for checkout doubling, not on a mean that moved from 180 ms to 200 ms. * Alert on throughput at zero when it is normally 400 req/min, not on traffic halving overnight, as it does every night. * Alert on a disk at 85% and gaining a point an hour, not on CPU touching 100% for one minute during a deploy. * Alert on a nightly invoicing job that never reported, not on the same job starting two minutes late. * Alert on a payment provider timing out 50 times in an hour, not on one request that timed out and succeeded on retry. If a metric is interesting but not actionable, put it on a [dashboard](/metrics/dashboards) instead of sending notifications for it. ## Review triggers regularly Alert configuration becomes outdated. Triggers outlive the incidents that motivated them, thresholds set for last year's traffic no longer fit, and hosts named in a trigger get replaced. Review your triggers roughly every quarter and ask, for each one: 1. **Has it opened an alert in the last 90 days?** If not, open it and check the chart preview. No data, or a hostname field warning that the host was not found, means it is watching something that no longer exists. Renamed or replaced hosts are the usual cause, and the trigger does not notify you when it matches nothing. 2. **Did anyone act on it?** An alert nobody acts on should be retuned, rerouted, or archived. 3. **Did it open many alerts for one incident?** Narrow its scope. 4. **Is its notifier still the right one?** Sending non-urgent problems to on-call is a main source of alert fatigue. 5. **Does it [explain itself](#make-the-notification-explain-itself)?** A trigger with no name and no description cannot be triaged, because nobody can tell what it does without reconstructing it. 6. **Is it a duplicate?** Two triggers with the same metric, threshold, and notifier send two notifications for one problem. 7. **Does anyone still own it?** Triggers created by people who have left are the most likely to be outdated and the least likely to be reviewed. > [!NOTE] > > Review triggers with no notifier before removing them. Some are deliberately configured without notifications but are still useful on a dashboard or in the alert history. Others had their notifiers removed during an incident and were never restored, which means a metric you believe is covered is not. You can list every configured trigger with the [AppSignal CLI](/cli/triggers) or through the [MCP server](/mcp-server) to review them without opening each one in the interface. ## Recap: tuning one trigger that sends too many notifications This section introduces nothing new. It puts the previous sections in order against one example: a trigger on host CPU usage above 80%, with no warm-up, no cooldown, and the default hostname of `*`, sending several on-call notifications a night when there is no user-visible issue. 1. [Check the metric.](#choose-a-metric-that-reflects-user-impact) CPU usage is a cause, not a user-visible symptom, and response time and error rate are both healthy during the CPU spikes. 2. [Narrow the scope.](#scope-one-trigger-can-open-many-alerts) The spikes come from background workers, so the hostname becomes `web-*`. 3. [Set the threshold from history.](#set-thresholds-from-metric-history) Two weeks of data show web hosts routinely reaching 85% at evening peak, so the threshold moves to 95%. 4. [Add a warm-up.](#use-warm-up-to-filter-out-spikes) Two minutes, because a short CPU spike is normal and should not notify on-call. 5. [Add a cooldown.](#use-cooldown-when-alerts-open-and-close-repeatedly) Set a short cooldown, so a host near the threshold produces one alert rather than six. 6. [Reroute it.](#route-by-severity-not-by-habit) Sustained CPU saturation is a capacity problem, not an outage, so it goes to team chat and the on-call notifier is removed. 7. **Add the alert that was missing.** The team needed an alert for user impact, so they add a p95 response time trigger on the `web` namespace, routed to on-call. [Alerting in production](/alerting/production#check-your-coverage) covers finding the rest. The result is fewer notifications, and the ones that remain describe something a person can act on. ## Next steps * Choose what to monitor with [alert recipes](/alerting/recipes). * Check setup order and coverage with [alerting in production](/alerting/production). * Review how [warm-up and cooldown](/anomaly-detection#warm-up-and-cooldown) work in detail. * Configure [notification settings](/application/notification-settings) for error incidents. * Set up [check-ins](/check-ins) for scheduled work instead of using long warm-ups. # Anomaly detection Source: https://docs.appsignal.com/anomaly-detection Set triggers that alert when a metric crosses a threshold, such as error rate or free memory. Covers alert states, warm-up, and cooldown. With [Anomaly detection](https://appsignal.com/redirect-to/app?to=alerts), you can configure triggers to send notifications when a metric value goes over or dips below a threshold value. For example: when the error rate of an application goes over 5% or free memory dips below 100 MB. Anomaly detection checks metric values once per minute. When a metric reaches a threshold condition, AppSignal opens an alert and notifies the selected notifiers. AppSignal notifies them again when the threshold condition is no longer met. Use [warm-up and cooldown](#warm-up-and-cooldown) settings to control when a new alert opens and closes. For guidance on choosing thresholds and keeping alert volume manageable, see [tune your alerts](/alerting/tuning) and [alert recipes](/alerting/recipes). ## Alert states Alerts can have five states: | State | Description | | - | - | | Warming up | The alert is in its warm-up phase. You can configure how long a condition has to be true before AppSignal opens the alert. | | Open | The alert is active because it reached its threshold condition. | | Closed | The alert is no longer active and has been closed. | | Cooldown | The alert is no longer over its threshold condition, but AppSignal will not end it or open a new alert until the cooldown duration ends. | | Ended | The alert has ended. If the trigger condition is met again, a new alert enters the warm-up phase. | ![Alert States](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/anomaly-states-alert-flow.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=2519900456160e5c3774fe2336b81c30) ### When will I be notified? AppSignal notifies you on two state transitions: when an alert opens, and when it is resolved. Email can also send reminders while an alert stays open. Every other channel, including Slack, PagerDuty, Opsgenie, and webhooks, is notified only on the open and resolved transitions. Alerts are sent to the notifiers selected on the trigger, not to every notifier configured on the app. ### Silencing a trigger Unlike error incidents, alerts have no [notification frequency options](/application/notification-settings#notification-options). There is no **Never Notify** or **Every Nth per Hour** setting, because notifications follow the alert state machine rather than a count of occurrences. To stop a trigger from notifying anyone, remove its notifiers. To stop it from producing alerts at all, archive it. Trigger alert routing is controlled on the trigger itself. Select the notifiers that should receive alerts from that trigger, or remove all notifiers to keep the trigger active without sending notifications. ### Email alerts Alert emails will include an overview of new alerts, reminders, and the status of other alerts that have yet to end. ## Creating and configuring triggers Configure anomaly detection per app from the ["Anomaly detection" section](https://appsignal.com/redirect-to/app?to=alerts) in the app navigation. The alert overview shows the latest alerts created by triggers configured for the app. Open the [triggers page](https://appsignal.com/redirect-to/app?to=triggers) to create and edit triggers. Select **Add trigger** to open the metric picker, then choose a trigger type from **Tracing**, **Host metrics**, or **Other**. Custom metric triggers are listed under **Other** as **Custom metrics**. ![Creating a trigger](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/anomaly-detection/create-trigger.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=60291d66268b4296b7e27620a00436db) You can configure triggers with a variety of metrics: * Error rates * Error (absolute) counts * App throughput * Performance of actions (slow actions) * Queue time * Host metrics * CPU load * Disk I/O * Disk usage * Load averages * Memory usage * Network usage ### Warm-up and cooldown You can configure warm-up and cooldown settings for each trigger. These settings define how long AppSignal waits before opening and closing an alert. ### Warm-up > [!WARNING] > > Do not use anomaly detection and warm-up to check whether hourly jobs, daily jobs, or cron jobs are running. Typically, when a trigger's threshold condition is reached, it opens an alert. For example, the error rate is higher than 5%. When a trigger has a warm-up period, AppSignal opens the alert only after the threshold condition has stayed true for the whole warm-up period. For example, the error rate must stay higher than 5% for more than 3 minutes. AppSignal will notify you when the alert status shifts from warm-up to open. ### Cooldown Alerts opened by a trigger are automatically closed when the threshold condition is no longer met. To avoid repeated open and close notifications for the same issue, configure a cooldown period. If you configure a cooldown period, AppSignal will not create a new alert unless the trigger condition is met again after the cooldown period expires. For example: 1. An alert opens because the error rate is higher than 5%. 2. The error rate drops, so the alert closes. 3. The trigger has a two-minute cooldown period. 4. The error rate goes above 5% again. 5. AppSignal does not create a new alert unless the error rate exceeds 5% after the cooldown period ends. ### Tags Some metrics require tags to be selected as well. For example, if you are sending a custom metric to AppSignal that has tags: ```ruby Ruby theme={null} Appsignal.set_gauge("checkout_queue_depth", 100, :namespace => "web", :queue => "default") ``` When you create a trigger for this metric, select tags as well. ![Trigger with tags](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/anomaly-detection/trigger-with-tags.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=2ea3350a43218d9937fbec766645035e) When you enter tags, AppSignal lists the tag combinations it has seen for that metric and warns you when the combination you entered has not been seen in the last hour. That warning usually means the trigger will not match any data. Use one of the tag-key combinations AppSignal lists for the metric, such as `namespace` or `namespace, queue`. Tag values can be exact values like `namespace=web` or wildcards like `queue=*`. ### One trigger can open several alerts A trigger opens one alert per matching series, not one alert in total. A trigger that matches 30 hosts opens 30 alerts when all 30 cross the threshold. Host metric triggers make this easy to overlook, because the hostname field supports wildcards and its default value of `*` matches every host reporting to the app. Enter a specific hostname, or a prefix such as `web-*`, to limit which hosts a trigger covers. The same applies to tags on any other metric. The narrower the tag filter, the more specific the alert, and the fewer notifications a single incident produces. ## Editing and archiving triggers Changing or archiving a trigger can affect the alerts and incidents attached to it. Editing or archiving a trigger can have these effects: * Alerts still in their warm-up phase are discarded. * Open alerts are closed and marked as archived. * When you edit a trigger, open anomaly incidents for the previous trigger are linked to the new trigger so the incident history and logbook stay available across the edit. * When you archive a trigger without replacing it, open anomaly incidents for that trigger are closed. Avoid retuning a trigger while you are still tracking an active alert through it. ## Missing datapoints as 0 By default, triggers assume that a data point is sent every minute. This may not be feasible in situations such as incrementing a counter only when a specific action occurs. In these cases, enable **Treat missing datapoints as 0**. AppSignal then treats a missing data point as zero, which helps an alert close when no data arrives in the next minute. It also makes absence alerts possible, such as alerting when a metric reaches `0`. ## Data processing The metrics used by triggers to create alerts are not instantly processed when the metrics are sent from your application to AppSignal. Your metrics data will go through multiple systems before it arrives at our processor. The data may also be sent from multiple servers that [send data at different intervals](/appsignal/how-appsignal-operates#agent). The processor then waits\* until all the data for a minute has arrived before processing that data and creating or updating alerts. If you experience problems with the metrics AppSignal reports for anomaly detection, ensure that your application's servers report simultaneously by configuring them using [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol). Incorrect or different reported times from multiple app servers can prevent alerts from opening or closing. You can learn more about how AppSignal processes data for Anomaly detection and what this means for the alerts in our [data life cycle documentation][data life cycle]. \*: For more information on wait time specifics, consult our [data life cycle page][data life cycle]. [data life cycle]: /appsignal/data-life-cycle.html ## Managing incidents You can view all alert incidents on the Anomaly Issues page in the AppSignal app. The Issues page displays an overview of all open alert incidents, ordered by their last occurrence, with columns for the anomaly: * Name * Status * Assignees * State * Last state change time You can also easily filter your incidents based on their [state](#alert-states). ![Overview of alert incidents](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/anomaly-detection/anomalies-overview.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=2642c56b253ef509627a0d3cffe25475) To investigate an incident further, you can open the incident summary. Here you'll find all the tools and information needed to investigate further the anomaly triggering your alert. On the summary page, you will have access to: * **Alert information:** The metric name, alert state, and tags of the alert. * **Occurrence frequency graph:** A visual representation of the alert's occurrence. * **Incident Settings:** Ability to close the alert, set its severity, and assign it to a team member. * **Trigger Information:** The conditions required to trigger the alert. * **Latest occurrences:** A table of the most recent occurrences, with their start/end time, state, and peak value. * **Logbook:** A logbook for logging important alert information about this alert for your team or future self. * **Access to the Time Detective:** Use the Time Detective tool to view the state of your application when the alert last occurred. All of these features are easily accessible in our intuitive UI: ![Overview of alert incident page](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/anomaly-detection/anomaly-incident.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=94936829029b33d372f54a700f287135) # Applications Source: https://docs.appsignal.com/application How AppSignal identifies an application by its name and environment, and how applications relate to organizations, environments, and namespaces. Applications (previously known as "sites", also referred to as "apps") are Ruby, Elixir and JavaScript front-end applications monitored by AppSignal. Every application is unique by the combination of its name and environment. A list of Applications appears on the [Application index] and in the application quick switcher. Every application has a parent [organization](/organization), which can have multiple applications. (Exception: Organizations created by the Heroku add-on only support one application.) ## Adding applications If you're just getting started with AppSignal and haven't set up your first app yet, please follow the [add a new application guide](/guides/new-application) first. > [!NOTE] > > 📖 Read our [add a new application guide](/guides/new-application). ## Environments An application can have multiple [environments](/appsignal/terminology#environments) as long as every environment uses the same application name. Every environment is currently listed separately on the [Application index]. * "Demo application" - development * "Demo application" - production * "Demo application" - staging * "Demo application" - test ## Namespaces Namespaces are a way to group error incidents, traces from [actions](/appsignal/terminology#actions), and host metrics in your app. By default AppSignal provides three namespaces: the "web", "background" and "frontend" namespaces. You can add your own namespaces to separate parts of your app like the API or Admin panel. Namespaces can be used to group together incidents that are related to the same part of an application. It's also possible to configure notification settings on a per-namespace level. Read more about [namespaces](/application/namespaces) and how to configure them for your app. ## See also * [📖 Removing an application guide](/guides/application/deleting-applications) * [📖 Migrating an application between organizations guide](/guides/application/migrating-applications) * [📖 Running multiple applications on one host](/guides/application/multiple-applications-on-one-host) [application index]: https://appsignal.com/accounts # Backtrace links Source: https://docs.appsignal.com/application/backtrace-links With backtrace links you can spend less time figuring out where an exception happened and more time debugging the exception. Backtrace links make every line to source code in your app link to your app's source code on your source code hosting platform of choice. ![Backtrace with Git link](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/backtrace_links/backtrace_links.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=31d3eb16ad02c40bfcf014681e7e8fe5) ## Steps to enable backtrace links To enable backtrace links an app on AppSignal.com needs to: 1. [Enable deploy markers](/application/markers/deploy-markers). * This will allow AppSignal to link to the specific revision of the source code in which the error occurred. 2. Configure the "repo url" for an application, or [link your organization to GitHub](https://appsignal.com/redirect-to/organization?to=admin/integrations/github), so AppSignal knows where to link to. * See the steps below for either option. ## Configure the repo url Owners of an Organization can specify a Repo url on [the app settings page](https://appsignal.com/redirect-to/app?to=edit). This is especially useful for Git hosting platforms AppSignal has no integration for (e.g. BitBucket) or private repositories. ![App settings repo URL form](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/backtrace_links/repo_url.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=0afdb9ff3eb24bcbb81c8080aa6cb6ef) ## Link your app to GitHub or GitLab Alternatively organization owners can [link an app to GitHub](https://appsignal.com/redirect-to/app?to=integrations) and the "repo url" from the selected repository will be stored automatically. With the GitHub integration you'll also be able to send incidents to GitHub directly from AppSignal. The [GitLab integration](/application/integrations/gitlab) stores the "repo url" the same way, and also lets you send incidents to GitLab as issues. Once the steps are completed we'll automatically enrich the backtrace lines with a link to the correct revision/file/line on the specified Git repository. ## Send error to GitHub When an error occurs, AppSignal will not create an issue automatically on GitHub, if you think it is an error that needs to be fixed then you can create this error as an issue in GitHub by clicking on the "Send to GitHub" button. ![Send error to github](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/backtrace_links/send_error_to_github.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=4a48abf446bcc950e70ab3e8cac77e5b) ## Open backtrace lines in your local editor Once configured, each app code line in an exception backtrace gets an **Open in editor** button that opens the file directly in your local editor. Before setup, the option is available in the extras menu, accessible via the there dots icon. ### Setup Go to **App Settings → Editor preferences**, select your editor, and enter the absolute path to the project on your local machine. These settings are personal — each developer on your team configures their own. Supported editors: **VS Code**, **Cursor**, **Windsurf**, **Zed**, **RubyMine**, and **Sublime Text**. # Configuration Source: https://docs.appsignal.com/application/configuration How AppSignal integrations are configured, which options are required, and the order in which configuration is loaded. Configuration. Important, because without it the AppSignal integrations won't know which application it's instrumenting or in which environment. In this section we'll explain how configuration works in AppSignal integrations, what options can be configured in the integrations, what the minimal configuration needed is and in what order the configuration is loaded. > [!NOTE] > > 📖 Want a more practical read on how to add or change AppSignal configuration? > Read our \[guide on how to configure AppSignal]\[guide] in your apps. ## Minimal required configuration Every app needs to have four key configuration options set for AppSignal to report data for it. These config options help AppSignal identify an app, and group all the data for it in an app environment on AppSignal.com. Every app is a combination of the app name and environment, in AppSignal terminology this is an "app". These required configuration options are: * App name * The app name as it is reported and shown on AppSignal.com * App environment * The app environment as it is reported and shown on AppSignal.com * [Push API key] * The key used to identify which organization the app belongs to or which app is reporting data. Read more about the [Push API key] on our terminology page. * AppSignal active * The config option used to enable, or disable, environments on the host's config. This allows users to disable development and test environments, and only report data for the production and staging environment, for example. The detailed list of required options per integration can be found in the [configuration options section](#configuration-options). Find the list of required configuration options at the top of each config options page. > [!TIP] > > For Front-end JavaScript all required options are combined in a \[`key` config > option]\[frontend config], and the app name and environment are configured on > AppSignal.com during the "add app" wizard. > [!TIP] > > Some of these configuration options may be set to a default value by the > integrations, such as the app name for Rails apps, and environment for Elixir > and Node.js apps. ## Configuration options Every integration has its own set of configuration options. There's a list of shared options and options specific to each integration. The full list of configuration options can be found in the language integration sections: * [Ruby](/ruby/configuration/options) * [Elixir](/elixir/configuration/options) * [Node.js](/nodejs/3.x/configuration/options) * [Python](/python/configuration/options) * [Front-end Javascript](/front-end/configuration/) * [Go](/go/configuration/options) ## Configuration methods There are two main ways to configure AppSignal integrations, by (configuration) file or by system environment variables. Use the configuration method that best fits your app setup. > [!NOTE] > > Read our \[guide on how to configure AppSignal]\[guide] in your app. ## Configuration load order Depending on the integration the load order of the configuration may differ, please consult the load order page for the integrations for more information: * [Ruby configuration load order](/ruby/configuration/load-order) * [Elixir configuration load order](/elixir/configuration/load-order) * [Node.js configuration load order](/nodejs/3.x/configuration/load-order) * [Python configuration load order](/python/configuration/load-order) *If a language is not listed, it has no different configuration sources to load configuration options from.* ## See also * [AppSignal configuration guide][guide] * AppSignal integration configuration topics: * [Ruby configuration topic](/ruby/configuration) * [Elixir configuration topic](/elixir/configuration) * [Node.js configuration topic](/nodejs/3.x/configuration) * [Python configuration topic](/python/configuration) * [Front-end JavaScript configuration topic][frontend config] * [Go configuration topic](/go/configuration) [guide]: /guides/configuration.html [Push API key]: /appsignal/terminology.html#push-api-key [frontend config]: /front-end/configuration.html # Tagging Source: https://docs.appsignal.com/application/tagging You can supply extra context on errors and performance traces using tags. Tags are key-value data that can be used to search and filter data. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > Use [Link Templates](https://docs.appsignal.com/application/link-templates) to link them back in your app. > [!NOTE] > > 📖 Also read our guides on how to set up [tags](/guides/tagging). ## Tags Tags can be used to add information that is not already part of the trace [metadata](/application/metadata) (request parameters, session data, request headers, etc.). Using tags you can easily add more information to errors and performance issues tracked by AppSignal. Maybe while debugging an issue you want to know which user faced the problem, you can pass in the user id or maybe to easily access the user data you can pass in the URL of your admin panel (using link templates) which will take you directly to the customer page. ### Link templates Tags can also be used to create link templates. Read more about link templates in our [link templates guide](/application/link-templates). # Terminology Source: https://docs.appsignal.com/appsignal/terminology At AppSignal we use a lot of technical terms. Read on to learn more about the language of AppSignal. See the list of terminology on the right-hand side of this page. ## Actions Actions are the location in the code where an HTTP request, background job, cron job or task is started. For Ruby on Rails and Elixir's Phoenix apps, this is the controller and action combination, such as `BlogPostsController#create` or `Api::UsersController#index`. For background jobs, this will be the worker/job name, such as `UserMailer#sign_up_mail`. Actions are used to group [traces](#traces) along with the [namespace](#namespace), and to group error [issues](#issues) along with the namespace and the [error](#errors) type. ## Agent AppSignal uses an "agent" to communicate with the AppSignal servers and instrument the hosts an application is running on. The host data is used in our [host metrics](/metrics/host-metrics) feature. The agent is started by the language-specific [library](#libraries) and runs as a separate UNIX process on the application's host. The language library and agent communicate with each other through a UNIX socket using an [extension](#extension). The transaction instrumentation data collected by the agent is sent to the AppSignal servers. The [transaction](#transactions) data is processed and used to detect events worth alerting users about. Read more about how the AppSignal [agent operates](/appsignal/how-appsignal-operates) and the [life cycle of an AppSignal request](/appsignal/data-life-cycle). ## Allocations During an HTTP request or a background job, an application uses memory. Every data structure that's loaded and object that's instantiated takes up memory. When a request or job handles a lot of data a lot more memory may be used than is normal. The AppSignal integration libraries keep track of allocations per [transaction](#transactions). The integration also keeps track of what part of the application allocates more memory objects than others, so it's possible to see if the application's ORM or template library is taking up more memory. On AppSignal.com the number of allocations is displayed in an Integer for an action, event groups and specific events. This allocation number is the number of objects that have been created in memory during an action/group/event. The size of the created object is not tracked. ## Anomaly detection Anomaly detection is an AppSignal feature that allows users to detect abnormalities in their apps. An anomaly could be something like an increased error rate or a limited amount of free memory on the app's host. Anomaly detection works with trigger threshold conditions that create Alerts when their threshold is reached. When an Alert is opened, AppSignal will send notifications to whichever notifiers have been selected for the specific trigger. See our documentation about [Anomaly detection](/anomaly-detection/) for more information. ## API An API is an "Application Programming Interface". The term API is broad and is used in many ways. In the context of our documentation, we refer to the AppSignal HTTP REST API when using "API". The AppSignal API is a HTTP REST API which can be used to retrieve data from the AppSignal servers and augment the existing data with more information such as [Markers](#markers). The API differs from the [Push API](#push-api) in its purpose. While the Push API is used to send data to AppSignal by the [agent](#agent), the HTTP REST API is primarily used to retrieve data from AppSignal. This allows users to use the available data in other tooling. You can read more about our API in our [API documentation](/api). ## API key To connect with the AppSignal [API](#api) it's necessary to be authenticated. Every user has their API key to authenticate with AppSignal. Your API key can be found on your [user profile](https://appsignal.com/users/edit). This key is not to be confused with the [Push API key](#push-api-key) which is used by [applications](#applications) with an AppSignal [agent](#agent) installed. ## Applications Applications (previously known as "sites", also referred to as "apps") are Ruby and Elixir applications monitored by AppSignal. After installing the AppSignal [library](#libraries) in an application AppSignal starts monitoring these applications. Once we receive data from an application, we register it using the application name and environment it's running in. An application can have multiple [environments](#environments) as long as every environment uses the same name. * "Demo application" - Development * "Demo application" - Production * "Demo application" - Staging * "Demo application" - Test Multiple applications can exist in one [organization](#organizations). Read more about applications in our [Applications documentation](/application). ## AppSignal vs Appsignal vs appsignal Wait, they're *three* different casings of the AppSignal name? Yes! Let's explain: | Casing | Usage | | - | - | | `AppSignal` | The brand name of the company, the application and almost everything else related to AppSignal. This is the version you should use when talking about AppSignal as a brand, product or service or [stroopwaffle supplier](#stroopwafels). | | `Appsignal` | The library name of our AppSignal integrations ([Ruby integration](/ruby), [Elixir integration](/elixir), [Node.js integration](/nodejs/3.x/), [Front-end integration](/front-end) etc.). Only used in the code context. | | `appsignal` | The AppSignal integration package names as published to package manager registries for the [Ruby gem](https://rubygems.org/gems/appsignal), [Elixir package and packages prefix](https://hex.pm/packages/appsignal) name, [Node.js packages prefix](https://www.npmjs.com/package/@appsignal/nodejs) and [Front-end packages prefix](https://www.npmjs.com/package/@appsignal/javascript), etc. | ## Blog We have a blog at [blog.appsignal.com](https://blog.appsignal.com/)! On our blog, we post all things relevant to AppSignal, such as new features, new major agent releases, [Ruby Magic](#ruby-magic) articles and other awesome stories from our internal process. Such as [how to eat stroopwafels](https://blog.appsignal.com/blog/2016/02/01/stroopwafels-and-how-to-eat-them.html). ## Changelog We keep a full product changelog at [appsignal.com/changelog](https://www.appsignal.com/changelog). All our new features, agent releases and other changes to the product can be found in this neatly organized list. We also have a small indicator in our top navigation that notifies you if there's a new entry to the changelog. ## Configuration The configuration is part of the libraries running in applications. It tells the AppSignal [libraries](#libraries) what to instrument in an [application](#applications), which application it is and in which environment it's running. The AppSignal libraries have multiple methods of configuration. The most common method of configuration is the usage of an `appsignal.yml` configuration file. The usage of environment variables is also recommended. For the configuration of the Ruby agent, we recommend you read the [configuration topic](/ruby/configuration) to get started. ## CPU usage During the operation of an application, the CPU usage can vary wildly. Some operations of an application can request more CPU time than others. Other factors can also affect the CPU usage. If the monitored application is not the only process on the host machine other processes can also affect the CPU usage metric. For example, if a database running on the same machine has to perform a complicated query it will request more CPU time. On AppSignal.com the CPU usage of an application is displayed in two ways. For an action where an error or a slow request occurred and for host metrics. This way it's possible to see if the performance of an action was directly affected by a busy CPU or if the entire host was affected for longer periods. Learn more about what [CPU metrics](https://blog.appsignal.com/2018/03/06/understanding-cpu-statistics.html) mean on our blog. ## Cross-Site Request Forgery Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application where they are authenticated. A victim may click on a link sent to them via email or web chat, allowing the attacker to steal and use the victim's credentials. The severity of the attack can vary depending on the application and authorization access of the victim's account. An attacker may be able to make state-altering actions to a user's account, such as changing their login credentials, and can compromise an entire application in severe cases, such as when a victim is an administrator. ## Elixir Alchemy Want to learn more about Elixir? In our email series Elixir Alchemy (1x p/mo) we dive deeper into Elixir and Erlang. You can sign up here: [appsignal.com/elixir-alchemy](https://blog.appsignal.com/elixir-alchemy). ## Environments Most [applications](#applications) can be run in different modes. During development of an application other rules apply and errors are not usually shown in the form of a "500 internal server error" page as they do in "production". AppSignal also understands the concept of an environment allowing different settings be configured per environment. For every environment a separate application is created on AppSignal.com to be configured with its own set of alerting rules and [third-party integrations](#third-party-integrations). ## Errors Errors are problems that occur during the runtime of an application. This can be anything ranging from a catastrophic failure causing the application to crash or a simple typo causing an error page. Once an error occurs in an application AppSignal sends an alert and records the details of the error for later viewing on AppSignal.com. Read more about the [errors feature](https://www.appsignal.com/tour/errors) on our tour page. To learn more about error handling in Ruby, read our [Exception handling](/ruby/instrumentation/exception-handling) topic describing how to effectively track errors with AppSignal. Errors are reported as issues. Learn more about what [issues](#issues) are. ## Events An event is something that happened. This is a very vague statement because the concept of an event is something very high-level. An [error](#errors) is an event, and so is a slow request. See [performance](#performance). AppSignal monitors many events inside an application and on a server using [host metrics](#metrics). By collecting many different types of events and combining the data we hope to provide an as complete as possible picture to gain more insights into [applications](#applications) performance. Also, see [instrumentation events documentation](#instrumentation-events). ## Extension The AppSignal [libraries](#libraries) and [agent](#agent) are in constant communication with each other. The libraries send data to the agent over a UNIX socket. To do so the libraries use an extension for the programming language they're written in. This extension is written in C and Rust, and installed when the language-specific agent is installed. Read more about the AppSignal [extension operates](/appsignal/how-appsignal-operates) and the [life cycle of an AppSignal request](/appsignal/data-life-cycle). ## Impact The impact of an action on an application is based on its usage compared to other actions. When one controller action or job takes more time or is executed more often than others its impact grows. For example: * Action A is triggered 1000 times with an average duration of 0.5 seconds. The combined duration is 500 seconds. * Action B is triggered 500 times with an average duration of 3 seconds. The combined duration is 1500 seconds. The total combined duration of both actions is 2000 seconds. * Action A has an impact of 25% (500 / 2000). * Action B has an impact of 75% (1500 / 2000). ## Instrumentation Instrumentation is what powers AppSignal. Without it, we wouldn't know anything about what's going on inside Applications. Instrumentation is hooks inside or around frameworks and libraries AppSignal uses to monitor application code. This instrumentation reports errors and slow code which is sent to AppSignal for analysis. Once a problem is detected an alert is sent. Learn more about [Ruby instrumentation](/ruby/instrumentation). ## Instrumentation events Events are blocks of code that are executed. These can be methods, functions or smaller parts of either. Events can be nested to show hierarchy and the total duration of operations. These individual events make it possible to see which parts of the code are slower than others. At the top of performance [traces](#traces) and [errors issue list](#issues) pages, we also group the event durations by group name, following [our event naming](/api/event-names), to give insights into what part of the app takes the longest. Some types of events that can be shown are database queries, JSON parsing, views rendering, HTTP requests, [custom instrumentation](#instrumentation), etc. Each event is shown on [trace](#traces) detail pages in the "performance timeline". If we detect the same event is repeated more than once in succession, we will mark them as potential N+1 events, such as N+1 queries. Also see [instrumentation](#instrumentation). ## Issues Whenever AppSignal detects a new error, an issue is created. The issue is grouped by [action](#actions), [namespace](#namespace) and [error](#errors). Issues also support errors without an action, as an error can occur outside of an action, such as in the app's framework before reaching the app's own code. The action, [namespace](#namespace) and the error type are the way we group issues. If an error of a new type occurs on the same action in the same namespace as another issue, a new issue will be created for that error. Per issue, it's possible to configure notification settings, assignment, state (open/closed/work in progress), and severity. Slow requests and background jobs are not grouped into issues. They are grouped by action, and you inspect them as [traces](#traces). See [performance](#performance). ## Libraries AppSignal uses language-specific libraries to monitor applications. Currently we have a [Ruby](/ruby) gem and [Elixir](/elixir) package. These libraries include hooks into frameworks and libraries to instrument code blocks such as database calls, file system calls and view rendering. Every library is specialized in the instrumentation of its subject language. Most AppSignal libraries also includes an "[agent](#agent)" which the libraries use to communicate with the AppSignal servers. Read more about how the AppSignal [agent operates](/appsignal/how-appsignal-operates) and the [life cycle of an AppSignal request](/appsignal/data-life-cycle). ### Library integrations AppSignal libraries integrate with a variety of different libraries and frameworks specific to the programming language. The Ruby gem integrates with pure Ruby, Rails, Sinatra and other available frameworks. The Elixir package integrates with pure Elixir and Phoenix. These automatic integrations make it easier to get more insight into applications without having to add AppSignal [instrumentation](#instrumentation) manually. Read more about what [Ruby integrations we offer](/ruby/integrations). ## Markers Markers are little icons used in graphs on AppSignal.com to indicate a change. This can be a code deploy using a "Deploy marker" or a special event with a "Custom marker". These custom markers can be anything from scaling operations, sudden spikes in traffic or when a database is experiencing issues. Read more about [markers](/application/markers). ## Metadata Metadata is data that gives information about other data. Metadata is information about an error or a slow request that provides more context to the data collected. By sending extra metadata on a [trace](#traces) it's easier to track down what the circumstances were around the particular issue. By default the metadata of a request includes the hostname on which the issue occurred, the SCM revision on which the application is running, and the request ID of the request the trace was derived from. It also includes data such as the request path and the request method for web requests. ## Metrics AppSignal provides two kinds of metrics. * [Custom metrics](/metrics/custom) * [Host metrics](/metrics/host-metrics) Custom metrics allow the collection of data from just about anything. With a couple lines of code it's possible to track and graph data such as the number of registered users, visits to a page, database sizes, etc. Host metrics are about data from the server an application is running on. Data such as [CPU usage](#cpu-usage), load averages, memory usage, etc. give more insight into performance issues than just the code itself. Maybe the disk space is running out causing the application to run much slower. Read more about [metrics](https://www.appsignal.com/tour/metrics) on our tour page. ## Namespace Namespaces are grouping mechanisms used by AppSignal to differentiate between different parts of the same application. By default, AppSignal splits an application up into two namespaces: "Web" and "Background". HTTP requests that are being monitored by AppSignal will be added to the "Web" namespace and jobs performed by background job libraries are added to the "Background" namespace. It's also possible to configure your namespaces to differentiate between requests on an application and a private administration panel. For more information about namespaces, please see our [namespaces](/application/namespaces) documentation. ## Notifications AppSignal sends notifications whenever a problem is detected with an [application](#applications). These notifications can be email messages, Slack messages, a PagerDuty notification, and more depending on which [third-party integrations](#third-party-integrations) are configured. We send notifications about [errors](#errors), [slow requests](#performance) and [Anomaly detection](/anomaly-detection/) alerts that occur in an application using an AppSignal [library](#libraries). Once a problematic event is detected a notification is sent out to alert users of a problem. ## Organizations Organizations are used to group [applications](#applications) and [users](#user-account) for a business. A business can have many users and clients that can be notified] whenever there's a problem with their applications. [Billing](/support/billing) for applications is done on organization level rather than per application. [Team management](/organization/team/members) is made easy using organizations. Whole teams can invited to an organization so there's no need for sharing sign-in details. Read more about organizations in our [Organizations documentation](/organization). ## Owners [Organizations](#organizations) have people that manage the organization. These owners decide who's a member of an organization, in which [team](#teams) they do or do not belong and decide how the billing is done. Organization owners can manage everything about an organization and the [applications](#applications) that belong to it. If you do not have permission to view or change something, ask your organization's owner to change it for you or give you more permission. ## Performance Using performance monitoring it's possible to deep dive into individual requests and see what parts of an application are slow. Using this information it's possible to find and improve problem areas. The Performance section lists the [actions](#actions) in your application with their mean duration, throughput and error rate, grouped by action name and [namespace](#namespace). From there you can open the individual [traces](#traces) recorded for an action and see where the time went. Not every slow request is a problem. It's up to you to determine whether an HTTP request of 200 ms is too slow for your application. To be notified when an action gets slow, set a threshold with an [anomaly detection trigger](/anomaly-detection). See [notification settings](/application/notification-settings) for how to create one from a performance action. Read more about the [performance feature](https://www.appsignal.com/tour/performance) on our tour page. ## Push API The AppSignal "Push API" is the API endpoint used by the AppSignal [agent](#agent) to send the collected data. This is different from the normal AppSignal [API](#api) which is primarily used to read data and add more context to the data that's sent to AppSignal. This Push API is the API where application instrumentation is sent from applications using the [Push API key](#push-api-key). ## Push API key The "Push API key" is a write-only API key used by applications to authenticate themselves when sending data to the AppSignal servers. Apps report data to the [Push API](#push-api) and authenticate using this key. There are several kinds of Push API keys that apps can use for different use cases. All Push API keys can be found on the [Push & deploy settings page](https://appsignal.com/redirect-to/app?to=info). * **Organization-level Push API key:** The recommended Push API key for back-end integrations, like Ruby, Elixir, Node.js, Python and Go. We recognize apps by a [combination of the Push API key, app name and app environment](/application/configuration), and create apps using this information if it does not yet exist. * **App-level Push API key:** After creation, an app also gets assigned its app-level Push API key. This key can be used to send data to a specific app, even if the app is configured to use a different app name or app environment. This is used when moving apps between organizations without data loss, or when no app name or app environment can be set, like for the [Vector](/vector) integration. * **Front-end API key:** This key is used by apps using our [front-end integration](/front-end) to report data and can be found in the "Front-end error monitoring" section. Note: These write-only keys are not to be confused with the user-specific [API key](#api-key) which can be used to authenticate on the [AppSignal API](#api) to retrieve data about your apps from our system. ## Response time The response time of an application's action is the time spent processing the action. The longer an action takes to perform the more it qualifies as a performance issue. The duration of this action is displayed on AppSignal.com for [traces](#traces) and in graphs for controllers/jobs and on the host level. ## Ruby Magic Did you know we write articles about the magic that is Ruby? We do! It's called Ruby Magic and you can sign up for it on [appsignal.com/ruby-magic](https://blog.appsignal.com/ruby-magic). A list of all the Ruby Magic articles we've written so far can be found on [our blog](https://blog.appsignal.com/). ## Samples Sampling is how AppSignal decides which [traces](#traces) to store. When a page request is slow a hundred times in a row, it's not as relevant to see all the slow requests. A smaller sample of these requests tells the same story. Instead, the AppSignal [agent](#agent) only sends a small set of traces per [issue](#issues) or [action](#actions) to the AppSignal servers. This saves data sent to the servers and processed on the application host, while still telling the same story about the issues. AppSignal decided [traces](#traces) was a better term for samples. The term "sample" still appears where renaming it would break existing integrations: the [Samples API](/api/samples), and the sample data you attach with the [customization helpers](/guides/custom-data). ## Stroopwafels Also written as "stroopwaffles". At AppSignal, we love stroopwafels. We've shipped over 25,000 of them to customers, friends and conferences. If you work at a tech company and have had a stroopwaffle at the office, chances it came from us. We've written a whole article about what stroopwafels are and how you should eat them. Read on to [become a stroopwafel expert](https://blog.appsignal.com/blog/2016/02/01/stroopwafels-and-how-to-eat-them.html). ## Tags Error and performance [traces](#traces) can be tagged. By tagging these traces it's easier to find and identify certain issues. By tagging it's possible to add more [metadata](#metadata) to a trace that can be used in [link templates](/application/link-templates) to easily link to the relevant data in your application. Read more about [tagging requests](/guides/tagging). ## Teams To manage members of [organizations](#organizations), organization owners can utilize teams to give access to applications. [Users](#user-account) that are part of a team can only access the applications the team they belong to have access to. If a user is part of more than one team this user can access all applications of all the teams they belong to. Teams give permission management to [owners](#owners) of an organization to limit user access to applications without the need for multiple organizations. Read more about organization [team management](/organization/team/teams). ## Third-party integrations AppSignal.com provides connections with other services such as Slack and PagerDuty to more effectively alert users about problems that are detected. These integrations can be managed through the UI on AppSignal.com on an application-by-application basis. Read more about [which third-party integrations we offer](/application/integrations/). ## Traces A trace is a tree of spans that belong to the same unit of work. A web request is one trace, and the database queries it made are spans inside that trace. Because each span records the span that started it, the spans in a trace form a tree that describes the operation from start to finish. A trace usually crosses several services, and those services can report to different AppSignal [applications](#applications). AppSignal does not keep a trace for every request. It stores a representative set instead. ## Transactions Transactions are created by the AppSignal [libraries](#libraries) for every monitored web request and background job. Within this transaction, the agents monitor for errors and slow code. A transaction is created at the start of a web request or when a background job is started. Once the request or job finishes or crashes, the transaction is closed and sent to the [agent](#agent) for processing. [Tags](#tags) and [metadata](#metadata) are added on transaction-level to more easily identify differences between transaction traces. ## Throughput The throughput of an application is the total number of requests sent through an action/job in a certain time frame. The throughput can differ per action and host. On AppSignal.com the throughput is displayed per action and displayed in graphs for every host. ## TLS TLS stands for Transport Layer Security. TLS is a cryptographic protocol that provides secure connections for computer networks, for example, between a server and a web browser. ## Queue time When a server or application is busy processing a lot of requests certain requests may be queued before they are processed. The time waiting to be processed is referred to as "queue time". Since queue time can negatively affect users' experience using an application this metric is tracked by AppSignal for HTTP requests and background jobs. For the background jobs, this represents the time between the request being queued (by a web request) and it being picked up by the background worker (sidekiq). ## User account Every user using AppSignal has a user account. With this user account you can configure notification preferences. Many users can belong to one or more organizations. No need for separate user accounts for every organization. [Organizations](#organizations) manage which users can access which applications and who can manage the billing as an [owner](#owners). # Browser monitoring Source: https://docs.appsignal.com/browser-monitoring What AppSignal reports about your users' browsers, and how front-end errors and web vitals are presented. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). Browser monitoring reports front-end errors with recent breadcrumbs and web vitals from real users. Your back-end telemetry cannot answer questions like these: * After a deploy, some users hit `Failed to fetch dynamically imported module` while your own testing stays clean. Which release introduced it, and what was the user doing when it happened? * Your traces show the server responding in 80 ms, but users still say the dashboard feels slow. Is the time going somewhere in the browser? * You shipped a change to your JavaScript bundle yesterday. Did the pages your users spend the most time on get slower? Browser monitoring is its own section of your application in AppSignal, with two views: * [Errors](/browser-monitoring/errors) groups front-end errors into issues you can triage, assign, and get notified about. * [Performance](/browser-monitoring/performance) reports web vitals per route, so you can compare releases and find the pages that need work. ## What the SDK collects Browser monitoring is fed by [AppSignal for Browser](/browser), the `@appsignal/browser` package you add to your front end. It collects three things once initialized, with no further setup: * [Errors](/browser/error-tracking) include uncaught JavaScript errors and unhandled promise rejections. Reports carry a stack trace when available and any tags you set. * [Breadcrumbs](/browser/breadcrumbs) show recent navigation, clicks, network requests, and console warnings and errors before an error. * [Web vitals](/browser/web-vitals) are five measurements of how the page feels to use. How long it takes to load, how quickly it responds, and whether the layout jumps around while loading. The SDK docs cover how to install and configure it, and exactly what each of those carries. This section covers what AppSignal does with it. ## How it relates to your back-end errors Front-end errors go to the `browser` [namespace](/guides/namespaces). This keeps them separate from back-end error lists and notification settings. The Browser section gives you a dedicated view of front-end errors and performance. These are regular [AppSignal issues](/errors). You can group, triage, and notify on them. Web vitals are separate from your back-end [performance and tracing](/performance-tracing) data. A browser measures how long a page took to become usable. A trace measures what your server did. When the same route is slow in both, you are looking at one problem from two sides. ## Two settings worth getting right These two choices decide how useful the data is: * **Report the route template.** Pass `/orders/:id` rather than `/orders/1042`. Errors use the raw path when you do not set a template, which can split one bug into many issues. The processor derives an approximate template for web vitals, but your router's pattern is more reliable. Read more in [reporting the current route](/browser/installation#report-the-current-route). * **Set an app version.** Both views can filter by the version that reported the data. That is how you tell whether a release made things worse. Read more in [`appVersion`](/browser/configuration#appversion). For the full list of what is recorded, and how to turn categories off, read the [breadcrumbs page](/browser/breadcrumbs). # Front-end errors in AppSignal Source: https://docs.appsignal.com/browser-monitoring/errors How front-end errors are grouped into issues, and what the Errors view shows you. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). The Errors view lists the errors your front end reported, grouped into issues. It uses the same issue model as back-end errors. You can triage and assign them in the same way. ## How errors are grouped AppSignal groups related errors into issues using the reported route and your application's grouping settings. Repeated occurrences can appear as one issue to triage. The route is what the SDK reported through [`setRouteTemplate()`](/browser/installation#report-the-current-route), or the page's path when nothing was declared. Without a template, `/orders/1` and `/orders/2` are different error routes. One bug can become two issues. ## Reading the issue list Each issue in the list carries: * The error class and message, with the route it happened on. * The version where it was **introduced**. If it first appears in your latest release, check that deploy. * A **trend** for the selected period, so a spike reads differently from a steady trickle. * The **total** number of occurrences in the period. * When it was **last** seen. * Who it is **assigned** to. Sort by recent occurrence to find new failures. Sort by volume to find frequent ones. ## Filtering by time and version * **Time range.** Presets from one hour to 30 days, or a custom range. * **Version.** Restrict the list to the errors reported by a single release. Combined with the introduced-in column, this is how you confirm whether a deploy is responsible. ## Investigating an issue Select an issue in the list to open it in a side panel. The panel has two tabs: * **Sample**: one time the error happened in a user's browser. * **Logbook**: your team's notes on the issue, with its state changes and linked GitHub issues. The **Sample** tab shows: * **Error message** and **Tags**. * The backtrace, for errors your code throws. * **Trace service map** and **Trace timeline**. * Related log lines, when the back end is instrumented. * **Breadcrumbs**. 1. **Read the message.** It tells you what failed. For example, `POST https://api.example.com/orders: HTTP 503` means the checkout API returned a server error. 2. **Check the backtrace for errors your code throws.** It shows where the error happened in your code. If you see minified code instead of readable file names and lines, [upload sourcemaps](/browser/error-tracking#sourcemaps) for the version set in `appVersion`. 3. **Read the [breadcrumbs](/browser/breadcrumbs).** They show events before the error, such as a button selection or a network request. If the user selected **Pay** just before `/orders` took three seconds, check that API request first. 4. **Check the version and tags.** Compare the sample's version with your recent deploys. Use tags set with [`setTags()`](/browser/error-tracking#tags) to narrow down who was affected. A failed API request reported as an `HTTPError` or `TimeoutError` has no backtrace. The **Sample** tab shows its trace instead. The **Trace service map** and **Trace timeline** cards show its browser span. If the back end is [instrumented](/browser/distributed-tracing#before-you-start), its spans appear there too, followed by its related log lines. **Open full trace page**, the icon next to the issue number, opens the full issue page. ![Side panel for HTTPError #747. The trace service map links Browser to django with an 81 ms edge. The trace timeline shows an 85 ms span, and no related log lines were found.](https://mintcdn.com/appsignal-715f5a51/qcNVjysU7GB972Yz/assets/images/screenshots/browser/errors-side-panel-trace.png?fit=max\&auto=format\&n=qcNVjysU7GB972Yz\&q=85\&s=17224328e4f8de5d3058841417848c7b) The side panel for a failed request: the browser and Django services in one trace, then its timeline and related log lines. You can export a sample as JSON or Markdown to share it with your team. Use the issue's logbook to record what you found. ## Triage and notifications You can assign, mute, and change the state of these issues. They also support notification settings. Read more in [errors](/errors). Because front-end errors live in the `browser` [namespace](/guides/namespaces), those settings are separate from your back-end ones. If you migrate from `@appsignal/javascript`, set up notifications for `browser`. Settings for `frontend` do not carry over. Read more in the [migration guide](/browser/migration). ## Errors you will not find here Some errors never reach the SDK. Examples include errors before `init()` and errors inside uninstrumented iframes. Opaque cross-origin script errors are dropped. Each has a workaround, listed in [errors that are not reported](/browser/error-tracking#errors-that-are-not-reported). If an error you expected is missing, work through [troubleshooting](/browser/troubleshooting#an-error-is-missing). # Front-end performance in AppSignal Source: https://docs.appsignal.com/browser-monitoring/performance How web vitals are aggregated per route and per release, and what the Performance view shows you. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). The Performance view reports [web vitals](/browser/web-vitals) measured on your users' devices and connections. ## Web vitals summary The view has cards for five metrics: LCP, INP, CLS, FCP, and TTFB. Values, ratings, and trends appear when measurements are available. The trend line is what tells a steady number apart from one that has been climbing. Each period is also compared against the one before it of the same length. For example, selecting the last four hours compares them with the previous four. This shows whether a value changed. When a trend spikes, check how many measurements sit behind it. A single measurement is too little to establish a regression. The ratings come from Google's thresholds, which are listed with each metric on the [web vitals page](/browser/web-vitals#what-each-metric-measures). The three Core Web Vitals are LCP, INP, and CLS. FCP and TTFB help explain a poor LCP. Slow TTFB points to the server or network. Fast TTFB with slow LCP points you toward resource loading or rendering. ## Percentiles Values are reported at a percentile you choose: p75, p90, or p95. Start with p75. Google's thresholds use it to rate Core Web Vitals. Use p90 or p95 to see slower experiences that an average can hide. ## Per-route breakdown Beneath the summary, the table shows up to 20 pages, with a sample count and available metrics for each. The sample count matters as much as the values: a route with four samples is a hint, not a finding. This table is where you find the work. The table prioritizes pages with more measurements, then sorts those shown by LCP. Compare metrics across a row for clues: * A slow TTFB points to time spent waiting for the server or network before rendering can start. * A fast TTFB with a poor CLS means the response starts quickly, but the layout shifts unexpectedly. Routes are listed as the templates your application reported. For other routes, the processor derives an approximate template from the URL. Read more in [reporting the current route](/browser/installation#report-the-current-route). ## Comparing releases Filtering by app version restricts the whole view, summary and table alike, to the page loads reported by that release. Selecting a version also labels the trend lines with it. This is the quickest way to answer whether a deploy made something slower. Set [`appVersion`](/browser/configuration#appversion) to your release tag or commit SHA and every measurement carries it. ## Filtering by route Filtering by route narrows both the summary and table. You can then inspect one part of the application. Those averages are often unhelpful on their own. A fast marketing page and a slow dashboard combine into a single number that describes neither of them. ## What the numbers leave out Two things to keep in mind when interpreting what you see: * **Metric availability varies by browser.** CLS and INP need specific performance entries, so browsers without them do not contribute those values. Read more in [browser support](/browser/web-vitals#browser-support). * **LCP, FCP, and TTFB belong to the page load, not the route.** The browser measures them once, when the page first loads. In a single-page application, they belong to whichever route the user opened first, not the ones they moved to afterwards. CLS and INP are measured per route. Read more in [how values are attributed to routes](/browser/web-vitals#how-values-are-attributed-to-routes). If no web vitals appear at all, remember that they are sent in batches rather than one at a time. Work through [troubleshooting](/browser/troubleshooting#errors-arrive-web-vitals-do-not). # Changelog Source: https://docs.appsignal.com/changelog Where AppSignal records what shipped: the product changelog on appsignal.com, and the release notes each integration keeps with its releases. The product changelog records what we ship across AppSignal: new features, changes to features you already use, and the fixes that come with them. > **[AppSignal product changelog](https://www.appsignal.com/changelog)** > > Every release, newest first, on appsignal.com. ## Integration releases Integrations version and release on their own schedule, separately from the product, and each one records its changes with its releases on GitHub. These are the notes to read before an upgrade, because they name the configuration options, instrumentation, and minimum language versions that changed. | Integration | Releases | | - | - | | Ruby | [appsignal-ruby](https://github.com/appsignal/appsignal-ruby/releases) | | Elixir | [appsignal-elixir](https://github.com/appsignal/appsignal-elixir/releases) | | Node.js | [appsignal-nodejs](https://github.com/appsignal/appsignal-nodejs/releases) | | Python | [appsignal-python](https://github.com/appsignal/appsignal-python/releases) | | JavaScript (browser) | [appsignal-javascript](https://github.com/appsignal/appsignal-javascript/releases) | | CLI | [appsignal-cli](https://github.com/appsignal/appsignal-cli/releases) | ## Features before they ship Some features are available before they reach the changelog. [AppSignal Labs](/labs) is where those land first, and it explains what to expect from a feature that is still changing. # Custom instrumentation Source: https://docs.appsignal.com/custom-instrumentation Where to add manual instrumentation when automatic tracing is not enough. Automatic instrumentation gives AppSignal a strong starting point, but some important work in your application is specific to your product. Custom instrumentation helps you add spans, attributes, metadata, and error context in the places that matter most to you. Pick the guide that matches the SDK you use: * [Ruby](/ruby/instrumentation) * [Elixir](/elixir/instrumentation) * [Node.js](/nodejs/3.x/instrumentation) * [Front-end JavaScript](/front-end/span) * [Python](/python/instrumentation) * [Go](/go/custom-instrumentation) * [Java](/java/custom-instrumentation) * [PHP](/php/instrumentation) * [OpenTelemetry](/opentelemetry/custom-instrumentation) If you are extending OpenTelemetry setup specifically, also see [Add additional OpenTelemetry Instrumentation](/guides/instrumentation/additional-opentelemetry-instrumentation). # Distributed tracing Source: https://docs.appsignal.com/distributed-tracing Follow one request across services and applications: how AppSignal assembles each service's subtrace into one trace. Where does a slow request actually spend its time? A request takes four seconds, but your web app looks normal and the database is quiet. A single request can authenticate against one service, load data from an internal API, enqueue a background job, and call a third-party payment API before the response comes back. When it slows down or fails, the cause often sits in a different service than the one that first showed the symptom. Distributed tracing lets you follow that one request across those boundaries. AppSignal groups the work from every service into one trace, so you can see the full path before you start comparing timestamps across apps. ## What is distributed tracing? When each service reports on its own, you can see that a web action is slow, but not that an inventory service farther down the call chain caused it. In AppSignal, those services may live in separate applications or namespaces, so following one request means opening each one and lining up the timestamps. Distributed tracing keeps those services connected. As a request moves from one service to the next, each service tags its work with the same trace identifier and records which span called it. AppSignal uses that data to reassemble the full path of the request across every service that took part. With a distributed trace, you can: * Follow one request from its entry point through every service it reached. * See where the time went, even when the slow part runs in a different service or application. * Find which service an error started in, not just where it surfaced. ## Spans, traces, and services AppSignal shows a distributed trace as three building blocks. * **Span**: a single unit of work, such as an incoming HTTP request, a database query, a call to another service, or a block of code you instrument yourself. A span has a name, a duration, and attributes, and it records the span that started it. Spans are the smallest thing a trace is made of. * **Trace**: all the spans that belong to one end-to-end operation. Because each span knows its parent, the spans in a trace form a tree that describes the request from start to finish. * **Service**: a named component that takes part in a trace, such as a web app, a background worker, or an internal API. You name a service with the `service_name` option (or the `APPSIGNAL_SERVICE_NAME` environment variable), and AppSignal uses that name to tell services apart in a trace. A single trace usually crosses several services, and those services can report to different AppSignal applications. ![A trace's spans arranged as a tree, from the root span down through parent and child spans](https://mintcdn.com/appsignal-715f5a51/ydExjxcWacNDpILG/assets/images/diagrams/distributed-tracing/span-tree.png?fit=max\&auto=format\&n=ydExjxcWacNDpILG\&q=85\&s=ada68a41a3078ae6ab60c8bf9bf578a3) The spans in a trace form a tree. Each span records the span that started it, from the root span down. > [!NOTE] > > AppSignal builds traces on top of OpenTelemetry, so these terms line up with > OpenTelemetry's. AppSignal groups each trace under an > [action](/appsignal/terminology#actions) and a > [namespace](/application/namespaces), based on the endpoint, job, or task the > trace belongs to. Within AppSignal, a trace is a kind of [sample](/appsignal/terminology#samples): the detailed record of one request, stored so you can open it and read it span by span. AppSignal derives your performance metrics, such as response time and throughput, from these traces, so a performance chart and a single trace are two views of the same data. ## Availability and setup Before you investigate a request across services, each application needs to report to a hosted collector and identify itself with a distinct service name. Distributed tracing is available through AppSignal integrations for Python, Ruby, and PHP, and through OpenTelemetry for Go and Java. Elixir and Node.js are not supported yet. Any other OpenTelemetry-instrumented application can also report trace data to a hosted collector. In the browser, AppSignal for Browser starts the trace for requests to your API. > [!NOTE] > > Distributed tracing is a beta [AppSignal Labs](/labs) feature, **only > available** when using the AppSignal hosted collector. What you need to configure depends on how your integration sends data to AppSignal. Python and Ruby can report either through their bundled agent or through a collector, so you need to enable collector mode. PHP, Go, Java, and custom OpenTelemetry setups already report through a collector, so there is nothing extra to switch on for distributed tracing. * **Python**: set the `collector_endpoint` option to your hosted collector's URL rather than a self-hosted one. See [collector configuration for Python](/python/configuration/collector). * **Ruby**: set the `collector_endpoint` option to your hosted collector's URL rather than a self-hosted one. Collector mode arrived in AppSignal for Ruby 5.0 and needs the `appsignal-opentelemetry` gem alongside it, on Ruby 3.1 or newer. See [collector configuration for Ruby](/ruby/configuration/collector) for the versions to install, and [distributed tracing for Ruby](/ruby/distributed-tracing) for the libraries that carry the trace for you. * **PHP**: no extra distributed tracing setting to enable. The PHP package already reports through a collector, so distributed tracing works once your app reports to AppSignal. * **Go**: instrument your app with the OpenTelemetry SDK and export to your hosted collector's URL. Register a propagator with `otel.SetTextMapPropagator`, as the [Go installation guide](/go/installation) does. The Go SDK doesn't propagate trace context without one. AppSignal has setup instructions for the [Gorilla mux](/go/instrumentations/gorilla-mux) and [Gin-gonic](/go/instrumentations/gin-gonic) frameworks. * **Java**: instrument with the OpenTelemetry SDK or Java agent and export to your hosted collector's URL. See the [Java installation guide](/java/installation) for the agent setup. * **A custom OpenTelemetry setup**: no AppSignal-specific distributed tracing setting to enable. Exporting to a hosted collector is already how these setups report, so traces connect on their own. * **Browser**: set `tracePropagationTargets` to your API hosts. Each matching request carries a `traceparent` header. The receiving back end needs HTTP server instrumentation to continue it. A 5xx response or timeout is reported as a browser error in that trace. See [distributed tracing for Browser](/browser/distributed-tracing). Set a service name for each application as well. Python, Ruby, and PHP take it as the `service_name` option or the `APPSIGNAL_SERVICE_NAME` environment variable; Go, Java, and custom OpenTelemetry setups set the `service.name` resource attribute. Set it explicitly for every service. Without it, AppSignal cannot distinguish the services in a trace reliably, and custom OpenTelemetry expects the `service.name` resource attribute to be present. Distributed tracing is built on OpenTelemetry, so it is not limited to the integrations above. Any OpenTelemetry-instrumented application can report distributed tracing data to a hosted collector. You can do this through an AppSignal integration such as the PHP package, or a [custom OpenTelemetry SDK setup](/opentelemetry/installation). Read more in the [Python collector configuration](/python/configuration/collector), [Ruby collector configuration](/ruby/configuration/collector), [PHP configuration](/php/configuration), [Go configuration](/go/configuration), [Java configuration](/java/configuration), and [OpenTelemetry service name option](/opentelemetry/configuration/options#service-name) docs. ## How does it work in AppSignal? AppSignal builds distributed traces on OpenTelemetry. The part that makes this possible is **context propagation**. When an instrumented service calls another service, OpenTelemetry attaches the trace identifier and the calling span to the outgoing call. It travels as headers on an HTTP request, or as metadata on a queued job, and the receiving service reads it and continues the same trace. Each service reports the portion of the trace it handled, called its **subtrace**. AppSignal receives these subtraces independently, often from different processes or hosts, and reassembles them into one trace using the shared trace identifier and the parent and child links between spans. You do not connect services together in AppSignal by hand. If a library is instrumented, its calls join the trace automatically. ![One trace across three services, each reporting its own subtrace and the spans within it](https://mintcdn.com/appsignal-715f5a51/ydExjxcWacNDpILG/assets/images/diagrams/distributed-tracing/trace-across-services.png?fit=max\&auto=format\&n=ydExjxcWacNDpILG\&q=85\&s=c2b8f1d2a9e12f272fdc4583604a4103) One trace spans several services. Each service reports a subtrace, and AppSignal assembles the subtraces into a single trace. AppSignal samples traces rather than keeping every one, and it makes that decision across services: when a trace is kept, the work from every service in it is kept too, so the trace arrives whole instead of as scattered fragments. Sampling favors the traces you most want to see, the ones with errors and the slowest requests. Gaps can still appear at the edges, when a service does not report or its data arrives too late. After traces start arriving, open the [trace page](/trace-page) to inspect them in two ways: the **service map**, which shows the services in the trace and the calls between them, and the **trace timeline**, which lays every span out over time. The trace page covers how to read both. ### Cross-application support A service in AppSignal is not the same thing as an application. Several services can report to one AppSignal application, and a single trace can also cross services that belong to entirely separate applications. For example, a web app, an inventory service, and an audit service might all report to one AppSignal application, each under its own service name, while a separate service reports as its own application. A single user action, such as a checkout, can produce a trace that includes services from both applications. AppSignal's service map treats this as one trace regardless of where each subtrace was reported. It resolves the application that owns each service and links each one to that application's view of the same trace. To follow a request across an application boundary, select the next service on the map. You move from one application to the next along the same trace. This works because context propagates across process and application boundaries the same way it does between services, and AppSignal matches subtraces by their shared trace identifier, not by which application or host they came from. Once each service reports through a hosted collector with its own service name, you can follow one request across services and applications from a single trace. ## Related > **[Trace page](/trace-page)** > > Open one stored trace and read its service map, timeline, span details, related logs, and triggers. > **[Distributed tracing for Ruby](/ruby/distributed-tracing)** > > See which Ruby HTTP and background job integrations carry the trace automatically. > **[Distributed tracing for Browser](/browser/distributed-tracing)** > > Start the trace in the browser, and see a failed API request as an error in the back-end trace. > **[OpenTelemetry](/opentelemetry/installation)** > > Set up a custom OpenTelemetry SDK to report through an AppSignal collector. > **[Custom instrumentation](/custom-instrumentation)** > > Add your own spans and attributes when the default instrumentation is not enough. > **[Link traces with logs](/guides/linking-traces-with-logs)** > > Connect a trace to its related logs so you can move between them while debugging. > **[Labs](/labs)** > > Try out distributed tracing and other experimental features. # Errors Source: https://docs.appsignal.com/errors How AppSignal tracks, groups, and alerts on errors, and where to report handled exceptions. AppSignal captures the exceptions your application raises, groups them so they are easy to triage, and alerts you when something needs attention. Errors are tightly coupled to traces: an error usually happens inside a request, background job, or script run, and the surrounding trace gives you the timing and context you need to debug it. ## How AppSignal groups errors When your application reports an exception, AppSignal groups it into an **issue** with other occurrences of the same error type on the same action and namespace. A single bug that fires thousands of times becomes one issue to triage, not thousands of separate alerts. Each issue keeps a set of **traces**: representative occurrences with the full backtrace, request metadata (such as hostname, revision, and request path), and any tags you add. ## See the errors a deploy introduced The **Pick a revision** filter on the errors page allows you to scope the errors list to a deploy or a timeframe. Open it to choose a scope, such as **By Revision (deploy)**, or **By Timeframe**, which covers a time range. ![Errors filter open on the errors page, showing the All errors and New errors switch, the By Revision (deploy) and By Timeframe tabs, and a list of recent revisions](https://mintcdn.com/appsignal-715f5a51/GfwJHrG20MDdZfue/assets/images/screenshots/error-filters.png?fit=max\&auto=format\&n=GfwJHrG20MDdZfue\&q=85\&s=2aaa2f788b99ee61a2a7d8fc03ea2d94) The errors filter with New errors selected and one revision chosen By default the filter is set to **All errors**, which lists all issues that occurred from the most recent to oldest. Select **New errors** to list only the errors that were first seen in it: * **Most recent revisions**: errors first seen since the most recent revisions per service. * **A specific revision**: errors first seen in that deploy. * **A timeframe**: errors first seen within that time range. Pick a start and end time, or choose a preset like **Last 24 hours** or **Last 7 days**. While **New errors** is selected, the filter label says so, for example **New in revision a1b2c3d** or **New in timeframe**. The switch stays on when you pick a different deploy or timeframe. It is also part of the page URL, so a link you share opens the same list. [Deploy markers](/application/markers/deploy-markers) tell AppSignal when each deploy happened. Until you add them, AppSignal counts everything since the app was created as one deploy. **New errors** on **Most recent revisions** then lists every error. Choose a timeframe instead. AI tools you connect to [AppSignal MCP](/mcp/setup), such as Claude Code or Cursor, can get the same list. They use the `new_only` parameter of the [`get_exception_incidents`](/mcp/reference#get_exception_incidents) tool. ## Filters and saved views The Errors page remembers your filters and applies them the next time you open it: namespace, status, severity, assignee, sort order, and the revision filter. AppSignal remembers them for each app, in the browser you used. The search query is not remembered. To keep a set of filters you return to, including a search query, save it as a view: 1. Set the filters on the Errors page. 2. Open the options menu (the vertical ellipsis icon) and select **Save view**. 3. Enter a name for the view and select **Save view**. Saved views are listed under **Errors** → **Views** in the app navigation, and everyone with access to the app can open them. A saved view opens with its own filters and does not change the filters the Errors page remembers. To update a view, open it, change the filters, and select **Save view** again. Choose **Save changes to current view**, or **Save changes to a new view** to keep the original. The same menu has **Rename view** and **Delete view**. Deleting a view removes it for everyone. ## Triage and notifications Each issue can be assigned to a team member, given a state and a severity, and configured with its own notification settings. AppSignal notifies you through your configured channels (email, Slack, and other integrations) when a new error is detected. ## Namespaces Errors are grouped by namespace, so you can separate web requests from background jobs. The default namespaces are Web and Background, and you can configure custom ones. See [Namespaces](/guides/namespaces) for details. ## Alerting on error rates Beyond per-error notifications, [anomaly detection](/anomaly-detection) can alert you when the error rate for an application or namespace crosses a threshold you set. ## Reporting handled exceptions If you catch an exception yourself, you can still report it to AppSignal with the helper methods provided by your SDK. The exact helper names vary by SDK, but the goal is the same: keep the error attached to the trace, or send it with useful context. * Ruby: [`report_error`, `set_error`, and `send_error`](/ruby/instrumentation/exception-handling) * Elixir: [`Appsignal.set_error/2` and `Appsignal.send_error/3`](/elixir/instrumentation/exception-handling) * Node.js: [`setError()` and `sendError()`](/nodejs/3.x/instrumentation/exception-handling) * Python: [`set_error` and `send_error`](/python/instrumentation/exception-handling) * PHP: [Exception handling](/php/exception-handling) * Front-end JavaScript: [Error handling](/front-end/error-handling) ## Add debugging context To make errors easier to investigate, add more context with: * [Tagging](/application/tagging) * [Backtrace links](/application/backtrace-links) * [Performance / tracing](/performance-tracing) ## See also * [The Ruby debug gem: breakpoints, stepping, and the stack](/tutorials/ruby/debugging-with-the-debug-gem): use the Ruby `debug` gem to inspect a problem while reproducing it locally. * [params.expect: strong parameters in Rails 8](/tutorials/ruby/params-expect): Rails 8 adds `params.expect` to permit and require parameters in one step. It rejects unexpected parameter shapes as bad requests. # Features Source: https://docs.appsignal.com/features Track errors and performance, search logs, chart custom metrics, and monitor your hosts, uptime, and processes with AppSignal. AppSignal monitors your application across errors, performance, logs, metrics, and the hosts and processes it runs on. Choose a feature to learn what it does and how to set it up. ## Application health > **[Errors](/errors)** > > Capture exceptions, group them into issues, and debug them with full trace context. > **[Performance / tracing](/performance-tracing)** > > Trace requests, jobs, and scripts to find where they spend time and slow down. > **[Anomaly detection](/anomaly-detection)** > > Trigger notifications when a metric goes over or under a threshold you set. > **[Alerting](/alerting)** > > Choose the right alerting system and route alerts to the right people, without the noise. ## Logs & metrics > **[Logs](/logging)** > > Store, view, and query your application's logs, and extract metrics from them. > **[Metrics & dashboards](/metrics/custom)** > > Track custom metrics and build dashboards that relate them to errors and response times. ## Infrastructure > **[Host monitoring](/metrics/host-metrics)** > > Correlate CPU, memory, disk, and network metrics with your errors and performance. > **[Uptime monitoring](/uptime-monitoring/setup)** > > Check your endpoints from regions worldwide and get alerted when they can't be reached. > **[Process monitoring](/check-ins)** > > Monitor cron jobs and background processes, and get alerted when they don't run as scheduled. ## Application customization > **[Application customization](/application)** > > Configure namespaces, metadata, data filtering, markers, limits, and notifications for your apps. # AppSignal documentation Source: https://docs.appsignal.com/getting-started Set up error tracking, performance monitoring, logging, and more for your application. Start with your language, then explore features, integrations, and the API. AppSignal is an application monitoring platform that provides error tracking, performance monitoring, logging, and uptime monitoring for your projects. Pick the block below that matches what you want to do. > [!NOTE] > > 🛟 Need help? The [support](#support) section lists your options. ## Getting started How you install AppSignal depends on the language your application is written in. Every language has its own installation instructions, so start with your language in the [languages](#languages) section and follow the steps there. The two guides below cover the rest: adding your first application to AppSignal, and configuring it once it reports data. > **[Add your first application](/guides/new-application)** > > Install AppSignal, send your first data, and see your application appear on AppSignal.com. > **[Configure your application](/guides/configuration)** > > Add and change configuration options, per environment, in a config file or environment variables. > **[Application concepts](/application)** > > How applications, environments, and namespaces relate to each other. > **[How configuration works](/application/configuration)** > > The four options every application needs, and where each integration loads them from. New to the vocabulary? The [terminology page](/appsignal/terminology) defines the terms used throughout these docs. ### AppSignal in 5 minutes: a quick start guide [YouTube video player](https://www.youtube.com/embed/hetBXN5db8k?si=xj0PRay-AXrptSJz) [Watch the quick start guide on YouTube →](https://www.youtube.com/watch?v=hetBXN5db8k) ## Languages Everything you need to know when integrating AppSignal with your application's programming language. ### Native integrations AppSignal's own SDKs with the deepest feature coverage. > **[Ruby](/ruby)** > > * [AppSignal for Ruby](/ruby) > * [Installation](/ruby/installation) > * [Configuration](/ruby/configuration) > * [Custom instrumentation](/ruby/instrumentation) > * [Example applications](https://github.com/appsignal/appsignal-examples#ruby-example-apps) > **[Elixir](/elixir)** > > * [AppSignal for Elixir](/elixir) > * [Installation](/elixir/installation) > * [Configuration](/elixir/configuration) > * [Custom instrumentation](/elixir/instrumentation) > * [Command line tools](/elixir/command-line) > **[Node.js](/nodejs/3.x)** > > * [AppSignal for Node.js](/nodejs/3.x) > * [Installation guides](/nodejs/3.x/installation) > * [Configuration](/nodejs/3.x/configuration) > * [Custom instrumentation](/nodejs/3.x/instrumentation) > * [Command line tools](/nodejs/3.x/command-line) > **[Python](/python)** > > * [AppSignal for Python](/python) > * [Installation guides](/python/installation) > * [Configuration](/python/configuration) > * [Custom instrumentation](/python/instrumentation) > * [Instrumentations](/python/instrumentations) > **[PHP](/php)** > > * [AppSignal for PHP](/php) > * [Installation](/php/installation) > * [Configuration](/php/configuration) > * [Custom instrumentation](/php/instrumentation) > * [Integrations](/php/integrations) > **[JavaScript (browser)](/front-end)** > > * [AppSignal for front-end](/front-end) > * [Installation](/front-end/installation) > * [Configuration](/front-end/configuration) > * [Integrations](/front-end/integrations) > * [Troubleshooting](/front-end/troubleshooting) ### Via OpenTelemetry AppSignal supports additional languages through OpenTelemetry. Any tool or service that exports OpenTelemetry data, including traces, metrics, and logs, can send it to AppSignal. > **[Go](/go)** > > * [AppSignal for Go](/go) > * [Installation](/go/installation) > * [Configuration](/go/configuration) > * [Custom instrumentation](/go/custom-instrumentation) > * [Instrumentations](/go/instrumentations) > **[Java](/java)** > > * [AppSignal for Java](/java) > * [Installation](/java/installation) > * [Configuration](/java/configuration) > * [Custom instrumentation](/java/custom-instrumentation) > * [Instrumentations](/java/instrumentations) > **[Other languages (via OpenTelemetry)](/opentelemetry)** > > * [OpenTelemetry overview](/opentelemetry) > * [Installation](/opentelemetry/installation) > * [Configuration](/opentelemetry/configuration) > * [Custom instrumentation](/opentelemetry/custom-instrumentation) > * [Troubleshooting](/opentelemetry/troubleshooting) ## Features What AppSignal does once your application reports data. > **[Errors](/errors)** > > Capture exceptions, group them into issues, and debug them with full trace context. > **[Performance](/performance-tracing)** > > Trace requests, jobs, and scripts to find where they spend time and slow down. > **[Anomaly detection](/anomaly-detection)** > > Trigger notifications when a metric goes over or under a threshold you set. > **[Metrics and dashboards](/metrics/custom)** > > Track custom metrics and build dashboards that relate them to errors and response times. > **[Logs](/logging)** > > Store, view, and query your application's logs, and extract metrics from them. > **[Workflow](/application/integrations)** > > Send incidents and alerts to Slack, GitHub, Jira, PagerDuty, and the rest of your stack. > **[Alerting](/alerting)** > > Choose the right alerting system and route alerts to the right people, without the noise. Host monitoring, uptime monitoring, and process monitoring are covered on the [features overview](/features). ## Integrations AppSignal works with the platforms, services, and tools you already use. > **[Hosting and deploy platforms](/services-integrations#hosting-and-deploy-platforms)** > > Heroku, Vercel, Render, Kubernetes, Kamal, Docker, and more. > **[Notifications and incident management](/services-integrations#notifications-and-incident-management)** > > Slack, Microsoft Teams, Discord, PagerDuty, OpsGenie, and webhooks. > **[Issue tracking and source control](/services-integrations#issue-tracking-and-source-control)** > > GitHub, GitLab, Jira, Linear, Asana, Trello, and Shortcut. > **[Cloud services and log sources](/services-integrations#cloud-services-and-log-sources)** > > AWS CloudWatch logs and metrics, Vector, and NGINX. Looking for the configuration and customization details for one language? Each integration page covers the frameworks and libraries AppSignal instruments: [Ruby](/ruby/integrations), [Elixir](/elixir/integrations), [Node.js](/nodejs/3.x/integrations), [Python](/python/instrumentations), [PHP](/php/integrations), and [front-end JavaScript](/front-end/integrations). [Browse all services and integrations →](/services-integrations) ## API Fetch data out of AppSignal, or push data in from your own code. > **[AppSignal API](/api)** > > Query your data with the GraphQL API, or push metrics and errors to the public endpoint. > **[AppSignal for agents](/agents)** > > Give AI agents and coding assistants access to your data through MCP or the CLI. ## Support Need help? The resources below can help you troubleshoot issues and reach our support team. * [Email AppSignal support](mailto:support@appsignal.com) * [Debugging guide](/support/debugging) * [Known issues](/support/known-issues) * [Supported operating systems](/support/operating-systems) * [Maintenance policy](/support/maintenance-policy) * [Security overview](/appsignal/security) * [AppSignal status page](https://status.appsignal.com) AppSignal also offers Business Add-Ons for additional monitoring needs: a [HIPAA Business Associate Agreement](/support/business-add-ons#hipaa-business-associate-agreement) and [long-term log storage](/support/business-add-ons#long-term-log-storage). ## Beyond the docs > **[Ruby and Rails tutorials](/tutorials)** > > Screencasts and written walkthroughs about Ruby and Rails from the GoRails team, including [Chris Oliver](/tutorials#meet-chris-oliver). > **[AppSignal blog](https://blog.appsignal.com)** > > Tutorials, deep dives, and engineering stories from the AppSignal team. > **[Learning Center](https://www.appsignal.com/learning-center)** > > Practical guides and lessons to help you get more out of AppSignal. > **[Status](https://status.appsignal.com)** > > Real-time status of AppSignal services and incident history. # AppSignal guides Source: https://docs.appsignal.com/guides Step-by-step walkthroughs for setting up AppSignal, customizing the data it collects, and managing your applications. These guides walk you through every step of integrating AppSignal with your application, from creating an account to finding slow queries. Each one is a task you can follow start to finish. If you get lost, our [support page](/support) will help you get back on track. > [!TIP] > > Many of these guides have you working in both AppSignal and your application's > codebase, so before starting, open your favorite text editor and grab a cup of > something refreshing to drink ☕️ ## Set up AppSignal AppSignal wasn't built in a day, but it can be installed in minutes. Follow these four guides in order to go from no account to an application reporting data. > **[Create a user account](/user-account)** > > Sign up with GitHub or an email address, and set your notification preferences. > **[Create an organization](/organization)** > > Set up the umbrella that holds your applications and your team. > **[Add a new application](/guides/new-application)** > > Install AppSignal in your application and send your first data. > **[Configuring applications](/guides/configuration)** > > Add and change configuration options, per environment. ## Get more out of your data Once your application reports data, these guides help you organize and enrich it. * [Reporting deploys to track improvements](/guides/deploy-markers) * [Grouping parts of your application with namespaces](/guides/namespaces) * [Grouping errors and performance traces with actions](/guides/actions) * [Add tags to error and performance traces](/guides/tagging) * [Customize the data added to error and performance traces](/guides/custom-data) * [Filtering application data](/guides/filter-data): choose which parameters, session data, headers, and more AppSignal collects * [Add additional OpenTelemetry instrumentation](/guides/instrumentation/additional-opentelemetry-instrumentation) ## Feature guides Use what AppSignal collects to answer a specific question. * [Find slow database queries](/guides/slow-queries) * [Find slow HTTP requests](/guides/slow-requests) * [Link traces with logs](/guides/linking-traces-with-logs) ## Application management guides Move, remove, and reorganize the applications in your organization. * [Migrating applications between organizations](/guides/application/migrating-applications) * [Removing an application](/guides/application/deleting-applications) * [Running multiple applications on one host](/guides/application/multiple-applications-on-one-host) ## Ruby and Rails tutorials from GoRails These guides explain how to set up and use AppSignal. The [Ruby and Rails tutorials](/tutorials), produced with [GoRails](https://gorails.com), pair screencasts with written walkthroughs. They cover background jobs, debugging, parameters, authentication, Markdown, and local CI. Each tutorial also explains the related AppSignal data. # Grouping with Action Names Source: https://docs.appsignal.com/guides/actions 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. ## 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: ```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 ``` 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. ```ruby Ruby theme={null} # 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**: ```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 ``` 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: ```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"); }); ``` 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: ```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") ``` 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: ```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 }); ``` Alternatively, you can update an existing span's action name: ```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 } ``` ### 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: ```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")) } ``` 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: ```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"; } } ``` 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: ```php PHP theme={null} [!TIP] > > Historical data will still use the original action names. Only newly reported actions will use the custom names you've defined. 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) # Deleting Applications Source: https://docs.appsignal.com/guides/application/deleting-applications An application (app) in AppSignal is defined as the combination of the application name and environment, e.g. "My app - production". You can only remove/delete one environment at a time through the UI. > [!TIP] > > Apps are automatically recreated when our servers receive data from your app. > To remove an app, first make sure AppSignal is completely uninstalled from > your applications before removing it on AppSignal.com Please follow the uninstall guide for the programming language of your application(s) listed below: * [Ruby gem uninstall guide](/ruby/installation/#uninstall) * [Elixir package uninstall guide](/elixir/installation#uninstall) * [JavaScript for Front-end package uninstall guide](/front-end/installation#uninstall) When your app is no longer pushing data to the AppSignal servers, remove your app on the [App Settings page](https://appsignal.com/redirect-to/app?to=edit) for your app on AppSignal.com. * Visit the [App Settings](https://appsignal.com/redirect-to/app?to=edit) page. * Scroll down to the bottom of the page. * In the "Delete \" section, click on the "delete \" button and confirm the confirmation prompt. Your app is now scheduled for deletion. It and all its data will be removed from your organization and our servers. This may take a few minutes, after which it will disappear from your apps list. ## See also * [Application topic](/application/) * [Guides index](/guides/) # Migrating applications between organizations Source: https://docs.appsignal.com/guides/application/migrating-applications While it's not possible to directly transfer apps between organizations in the AppSignal.com interface, they can be moved with some configuration changes. We do not have an option for migrating on the AppSignal.com app because of these configuration changes. The organization-level Push API key needs to be changed in an app to migrate an app. To migrate an app you can choose to [either keep](#migration-with-app-data-and-history), or [not keep](#migration-without-keeping-app-data-and-history) the app's data and history: errors, performance measurements, metrics, etc. ## Migration without keeping app data and history If you do not want to keep the app's data we recommend to update your application config with the new organization's Push API key. After a deploy, a new app with the same name and environment will appear under the new organisation. Once the new app reports data, you can [remove the old app][remove guide] in the other organization. ## Migration with app data and history If you like to have the history of the application as well, you will then need to [contact us][contact] so we can help you in this process by going through the following steps. * Step 1 * First you'd need to update your Push API key for the app you'd like to move to an app-specific key, instead of an organization-specific key. This ensures data that's being sent during the move will end up under the correct app. You can find the app-specific key in the [app settings section][app settings], the second key listed there. * Step 2 * Once you [inform us][contact] that you have taken care of the step above, we will then move the application data to the new organization. This process can take a couple of hours, depending on the amount of traces. * Step 3 * Once the data migration is complete, we move the app itself to the new organization. * Note that we can't migrate everything, as some things are organization specific, such as certain integration such as Jira/GitHub or notifiers such as Slack. * Step 4 * Deploy the app again with the new organization-specific API key (from the new organization) as found in the [app settings section][app settings], first key listed there. * The migration is now complete. ## See also * [Application topic](/application/) * [Guides index](/guides/) [contact]: mailto:support@appsignal.com [app settings]: https://appsignal.com/redirect-to/app?to=info [remove guide]: /guides/application/deleting-applications.html # Running multiple applications on one host Source: https://docs.appsignal.com/guides/application/multiple-applications-on-one-host ## The problem When running multiple applications on one host some odd behavior may occur. One common problem we've seen is that Applications start reporting under different names and/or environments. Such as an application switching between the staging and production environment after a deploy or restart of an application process or worker. ## Background The AppSignal agent starts using an application config. It uses this configuration to send the data to the AppSignal servers to report it as that app on AppSignal.com. By default AppSignal is configured to assume one application runs on one host. If you run more than one application on a host, some configuration is required to avoid sharing the AppSignal working directory between multiple applications. This way multiple AppSignal agents can run at the same time with a different application config. > [!TIP] > > Read more about the AppSignal [working > directory](/appsignal/how-appsignal-operates#working-directory). ## Configuration To allow AppSignal to be used for multiple applications on one host we need to set the "working directory path" configuration option. Using this configuration option, we need to set a unique working directory path per application for AppSignal to store its (temporary) files. This way the AppSignal agent will not share the working directory between multiple applications. ### Ruby To set the working directory path in the Ruby integration, add the following to your AppSignal configuration file. The [`working_directory_path`][ruby working_directory_path] value is a path to an existing directory on your host system. ```ruby Ruby theme={null} Appsignal.configure do |config| config.working_directory_path = "/tmp/project_1/" end ``` ```yaml YAML theme={null} production: working_directory_path: "/tmp/project_1/" ``` #### Read more * [Ruby integration `working_directory_path` config option details][ruby working_directory_path] [ruby working_directory_path]: /ruby/configuration/options.html#option-working_directory_path ### Elixir To set the working directory path in the Elixir integration, add the following to your AppSignal configuration file. The [`working_directory_path`][elixir working_directory_path] value is a path to an existing directory on your host system. ```elixir Elixir theme={null} config :appsignal, :config, working_directory_path: "/tmp/project_1/" ``` #### Read more * [Elixir integration `working_directory_path` config option details][elixir working_directory_path] [elixir working_directory_path]: /elixir/configuration/options.html#option-working_directory_path ### Node.js To set the working directory path in the Node.js integration, add the following to your AppSignal configuration file. The [`workingDirectoryPath`][nodejs working_directory_path] value is a path to an existing directory on your host system. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); const appsignal = new Appsignal({ // Other config workingDirectoryPath: "/tmp/project_1", }); module.exports = { appsignal }; ``` #### Read more * [Node.js integration `workingDirectoryPath` config option details][nodejs working_directory_path] [nodejs working_directory_path]: /nodejs/3.x/configuration/options.html#option-workingdirectorypath ### Python For the Python integration, two config options need to be changed. The first is the `working_directory_path` config option, and the other the `opentelemetry_port` config option. To set these config options in the Python integration, add the following to your AppSignal configuration file. The [`opentelemetry_port`][python opentelemetry_port] value is a number of a port that is available and the [`working_directory_path`][python working_directory_path] value is a path to an existing directory on your host system. These should be unique values per app. ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( # Other config opentelemetry_port: 9001, working_directory_path: "/tmp/project_1" ) ``` #### Read more * [Python integration `opentelemetry_port` config option details][python opentelemetry_port] * [Python integration `working_directory_path` config option details][python working_directory_path] [python opentelemetry_port]: /python/configuration/options.html#option-opentelemetry_port [python working_directory_path]: /python/configuration/options.html#option-working_directory_path ### Front-end JavaScript No working directory can be configured for Front-end JavaScript applications as it does not rely on the AppSignal agent process. If data is reported for the wrong application, please make sure the application is using the correct [Push API key](/appsignal/terminology#push-api-key) ## See also * [Application topic](/application/) * [Guides index](/guides/) # Configuring Applications Source: https://docs.appsignal.com/guides/configuration Add or change AppSignal configuration in Ruby, Elixir, Node.js, Python, or front-end JavaScript, using a file or environment variables. Welcome to our Configuration Guide. This guide will teach you how to add and modify configurations for your AppSignal integration. > [!TIP] > > Read more information about AppSignal integration configuration in your app in > our \[configuration section]\[config topic]. ## Choose a Configuration Option This guide will walk you through the steps necessary to configure your application to best suit your needs. There are, of course, multiple configuration options for your application, but since the implementation method for all options is identical, in this guide, we'll focus on the following configurations: We'll be using the `log_level` option as an example for [Ruby](/ruby/configuration/options#option-log_level), [Elixir](/elixir/configuration/options#option-log_level), [Node.js](/nodejs/3.x/configuration/options#option-loglevel) and [Python](/python/configuration/options#option-log_level) applications. We'll use the `namespace` option as an example for [Front-end JavaScript applications](/front-end/configuration). ## Configuration Methods There are multiple ways to configure your AppSignal integration, and integrations can vary depending on your application's language, but they all have the following configuration methods: * [File Based Configuration:](#file-based-configuration) \ A config file where the AppSignal integration reads the AppSignal configuration. * [System Environment Variable Configuration:][env] Environment variables are set on the host system (server) on the parent process that starts your application. \ **Note**: This method is not available for front-end JavaScript. ## File Based Configuration File-based configuration is the easiest way to configure your integration. Some integrations create a config file during the installation of AppSignal in the app. In these config files, you can uniquely configure one or multiple application environments. > [!TIP] > > Make sure to use the "Config file key" value from the config options table as > the config key. This key is either a snake\_cased (Ruby, Elixir, Python) or > camelCased string (Node, Front-End JavaScript). Config options for: * [Ruby](/ruby/configuration/options) * [Elixir](/elixir/configuration/options) * [Node.js](/nodejs/3.x/configuration/options) * [Python](/python/configuration/options) * [Front-end Javascript](/front-end/configuration/) * [Go](/go/configuration/options) > [!WARNING] > > Make sure to not check-in any sensitive configuration values, such as the Push > API key into a source-control management system like Git, unless they are > encrypted. ### Ruby When you install the Ruby gem, it creates a `config/appsignal.rb` file in your application's root folder with basic configuration settings. This file configures the gem in Ruby code with [the `Appsignal.configure` helper][ruby config]. If your application reports data to AppSignal without a config file, it's most likely using [system environment variables][env]. > [!TIP] > > Applications set up before Ruby gem version 4.2.0 may have a > `config/appsignal.yml` file instead. YAML configuration still works, but it's a > legacy method that will be removed in the next major version of the gem. The > \[Ruby configuration]\[ruby config] page documents both, and each example below > has a YAML tab showing the equivalent legacy config. The `config.env?` helper checks which environment AppSignal detected, so you can set an option for one environment only. In the example below, `log_level` is set to `debug` in the `development` environment, and left at its default everywhere else: ```ruby Ruby theme={null} # config/appsignal.rb Appsignal.configure do |config| # Enable AppSignal for these environments config.activate_if_environment(:development, :production) config.name = "My awesome app" config.push_api_key = "" if config.env?(:development) config.log_level = "debug" # This enables debug mode for only the development environment end end ``` ```yaml YAML theme={null} # config/appsignal.yml # Legacy config method default: &defaults # Shared configuration options for all environments active: true name: "My awesome app" push_api_key: "" development: # Development environment <<: *defaults log_level: "debug" # This enables debug mode for only the development environment production: # Production environment <<: *defaults ``` To apply an option to every environment, set it outside any `config.env?` block: ```ruby Ruby theme={null} # config/appsignal.rb Appsignal.configure do |config| config.activate_if_environment(:development, :production) config.name = "My awesome app" config.push_api_key = "" config.log_level = "debug" # This enables debug mode for all environments # Other AppSignal config... end ``` ```yaml YAML theme={null} # config/appsignal.yml # Legacy config method default: &defaults active: true name: "My awesome app" push_api_key: "" log_level: "debug" # This enables debug mode for all environments # Other AppSignal config... development: # Development environment <<: *defaults production: # Production environment <<: *defaults ``` Configuration options are set by calling writer methods on the `config` object, using the "Config file key" listed for each [configuration option](/ruby/configuration/options). For example, the [`send_params` option](/ruby/configuration/options#option-send_params) is set with `config.send_params = false`. That's how you configure AppSignal in a Ruby application. #### Read more * [Ruby configuration][ruby config] * [Ruby configuration load order](/ruby/configuration/load-order) ### Elixir Upon installation, the Elixir integration creates a `config/appsignal.exs` (default location) file with basic configurations. If this file is not present but your application reports data to AppSignal, check any of the other `.exs` files in the `config/` directory of your Elixir app. If no AppSignal configuration is present in any of the files, your application is likely using [system environment variables][env] as a configuration method instead. To add a configuration option and have it apply to all your application's environments, add the config option to the `config/appsignal.exs` file, like on line 7 of the example below: ```elixir Elixir theme={null} # Example: config/config.exs config :appsignal, :config, active: true, name: "My awesome app", push_api_key: "", env: Mix.env, log_level: "debug" # This sets the log_level to debug for all environments ``` To only apply the config option to a single environment, add the AppSignal configuration to the environment's config file, located in the `config/` directory. In the example below, the log\_level option has been added on line 3 of the development (or "dev") environment: ```elixir Elixir theme={null} # Example: config/dev.exs config :appsignal, :config, log_level: "debug" # This only sets the log_level to debug for the "dev" environment ``` Great, now you've learned how to configure AppSignal in your Elixir application! #### Read More * [Elixir Integration Configuration Topic](/elixir/configuration/) * [Elixir Integration Configuration Load Order Details](/elixir/configuration/load-order) ### Node.js After installation, you need to create an AppSignal config file to configure your application. If no file with AppSignal configuration is present, it is most likely using [system environment variables][env] as a configuration method instead. To configure AppSignal for Node.js apps, we recommend creating an `appsignal.js` file with the AppSignal config in your application's root or `src` directory. Then require/import it from the app's code before any other packages are required or imported. In the example below, there is an `appsignal.js` file in the root of the app directory. In this file, we'll add the `logLevel` config option. ```javascript Node.js theme={null} // appsignal.js const { Appsignal } = require("@appsignal/nodejs"); const appsignal = new Appsignal({ active: true, name: "", pushApiKey: "", logLevel: "debug", // Sets logLevel to debug for the Node.js environment }); module.exports = { appsignal }; ``` The config in the example above applies to the environment Node.js is running in (`NODE_ENV`, defaults to "development"). In Node.js there are many ways to create environment-specific configurations for AppSignal. If you are unsure how to do this within your own application, one method we recommend is using conditionals in your `appsignal.js`, such as in the example below where we specify debug for the production environment. 1. On line 4 - we only activate the AppSignal integration if the environment is production. 2. On line 8 - as in our previous code example we set the `logLevel` to `debug` ```javascript Node.js theme={null} // appsignal.js const appsignal = new Appsignal({ active: process.env.NODE_ENV === "production" name: "", pushApiKey: "", logLevel: "debug" // Sets logLevel to debug for the Node.js environment }); ``` Once your configuration is completed, you need to require `appsignal.js` at the very top of your app's main file. Your application's main file name may vary depending on how your application is structured. It is the file you use to start your Node application and is usually called `index.js` or `app.js`. Ensure AppSignal is required at the very top of the file like in the example below: ```javascript Node.js theme={null} // index.js // Place this at the top const { appsignal } = require("./appsignal"); // Update to the location used in the previous step // Place your app code below this ``` Great, now you've learned how to configure AppSignal in your Node.js application! #### Read More * [Node.js Integration Configuration][nodejs config] * [Node.js Integration Configuration Load Order](/nodejs/3.x/configuration/load-order) ### Python When using the Python integration installer, it will create the `__appsignal__.py` in your applications root folder, with basic configuration settings. Your application can also be configured using [system environment variables][env]. To add a configuration option and have it apply to your development application environment, add the config option to the `__appsignal__.py` file, like in the example below. ```python Python theme={null} # __appsignal__.py from appsignal import Appsignal appsignal = Appsignal( active=True, name="My awesome app", push_api_key="", environment="development", log_level="debug", ) ``` To configure AppSignal for Python for another environment, or apply the config to all to environments, configure the `environment` config option in the same way your app determines its environment (development/staging/production). This can be using a system environment variable or some other application specific method. In the example below we'll be using a system environment variable `MY_APP_ENV` to both set the app environment and only activate for the production environment. ```python Python theme={null} # __appsignal__.py import os from appsignal import Appsignal app_env = os.environ.get("MY_APP_ENV") appsignal = Appsignal( active=app_env == "production", name="My awesome app", push_api_key="", environment=app_env, ) ``` If you want some config options to only apply to certain environments, create conditionals to fit your needs. ```python Python theme={null} # __appsignal__.py import os from appsignal import Appsignal app_env = os.environ.get("MY_APP_ENV") options = { "active": app_env == "development", "name": "python/django4-celery", "environment": app_env, } if app_env == "development": options["log_level"] = "debug" appsignal = Appsignal(**options) ``` Great, now you've learned how to configure AppSignal in your Python application! #### Read More: * [Python Integration Configuration Topic][python config] * [Python Integration Configuration Load Order Details](/python/configuration/load-order) ### Front-end JavaScript To configure AppSignal for front-end JavaScript, we recommend creating an `appsignal.js` file with the AppSignal config in your project's root or `src` directory. Then require or import it from the app's code before any other packages are required or imported. In the example below, there is an `appsignal.js` file in the root of the applications directory. On line 8 we've added the `namespace` config option. ```javascript JavaScript theme={null} // appsignal.js import Appsignal from "@appsignal/javascript"; // For ES Module const Appsignal = require("@appsignal/javascript").default; // For CommonJS module const appsignal = new Appsignal({ key: "", namespace: "frontend", // Configure the AppSignal namespace for front-end errors in this app }); module.exports = { appsignal }; ``` Once you're done with your application's config, you need to require `appsignal.js` the very top of your application's main file, like in the example below: ```javascript JavaScript theme={null} // index.js // Place this at the top const { appsignal } = require("./appsignal"); // Update to the location used in the previous step // Place your app code below this ``` And that's it - you're ready to roll! Follow these simple steps for all future config option modifications. #### Read More * [Front-end JavaScript Integration Configuration](/front-end/configuration/) ## System Environment Variable Configuration > [!WARNING] > > This configuration method is not available for Front-end JavaScript. System environment variables, or "environment variables" for short, are variables that are accessible by processes, and are inherited from the parent process who starts them. Instead of using a [configuration file][file] for configuration, it's possible to configure AppSignal using only environment variables. It is also possible to store config keys that contain sensitive data, such as the Push API key in an environment variable, and use [config files][file] for the rest of the config. This configuration method is compatible with Ruby, Elixir, and Node.js applications. Before moving on to the following example of setting environment variables via a shell, let's explain how environment variables work concerning shells and processes. Environment variables can belong to a process such as a shell or your application. The command `export FOO=BAR`, for example, would set your shell's `FOO` environment variable to equal `BAR`. Environment variables are inherited between processes, so when that shell starts a new process, that process will also have any of the shell's environment variables. When you launch a process in the shell (i.e., npm start) you can also provide more environment variables for only that process by assigning the variables like so: `FOO=BAR npm start` For convenience, you may want to configure your shell to set certain environment variables when it starts, so that any processes started from that shell inherits those environment variables. If you're using the `bash` shell, the commands in the `.bash_profile` file in your home directory are executed when the shell is started. If using `zsh`, which is the default shell in macOS, the `.zshenv` file would be used instead to configure environment variables. In the example file below, we export the environment variables that configure AppSignal's push API key and log level, so that when a new shell is started, the correct environment variables are accessible to your application, allowing it to communicate with AppSignal. Config options set via environment variables apply to all application environments, however some config options are language specific. For example, the config option `instrument_sequel` only exists in the Ruby integration, because Sequel is a Ruby gem, and therefore setting the `APPSIGNAL_INSTRUMENT_SEQUEL` environment variable has no effect for other integrations. ```sh Shell theme={null} # Bash shell example export APPSIGNAL_PUSH_API_KEY= export APPSIGNAL_LOG_LEVEL=debug # Sets log_level to debug for all environments. ``` There are several possible locations for files with environment variables configuration. Please choose the best option that suits your application, and be sure to reload your terminal shell after making any changes to ensure it has access to your updated variables. * `~/.profile` or `~/.bash_profile` - User specific settings. Use this location to configure environment variables per user. * `/etc/profile` - System-wide settings. If multiple users or apps use the same host machine, do not use this location. Platform As A Service (PaaS) hosting providers like Heroku, do not provide a system for directly configuring environment variables in the shell. You can instead use their web interface or CLI to configure these environment variables. > [!NOTE] > > When using system environment variable based configuration, make sure to use > the "System environment key" value from the config options table as the config > key. This key is always is capitalized\* snake case, like this: > `EXAMPLE_OF_A_CONFIG_KEY` > > ***Fun Fact:** this is also known as SCREAMING\_SNAKE\_CASE 🐍* ## Completing The Configuration After changing your AppSignal configuration, your application needs to be restarted or deployed for the configuration changes to be detected by AppSignal. Are configuration changes not being detected? [Get in touch][contact], and we'll help you out! To help us debug your issue quicker, we recommend sending us a [diagnose report](/support/debugging#diagnose) from your application's host. ## Further Reading Read more about configuration in our [Application Configuration][config topic] documentation. [config topic]: /application/configuration.html [contact]: mailto:support@appsignal.com [env]: #system-environment-variable-configuration [file]: #file-based-configuration [nodejs config]: /nodejs/3.x/configuration/ [ruby config]: /ruby/configuration/ [python config]: /python/configuration/ # Data customization Source: https://docs.appsignal.com/guides/custom-data To help you keep an eye on errors and performance issues AppSignal allows you to provide the extra context by adding additional data to requests. ## Request Parameters [Request parameters](/guides/custom-data/request-parameters) are both request query parameters and POST request payloads. AppSignal captures these parameters to help you understand what specific input may have triggered an error or performance issue. ## Request Session Data [Request session data](/guides/custom-data/request-session-data) are values stored in a user's session, such as preferences and state. This data can help debug issues with specific states of a user session. ## Request Headers [Request headers](/guides/custom-data/request-headers) include metadata about the HTTP request, such as the User-Agent, Content-Type, and custom headers. Capturing these can help you debug issues related to browsers, platforms, API versions, etc. ## Function parameters [Function parameters](/guides/custom-data/function-parameters) are the parameters that background jobs or scripts start with. Capturing them can help you debug issues related to the initial context of those scripts. ## Custom Data [Custom data](/guides/custom-data/custom-data) lets you attach any additional information you consider useful that does not fit in any of the other data categories. # Add Custom Data Source: https://docs.appsignal.com/guides/custom-data/custom-data You can use custom sample data to set more dynamic values than is possible with [other types of data customization](/guides/custom-data). > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > Use [Link Templates](https://docs.appsignal.com/application/link-templates) to link them back in your app. See the table below for a list of accepted root values per language. Each nested object can contain values that result in valid JSON (strings, integers, floats, booleans, nulls, etc.). | Language | Accepted root values | | - | - | | Ruby | Arrays, Hashes | | JavaScript | Arrays, Objects | | Elixir | Lists, Maps | | Python | Lists, Maps | | PHP | Arrays, Objects | It is not possible to filter or search on the data set as custom data. It only provides an additional area in the interface to list more metadata. When using custom data for nested objects, you can view the object on the Incident Trace page for both Exception and Performance traces formatted as JSON, like in the example below: ```ruby Ruby theme={null} # Call `add_custom_data` multiple times to add more custom data # Hash example Appsignal.add_custom_data( :stroopwaffle => { :caramel => true }, :market => { :type => "outdoors" } ) Appsignal.add_custom_data(:market => { :state => :closed }) Appsignal.add_custom_data(:market => { :state => :open }) # Custom data: # { # :stroopwaffle => { :caramel => true }, # :market => { :state => :open } # } # Array example Appsignal.add_custom_data(["value 1"]) Appsignal.add_custom_data(["value 2"]) # Custom data: ["value 1", "value 2"] # Mixed data type example # The Hash and Array data type cannot be mixed at the root level Appsignal.add_custom_data(:market => :open) Appsignal.add_custom_data(["value 1"]) # Custom data: ["value 1"] ``` ```elixir Elixir theme={null} # Map Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "custom_data", %{ stroopwaffle: %{ caramel: true, origin: "market" } } ) # List Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "custom_data", [ "value 1", "value 2" ] ) ``` ```javascript Node.js theme={null} import { setCustomData } from "@appsignal/nodejs"; // Object setCustomData({ stroopwaffle: { caramel: true, origin: "market", }, }); // Array setCustomData(["value 1", "value 2"]); ``` ```python Python theme={null} from appsignal import set_custom_data # Map set_custom_data({ "stroopwaffle": { "caramel": true, "origin": "market" } }) # Array set_custom_data(["value 1", "value 2"]) ``` ```php PHP theme={null} [ 'caramel' => true, 'origin' => 'market', ], ]); ``` If the application sets custom data multiple times, the Ruby gem will merge values at the root level. For other integrations, only the last set value is stored. ![custom\_data](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/sample_data/custom-data.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=0219d24992c0f08a2cd65e2ced181c1e) # Add Function Parameters Source: https://docs.appsignal.com/guides/custom-data/function-parameters PHP, Python, Ruby, and the languages supported through our OpenTelemetry beta can set function parameters. Function parameters are designated for background jobs and scripts, not for storing parameters for each function call in a trace. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > Use [Link Templates](https://docs.appsignal.com/application/link-templates) to link them back in your app. For security and privacy we recommend [filtering function parameters](/guides/filter-data/filter-function-parameters) before sending them to our servers. See the table below for a list of accepted root values per language. Each nested object can contain values that result in valid JSON (strings, integers, floats, booleans, nulls, etc.). | Language | Accepted root values | | - | - | | Ruby | Arrays, Hashes | | Python | Lists, Dicts | | Go | JSON serialized string | | Java | JSON serialized string | | PHP | Arrays, Objects | The below code sample shows how to set custom request parameters: ```ruby Ruby theme={null} Appsignal.add_function_parameters( :param1 => "value1", :param2 => "value2", :nested => { :param3 => "value3", :param4 => "value4" } ) ``` ```python Python theme={null} from appsignal import set_function_parameters set_function_parameters({ "param1": "value1", "param2": "value2", "nested": { "param3": "value3", "param4": "value4", }, }) ``` ```go Go theme={null} // Additional setup is required to first fetch or create a new span import ( "encoding/json" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) params := map[string]interface{}{ "param1": "value1", "param2": "value2", "nested": map[string]interface{}{ "param3": "value3", "param4": "value4", }, } json, _ := json.Marshal(params) span.SetAttributes(attribute.String("appsignal.function.parameters", string(json))) ``` ```java Java theme={null} // Additional setup is required to first fetch or create a new span import io.opentelemetry.api.trace.Span; // We're using the Jackson JSON library // You may need to add it to your project as a dependency import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; Map params = new HashMap<>(); params.put("param1", "value1"); params.put("param2", "value2"); Map nested = new HashMap<>(); nested.put("param3", "value3"); nested.put("param4", "value4"); params.put("nested", nested); try { ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(params); Span span = Span.current(); span.setAttribute("appsignal.function.parameters", jsonString); } catch (Exception e) { // Add error handling here } ``` ```php PHP theme={null} 'value1', 'param2' => 'value2', 'nested' => [ 'param3' => 'value3', 'param4' => 'value4', ], ]; Appsignal::setFunctionParams($params); ``` For certain languages, additional setup is required. Please follow the instructions for these languages: * [Go](/go/custom-instrumentation) * [Java](/java/custom-instrumentation) ### Function parameters In [collector mode](/collector), function parameters are reported as their own attribute, separate from the [request payload](/guides/custom-data/request-parameters#request-payload-data) and the query parameters. Otherwise all three write to the same parameters and show up in the same box. See [parameter types](/guides/custom-data/request-parameters#parameter-types) for the three methods and when to use each. ## Limitations If the application sets function parameters multiple times, the latest set value is leading. # Add Request Headers Source: https://docs.appsignal.com/guides/custom-data/request-headers By default, the AppSignal integrations track request HTTP headers for web applications in supported libraries. You can set custom request headers on a transaction or span. Modifying the request headers will overwrite the data set by the AppSignal instrumentations. [All request headers are filtered](/guides/filter-data/filter-headers) by our integrations before being sent to our servers. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > Use [Link Templates](https://docs.appsignal.com/application/link-templates) to link them back in your app. See the table below for a list of accepted value types for request headers. | Language | Accepted header name | Accepted header value | | - | - | - | | Ruby | String | String | | Elixir | String | String | | Node.js | String | String | | Python | String | String | | Go | String | String, String slice | | Java | String | String, String array | | PHP | String | String, String array | The below code sample shows how to set custom request headers: ```ruby Ruby theme={null} # Call `add_headers` multiple times to set more headers Appsignal.add_headers("REQUEST_METHOD" => "GET", "REQUEST_PATH" => "/some-path") Appsignal.add_headers("PATH_INFO" => "/a-path") Appsignal.add_headers("PATH_INFO" => "/some-path") # Headers: # { # "REQUEST_METHOD" => "GET", # "REQUEST_PATH" => "/some-path", # "PATH_INFO" => "/some-path" # } ``` ```elixir Elixir theme={null} Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "environment", %{ "request_method" => "GET", "path_info" => "/some-path" } ) ``` ```javascript Node.js theme={null} import { setHeader } from "@appsignal/nodejs"; setHeader("request_method", "GET"); setHeader("path_info", "/some-path"); ``` ```python Python theme={null} from appsignal import set_header set_header("request_method", "GET"); set_header("path_info", "/some-path"); ``` ```go Go theme={null} // Additional setup is required to first fetch or create a new span span.SetAttributes(attribute.StringSlice("http.request.header.content-type", []string{"application/json"})) span.SetAttributes(attribute.StringSlice("http.request.header.custom-header"), []string{"abc", "def"}) ``` ```java Java theme={null} import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.common.AttributeKey; import java.util.Arrays; // Additional setup is required to first fetch or create a new span Span span = Span.current(); // Set single header values span.setAttribute("http.request.header.request-method", "GET"); span.setAttribute("http.request.header.path-info", "/some-path"); span.setAttribute("http.request.header.content-type", "application/json"); // Set header with multiple values (array) span.setAttribute( AttributeKey.stringArrayKey("http.request.header.custom-header"), Arrays.asList("value1", "value2") ); ``` ```php PHP theme={null} 'GET', 'path-info' => '/some-path', 'content-type' => 'application/json', ]); // Set header with multiple values (array) Appsignal::addHeaders([ 'custom-header' => ['value1', 'value2'], ]); ``` For certain languages, additional setup is required. Please follow the instructions for these languages: * [Go](/go/custom-instrumentation) * [Java](/java/custom-instrumentation) ![environment](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/sample_data/environment.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=a49d2e57199a1a6cedce022104387b96) ## Limitations Only the last value for a request header is stored if the application sets a request header multiple times. For Elixir, if the helper is called multiple times, only the last set of request headers (environment) is stored. # Add Request Parameters Source: https://docs.appsignal.com/guides/custom-data/request-parameters By default, the AppSignal integrations track request parameters for web requests in supported libraries. These include query parameters and the POST request body\*. For background jobs, we store the job arguments in the parameters. > [!TIP] > > \*: The AppSignal for PHP package and the languages supported through our [OpenTelemetry beta](/opentelemetry) store the request query parameters and request payload data separately. > See the [request payload data](#request-payload-data) section for more information on how to set request payload data separately. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > Use [Link Templates](https://docs.appsignal.com/application/link-templates) to link them back in your app. You can set custom parameters on a transaction or span. Modifying the parameters of a transaction will overwrite the data set by the AppSignal instrumentations. [All parameters are filtered](/guides/filter-data/filter-parameters) by our integrations before being sent to our servers. See the table below for a list of accepted root values per language. Each nested object can contain values that result in valid JSON (strings, integers, floats, booleans, nulls, etc.). | Language | Accepted root values | | - | - | | Ruby | Arrays, Hashes | | JavaScript | Arrays, Objects | | Elixir | Lists, Maps | | Python | Lists, Maps | | Go | JSON serialized string | | Java | JSON serialized string | | PHP | Arrays, Objects | The below code sample shows how to set custom request parameters: ```ruby Ruby 5.x theme={null} # Values are merged at the top level Appsignal.add_request_payload( :post => { :title => "My title", :body => "Post text." } ) Appsignal.add_request_payload(:user => { :login => "some_name" }) Appsignal.add_request_payload(:user => { :id => 123 }) # Parameters: # { # :post => { :title => "My title", :body => "Post text." }, # :user => { :id => 123 } # } ``` ```ruby Ruby 4.x theme={null} # Values are merged at the top level Appsignal.add_params( :post => { :title => "My title", :body => "Post text." } ) Appsignal.add_params(:user => { :login => "some_name" }) Appsignal.add_params(:user => { :id => 123 }) # Parameters: # { # :post => { :title => "My title", :body => "Post text." }, # :user => { :id => 123 } # } ``` ```elixir Elixir theme={null} Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "params", %{ post: %{ title: "My new blog post!", body: "Some long blog post text." } } ) ``` ```javascript Node.js theme={null} import { setParams } from "@appsignal/nodejs"; setParams({ post: { title: "My new blog post!", body: "Some long blog post text.", }, }); ``` ```python Python theme={null} from appsignal import set_params set_params({ post: { title: "My new blog post!", body: "Some long blog post text." } }) ``` ```go Go theme={null} // Additional setup is required to first fetch or create a new span import ( "encoding/json" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) params := map[string]interface{}{ "param1": "value1", "param2": "value2", "nested": map[string]interface{}{ "param3": "value3", "param4": "value4", }, } json, _ := json.Marshal(params) span.SetAttributes(attribute.String("appsignal.request.query_parameters", string(json))) ``` ```java Java theme={null} // Additional setup is required to first fetch or create a new span import io.opentelemetry.api.trace.Span; // We're using the Jackson JSON library // You may need to add it to your project as a dependency import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; Map queryParams = new HashMap<>(); queryParams.put("param1", "value1"); queryParams.put("param2", "value2"); Map nested = new HashMap<>(); nested.put("param3", "value3"); nested.put("param4", "value4"); queryParams.put("nested", nested); try { ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(queryParams); Span span = Span.current(); span.setAttribute("appsignal.request.query_parameters", jsonString); } catch (Exception e) { // Add error handling here } ``` ```php PHP theme={null} 'value1', 'param2' => 'value2', 'nested' => [ 'param3' => 'value3', 'param4' => 'value4', ], ]; Appsignal::setParams($params); ``` > [!NOTE] > > **Deprecated in [collector mode](/collector):** the helpers above do not say which type of parameters they are given, so everything they report becomes the request payload. They keep working in agent mode, and AppSignal warns the first time you use one in collector mode. See [parameter types](#parameter-types) for the helper that matches your data. For certain languages, additional setup is required. Please follow the instructions for these languages: * [Go](/go/custom-instrumentation) * [Java](/java/custom-instrumentation) ![params](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/sample_data/params.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=20e1ff3948a2f1fc3739ee2ea82a3ffb) ### Parameter types Request payloads, request query parameters and function parameters can be reported separately, through a helper of their own: ```ruby Ruby theme={null} # The body of a request. Appsignal.add_request_payload(:post => { :title => "My title" }) # The parameters read from a request's query string. Appsignal.add_query_parameters(:page => "2") # The arguments a background job or script was called with. Appsignal.add_function_parameters(:user_id => 123) ``` ```python Python theme={null} from appsignal import ( set_function_parameters, set_request_payload, set_request_query_parameters, ) # The body of a request. set_request_payload({"post": {"title": "My title"}}) # The parameters read from a request's query string. set_request_query_parameters({"page": "2"}) # The arguments a background job or script was called with. set_function_parameters({"user_id": 123}) ``` In [collector mode](/collector), each type is reported as its own attribute. You can [filter](/guides/filter-data/filter-parameters) and disable sending each one independently. In agent mode, all three write to the same attribute and appear in the same "Parameters" box. In Ruby, the values from the different calls are merged together. In Python, the last helper you call is the one whose values are reported. ## Request payload data The AppSignal for PHP package, version 5.0.0 and higher of the AppSignal for Ruby gem, and the languages supported through our [OpenTelemetry beta](/opentelemetry) store the request query parameters and request payload data separately. This section describes how to set the request payload data from POST requests. You can set custom request payload data on a span. Modifying the request payload data of a span will overwrite the data set by the AppSignal instrumentations. [All parameters are filtered](/guides/filter-data/filter-parameters) by our integrations before being sent to our servers. See the table below for a list of accepted root values per language. Each nested object can contain values that result in valid JSON (strings, integers, floats, booleans, nulls, etc.). | Language | Accepted root values | | - | - | | Ruby | Arrays, Hashes | | Go | JSON serialized string | | Java | JSON serialized string | | PHP | Arrays, Objects | The below code sample shows how to set custom request payload data: ```ruby Ruby theme={null} Appsignal.add_request_payload( :post => { :title => "My title", :body => "Post text." } ) ``` ```go Go theme={null} // Additional setup is required to first fetch or create a new span import ( "encoding/json" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) payload := map[string]interface{}{ "param1": "value1", "param2": "value2", "nested": map[string]interface{}{ "param3": "value3", "param4": "value4", }, } json, _ := json.Marshal(payload) span.SetAttributes(attribute.String("appsignal.request.payload", string(json))) ``` ```java Java theme={null} // Additional setup is required to first fetch or create a new span import io.opentelemetry.api.trace.Span; // We're using the Jackson JSON library // You may need to add it to your project as a dependency import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; Map payload = new HashMap<>(); payload.put("param1", "value1"); payload.put("param2", "value2"); Map nested = new HashMap<>(); nested.put("param3", "value3"); nested.put("param4", "value4"); payload.put("nested", nested); try { ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(payload); Span span = Span.current(); span.setAttribute("appsignal.request.payload", jsonString); } catch (Exception e) { // Add error handling here } ``` ```php PHP theme={null} 'value1', 'param2' => 'value2', 'nested' => [ 'param3' => 'value3', 'param4' => 'value4', ], ]; Appsignal::setPayload($payload); ``` For certain languages, additional setup is required. Please follow the instructions for these languages: * [Go](/go/custom-instrumentation) * [Java](/java/custom-instrumentation) ## Limitations If the application sets request query parameters or request payload data multiple times, the Ruby gem will merge values at the root level. For other integrations, only the last set value is stored. ## See also * [params.expect: strong parameters in Rails 8](/tutorials/ruby/params-expect): Rails 8 adds `params.expect` to permit and require parameters in one step. It rejects unexpected parameter shapes as bad requests. * [params.with\_defaults: default values for Rails parameters](/tutorials/ruby/parameters-with-defaults): set fallback values for parameters the browser may omit. Submitted values override these defaults. # Add Request Session Data Source: https://docs.appsignal.com/guides/custom-data/request-session-data By default, the AppSignal integrations will track request session data for web applications in supported libraries. You can set custom request session data on a transaction or span. Modifying the session data will overwrite the data set by the AppSignal instrumentations. [All request session data is filtered](/guides/filter-data/filter-session-data) by our integrations before being sent to our servers. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > Use [Link Templates](https://docs.appsignal.com/application/link-templates) to link them back in your app. See the table below for a list of accepted root values per language. Each nested object can contain values that result in valid JSON (strings, integers, floats, booleans, nulls, etc.). | Language | Accepted root values | | - | - | | Ruby | Arrays, Hashes | | JavaScript | Arrays, Objects | | Elixir | Lists, Maps | | Python | Lists, Maps | | Go | JSON serialized string | | Java | JSON serialized string | | PHP | Arrays, Objects | ```ruby Ruby theme={null} # Call `add_session_data` multiple times to set more session data Appsignal.add_session_data( :user_id => "123", :menu => { :type => "hamburger" } ) Appsignal.add_session_data(:menu => { :state => "closed" }) Appsignal.add_session_data(:menu => { :state => "open" }) # Session data: # { # :user_id => "123", # :menu => { :state => "open" } # } ``` ```elixir Elixir theme={null} Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "session_data", %{user_id: "123", menu: "open"} ) ``` ```javascript Node.js theme={null} import { setSessionData } from "@appsignal/nodejs"; setSessionData({ user_id: "123", menu: "open" }); ``` ```python Python theme={null} from appsignal import set_session_data set_session_data({"user_id": "123", "menu": "open"}) ``` ```go Go theme={null} // Additional setup is required to first fetch or create a new span import ( "encoding/json" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) session_data := map[string]interface{}{ "key1": "value1", "key2": "value2", "nested": map[string]interface{}{ "key3": "value3", "key4": "value4", }, } json, _ := json.Marshal(session_data) span.SetAttributes(attribute.String("appsignal.request.session_data", string(json))) ``` ```java Java theme={null} // Additional setup is required to first fetch or create a new span import io.opentelemetry.api.trace.Span; // We're using the Jackson JSON library // You may need to add it to your project as a dependency import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; Map sessionData = new HashMap<>(); sessionData.put("user_id", "123"); sessionData.put("menu", "open"); Map nested = new HashMap<>(); nested.put("key3", "value3"); nested.put("key4", "value4"); sessionData.put("nested", nested); try { ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(sessionData); Span span = Span.current(); span.setAttribute("appsignal.request.session_data", jsonString); } catch (Exception e) { // Add error handling here } ``` ```php PHP theme={null} 'value1', 'param2' => 'value2', 'nested' => [ 'param3' => 'value3', 'param4' => 'value4', ], ]; Appsignal::setSessionData($data); ``` For certain languages, additional setup is required. Please follow the instructions for these languages: * [Go](/go/custom-instrumentation) * [Java](/java/custom-instrumentation) ![session\_data](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/sample_data/session-data.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=33aa45b3b82dd9c45234e7ea4fbf2c19) ## Limitations If the application sets session data multiple times, the Ruby gem will merge values at the root level. For other integrations, only the last set value is stored. # Reporting deploys to track improvements Source: https://docs.appsignal.com/guides/deploy-markers How your application functions can change with each new deployment. When tracking your deploys with AppSignal, error incidents and performance measurements are grouped per deployment, so you can easily see what impacts your deployment has had on your application's performance and error rate. AppSignal can take you from an [error backtrace][error backtrace links] to the line of code from which a specific error originated, and this help This guide will show you how to track deploys in AppSignal using deploy markers. > [!TIP] > > Read more in-depth information about \[deploy markers]\[deploy markers] and what > they're used for. ## Configuring AppSignal This guide will use the `revision` config option method of reporting deploy markers. You can read about alternative approaches to this in our [Deploy Markers] documentation. The `revision` config option is configured differently per integration language. See the list of integrations below for the one your app uses. Note that AppSignal will [automatically report a deploy][automatic report] when using platforms such as Heroku or Render, or deployment orchestrators such as Kamal. ### Automatically Update the Revision We recommend dynamically fetching the revision config option value from the source control management used for your project (such as Git or SVN) on start or deploy. This way, the value doesn't have to be manually updated per deploy. If a Git commit hash is used, it will also be compatible with [error backtrace links]. Below is an example of how you would do this using Git: ```bash Bash theme={null} git rev-parse --short HEAD # Will output the current commit's short SHA ``` We'll continue to use Git for all integration examples in this documentation. Whichever source you use, keep the revision to a single value without spaces, such as a Git commit SHA or a version number. AppSignal builds links to your source code from the revision, so a value your Git host cannot resolve produces links that do not open the code they name. Read more about [choosing a revision value][revision value]. ## Configurations per Language * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Front-end JavaScript](#front-end-javascript) * [Go](#go) * [Java](#java) * [PHP](#php) ### Ruby For Ruby applications we will load the Git revision from the config file. The shell command that we run in the `revision` configuration option is the same command we used [previously](#automatically-update-the-revision) to retrieve the hash of the current commit. We call the `git rev-parse` command and set the output as the `revision` config option, as shown in the example below: ```ruby Ruby theme={null} Appsignal.configure do |config| config.revision = `git rev-parse --short HEAD`.strip end ``` ```yaml YAML theme={null} production: revision: "<%= `git rev-parse --short HEAD`.strip %>" # Other config options ``` #### Using Ruby deploy gems Deployment tools like [Capistrano](https://github.com/capistrano/capistrano) and [Hatchbox](https://www.hatchbox.io/) exclude the `.git` folder from the deployed application, so the `git rev-parse` command in the previous example cannot find the revision. These tools write a `REVISION` file with the deployed Git commit SHA to the release folder instead. From Ruby gem 4.6.0, AppSignal reads this file and sets the `revision` config option to its contents. If your deployment tool does not write a `REVISION` file, create one in the application's root directory during the deploy: ```bash Bash theme={null} git rev-parse --short HEAD > REVISION ``` Heroku, Render, Kamal and Scalingo set the revision in an environment variable, which AppSignal also reads automatically. The `revision` option page lists [which source AppSignal uses](/ruby/configuration/options#option-revision) when more than one is set. On Ruby gem versions older than 4.6.0, read the `REVISION` file in your configuration. Below is an example for `Rails`: ```ruby Ruby theme={null} Appsignal.configure do |config| revision = Rails.root.join("REVISION") if defined?(Rails) config.revision = revision.read.strip[0, 7] if revision&.exist? end ``` ```yaml YAML theme={null} production: <% revision = if (defined?(Rails)); Rails.root.join('REVISION'); end %> <% if revision&.exist? %> revision: "<%= revision.read.strip[0, 7] %>" <% end %> ``` [Read more about Ruby `revision` configuration option details](/ruby/configuration/options#option-revision) ### Elixir For Elixir applications we will load the Git revision in the `config/appsignal.exs` config file (your file location may differ). In the example `config/appsignal.exs` file below, we call the `git rev-parse` command with Elixir and set the output as the `revision` config option. ```elixir Elixir theme={null} # Example: config/appsignal.exs {revision, _exitcode} = System.cmd("git", ["log", "--pretty=format:%h", "-n 1"]) config :appsignal, :config, revision: revision # Other config options ``` [Read more about Elixir `revision` configuration option details](/elixir/configuration/options#option-revision) ### Node.js For Node.js applications, the Git revision is loaded in the app's config file. In the below `.js` snippet we call the `git rev-parse` command with Node.js and set the output as the `revision` config option. ```javascript Node.js theme={null} // Example: appsignal.js const childProcess = require("child_process"); const REVISION = childProcess.execSync("git rev-parse --short HEAD").toString(); const appsignal = new Appsignal({ revision: REVISION, // Other config }); module.exports = { appsignal }; ``` [Read more about Node.js `revision` configuration option details](/nodejs/3.x/configuration/options#option-revision) ### Python For Python applications, the Git revision is loaded in the application's `__appsignal__.py` config file. In the example below, we call the `git rev-parse` command with Python and set the output as the `revision` config option. The shell command that we run is the same command we used [previously](#automatically-update-the-revision) to retrieve the hash of the current commit. ```python Python theme={null} # Example: __appsignal__.py import subprocess from appsignal import Appsignal revision = subprocess.check_output( "git rev-parse --short HEAD", shell=True, text=True ).strip() appsignal = Appsignal( # Other config revision=revision ) ``` [Read more about the Python `revision` configuration option details](/python/configuration/options#option-revision) ### Front-end JavaScript Because Front-end JavaScript applications run in-browser, it is not possible to call the `git` executable command from your front-end application to get the current `revision`. There are two common approaches to pass the revision value to your front-end application: #### Using build-time environment variables (recommended for decoupled front-ends) Modern front-end build tools embed environment variables into your bundle at build time. You can pass the Git revision through one of these variables and reference it in your AppSignal config. The variable prefix and access pattern depend on your build tool. The example below uses **Vite**, which exposes environment variables prefixed with `VITE_` through the `import.meta.env` object. Set the variable before building: ```bash Bash theme={null} export VITE_REVISION=$(git rev-parse --short HEAD) npm run build ``` Then read it in the file where you configure AppSignal: ```javascript JavaScript theme={null} // Example: appsignal.js export const appsignal = new Appsignal({ revision: import.meta.env.VITE_REVISION, // Other config }); ``` Import the configured `appsignal` instance wherever you initialize your app. For example, in a Vue application's `main.js`: ```javascript JavaScript theme={null} // Example: main.js import { createApp } from "vue"; import App from "./App.vue"; import { appsignal } from "./appsignal"; import { errorHandler } from "@appsignal/vue"; const app = createApp(App); app.config.errorHandler = errorHandler(appsignal, app); app.mount("#app"); ``` #### Using a back-end rendered HTML attribute If your front-end is rendered by a back-end application (such as a Ruby or Elixir application), you can define the `revision` value in the HTML body as a data attribute: ```html HTML theme={null} ``` Then retrieve this value in your JavaScript: ```javascript JavaScript theme={null} // Example: appsignal.js const body = document.body; export const appsignal = new Appsignal({ revision: body.dataset.appRevision, // Other config }); ``` [Read more about JavaScript `revision` configuration option details](/front-end/configuration/options#revision) ### Go For Go applications, the revision is set on an OpenTelemetry resource attribute when OpenTelemetry is initialized. In the example below, we call the `git rev-parse` command and set the output as the `appsignal.config.revision` resource attribute. The shell command that we run is the same command we used [previously](#automatically-update-the-revision) to retrieve the hash of the current commit. ```go Go theme={null} import ( "os/exec" // And other imports ) var revision string cmd := exec.Command("git", "rev-parse", "--short", "HEAD") output, err := cmd.Output() if err != nil { revision = "unknown" } else { revision = strings.TrimSpace(string(output)) } res := resource.NewWithAttributes( resource.WithAttributes(attribute.String("appsignal.config.revision", revision)), // And other resource attributes ) ``` For Go applications the [`appsignal.config.revision` config option][go revision option] is required configuration, so it should already be set. Please consult the [`appsignal.config.revision` config option][go revision option] for more information. [go revision option]: /go/configuration/options.html#option-revision ### Java For Java applications, set the revision using the `OTEL_RESOURCE_ATTRIBUTES` environment variable. We'll use the same Git command as shown [previously](#automatically-update-the-revision). ```bash Bash theme={null} export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.revision=$(git rev-parse --short HEAD),\ ..." ``` For Java applications the [`appsignal.config.revision` config option][java revision option] is required configuration, so it should already be set. Please consult the [`appsignal.config.revision` config option][java revision option] for more information. [java revision option]: /java/configuration/options.html#option-revision ### PHP For PHP applications, set the revision in your configuration to override the default. By default, AppSignal sets the revision using the same Git command shown in [Automatically update the revision](#automatically-update-the-revision). ```php PHP theme={null} $revision = trim(shell_exec('git rev-parse --short HEAD 2>/dev/null')) ?: 'unknown'; return [ 'revision' => $revision, // ... other options ]; ``` Please consult the [`appsignal.config.revision` config option][php revision option] for more information. [php revision option]: /php/configuration/options.html#option-revision ## Deploy When finished configuring the `revision` option, commit your changes and deploy your application. When the app starts/restarts, AppSignal will create a deploy in the [deploys section] for your app. That's it! You've successfully configured your application to notify AppSignal of deploys! Your application's data will be tracked alongside the appropriate deployment, helping level up your ability to analyze your application's performance. Are deploys not being reported or incorrectly? [Contact us][contact] and we will help you out! ## See also * [Local CI in Rails 8.1: run checks and sign off on GitHub](/tutorials/ruby/local-ci): run checks locally with `bin/ci` and post a passing result to a GitHub pull request. Use deploy markers to record when each revision reaches production. [deploy markers]: /application/markers/deploy-markers.html [revision value]: /application/markers/deploy-markers.html#choosing-a-revision-value [automatic report]: /application/markers/deploy-markers.html#revision-config-option [error backtrace links]: /application/backtrace-links.html [deploys section]: https://appsignal.com/redirect-to/app?to=markers [contact]: mailto:support@appsignal.com # Filtering Application Data Source: https://docs.appsignal.com/guides/filter-data To help you find the cause of an issue, AppSignal gathers relevant error and performance measurement data by default. In some instances, your AppSignal integration may be collecting too much or too little app-specific data. > [!WARNING] > > Your application should not collect user-identifiable information (such as > personal names, email addresses, passwords, etc.). Use the tools described in > this guide to limit and filter out this data. You can configure AppSignal what kind of data it should not collect by filtering parameters, headers and session data: * [Filter request parameters](/guides/filter-data/filter-parameters) * [Filter request headers](/guides/filter-data/filter-headers) * [Filter session data](/guides/filter-data/filter-session-data) * [Filter function parameters](/guides/filter-data/filter-function-parameters) You can also configure AppSignal to ignore certain actions, errors, log messages and namespaces, based on their name or contents: * [Ignore actions](/guides/filter-data/ignore-actions) * [Ignore errors](/guides/filter-data/ignore-errors) * [Ignore logs](/guides/filter-data/ignore-logs) * [Ignore namespaces](/guides/filter-data/ignore-namespaces) # Filter function parameters Source: https://docs.appsignal.com/guides/filter-data/filter-function-parameters You can store function parameters for languages supported through our OpenTelemetry beta Storing function parameters makes it possible to view the parameters that background jobs or scripts started with. It's not meant to store the parameters for each function call in a trace, only the top-level parameters. Function parameter data may contain user-identifiable information such as email addresses, API tokens, etc. To protect your application's sensitive data, you must ensure this data is filtered out before being sent to the AppSignal servers. This way, your application doesn't leak any sensitive data. > [!WARNING] > > Your application should not collect user-identifiable information (such as > personal names, email addresses, passwords, etc.). Use the tools described in > this guide to limit and filter out this data. ## Function Parameter Filtering Function parameter filtering works with a denylist: a list of keys to filter out and not to send. You can set a "filter function parameters" option with a list of parameter keys to filter. Values of parameters you've configured to filter out will be replaced with a `[FILTERED]` value. This way, the list of parameters in the app data on AppSignal.com still includes the parameter key but not the value, so you still have visibility that a value had potentially sensitive data filtered out before being sent to AppSignal. ### Example For example, an application with this AppSignal config: ```yaml YAML theme={null} filter_function_parameters: ["secret_key"] ``` Results in this view for the parameters of a trace on AppSignal.com: ```json JSON theme={null} { "secret_key": "[FILTERED]" } ``` This guide will show you how to configure your application's function parameter filtering denylist based on what language your application uses: * [Go](#go) * [Java](#java) * [PHP](#php) ## Go Use the [`filter_function_parameters` denylist](/go/configuration/options#option-filter_function_parameters) for function parameter filtering. Set the [`send_function_parameters` option](/go/configuration/options#option-send_function_parameters) to `true` to avoid sending any function parameters. For more information on configuring OpenTelemetry for Go apps, see the [Go configuration page](/go/configuration/options). ```go Go theme={null} res := resource.NewWithAttributes( attribute.StringSlice("appsignal.config.filter_function_parameters", []string{"api_token", "secret"}), ) ``` ## Java Use the [`filter_function_parameters` denylist](/java/configuration/options#option-filter_function_parameters) for function parameter filtering. Set the [`send_function_parameters` option](/java/configuration/options#option-send_function_parameters) to `true` to avoid sending any function parameters. For more information on configuring OpenTelemetry for Java apps, see the [Java configuration page](/java/configuration/options). ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.filter_function_parameters=$(encode "api_token,secret"),\ ..." ``` ## PHP Use the [`filter_function_parameters` denylist](/php/configuration/options#option-filter_function_parameters) for function parameter filtering. Set the [`send_function_parameters` option](/php/configuration/options#option-send_function_parameters) to `true` to avoid sending any function parameters. For more information on configuring AppSignal for PHP, see the [PHP configuration page](/php/configuration/options). ```php PHP theme={null} return [ 'filter_function_parameters' => ['api_token', 'secret'], // ... other options ]; ``` # Request Header Collection Source: https://docs.appsignal.com/guides/filter-data/filter-headers AppSignal collects a limited set of HTTP request headers by default for supported frameworks. These headers can help track down errors or performance issues caused by a client request. To comply with [GDPR](/appsignal/gdpr), AppSignal keeps this default set small, collecting no user identifiable data. You can limit it further by configuring which headers AppSignal collects. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). ## Configure Headers Request headers are configured in an *allowlist*. AppSignal collects the headers on the list, and neither the name nor the value of any other header outside of it. Header names are lowercase and dash-separated, the way an HTTP request writes them. Report the `X-Custom-Header` header by adding `x-custom-header` to the list. [AppSignal for Ruby](#ruby) names them differently when it reports to the agent. This guide will show you how to configure your application's request header filtering allowlist based on what language your application uses: * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Go](#go) * [Java](#java) * [PHP](#php) ## Ruby AppSignal automatically stores the configured request headers in the Ruby integration for Rails apps and other frameworks. It reads them from the [Rack](https://rack.github.io/) environment, which names a header's key by prefixing it with `HTTP_`, uppercasing it, and replacing dashes (`-`) with underscores (`_`). So `X-Custom-Header` becomes `HTTP_X_CUSTOM_HEADER`. `CONTENT_LENGTH` and `CONTENT_TYPE` are the two keys Rack does not prefix. The [`request_headers`][ruby request headers] config option lists those Rack keys. Some of them hold values other than headers, such as `REQUEST_METHOD` and `SERVER_NAME`. * [Default list of request headers][ruby request headers] ```ruby Ruby theme={null} Appsignal.configure do |config| config.request_headers += ["HTTP_X_CUSTOM_HEADER"] end ``` ```yaml YAML theme={null} production: request_headers: # Example list of Rack environment keys - HTTP_ACCEPT - HTTP_X_CUSTOM_HEADER ``` ### Ruby in collector mode When AppSignal for Ruby reports to [a collector](/ruby/configuration/collector), it reports request headers under their HTTP names, and reports the rest of the Rack environment separately. Two config options replace `request_headers`: * [`keep_request_headers`][ruby keep request headers] lists request headers, named the way an HTTP request writes them. Report the `X-Custom-Header` header by adding `x-custom-header` to the list. * [`keep_request_environment`][ruby keep request environment] lists the Rack environment keys to report that represent information other than headers, such as `REMOTE_ADDR`. ```ruby Ruby theme={null} Appsignal.configure do |config| config.keep_request_headers += ["x-custom-header"] config.keep_request_environment += ["REMOTE_ADDR"] end ``` ```yaml YAML theme={null} production: keep_request_headers: - accept - x-custom-header keep_request_environment: - REMOTE_ADDR ``` Until you set these configuration options, AppSignal derives their values from `request_headers`, so that the same headers are reported in collector mode as they were in agent mode. ## Elixir AppSignal automatically stores the configured request headers for Phoenix apps and other frameworks in the Elixir integration. It has a built-in list of request headers collected by default which you can customize using the [request\_headers][elixir request headers] config option. * [Default list of request headers][elixir request headers] To configure which request headers to collect for each request, add the following configuration to your `config/appsignal.exs` file in the environment group where you want it to apply. The [request\_headers][elixir request headers] value is a list of strings. ```yaml YAML theme={null} config :appsignal, :config, request_headers: ~w( path-info request-method request-uri server-name server-port server-protocol ) # Example list of headers ``` ## Node.js In the Node.js integration, AppSignal automatically stores the configured request headers for Express apps and other frameworks. It has a built-in list of request headers to collect by default that you can customize with the [requestHeaders][node request headers] config option. * [Default list of request headers][node request headers] To configure which request headers to collect for each request, add the following configuration to your AppSignal client instance creation. The [requestHeaders][node request headers] value is an array of strings. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ requestHeaders: ["accept", "cache-control", "content-length", "range"], }); ``` ## Python In the Python integration, if an app sets request headers, AppSignal will automatically collect the configured request headers. It has a built-in list of request headers to collect by default that you can customize with the [request\_headers][python request headers] config option. * [Default list of request headers][python request headers] To configure which request headers to collect for each request, add the following configuration to your AppSignal client instance creation. The [`request_headers`][python request headers] value is a list of strings. ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( # Other config request_headers=["accept", "cache-control", "content-length", "range"], ) ``` ## Go If an app records request headers, AppSignal will automatically filter the configured request headers. It has a built-in list of request headers to collect by default that you can customize with the [`request_headers` config option][go request headers]. * [Default list of request headers][go request headers] See the [Go configuration page](/go/configuration/options) for more information on how to configure OpenTelemetry for Go apps. To configure which request headers to collect for each request, add the following configuration to your AppSignal client instance creation. The [`request_headers`][go request headers] value is a slice of strings. ```go Go theme={null} res := resource.NewWithAttributes( // Only send these specific headers attribute.StringSlice("appsignal.config.request_headers", []string{"accept", "request_method", "content_length"}), // Do not send any headers attribute.StringSlice("appsignal.config.request_headers", []string{}), ) ``` ## Java In the Java integration, if an app sets request headers, AppSignal will automatically collect the configured request headers. It has a built-in list of request headers to collect by default that you can customize with the [`request_headers`][java request headers] config option. * [Default list of request headers][java request headers] To configure which request headers to collect for each request, add the following configuration. The [`request_headers`][java request headers] value is an array of strings. ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.request_headers=$(encode "accept,cache-control,content-length,range"),\ ..." # Do not send any headers export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.request_headers=,\ ..." ``` ## PHP In the PHP integration, if an app sets request headers, AppSignal will automatically collect the configured request headers. It has a built-in list of request headers to collect by default that you can customize with the [`request_headers`][php request headers] config option. * [Default list of request headers][php request headers] To configure which request headers to collect for each request, add the following configuration. The [`request_headers`][php request headers] value is an array of strings. ```php PHP theme={null} return [ // Send selected headers 'request_headers' => ['accept', 'cache-control', 'content-length', 'range'], // Do not send any headers 'request_headers' => [], // ... other options ]; ``` [elixir request headers]: /elixir/configuration/options.html#option-request_headers [node request headers]: /nodejs/3.x/configuration/options.html#option-requestheaders [ruby request headers]: /ruby/configuration/options.html#option-request_headers [ruby keep request headers]: /ruby/configuration/options.html#option-keep_request_headers [ruby keep request environment]: /ruby/configuration/options.html#option-keep_request_environment [python request headers]: /python/configuration/options.html#option-request_headers [go request headers]: /go/configuration/options.html#option-request_headers [java request headers]: /java/configuration/options.html#option-request_headers [php request headers]: /php/configuration/options.html#option-request_headers # Filter request parameters Source: https://docs.appsignal.com/guides/filter-data/filter-parameters Every time a request is made on your application, AppSignal collects the parameters sent with that request. This includes form data (POST), query parameters, and keys in routes (e.g., /user/:id/) in some frameworks. This data could contain user-identifiable information such as names, email addresses, passwords, two-factor authentication codes, API tokens, etc. To protect your application's sensitive data, you must ensure this data is filtered out before being to the AppSignal servers. This way, your application doesn't leak any sensitive data. > [!TIP] > > Read more about parameter filtering in our \[Parameter Filtering]\[parameter > filtering] documentation. > [!WARNING] > > Your application should not collect user-identifiable information (such as > personal names, email addresses, passwords, etc.). Use the tools described in > this guide to limit and filter out this data. ## Parameter Filtering Basic parameter filtering in the AppSignal integrations works with a denylist, a list of keys to filter out and to not send. You can set a "filter parameters" option in the AppSignal configuration with a list of parameter keys to filter. Parameter values you've configured to filter out by will be replaced with a `[FILTERED]` value. This way, the list of parameters in the app data on AppSignal.com still includes the parameter key but not the value, so you still have visibility that a value had potentially sensitive data filtered out before being sent to AppSignal. > [!TIP] > > Some [parameter keys are also removed by our > processor](/application/parameter-filtering#processor-parameter-filtering) > on our servers. ### Example For example, an application with this AppSignal config: ```yaml YAML theme={null} filter_parameters: ["password"] ``` Results in this view for the parameters of a web request on AppSignal.com: ```json JSON theme={null} { "password": "[FILTERED]" } ``` This guide will show you how to configure your application's parameter filtering denylist based on what language your application uses: * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Go](#go) * [Java](#java) * [PHP](#php) ## Ruby The [AppSignal for Ruby](/ruby) gem has two parameter filtering methods: * If your app uses Rails, you can use the [Rails configuration directly](/guides/filter-data/filter-parameters#rails-parameter-filtering). * If your app uses another framework, like Sinatra or Padrino, you can use [AppSignal's built-in filtering](#rails-parameter-filtering) instead. ### AppSignal Parameter Filtering Use the denylist for basic parameters filtering. This parameter filtering is applied to any query parameters in an HTTP request and any argument for background jobs. This filtering supports key based filtering for hashes, which will have their values replaced with `[FILTERED]`. There's support for nested hashes and nested hashes in arrays. Any hash we encounter in your parameters will be filtered. To use this filtering, add the following to your `config/appsignal.yml` file in the environment group you want it to apply. The [`filter_parameters`](/ruby/configuration/options#option-filter_parameters) value is an array of strings. ```ruby Ruby theme={null} Appsignal.configure do |config| config.filter_parameters << "password" end ``` ```yaml YAML theme={null} production: filter_parameters: - password - confirm_password ``` ### Rails Parameter Filtering Luckily Rails provides a request parameter filtering mechanism to scrub data from log files. AppSignal leverages this request parameter mechanism so both your request logs and the request data sent to AppSignal are filtered by one configuration. Suppose the application should filter the same keys for request parameters and job arguments reported for different Ruby gems, like Sidekiq job arguments. In that case, it's necessary to configure the parameter filtering in AppSignal using the [`filter_parameters` option](/ruby/configuration/options#option-filter_parameters) to also include the keys set in the Rails config as it will not reuse the Rails parameter filtering configuration for those gems. #### Denylist: Filtering Specific Keys There are two ways to determine which keys get filtered. The first one is adding specific keys to the denylist. In the below example, the value of `:secret` in any post in the app will be replaced with `[FILTERED]`. ```ruby Ruby theme={null} module Blog class Application < Rails::Application config.filter_parameters << :secrets end end ``` The downside of this approach is that it is more complicated when dealing with larger, more complex applications, especially when using features like `accepts_nested_attributes_for`. If we forget to explicitly add keys, they will not be filtered. #### Allowlist: Allowing Specific Keys Using a lambda instead of a list of keys gives more flexibility. In the following example, we use a lambda to set up an allowlist instead of a denylist. ```ruby Ruby theme={null} ALLOWED_KEYS_MATCHER = /((^|_)ids?|action|controller|code$)/.freeze SANITIZED_VALUE = '[FILTERED]'.freeze Rails.application.config.filter_parameters << lambda do |key, value| unless key.match(ALLOWED_KEYS_MATCHER) value.replace(SANITIZED_VALUE) if value.is_a?(String) end end ``` You can make the lambda check any key you'd like, so you can determine and use a filtering method that best suits your application's needs. Some further information about filtering parameters can be found in the Rails guides about [ActionController](http://guides.rubyonrails.org/action_controller_overview.html#parameters-filtering). ## Elixir If your app uses Phoenix, you can use the [Phoenix parameter filtering](/guides/filter-data/filter-parameters#phoenix-filter_parameters-configuration). You can use AppSignal's built-in filtering if your app uses a different Elixir framework. ### AppSignal parameter filtering Use the denylist for basic parameters filtering. This parameter filtering is applied to any query parameters in an HTTP request. Set up parameter filtering using the [`filter_parameters` config option](/elixir/configuration/options#option-filter_parameters). The filter\_parameters value is a List of Strings. ```elixir Elixir theme={null} config :appsignal, :config, filter_parameters: ["password", "secret"] ``` ### Phoenix filter\_parameters Configuration Use Phoenix's parameter filtering to centralize your config, which is used to keep sensitive information from the logs. AppSignal will follow these filtering rules. ```elixir Elixir theme={null} config :phoenix, :filter_parameters, ["password", "secret"] ``` If the `filter_parameters` config option is not set, Phoenix will default to `["password"]` as a config. This means that a Phoenix app will not send any passwords to AppSignal without any configuration. ## Node.js Use the `filterParameters` denylist for basic parameter filtering. This filtering is applied to all parameters of an HTTP request. You can set up parameter filtering using the [`filterParameters` config option](/nodejs/3.x/configuration/options#option-filterparameters). The `filterParameters` value is an array of strings. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ // Other config options filterParameters: ["password", "secret"], }); ``` ## Python Use the `filter_parameters` denylist for basic parameter filtering. This filtering is applied to all parameters of an HTTP request. You can set up parameter filtering using the [`filter_parameters` config option](/python/configuration/options#option-filter_parameters). The `filter_parameters` value is an array of strings. ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( # Other config filter_parameters: ["password", "secret"] ) ``` ## Go For Go, we report the request parameters as query parameters (`?query=text`) and payload data (POST request payload). Use the [`filter_request_query_parameters` denylist](/go/configuration/options#option-filter_request_query_parameters) for request query parameter filtering. Set the [`send_request_query_parameters` option](/go/configuration/options#option-send_request_query_parameters) to `false` to not send any request query parameters at all. Use the [`filter_request_payload` denylist](/go/configuration/options#option-filter_request_payload) for request payload data filtering. Set the [`send_request_payload` option](/go/configuration/options#option-send_request_payload) to `false` to not send any request payload data at all. See the [Go configuration page](/go/configuration/options) for more information on how to configure OpenTelemetry for Go apps. ```go Go theme={null} res := resource.NewWithAttributes( attribute.StringSlice("appsignal.config.filter_request_query_parameters", []string{"password", "cvv"}), attribute.StringSlice("appsignal.config.filter_request_payload", []string{"password", "cvv"}), ) ``` ## Java For Java, we report the request parameters as query parameters (`?query=text`) and payload data (POST request payload). Use the [`filter_request_query_parameters` denylist](/java/configuration/options#option-filter_request_query_parameters) for request query parameter filtering. Set the [`send_request_query_parameters` option](/java/configuration/options#option-send_request_query_parameters) to `false` to not send any request query parameters at all. Use the [`filter_request_payload` denylist](/java/configuration/options#option-filter_request_payload) for request payload data filtering. Set the [`send_request_payload` option](/java/configuration/options#option-send_request_payload) to `false` to not send any request payload data at all. See the [Java configuration page](/java/configuration/options) for more information on how to configure OpenTelemetry for Java apps. ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.filter_request_query_parameters=$(encode "password,cvv"),\ appsignal.config.filter_request_payload=$(encode "password,cvv"),\ ..." ``` ## PHP For PHP, we report the request parameters as query parameters (`?query=text`) and payload data (POST request payload). Use the [`filter_request_query_parameters` denylist](/php/configuration/options#option-filter_request_query_parameters) for request query parameter filtering. Set the [`send_request_query_parameters` option](/php/configuration/options#option-send_request_query_parameters) to `false` to not send any request query parameters at all. Use the [`filter_request_payload` denylist](/php/configuration/options#option-filter_request_payload) for request payload data filtering. Set the [`send_request_payload` option](/php/configuration/options#option-send_request_payload) to `false` to not send any request payload data at all. See the [PHP configuration page](/php/configuration/options) for more information on how to configure AppSignal for PHP. ```php PHP theme={null} return [ 'filter_request_query_parameters' => ['password', 'cvv'], 'filter_request_payload' => ['password', 'cvv'], // ... other options ]; ``` [parameter filtering]: /application/parameter-filtering.html # Filter Session Data Source: https://docs.appsignal.com/guides/filter-data/filter-session-data Every time a request is made on a web app, AppSignal collects the session data that were sent with the request for supported frameworks. Sessions contain data specific to your application, but some dependencies an app uses may store data here as well. For example: when a user signs in, some data of the user who is signed in is stored in a session. Sessions can contain sensitive or personally identifiable information that should not leave the app. Make sure this data is filtered out before it is sent to the AppSignal servers, this way the app doesn't leak any sensitive data. > [!TIP] > > Read more about session data filtering and what types of session data to set > up filtering for in our \[session data filtering topic]\[session data > filtering]. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). ## Session Data Filtering Basic session data filtering in the AppSignal integrations works with a denylist, a list of keys to filter out and to not send. In the integrations it's possible to set a "filter session data" option in the AppSignal configuration with a list of session data keys to filter. Any session data values that are filtered out by these systems will be replaced with a `[FILTERED]` value. This way the list of session data in the app data on AppSignal.com still includes the session data key, but not the value. Making it easier to see that a value was sent, but the potentially sensitive data was filtered out. ### Example For example, an application with this AppSignal config: ```yaml YAML theme={null} filter_session_data: ["password"] ``` Results in this view for the session data of a web request on AppSignal.com: ```json JSON theme={null} { "password": "[FILTERED]" } ``` This guide will show you how to configure your application's session filtering denylist based on what language your application uses: * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Go](#go) * [Java](#java) * [PHP](#php) ## Ruby In the Ruby integration, AppSignal automatically stores the contents of the user's session for Rails apps and other frameworks. Specific values can be filtered out or it can be [disabled entirely]. In session data filtering, there's support for nested hashes and nested hashes in arrays. Any hash we encounter in your session data will be filtered. To use this filtering, add the following to your `config/appsignal.yml` file in the environment group you want it to apply. The [`filter_session_data`](/ruby/configuration/options#option-filter_session_data) value is an Array of Strings. ```ruby Ruby theme={null} Appsignal.configure do |config| config.filter_session_data += ["name", "email", "api_token", "token"] end ``` ```yaml YAML theme={null} production: filter_session_data: - name - email - api_token - token ``` ## Elixir In the Elixir integration, AppSignal automatically stores the contents of the user's session for Phoenix apps. Specific values can be filtered out or it can be [disabled entirely]. In the session data filtering, there's support for nested hashes and nested hashes in arrays. Any hash we encounter in your session data will be filtered. To use this filtering, add the following to your `config/appsignal.exs` file. The [`filter_session_data`](/elixir/configuration/options#option-filter_session_data) value is an Array of Strings. ```elixir Elixir theme={null} config :appsignal, :config, filter_session_data: ["name", "email", "api_token", "token"] ``` ## Node.js If a request stores session data on the trace, use the session data filter to filter out any data you do not want to include. In the session data filtering, there's support for nested hashes and nested hashes in arrays. Any hash we encounter in your session data will be filtered. To use this filtering, use the [`filterSessionData`](/nodejs/3.x/configuration/options#option-filtersessiondata) config option to select which session data keys to filter out. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ // Other config options filterSessionData: ["name", "email", "api_token", "token"], }); ``` ## Python If a request stores session data on the trace, use the session data filter to filter out any data you do not want to include. In the session data filtering, there's support for nested hashes and nested dictionaries in lists. Any dictionary we encounter in your session data will be filtered. To use this filtering, use the [`filter_session_data`](/python/configuration/options#option-filter_session_data) config option to select which session data keys to filter out. ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( # Other config filter_session_data: ["name", "email", "api_token", "token"] ) ``` ## Go If a request stores session data on the trace, use the session data filter to filter out any data you do not want to include. In the session data filtering, there's support for nested slices and nested maps. Any map we encounter in your session data will be filtered. Use the [`filter_request_session_data` denylist](/go/configuration/options#option-filter_request_session_data) for request session data filtering. Set the [`send_request_session_data` option](/go/configuration/options#option-send_request_session_data) to `false` to not send any request session data at all. See the [Go configuration page](/go/configuration/options) for more information on how to configure OpenTelemetry for Go apps. ```go Go theme={null} res := resource.NewWithAttributes( attribute.StringSlice("appsignal.config.filter_session_data", []string{"password", "cvv"}), ) ``` ## Java If a request stores session data on the trace, use the session data filter to filter out any data you do not want to include. In the session data filtering, there's support for nested maps and arrays. Any map encountered in your session data will be filtered. Use the [`filter_request_session_data`](/java/configuration/options#option-filter_request_session_data) denylist for session data filtering. Set the [`send_request_session_data` option](/java/configuration/options#option-send_request_session_data) to `false` to avoid sending any session data. See the [Java configuration page](/java/configuration/options) for more information on how to configure OpenTelemetry for Java apps. ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.filter_request_session_data=$(encode "name,email,api_token,token"),\ ..." ``` ## PHP If a request stores session data on the trace, use the session data filter to filter out any data you do not want to include. In the session data filtering, there's support for nested arrays. Any array encountered in your session data will be filtered. Use the [`filter_request_session_data`][php filter_request_session_data] denylist for session data filtering. Set the [`send_request_session_data`][php send_request_session_data] option to `false` to avoid sending any session data. ```php PHP theme={null} return [ 'filter_request_session_data' => ['name', 'email', 'api_token', 'token'], // ... other options ]; ``` [session data filtering]: /application/session-data-filtering.html [disabled entirely]: /application/session-data-filtering.html#filter-all-session-data [php filter_request_session_data]: /php/configuration/options.html#option-filter_request_session_data [php send_request_session_data]: /php/configuration/options.html#option-send_request_session_data # Ignore Actions Source: https://docs.appsignal.com/guides/filter-data/ignore-actions > [!TIP] > > Ignoring actions will **ignore error and performance data** from those > actions. [Custom metrics data](/metrics/custom) and [logs](/logging) > recorded in an action will still be reported. There may be specific actions in your application you don't want to report to AppSignal. The most common use case is a web endpoint that your load balancer uses to check if your application is still responding or all actions that occur within your application's admin panel. These endpoints may receive a lot of traffic but are not crucial endpoints to have AppSignal monitor and may disrupt the usability of metrics AppSignal provides you for your application's [namespaces](/application/namespaces). # Ignoring Actions > [!TIP] > > If you're unsure of the action names to configure in your application > configuration, find the action name to ignore in your application on > AppSignal.com, and copy it into your AppSignal configuration. Specific actions can ignore actions by using the "ignore actions" option in your application's AppSignal integration configuration. The "ignore actions" configuration option allows you to define a denylist of actions you want to ignore. All actions in this list will be ignored, meaning the data from these actions will not be sent to the AppSignal servers and will not count towards your [organization's billing plan](https://www.appsignal.com/plans). This guide will show you how to configure your ignore action denylist in the language your application uses: * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Go](#go) * [Java](#java) * [PHP](#php) **Note:** This configuration is not available for Front-end JavaScript. ## Ruby To ignore actions in Ruby, add the following to your AppSignal configuration file. The [`ignore_actions`][ruby ignore_actions] value is an Array of Strings. The below example is for a Rails application. ```ruby Ruby theme={null} Appsignal.configure do |config| config.ignore_actions += [ "UptimeController#healthcheck", "AdminController#index", "Admin::UsersController#show" ] end ``` ```yaml YAML theme={null} production: ignore_actions: - "UptimeController#healthcheck" - "AdminController#index" - "Admin::UsersController#show" ``` If you use Sinatra or any other framework, use the HTTP method and path you used to specify your route, for example: ```ruby Ruby theme={null} Appsignal.configure do |config| config.ignore_actions += [ "GET /healthcheck", "GET /pages/:id", "POST /pages/create" ] end ``` ```yaml YAML theme={null} production: ignore_actions: - "GET /healthcheck" - "GET /pages/:id" - "POST /pages/create" ``` [ruby ignore_actions]: /ruby/configuration/options.html#option-ignore_actions ## Elixir To ignore actions in Elixir, add the following to your AppSignal configuration file. The [`ignore_actions`][elixir ignore_actions] value is a List of Strings. ```elixir Elixir theme={null} config :appsignal, :config, ignore_actions: ["AppsignalPhoenixExampleWeb.UptimeController#healthcheck", "AppsignalPhoenixExampleWeb.AdminController#index"] ``` [elixir ignore_actions]: /elixir/configuration/options.html#option-ignore_actions ## Node.js To ignore actions in Node.js, add the following to your AppSignal configuration file. The [`ignoreActions`][nodejs ignore_actions] value is an Array of Strings. Action names are used to group errors and performance issues. Their names are usually a controller/endpoint or background job. You can see a list of these in the "Action name" column of the *Traces* list under [Performance](https://appsignal.com/redirect-to/app?to=traces) in the sidebar. To ignore a specific action, copy the name as it appears in the UI and add it to the `ignoreActions` option. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ // Other config ignoreActions: ["GET /pages/:id", "GET /healthcheck", "GET /admin"], }); ``` [nodejs ignore_actions]: /nodejs/3.x/configuration/options.html#option-ignoreactions ## Python To ignore actions in Python, add the following to your AppSignal configuration file. The [`ignore_actions`][python ignore_actions] value is a list of strings. Action names are used to group errors and performance issues. Their names are usually a controller/endpoint or background job. You can see a list of these in the "Action name" column of the *Traces* list under [Performance](https://appsignal.com/redirect-to/app?to=traces) in the sidebar. To ignore a specific action, copy the name as it appears in the UI and add it to the `ignore_actions` option. ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( # Other config ignore_actions=["GET /pages/:id", "GET /healthcheck", "GET /admin"] ) ``` [python ignore_actions]: /python/configuration/options.html#option-ignore_actions ## Go To ignore actions in Go applications, configure the [`ignore_actions`][go ignore_actions] config option. Action names are used to group errors and performance issues. Their names are usually a controller/endpoint or background job. You can see a list of these in the "Action name" column of the *Traces* list under [Performance](https://appsignal.com/redirect-to/app?to=traces) in the sidebar. To ignore a specific action, copy the name as it appears in the UI and add it to the `ignore_actions` option. See the [Go configuration page](/go/configuration/options) for more information on how to configure OpenTelemetry for Go apps. ```go Go theme={null} res := resource.NewWithAttributes( attribute.StringSlice("appsignal.config.ignore_actions", []string{"GET /heath_check", "POST /ping"}), // And other resource attributes ) ``` [go ignore_actions]: /go/configuration/options.html#option-ignore_actions ## Java To ignore actions in Java applications, configure the [`ignore_actions`][java ignore_actions] option. Action names are used to group errors and performance issues. Their names are usually a controller/endpoint or background job. You can see a list of these in the "Action name" column of the *Traces* list under [Performance](https://appsignal.com/redirect-to/app?to=traces) in the sidebar. To ignore a specific action, copy the name as it appears in the UI and add it to the `ignore_actions` option. See the [Java configuration page](/java/configuration/options) for more information on how to configure OpenTelemetry for Java apps. ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.ignore_actions=$(encode "UptimeController#healthcheck,AdminController#index"),\ ..." ``` ### Read More * Read more about the [Java `ignore_actions` config option][java ignore_actions]. [java ignore_actions]: /java/configuration/options.html#option-ignore_actions ## PHP To ignore actions in PHP applications, configure the [`ignore_actions`][php ignore_actions] option. ```php PHP theme={null} return [ 'ignore_actions' => ['GET /admin', 'GET /ignored-route'], // ... other options ]; ``` ### Read More * Read more about the [PHP `ignore_actions` config option][php ignore_actions]. [php ignore_actions]: /php/configuration/options.html#option-ignore_actions [notifications]: /application/notification-settings.html # Ignore Errors Source: https://docs.appsignal.com/guides/filter-data/ignore-errors Errors (or exceptions) raised by your application will be visible in the [Error incident list][error incident list]. You may find AppSignal notifying you of errors you do not consider important. To prevent this, you can add a list of errors to an ignore list in your application's configuration. AppSignal will then only notify you of errors that are not on the ignore list. > [!NOTE] > > 🔕 If you want AppSignal to mute error notifications rather than ignore them, > \[read our Notification Settings]\[notifications] Documentation to learn how to > customize your application's notification settings. ## Ignoring errors To ignore errors you can configure an "ignore errors" *denylist* in your AppSignal integration configuration. By adding error names to this list the integrations will filter out ignored errors from data sent to AppSignal. This guide will show you how to configure your ignore errors denylist based on what language your application uses: * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Front-end JavaScript](#front-end-javascript) * [Go](#go) * [Java](#java) * [PHP](#php) > [!TIP] > > It's not possible to ignore all errors, or disable error reporting entirely. > It is possible to \[disable notifications for errors]\[notifications]. ## Ruby To ignore errors in Ruby, add the following to your AppSignal configuration file. The [`ignore_errors`][ruby ignore_errors] value is an Array of Strings. ```ruby Ruby theme={null} Appsignal.configure do |config| config.ignore_errors += ["ActiveRecord::RecordNotFound", "ActionController::RoutingError"] end ``` ```yaml YAML theme={null} production: ignore_errors: - ActiveRecord::RecordNotFound - ActionController::RoutingError ``` > [!WARNING] > > Names set in \[`ignore_errors`]\[ruby ignore\_errors] will be matched on class > name and not class inheritance. If you want to match all subclasses of a > certain Exception, all subclasses have to be listed separately. ### Read More * Read more about the [Ruby `ignore_errors` config option][ruby ignore_errors]. * [Exception handling with AppSignal in Ruby](/ruby/instrumentation/exception-handling). ## Elixir To ignore errors in Elixir, add the following to your AppSignal configuration file. The [`ignore_errors`][elixir ignore_errors] value is a List of Strings. ```elixir Elixir theme={null} config :appsignal, :config, ignore_errors: ["SpecificError", "AnotherError"] ``` > [!WARNING] > > Names set in \[`ignore_errors`]\[elixir ignore\_errors] will be matched on module > name. ### Read More * Read more about the [Elixir `ignore_errors` config option][elixir ignore_errors]. * [Exception handling with AppSignal in Elixir](/elixir/instrumentation/exception-handling). ## Node.js To ignore errors in Node.js, add the following to your AppSignal configuration file. The [`ignoreErrors`][nodejs ignore_errors] value is an Array of Strings. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ // Other config ignoreErrors: ["SpecificError", "AnotherError"], }); ``` > [!WARNING] > > Names set in \[`ignoreErrors`]\[nodejs ignore\_errors] will be matched on the > `Error` objects `name` property only, and will not honor any class > inheritance. If you want to match subclasses of `Error`, each subclass has to > be listed separately. ### Read More * Read more about the [Node.js `ignoreErrors` config option][nodejs ignore_errors]. * [Exception handling with AppSignal in Node.js](/nodejs/3.x/instrumentation/exception-handling). ## Python To ignore errors in Python, add the following to your AppSignal configuration file. The [`ignore_errors`][python ignore_errors] value is a list of strings. ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( # Other config ignore_errors: ["SpecificError", "AnotherError"], ) ``` > [!WARNING] > > Names set in \[`ignore_errors`]\[python ignore\_errors] will be matched on the > Exception class name only, and will not honor any class inheritance. If you > want to match subclasses of `Exception`, each subclass has to be listed > separately. ### Read More * Read more about the [Python `ignore_errors` config option][python ignore_errors]. * [Exception handling with AppSignal in Python](/python/instrumentation/exception-handling). ## Front-end JavaScript To ignore errors in Front-end JavaScript, add the following to your AppSignal configuration file. The [`ignoreErrors`][js ignore_errors] value is an Array of Regular expressions. ```javascript JavaScript theme={null} import Appsignal from "@appsignal/javascript"; export const appsignal = new Appsignal({ // Other config ignoreErrors: [/a specific error message/, /another error message/], }); ``` > [!WARNING] > > Names set in \[`ignoreErrors`]\[js ignore\_errors] will be matched by using a > regular expression. The regular expression is matched `message` property of a > given `Error`. ### Read More * Read more about the [front-end JavaScript `ignoreErrors` config option][js ignore_errors]. * [Exception handling with AppSignal in front-end JavaScript](/front-end/error-handling). ## Go To ignore errors in Go applications, configure the [`ignore_errors` config option][go ignore_errors]. Error names are matched exactly by their name, not by inheritance. You can see a list of errors in the "Action and error type" column of the *Issue list* under [Errors](https://appsignal.com/redirect-to/app?to=exceptions) in the sidebar. To ignore a specific error, copy the name as it appears in the UI and add it to the `ignore_errors` option. See the [Go configuration page](/go/configuration/options) for more information on how to configure OpenTelemetry for Go apps. ```go Go theme={null} res := resource.NewWithAttributes( attribute.StringSlice("appsignal.config.ignore_errors", []string{"MyCustomError", "ExpectedError"}), // And other resource attributes ) ``` ### Read More * Read more about the [Go `ignore_errors` config option][go ignore_errors]. ## Java To ignore errors in Java applications, configure the [`ignore_errors` config option](/java/configuration/options#option-ignore_errors) using the `OTEL_RESOURCE_ATTRIBUTES` environment variable. Error names are matched exactly by their name, not by inheritance. You can see a list of errors in the "Action and error type" column of the *Issue list* under [Errors](https://appsignal.com/redirect-to/app?to=exceptions) in the sidebar. To ignore a specific error, copy the name as it appears in the UI and add it to the `ignore_errors` option. See the [Java configuration page](/java/configuration/options) for more information on how to configure OpenTelemetry for Java apps. ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.ignore_errors=$(encode "MyCustomError,ExpectedError"),\ ..." ``` > [!WARNING] > > Names set in > [`ignore_errors`](/java/configuration/options#option-ignore_errors) will > be matched on the Exception class name only, and will not honor any class > inheritance. If you want to match subclasses of `Exception`, each subclass has > to be listed separately. ### Read More * Read more about the [Java `ignore_errors` config option](/java/configuration/options#option-ignore_errors). ## PHP To ignore errors in PHP applications, configure the [`ignore_errors` config option](/php/configuration/options#option-ignore_errors). ```php PHP theme={null} return [ 'ignore_errors' => ['SpecificError', 'AnotherError'], // ... other options ]; ``` > [!WARNING] > > Names set in > [`ignore_errors`](/php/configuration/options#option-ignore_errors) will > be matched on the Exception class name only, and will not honor any class > inheritance. If you want to match subclasses of `Exception`, each subclass has > to be listed separately. ### Read More * Read more about the [PHP `ignore_errors` config option](/php/configuration/options#option-ignore_errors). [elixir ignore_errors]: /elixir/configuration/options.html#option-ignore_errors [error incident list]: https://appsignal.com/redirect-to/app?to=exceptions [js ignore_errors]: /front-end/configuration/ [nodejs ignore_errors]: /nodejs/3.x/configuration/options.html#option-ignoreerrors [notifications]: /application/notification-settings.html [ruby ignore_errors]: /ruby/configuration/options.html#option-ignore_errors [python ignore_errors]: /python/configuration/options.html#option-ignore_errors [go ignore_errors]: /go/configuration/options.html#option-ignore_errors # Ignore Logs Source: https://docs.appsignal.com/guides/filter-data/ignore-logs When using [AppSignal Logging](/logging), log lines emitted [using the AppSignal Integrations](/logging/integrations) can be filtered using our "ignore logs" denylist. Ignoring log lines allows you to remove noise from the logs you view in AppSignal, keeping only those log lines that are meaningful to you. Ignored log lines are not sent to AppSignal, and are not counted towards your log storage quota. ## Ignoring logs To ignore logs you can configure an "ignore logs" *denylist* in your AppSignal integration configuration. By adding log messages to this list the integrations will filter out log lines containing those messages from data sent to AppSignal. This guide will show you how to configure your ignore errors denylist based on what language your application uses: * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Go](#go) * [Java](#java) * [PHP](#php) ### Log message matching syntax A log line will be ignored if its message contains any of the messages in the "ignore logs" *denylist*. For example, an ignore logs entry with the word `start` will ignore log lines whose messages are "Process started" or "Process failed to start". A limited subset of regular expression syntax can be used to narrow the log lines accepted: * `^` will match the beginning of the message * `$` will match the end of the message * `.*` will match any characters No other regular expression syntax is supported. For example, `^job` will match any log line whose message starts with "job", like "job #123 completed successfully", but it will not ignore any log lines that contain "job" at any other position in the message. Similarly, `completed successfully$` will ignore a log line whose message ends with the words "completed successfully", but it will not ignore any log lines that contain "completed successfully" at any other position in the message. Finally, `^job .* completed successfully$` allows you to ignore log lines that start with "job" and finish with "completed successfully", regardless of what the log message contains in between those words. Log message matching is case-sensitive, meaning that ignoring `job` (lowercase `j`) does not ignore the log message "Job completed" (uppercase `J`). ## Ruby To ignore logs in Ruby, add the following to your AppSignal configuration file. The [`ignore_logs`][ruby ignore_logs] value is an Array of Strings. ```ruby Ruby theme={null} Appsignal.configure do |config| config.ignore_logs += [ "^done$", "Task .* completed successfully" ] end ``` ```yaml YAML theme={null} production: ignore_logs: - "^done$" - "Task .* completed successfully" ``` ### Read More * Read more about the [Ruby `ignore_logs` config option][ruby ignore_logs]. * [Logging with AppSignal for Ruby](/logging/integrations/ruby). ## Elixir To ignore logs in Elixir, add the following to your AppSignal configuration file. The [`ignore_logs`][elixir ignore_logs] value is a List of Strings. ```elixir Elixir theme={null} config :appsignal, :config, ignore_logs: ["^done$", "Task .* completed successfully"] ``` ### Read More * Read more about the [Elixir `ignore_logs` config option][elixir ignore_logs]. * [Logging with AppSignal for Elixir](/logging/integrations/elixir). ## Node.js To ignore logs in Node.js, add the following to your AppSignal configuration file. The [`ignoreLogs`][nodejs ignore_logs] value is an Array of Strings. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ // Other config ignoreLogs: ["^done$", "Task .* completed successfully"], }); ``` ### Read More * Read more about the [Node.js `ignoreLogs` config option][nodejs ignore_logs]. * [Logging with AppSignal for Node.js](/logging/integrations/nodejs). ## Python To ignore logs in Python, add the following to your AppSignal configuration file. The [`ignore_logs`][python ignore_logs] value is a list of strings. ```python Python theme={null} # __appsignal__.py from appsignal import Appsignal appsignal = Appsignal( # Other config ignore_logs=["^done$", "Task .* completed successfully"], ) ``` > [!NOTE] > > AppSignal for Python sends logs only in [collector mode](/python/configuration/collector), so `ignore_logs` has no effect when you use the AppSignal agent. ### Read More * Read more about the [Python `ignore_logs` config option][python ignore_logs]. * [Logging with AppSignal for Python](/logging/integrations/python). ## Go To ignore logs in Go applications, configure the [`ignore_logs` config option][go ignore_logs]. See the [Go configuration page](/go/configuration/options) for more information on how to configure OpenTelemetry for Go apps. ```go Go theme={null} res := resource.NewWithAttributes( attribute.StringSlice("appsignal.config.ignore_logs", []string{"^done$", "Task .* completed successfully"}), // And other resource attributes ) ``` ### Read More * Read more about the [Go `ignore_logs` config option][go ignore_logs]. ## Java To ignore logs in Java applications, configure the [`ignore_logs` config option](/java/configuration/options#option-ignore_logs) using the `OTEL_RESOURCE_ATTRIBUTES` environment variable. The `ignore_logs` value is an array of strings. ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.ignore_logs=$(encode "^done$,Task .* completed successfully"),\ ..." ``` ### Read More * Read more about the [Java `ignore_logs` config option](/java/configuration/options#option-ignore_logs). ## PHP To ignore logs in PHP applications, configure the [`ignore_logs` config option](/php/configuration/options#option-ignore_logs). The `ignore_logs` value is an array of strings. ```php PHP theme={null} return [ 'ignore_logs' => ['^done$', 'Task .* completed successfully'], // ... other options ]; ``` ### Read More * Read more about the [PHP `ignore_logs` config option](/php/configuration/options#option-ignore_logs). [elixir ignore_logs]: /elixir/configuration/options.html#option-ignore_logs [nodejs ignore_logs]: /nodejs/3.x/configuration/options.html#option-ignorelogs [python ignore_logs]: /python/configuration/options.html#option-ignore_logs [ruby ignore_logs]: /ruby/configuration/options.html#option-ignore_logs [go ignore_logs]: /go/configuration/options.html#option-ignore_logs # Ignore Namespaces Source: https://docs.appsignal.com/guides/filter-data/ignore-namespaces In a previous guide, we walked through the steps needed to [set up custom namespaces](/guides/namespaces) in your application. You can use these namespaces to group parts of an application together, but you can also use them to ignore these namespaces entirely. This could be a good alternative to ignoring many [individual actions](/guides/filter-data/ignore-actions). > [!TIP] > > Ignoring namespaces will **ignore error and performance data** from all > actions in namespaces. AppSignal will still report [custom metrics > data](/metrics/custom) recorded in any of the namespace actions. ## Ignoring namespaces Namespaces can be ignored by customizing your application's AppSignal integration configuration. The "ignore namespaces" configuration option will allow you to configure a denylist of namespaces. Any namespaces in this list will be ignored, meaning the data from these actions will not be sent to the AppSignal servers and will not count towards your [organization's billing plan](https://www.appsignal.com/plans). The "ignore namespaces" config option is configured differently per integration language. See the list of integrations below for the one your app uses: * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Go](#go) * [Java](#java) * [PHP](#php) > [!TIP] > > If you're unsure what namespaces you need to configure in your application's > AppSignal configuration, you can use the namespaces filtering dropdown on > AppSignal.com and copy those namespaces into your AppSignal configuration. ## Ruby To ignore namespaces in Ruby, add the following to your AppSignal configuration file. The [`ignore_namespaces`][ruby ignore_namespaces] value is an Array of Strings. ```ruby Ruby theme={null} Appsignal.configure do |config| config.ignore_namespaces += [ "http_request", # "web" namespace on AppSignal "background_job", # "background" namespace on AppSignal "admin", "private" ] end ``` ```yaml YAML theme={null} production: ignore_namespaces: - "http_request" # "web" namespace on AppSignal - "background_job" # "background" namespace on AppSignal - "admin" - "private" ``` For more information about this config option, see the [`ignore_namespaces` config option][ruby ignore_namespaces] documentation. ## Elixir To ignore namespaces in Elixir, add the following to your AppSignal configuration file. The [`ignore_namespaces`][elixir ignore_namespaces] value is a List of Strings. ```elixir Elixir theme={null} import Config config :appsignal, :config, ignore_namespaces: [ "http_request", # "web" namespace on AppSignal "background_job", # "background" namespace on AppSignal "admin", "private" ] ``` For more information about this config option, see the [`ignore_namespaces` config option][elixir ignore_namespaces] documentation. ## Node.js To ignore namespaces in Node.js, add the following to your AppSignal configuration file. The [`ignoreNamespaces`][nodejs ignore_namespaces] value is an Array of Strings. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ // Other config ignoreNamespaces: ["web", "background", "admin", "private"], }); ``` For more information about this config option, see the [`ignoreNamespaces` config option][nodejs ignore_namespaces] documentation. ## Python To ignore namespaces in Python, add the following to your AppSignal configuration file. The [`ignore_namespaces`][python ignore_namespaces] value is a list of strings. ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( # Other config ignore_namespaces=["web", "background", "admin", "private"] ) ``` For more information about this config option, see the [`ignore_namespaces` config option][python ignore_namespaces] documentation. ## Go To ignore namespaces in Go applications, add the following to your AppSignal configuration file. The [`ignore_namespaces`][go ignore_namespaces] value is a slice of strings. ```go Go theme={null} res := resource.NewWithAttributes( attribute.StringSlice("appsignal.config.ignore_namespaces", []string{"admin", "secret"}), // And other resource attributes ) ``` For more information about this config option, configure the [`ignore_namespaces` config option][go ignore_namespaces]. ## Java To ignore namespaces in Java applications, configure the [`ignore_namespaces` config option](/java/configuration/options#option-ignore_namespaces) using the `OTEL_RESOURCE_ATTRIBUTES` environment variable. ```bash Bash theme={null} function encode() { echo -n "$@" | sed 's/,/%2C/g' } export OTEL_RESOURCE_ATTRIBUTES="\ appsignal.config.ignore_namespaces=$(encode "admin,secret"),\ ..." ``` For more information about this config option, see the [`ignore_namespaces` config option](/java/configuration/options#option-ignore_namespaces) documentation. ## PHP To ignore namespaces in PHP applications, configure the [`ignore_namespaces` config option](/php/configuration/options#option-ignore_namespaces). ```php PHP theme={null} return [ 'ignore_namespaces' => ['admin', 'secret'], // ... other options ]; ``` For more information about this config option, see the [`ignore_namespaces` config option](/php/configuration/options#option-ignore_namespaces) documentation. [elixir ignore_namespaces]: /elixir/configuration/options.html#option-ignore_namespaces [nodejs ignore_namespaces]: /nodejs/3.x/configuration/options.html#option-ignorenamespaces [notifications]: /application/notification-settings.html [ruby ignore_namespaces]: /ruby/configuration/options.html#option-ignore_namespaces [python ignore_namespaces]: /python/configuration/options.html#option-ignore_namespaces [go ignore_namespaces]: /go/configuration/options.html#option-ignore_namespaces # Set up a new application with AI Source: https://docs.appsignal.com/guides/install-with-agents Set up AppSignal in your application with an AI agent and send your first data. > [!WARNING] > > **AI agents: stop here.** Agent-friendly instructions are at `https://docs.appsignal.com/agents/new-application.md` and `https://docs.appsignal.com/agents/pre-install-checks.md`. Follow those, not this page. The agent inspects the project and, if necessary, waits and asks for your confirmation on application name, environment and so on. The install is complete only once the agent has sent the first data to AppSignal. ## Adding an app with an AI prompt Go to your organization and select **Add app**, choose [**Set up with AI**](https://appsignal.com/redirect-to/organization?to=sites/new/provisioning), copy and paste the ready prompt that appears on your screen into your AI agent. The prompt will look like this: ```text Prompt theme={null} Add AppSignal to this application. Your job is to read AppSignal's installation instructions and follow them. Retrieve them at https://docs.appsignal.com/agents/new-application.md Your AppSignal provisioning status URL, which carries your provisioning token: https://appsignal.com/api/provision/v1/status?token= ``` This should work with any agent that can read a URL and change files, such as Claude Code, Cursor, or Codex. Confirm your agent settings are correct, let it run the installs and send your first data. > [!WARNING] > > Your tokens, Organization-level Push API key and other keys are a write-only secrets, so give them only to an agent and an environment you trust. The agent instructions require them to go in the project's existing secret storage or environment and never into a commit. ## Agent instruction files These are plain Markdown files. Link them, download them, or attach them to your agent as needed. Your agent should automatically identify your current language and framework, and follow the instructions for that integration from the [installation entry point](/agents/new-application.md). If it does not, give it the link to the right file. ### Start and safety checks * [Installation entry point](/agents/new-application.md) * [Pre-install checks](/agents/pre-install-checks.md) ### Language and integration instructions Not entry points, each of them assumes you have already run the pre-install checks. Send your agent the entry point and let it choose from this list. * [Ruby](/agents/install/ruby.md) * [Elixir](/agents/install/elixir.md) * [Node.js](/agents/install/nodejs.md) * [Python](/agents/install/python.md) * [PHP](/agents/install/php.md) * [Go](/agents/install/go.md) * [Java](/agents/install/java.md) * [AppSignal for Browser](/agents/install/browser.md) ## Confirm the first data arrived Back-end demonstration commands send one error and one performance trace. Real requests and jobs add more once the app runs with AppSignal enabled. Host metrics take longest, because the AppSignal agent must keep running to send them. AppSignal for Browser has no demonstration command, so the agent throws a temporary test error instead. Look for `AppSignal test error` in Browser errors. Web vitals arrive after someone loads a page and then closes it or navigates away. If nothing appears, contact us at [support@appsignal.com](mailto:support@appsignal.com) or send your feedback to the [AppSignal Labs Discord channel](https://discord.gg/EjF6ykYx63). # Add additional OpenTelemetry Instrumentation Source: https://docs.appsignal.com/guides/instrumentation/additional-opentelemetry-instrumentation OpenTelemetry provides extensive instrumentation for many popular libraries and frameworks. During the installation of AppSignal and OpenTelemetry, you may have installed some instrumentation packages already, but you may need to add additional instrumentation packages to monitor specific libraries your application uses. This guide explains how to identify, install, and configure additional OpenTelemetry instrumentation packages for better observability coverage. ## Why Add Additional Instrumentation? Your application might use libraries that aren't covered by the instrumentation packages you installed during setup, such as: * Database drivers * HTTP client libraries * Message queue systems * Custom or niche libraries Adding instrumentation for these libraries provides a more complete monitoring setup for all components of your application. ## General Steps This section describes the steps that are needed for most languages to instrument additional library. Check the [Language-Specific Instructions](#language-specific-instructions) section for language specific steps. ### Identify Libraries to Instrument First, determine which libraries your application uses that you'd like to monitor. Common candidates include: * Database clients (MySQL, PostgreSQL, MongoDB, Redis) * HTTP clients * Message queues (RabbitMQ, Kafka, SQS) * Template engines ### Find Instrumentation Packages Look for instrumentation packages in this order of preference: 1. **Official OpenTelemetry packages** - Maintained by the OpenTelemetry community 2. **OpenTelemetry contrib packages** - Community-contributed instrumentation 3. **Third-party packages** - Ensure you trust the maintainer and review the code Check the [OpenTelemetry Registry](https://opentelemetry.io/ecosystem/registry/) for available instrumentation packages. Note that some libraries may include OpenTelemetry instrumentation on their own and no further setup is needed. ### Install the Package Once you've found a relevant instrumentation package, install the instrumentation package using your language's package manager. For example: ```sh Go theme={null} go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp ``` ```sh PHP theme={null} composer require open-telemetry/opentelemetry-auto-guzzle ``` ### Initialize the Instrumentation Depending on the language and SDK instrumentation method, instrumentation packages may require initialization in your application's startup code. This typically involves: * Importing the instrumentation package * Calling an initialization function * Configuring any package-specific options For some languages, like PHP and Java using auto instrumentations, this step is not necessary. It will automatically set up the instrumentation, unless instructed otherwise. ### Check Incoming Data After installation, verify that the instrumentation is working: * Check that new spans about the instrumented library appear in your traces reported to AppSignal.com. * Confirm metrics about the instrumented library are being reported to AppSignal.com. * Test error scenarios to ensure errors are reported. ## Language-Specific Instructions For detailed instructions on adding instrumentation packages for specific languages: * [Go Instrumentations](/go/instrumentations) * [Java Instrumentations](/java/instrumentations) * [PHP Instrumentations](/php/instrumentations) ## Troubleshooting ### Common Issues * **Missing traces**: Ensure the instrumentation is initialized before the library is used. * **Incomplete data**: Check if the instrumentation package supports your library version. * **Duplicate spans**: Avoid instrumenting the same library multiple times. ### Getting Help If you encounter issues: 1. Check the instrumentation package documentation 2. Contact [AppSignal support](mailto:support@appsignal.com) for assistance # Link Traces with Logs Source: https://docs.appsignal.com/guides/linking-traces-with-logs Linking traces with [logs](/logging) allows you to correlate error incidents and traces with log messages, making it easier to debug issues by viewing relevant logs directly alongside your traces. By adding an identifier to both your traces and logs, you can navigate between them in the AppSignal interface. ## How It Works To link traces with logs, you need to add the same identifier to both, such as `request_id` or `trace_id`. This will be set up automatically in most cases, but when it's not make sure the following identifiers are set. 1. Add a request or trace identifier to your trace as an AppSignal tag or OpenTelemetry attribute. 2. Add the same identifier to your logs as a log attribute. When AppSignal receives traces and logs with matching identifiers, it can correlate them, allowing you to view related logs when inspecting a trace. ## Choosing an Identifier You can use any of the following identifiers to link traces and logs: * **`request_id`** - A unique identifier for each HTTP request (common in web frameworks). * **`trace_id`** - The AppSignal or OpenTelemetry trace ID. Many web frameworks automatically generate a `request_id` for each request, making it a convenient choice. For OpenTelemetry-based integrations, you can use the trace ID directly. ## Linking Application Logs Report logs from your application by [setting up logging](/logging/integrations) using the AppSignal packages or OpenTelemetry SDK. Most framework configuration will already have `request_id` or `trace_id` tags set up. If no relevant logs are detected, follow the [logging set up instructions](/logging/integrations) for the framework your application uses or report the identifier manually as a trace tag and log attribute. ## Viewing Linked Logs Once you've configured your application to link traces with logs, you can view related logs directly in the AppSignal interface: 1. Navigate to a performance trace or error incident. 2. Look for the related logs block, which will link to the relevant log messages. 3. Use the logs to gain additional context about what happened during the request. This correlation makes debugging faster, as you can quickly find the relevant trace and logs. ## Next Steps * Set up [log reporting](/logging) to send your application logs to AppSignal. * Learn more about [adding tags](/guides/tagging) to your traces. # Grouping with Namespaces Source: https://docs.appsignal.com/guides/namespaces Namespaces are a way to group error incidents, traces and metrics from actions. AppSignal uses three [namespaces] by default: * `web` for web requests * `frontend` for Front-end JavaScript * `background` for background jobs Applications can have any number of namespaces, for example, you could have a separate namespace for your application's administration panel, API or scheduled tasks. This guide will go through the steps needed to report actions in custom namespaces. > [!TIP] > > Want to know more about what namespaces can be used for? Check out this list: > [What Can You Do With > Namespaces?](/application/namespaces#what-can-you-do-with-namespaces) ![App Graphs Namespaces](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/namespaces/graphs.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=044f86ecbea3baac50432a8337ae69b2) The above image shows example graphs with multiple namespaces, splitting out a GraphQL API and the Web namespace. ## Configuring Namespaces Namespaces are defined by your application's code. With small helpers, you can customize the namespace of an action. This guide will teach you how to split requests up into different namespaces. For this guide, we'll create an "admin" and a "critical" namespace for background jobs. > [!TIP] > > Namespace names may only contain letters (a-z) and underscores > \ > We do not recommend having more than **15** namespaces per application. #### Configurations per Language * [Ruby](#ruby) * [Elixir](#elixir) * [Node.js](#nodejs) * [Python](#python) * [Front-end JavaScript](#front-end-javascript) * [Go](#go) * [Java](#java) * [PHP](#php) ### Ruby In Rails we can use the `before_action` callback to call a method before a request is handled. In the code example below, we've created a `before_action` that calls the `set_appsignal_namespace` method. In this method we call the [`Appsignal.set_namespace` helper method][ruby helper] to configure "admin" as the namespace for this request. This also works if other controllers are subclasses of the `AdminController`. ```ruby Ruby theme={null} # In a Rails controller # app/controllers/admin_controller.rb class AdminController < ApplicationController before_action :set_appsignal_namespace def set_appsignal_namespace # Configures all actions in this controller to report # in the "admin" namespace Appsignal.set_namespace("admin") end # Any other controller actions end ``` Next we'll define the namespace of code executed by our application's Sidekiq background workers. To correctly namespace errors triggered in our background worker, we must define the namespace before any other code runs. In the example Sidekiq worker code below, we do this immediately in the perform method on line 7. ```ruby Ruby theme={null} # In a Sidekiq worker # app/workers/critical_worker.rb class CriticalWorker include Sidekiq::Worker def perform # Configures this worker's jobs to report in the "critical" namespace Appsignal.set_namespace("critical") # The actual worker code end end ``` It's also possible to configure the namespace when creating a transaction using the [`Appsignal.monitor`](https://rubydoc.info/gems/appsignal/Appsignal/Helpers/Instrumentation#monitor-instance_method) helper. It accepts the namespace as a keyword argument. ```ruby Ruby theme={null} # When creating a new transaction Appsignal.monitor(namespace: "admin") do # Your code to instrument end ``` For transactions that have already been created, you can use the `set_namespace` method to configure the transaction's namespace, like in the example below: ```ruby Ruby theme={null} # When changing the namespace later on for a transaction transaction.set_namespace("slow_admin") ``` ##### A note on helper location The `set_namespace` helpers used in this guide can be called in any action that is part of an AppSignal trace. We recommend calling this as early in the request or background job as possible, so the transaction is configured with the given namespace before any error occurs. Otherwise, if an error occurs, or anything else that stops the process, the transaction is sent to AppSignal before the `set_namespace` helper is called, and the trace is reported under the default namespace instead. #### Read More * [`Appsignal.set_namespace` helper method documentation][ruby helper] ### Elixir In Phoenix controllers we use a `plug` to call a function before the request is handled by Phoenix. In the code example below we use `plug` to call the `set_appsignal_namespace` function (line 5). In this function we call the [`Appsignal.Span.set_namespace` helper][elixir helper] to configure the namespace for this request (line 10). ```elixir Elixir theme={null} # In a Phoenix controller defmodule AppsignalPhoenixExampleWeb.AdminController do use AppsignalPhoenixExampleWeb, :controller plug :set_appsignal_namespace defp set_appsignal_namespace(conn, _params) do # Configures all actions in this controller to report # in the "admin" namespace Appsignal.Span.set_namespace(Appsignal.Tracer.root_span(), "admin") conn end # ... end ``` Next we'll configure the namespace for a background job. To catch any errors from within the job within the desired namespace, `Appsignal.Span.set_namespace` must be called at the beginning of the function before any other code, like on line 4 of the below code example: ```elixir Elixir theme={null} defmodule MyApp.CriticalJob do def run do # Configures this worker's jobs to report in the "critical" namespace Appsignal.Span.set_namespace(Appsignal.Tracer.root_span(), "critical") # The actual worker code end end ``` It's also possible to configure the namespace when creating a transaction. Please see the documentation for [decorators][elixir namespace_decorator] or [instrumentation helpers][elixir namespace_helper] for more information on how to configure namespaces. #### A note on helper location The `set_namespace` helpers used in this guide can be called in any action that starts an AppSignal transaction. We recommend calling this as early in the request or background job as possible, so the transaction is configured with the given namespace before any error occurs. Otherwise, if an error occurs—or anything else that stops the process—the transaction is sent to AppSignal before the `set_namespace` code is called and it is reported under the default namespace instead. #### Read More * [`Appsignal.Span.set_namespace` Helper Method Documentation][elixir helper] * [Elixir Namespace Decorator][elixir namespace_decorator] * [Elixir Namespace Instrumentation Helper][elixir namespace_helper] ### Node.js In Node.js applications, AppSignal works with OpenTelemetry, which uses spans to track metadata, such as which namespace a span belongs to. Use the `setNamespace` helper function as sampled below to set the namespace for the active span's trace. ```javascript Node.js theme={null} import { setNamespace } from "@appsignal/nodejs"; setNamespace("custom-namespace"); ``` [Read more about how spans work in Node.js](/nodejs/3.x/instrumentation/instrumentation). ### PHP In PHP applications, AppSignal works with OpenTelemetry, which uses spans to track metadata, such as which namespace a span belongs to. Use the `Appsignal::setNamespace` helper method to set the namespace for the active span's trace. ```php PHP theme={null} Appsignal::setNamespace("admin"); ``` If you call this helper multiple times within a single trace, AppSignal uses the call whose span has the newest timestamp. [Read more about how custom instrumentation works in PHP][php custom instrumentation]. [php custom instrumentation]: /php/instrumentation.html ### Python In Python applications, AppSignal works with OpenTelemetry, which uses spans to track metadata, such as which namespace a span belongs to. Use the `set_namespace` helper function as sampled below to set the namespace for the active span's trace. ```python Python theme={null} from appsignal import set_namespace set_namespace("custom-namespace") ``` [Read more about how spans work in Python](/python/instrumentation/instrumentation). ### Front-end JavaScript In Front-end JavaScript applications AppSignal works with spans to track metadata such as a span's namespace. > [!TIP] > > Unlike Ruby, Node.js, PHP, and Python, the Front-end JavaScript API does not > have a global `setNamespace` / `set_namespace` helper. Instead, like Elixir, > Go, and Java, you set the namespace directly on a span. When creating this span, call `setNamespace` with a `String` value of the desired namespace name, as demonstrated in the below example: ```javascript JavaScript theme={null} const span = appsignal.createSpan(); span.setNamespace("admin"); // a custom namespace for this span (defaults to `frontend`) ``` [Read more about how spans work in Front-End JavaScript](/front-end/span). ### Go In Go applications, AppSignal works with OpenTelemetry, which uses spans to track metadata, such as which namespace a span belongs to. On any span in the trace, set a `appsignal.namespace` attribute with a String value of the new namespace. ```go Go theme={null} span.SetAttributes(attribute.String("appsignal.namespace", "admin")) ``` Please see the [Go custom instrumentation docs][go custom instrumentation] on how to fetch a span or create a new one. If multiple attributes with the `appsignal.namespace` attribute are found, the span with the newest timestamp is leading. [Read more about how custom instrumentation works in Go][go custom instrumentation]. [go custom instrumentation]: /go/custom-instrumentation.html ### Java In Java applications, AppSignal works with OpenTelemetry, which uses spans to track metadata, such as which namespace a span belongs to. On any span in the trace, set a `appsignal.namespace` attribute with a String value of the new namespace. ```java Java theme={null} span.setAttribute("appsignal.namespace", "admin"); ``` Please see the [Java custom instrumentation docs][java custom instrumentation] on how to fetch a span or create a new one. If multiple attributes with the `appsignal.namespace` attribute are found, the span with the newest timestamp is leading. [Read more about how custom instrumentation works in Java][java custom instrumentation]. [java custom instrumentation]: /java/custom-instrumentation.html ## Deploy When your application is configured with its new namespace helpers, commit your changes and deploy the app. When the app starts/restarts, AppSignal will report actions under their new namespace 🥳! > [!TIP] > > Data from old deploys will remain grouped by their original namespace. Only > newly reported actions will be grouped by their new namespaces. Are namespaces not being reported correctly? Don't panic, [give us a shout][contact] and we will help you out! ## Further Reading * [Filtering App Data][filtering] * [Namespaces][namespaces] * [Ignoring Namespaces][ignoring namespaces] [contact]: mailto:support@appsignal.com [elixir helper]: https://hexdocs.pm/appsignal/Appsignal.Span.html?#set_namespace/2 [elixir namespace_decorator]: /elixir/instrumentation/instrumentation#decorator-namespaces [elixir namespace_helper]: /elixir/instrumentation/instrumentation#starting-new-traces [filtering]: /guides/filter-data/ [ignoring namespaces]: /guides/filter-data/ignore-namespaces.html [namespaces]: /application/namespaces.html [ruby helper]: https://gemdocs.org/gems/appsignal/3.4.0/Appsignal/Transaction.html#initialize-instance_method [tagging]: /guides/tagging.html # Add a new application from our UI Source: https://docs.appsignal.com/guides/new-application Add your first application to AppSignal with the installation wizard. Ruby, Elixir, Node.js, Python, and PHP share five steps, from the Push API key to your first data. Getting your application up and running with AppSignal shouldn't take more than ten minutes. This guide walks through the whole process for Ruby, Elixir, Node.js, Python, and PHP, and links to the equivalent instructions for every other language. ## Requirements AppSignal has an installation wizard that guides you through each step, so [sign in](https://appsignal.com/users/sign_in) to your AppSignal account before you start. If you don't have an account yet, [create a user account](/user-account) and [an organization](/organization) first. Check the [supported operating systems](/support/operating-systems) documentation to make sure your system is compatible with AppSignal. ## Adding your application To register a new application and open the installation wizard, select **Add app** on the applications overview page. If you're already signed in, [this link](https://appsignal.com/redirect-to/organization?to=sites/new) opens the wizard directly. ![The AppSignal applications overview page with the Add app button](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/guides/new_application/dashboard.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=64860dbe64e93436169ff5ce370a787b) The wizard first asks which language your application is written in, then shows the installation steps for it. Those steps vary per language, and they include your **Push API key**, the key that tells AppSignal which organization the data belongs to. You can also find it in [your organization's API keys](https://appsignal.com/redirect-to/organization?to=admin/api_keys). ## Quick install Ruby, Elixir, Node.js, Python, and PHP follow the same five steps: get your Push API key, add the package, configure it, send test data, and deploy. Select your language in any code block below and the rest of this section follows your choice. For front-end JavaScript, Go, and Java, skip to [installing other languages](#installing-other-languages). > [!NOTE] > > PHP needs the OpenTelemetry PHP extension before you start. Read the [PHP > requirements](/php/requirements) page first. ### Step 1: Get your Push API key Every step below needs your **organization-wide Push API key**. Open [your organization's API keys](https://appsignal.com/redirect-to/organization?to=admin/api_keys) and copy the first key shown there. The installation wizard also shows it. ### Step 2: Add the package Add AppSignal to your project's dependencies, then install them: ```sh Ruby theme={null} # Add to your Gemfile: # source "https://rubygems.org" # gem "appsignal" bundle install ``` ```sh Elixir theme={null} # Add to your deps in mix.exs: def deps do [ {:appsignal, "~> 2.8"} ] end mix deps.get ``` ```sh Python theme={null} # Add to requirements.txt: # appsignal pip install -r requirements.txt ``` ```sh PHP theme={null} composer require appsignal/appsignal-php ``` ```sh Node.js theme={null} # npm npm install @appsignal/nodejs # pnpm — the --allow-build flag is required pnpm --allow-build=@appsignal/nodejs add @appsignal/nodejs ``` Ruby, Elixir, Node.js, and Python compile a native extension during installation. Check the [supported operating systems](/support/operating-systems) page for the build tools your system needs. This is why pnpm needs `--allow-build`: it suppresses lifecycle scripts by default, so without the flag the extension is never built and AppSignal reports nothing. ### Step 3: Configure Step 2 installed the package. This step creates its configuration file. Ruby, Elixir, Python and PHP ship a command that writes that file for you: run it from your application's root directory with the Push API key from the wizard, and it asks for anything else it needs. Node.js ships no such command, so you write its file by hand, check the [Node.js installation page](/nodejs/3.x/installation) for the full walkthrough. > [!NOTE] > > [Distributed tracing](/distributed-tracing) needs your app to send its data through an AppSignal hosted collector. Create a collector on the ["Hosted Collector"](https://appsignal.com/redirect-to/organization?to=admin/hosted_collectors) page in your organization's settings. You can also [set up AppSignal with AI](/guides/install-with-agents), which creates one automatically. > > PHP always sends data through a collector, so use its "Collector URL" as the collector endpoint below. Python and Ruby need collector mode, which also enables [logging](/logging/integrations/python) for Python. Follow the [Python](/python/configuration/collector) or [Ruby](/ruby/configuration/collector) collector configuration guide. ```sh Ruby theme={null} bundle exec appsignal install ``` ```sh Elixir theme={null} mix appsignal.install ``` ```sh Python theme={null} # Automated install python -m appsignal install # Or install it manually: # __appsignal__.py from appsignal import Appsignal appsignal = Appsignal( name="My app name", push_api_key="my-push-api-key", active=True, # Default environment is development, # but you can set a different one like "production" environment="development", collector_endpoint="", # Use a different service name for each service service_name="web-server", ) ``` ```sh PHP theme={null} vendor/bin/appsignal install \ --push-api-key= \ --collector-endpoint= \ --app-name= \ --app-environment= ``` ```sh Node.js theme={null} # No `appsignal install` command for Node.js. # Write appsignal.cjs by hand, as shown below. ``` The minimal configuration file it creates is where you also change configuration later: ```ruby Ruby theme={null} # config/appsignal.rb Appsignal.configure do |config| config.activate_if_environment(:development, :staging, :production) config.name = "My app" config.push_api_key = "" end ``` ```elixir Elixir theme={null} # config/appsignal.exs config :appsignal, :config, otp_app: :my_app, name: "My app", push_api_key: "", env: Mix.env, active: true ``` ```python Python theme={null} # Your app file # Add this import statement import appsignal def main(): # Add this method call appsignal.start() if __name__ == '__main__': main() ``` ```php PHP theme={null} # config/appsignal.php # Laravel return [ 'active' => true, 'app_name' => 'My app', 'environment' => 'production', 'push_api_key' => env('APPSIGNAL_PUSH_API_KEY'), 'collector_endpoint' => env('APPSIGNAL_COLLECTOR_ENDPOINT'), ]; # Symfony and Vanilla PHP return [ 'active' => true, 'app_name' => 'My app', 'environment' => 'production', 'push_api_key' => $_ENV['APPSIGNAL_PUSH_API_KEY'], 'collector_endpoint' => $_ENV['APPSIGNAL_COLLECTOR_ENDPOINT'], ]; ``` ```javascript Node.js theme={null} // appsignal.cjs — always .cjs, including in a TypeScript project const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ active: true, name: "My app", pushApiKey: process.env.APPSIGNAL_PUSH_API_KEY, }); ``` > [!WARNING] > > Don't check the Push API key into version control. Read it from a system > environment variable instead, or set `APPSIGNAL_PUSH_API_KEY` on the host and > leave the key out of the config file altogether. Some frameworks and libraries need a step the installer can't do for you: * **Ruby**: Rails is wired up automatically. Sidekiq, Puma, Sinatra, and others are covered in the [Ruby integrations documentation](/ruby/integrations). * **Elixir**: continue with the [Phoenix](/elixir/integrations/phoenix) or [Plug](/elixir/integrations/plug) guide if you use either. * **Python**: AppSignal does not instrument libraries automatically. Add the packages for the libraries you use from the [Python instrumentations documentation](/python/instrumentations). * **PHP**: the installer adds framework auto-instrumentation for you. See the [PHP integrations documentation](/php/integrations) for what it covers. * **Node.js**: load `appsignal.cjs` before every other library by adding `--require ./appsignal.cjs` to the command that starts the app, for example `node --require ./appsignal.cjs index.js`. Nothing is instrumented without it. For compiled TypeScript, add `--enable-source-maps` so backtraces point at your `.ts` source: `node --enable-source-maps --require './appsignal.cjs' dist/src/main.js`. See the [Node.js integrations documentation](/nodejs/3.x/integrations). ### Step 4: Send your first data AppSignal registers a new application only once it receives data. The demo command sends an error and a performance trace so you can confirm the connection works: ```sh Ruby theme={null} appsignal demo ``` ```sh Elixir theme={null} mix appsignal.demo ``` ```sh Python theme={null} python -m appsignal demo ``` ```sh PHP theme={null} vendor/bin/appsignal demo ``` ```sh Node.js theme={null} npx @appsignal/cli demo ``` The Ruby, Elixir, and PHP `appsignal install` commands run this for you at the end, so you may already have seen it. Node.js has no such command, so run the demo yourself. Run it again at any time, or start your application and make a few requests instead. ### Step 5: Deploy Commit the changes and deploy your application. Once the deployed application handles traffic, its errors, traces, and host metrics appear on AppSignal.com. For the full reference on your language, read its installation and configuration pages: * [Ruby installation](/ruby/installation) and [Ruby configuration](/ruby/configuration) * [Elixir installation](/elixir/installation) and [Elixir configuration](/elixir/configuration) * [Python installation](/python/installation) and [Python configuration](/python/configuration) * [PHP installation](/php/installation) and [PHP configuration](/php/configuration) * [Node.js installation](/nodejs/3.x/installation) and [Node.js configuration](/nodejs/3.x/configuration) ## Installing other languages These languages don't use the installer flow above. Follow their own installation instructions instead: * [Front-end JavaScript installation instructions](/front-end/installation): configured with a front-end Push API key, with the application name and environment set in the wizard. * [Go installation instructions](/go/installation): wire up the OpenTelemetry SDK in your application code. * [Java installation instructions](/java/installation): run your application with the OpenTelemetry Java agent. * [OpenTelemetry installation instructions](/opentelemetry/installation): for any other language that exports OpenTelemetry data. For these languages, start your application and make some requests, or trigger a script, to report the first data. ## Completing your installation Once installed, the wizard checks that AppSignal can receive data from your application. If the wizard can't verify the installation, [we're here to help](mailto:support@appsignal.com). A [diagnose report](/support/debugging#diagnose) from your application's host helps us find the cause faster. Once AppSignal is installed successfully, commit and deploy your changes. AppSignal starts receiving data, and you're good to go. Now it's time to [configure your application](/guides/configuration). # Find Slow Database Queries Source: https://docs.appsignal.com/guides/slow-queries Requests and background jobs can be slow for various reasons, but a common cause are slow database queries. Large tables and missing indexes may cause database queries to take longer than needed, increasing the amount of time that your application's users have to wait. AppSignal's Slow Queries feature makes it easier to find an application's slowest queries, to help you decide which queries require optimization. You can view your application's slow queries [here][slow queries]. ## Finding Slow Queries for Ruby, Elixir, Node.js and Python The type of events that can be found in the Slow Queries page are listed below. * Elasticsearch * MongoDB * MySQL * PostgreSQL * Redis * SQLite Events may be grouped under the ORM (Object-relational mapping) event group name for some integrations. ## Finding Slow Queries for OpenTelemetry For OpenTelemetry-based integrations, we look for spans with a certain set of attributes listed below. For the **query body**, we look for the following attributes in order: * `db.query.text` * `db.query.statement` * `db.stored_procedure.name` One of these attributes must be present, and not empty. For the **system name**, we look for the following attributes in order: * `db.system.name` * `db.system` If neither is present, the system will be shown as `Unknown`. If your application is reporting queries in a differently named attribute, or you would like to customize the recognized attributes, please [give us feedback](mailto:support@appsignal.com). ## Sorting Queries By default the slow query list is sorted by impact: the queries that take up the most time either by duration of queries or by how often they are performed. It is also possible to sort this table by "Throughput", how often the query has been recorded, and "Mean", the mean duration of the queries. ## Query Details ![Query details screenshot](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/guides/slow_queries/slow-queries.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=7b4454afee7a54e163b9422a985096b1) You can click on a query to gain the following insights: * Full query with optional event title for more context * The database query event summary: * Mean duration of query * Throughput, how often the query was recorded * The impact of the query in percentage of all database queries in the selected timeframe. * Response time graph * Throughput graph * Actions and performance measurements in which the event occurred: * You can go directly to actions and performance measurements in which the event was recorded to view the impact per request/background job in the trace event timeline. [slow queries]: https://appsignal.com/redirect-to/app?to=improve/queries # Find Slow HTTP requests Source: https://docs.appsignal.com/guides/slow-requests Requests and background jobs can be slow for various reasons, but a common cause are slow HTTP requests to external services. This can include sending emails, fetching data from third-party APIs, and other HTTP requests. AppSignal's Slow Requests feature makes it easier to find an application's slowest HTTP requests, to help you decide which requests require optimization or should be moved to asynchronous processes. View your application's [Slow Requests][slow requests]. ## Finding Slow Requests for Ruby, Elixir, Node.js and Python The type of [event groups](/api/event-names) that can be found in the Slow Requests page are listed below. * faraday * grpc * http * http\_rb * net\_http * excon * request * requests * service * finch * tesla * fetch Events may be grouped under the HTTP library's event group name for some integrations. If your application is reporting HTTP requests in a differently named attribute, or you would like to customize the recognized attributes, please [give us feedback](mailto:support@appsignal.com). ## Finding Slow Requests for OpenTelemetry For OpenTelemetry-based integrations, we look for spans with a certain set of attributes listed below. We follow the [OpenTelemetry HTTP client span specification](https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client-span). For the **HTTP request server name**, we look for the following attributes in order: * `server.address` * `net.peer.name` * `http.server_name` One of these attributes must be present, and not empty. For the **HTTP request method**, we look for the following attributes in order: * `http.request.method` * `http.method` If neither is present, the system will be shown as `Unknown`. If your application is reporting HTTP requests in a differently named attribute, or you would like to customize the recognized attributes, please [give us feedback](mailto:support@appsignal.com). ## Sorting HTTP requests By default the slow HTTP requests list is sorted by impact: the requests that take up the most time either by duration or by how often they are performed. It is also possible to sort this table by "Throughput", how often the request has been recorded, and "Mean", the mean duration of the requests. ## HTTP Request Details ![Query details screenshot](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/guides/slow_requests/slow_requests.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=c17a85461da5de9b4d17d1b1d8e659c1) You can click on an HTTP request to gain the following insights: * Domain that was contacted * Which HTTP request method was used * The HTTP request event summary: * Mean duration of the HTTP request * Throughput, how often the HTTP request was recorded * The impact of the HTTP request in percentage of all HTTP requests in the selected timeframe. * Response time graph * Throughput graph * Actions and performance measurements in which the event occurred: * You can go directly to actions and performance measurements in which the event was recorded to view the impact per request/background job in the trace event timeline. [slow requests]: https://appsignal.com/redirect-to/app?to=improve/requests # Add Tags to a Request Source: https://docs.appsignal.com/guides/tagging You can use tagging to supply extra context on errors and traces. Tagging can help to add information that is not already part of a request, such as the session data, headers, environment data, or parameters. Tags can also be used to filter traces to find all errors for a specific user or slow pages for a particular locale. You can set tags wherever the current transaction or span is accessible. We recommend calling it before your application code runs in a request, such as a callback. You can see what tags apply to a trace on the [Errors and Performance](https://appsignal.com/redirect-to/app?to=performance) pages. Using [Link Templates](/application/link-templates) it's possible to add links to your application with tag data, such as the admin panel for the signed-in user. You can see this in practice in the below screenshot, with the `Link 1` and `Link 2` tags. ![Tag a request](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/tags/tags.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=01142180faf7fb0a63eb54549eb76f50) > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > Use [Link Templates](https://docs.appsignal.com/application/link-templates) to link them back in your app. ## Ruby With the [AppSignal for Ruby](/ruby) gem, use the `Appsignal.add_tags` helper methods to add tags to error and performance traces. On Ruby gem version 3 and older, use the `Appsignal.set_tags` helper. You can use `Appsignal.add_tags` wherever an active transaction is accessible, we recommend calling it before your application code runs in the request, such as in a `before_action` using Rails. ```ruby Ruby theme={null} before_action do Appsignal.add_tags( :user_id => current_user.id, :stripe_customer_id => stripe_customer_id, :locale => I18n.locale, :default_locale => I18n.default_locale ) end ``` ### Default tags You can configure tags that will be added to all transactions using the [`default_tags` config option](/ruby/configuration/options#option-default_tags). These tags are applied automatically to every transaction. Transaction-specific tags set with `Appsignal.add_tags` will override default tags with the same key. ```ruby Ruby theme={null} Appsignal.configure do |config| config.default_tags = { "region" => "europe", "shard" => "shard-1" } end ``` ```yaml YAML theme={null} default: &defaults default_tags: region: europe shard: shard-1 ``` ```bash Shell theme={null} export APPSIGNAL_DEFAULT_TAGS="region=europe,shard=shard-1" ``` ### Limitations Tags that do not meet these limitations are dropped without warning. * The tag key must be a String or Symbol. * The tagged value must be a String, Symbol, Integer or Boolean (true/false). * Boolean values are supported in Ruby gem 3.11 and newer. * The length of the tag value must be less than 256 characters. * Nested hash values are not supported for tags, please use [custom data](/guides/custom-data/custom-data) instead. ```ruby Ruby theme={null} # Unsupported: hash value type is not supported Appsignal.add_tags( :i18n => { :locale => I18n.locale, :default_locale => I18n.default_locale } ) ``` ## Elixir Use the [`Appsignal.Span.set_sample_data`](https://hexdocs.pm/appsignal/Appsignal.Span.html#set_sample_data/2) function to supply extra context on errors and performance traces. Use the `"tags"` sample key for the function to add tags to the span. ```elixir Elixir theme={null} Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "tags", %{ locale: "en", user_id: user_id, stripe_customer_id: stripe_customer_id, locale: locale, default_locale: default_locale } ) ``` ### Last call is leading The `set_sample_data` helper can be called multiple times, but only the last value will be retained. When the code is run below: ```elixir Elixir theme={null} Appsignal.Span.set_sample_data(Appsignal.Tracer.root_span, "tags", %{locale: "en"}) Appsignal.Span.set_sample_data(Appsignal.Tracer.root_span, "tags", %{user: "bob"}) Appsignal.Span.set_sample_data(Appsignal.Tracer.root_span, "tags", %{locale: "de"}) ``` it will result in the following tags being stored: ```elixir Elixir theme={null} %{ locale: "de" } ``` ### Setting sample data on a span To add sample data to a span as soon as it's created, add a `custom_on_create_fun`: ```elixir Elixir theme={null} defmodule MyApp.Appsignal do def custom_on_create_fun(_span) do Appsignal.Span.set_sample_data(Appsignal.Tracer.root_span, "tags", %{"locale": "en"}) end end ``` Then, add it to your app's configuration: ```elixir Elixir theme={null} # config/config.exs config :appsignal, custom_on_create_fun: &MyApp.Appsignal.custom_on_create_fun/1 ``` The `custom_on_create_fun` requires AppSignal for Elixir version 2.8.3 or higher. ### Limitations Tags that do not meet these limitations are dropped without warning. * The tag key must be a `String` or `Atom`. * The tagged value must be a `String`, `Atom` or `Integer`. * The length of the tag value must be less than 256 characters. * Nested map values are not supported for tags, please use [custom data](/guides/custom-data/custom-data) instead. ```elixir Elixir theme={null} # Unsupported: map value type is not supported Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "tags", %{ i18n: %{ locale: "en_GB", default_locale: "en_US" } } ) ``` ## Node.js Import the `setTag` helper function to add tags to spans for errors and performance traces. ```javascript Node.js theme={null} import { setTag } from "@appsignal/nodejs"; setTag("user_id", user_id); setTag("stripe_customer_id", stripe_customer_id); setTag("locale", locale); setTag("default_locale", default_locale); ``` ### Limitations Tags that do not meet these limitations are dropped without warning. * The tag key must be a `String`. * The tagged value must be a `String`, `Number` or `Boolean`. * The length of the tag value must be less than 256 characters. * Nested object values are not supported for tags, please use the [`setCustomData`](/guides/custom-data/custom-data) helper function instead. ```javascript Node.js theme={null} const tracer = appsignal.tracer(); const span = tracer.currentSpan(); # Unsupported: object value type is not supported span.set("i18n", { locale: "en_GB", default_locale: "en_US" }); ``` ## Python Import the `set_tag` helper method to add tags to spans for errors and performance traces. ```python Python theme={null} from appsignal import set_tag set_tag("user_id", user_id) set_tag("stripe_customer_id", stripe_customer_id) set_tag("locale", locale) set_tag("default_locale", default_locale) ``` ### Limitations Tags that do not meet these limitations are dropped without warning. * The tag key must be a String. * The tagged value must be a String, Integer, Float or Boolean. * The length of the tag value must be less than 256 characters. * Nested object values are not supported for tags, please use the [`set_custom_data`](/guides/custom-data/custom-data) helper function instead. ## Go In a Go app, to add an AppSignal tag to a span on a trace, first fetch the active span or create a new span as described on [our Go custom instrumentation page](/go/custom-instrumentation). Then, set an attribute on the span using the attribute helper that matches the type of the tag value, see also [the tag limitations below](#go-limitations). The span attribute name has the following format: `appsignal.tag.`. Replace `` with the name of the tag. ```go Go theme={null} // Example format span.SetAttributes(attribute.String("appsignal.tag.", "string")) // Supported types span.SetAttributes(attribute.String("appsignal.tag.my_tag_string", "tag value")) span.SetAttributes(attribute.StringSlice("appsignal.tag.my_tag_int64", []string{"abc", "def"})) span.SetAttributes(attribute.Bool("appsignal.tag.my_tag_bool_true", true)) span.SetAttributes(attribute.Bool("appsignal.tag.my_tag_bool_false", false)) span.SetAttributes(attribute.BoolSlice("appsignal.tag.my_tag_bool_slice", []bool{true, false})) span.SetAttributes(attribute.Float64("appsignal.tag.my_tag_float64", 12.34)) span.SetAttributes(attribute.Float64Slice("appsignal.tag.my_tag_float64_slice", []float64{12.34, 56.78})) span.SetAttributes(attribute.Int("appsignal.tag.my_tag_int", 1234)) span.SetAttributes(attribute.IntSlice("appsignal.tag.my_tag_int", []int{1234, 5678})) span.SetAttributes(attribute.Int64("appsignal.tag.my_tag_int64", 1234)) span.SetAttributes(attribute.Int64Slice("appsignal.tag.my_tag_int64_slice", []int64{1234, 5678})) ``` ### Limitations Tags that do not meet these limitations are dropped without warning. * The tag key must be a String. * The tagged value must be a String, Integer, Float, Boolean, or a slice of those types. * The length of the tag value must be less than 256 characters. * Array values are flattened to comma separated values. * Nested object values (maps) are not supported for tags. ## Java In a Java app, to add an AppSignal tag to a span on a trace, first fetch the active span or create a new span as described on [our Java custom instrumentation page](/java/custom-instrumentation). Then, set an attribute on the span using the `setAttribute` method. The span attribute name has the following format: `appsignal.tag.`. Replace `` with the name of the tag. ```java Java theme={null} import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.common.AttributeKey; // Get the current span Span span = Span.current(); // Example format span.setAttribute("appsignal.tag.", "string"); // Set tags as span attributes span.setAttribute("appsignal.tag.my_tag_string", "tag value"); span.setAttribute(AttributeKey.stringArrayKey("appsignal.tag.my_tag_string_array"), Arrays.asList("abc", "def")); span.setAttribute("appsignal.tag.my_tag_bool_true", true); span.setAttribute("appsignal.tag.my_tag_bool_false", false); span.setAttribute(AttributeKey.booleanArrayKey("appsignal.tag.my_tag_bool_array"), Arrays.asList(true, false)); span.setAttribute("appsignal.tag.my_tag_float64", 12.34); span.setAttribute(AttributeKey.doubleArrayKey("appsignal.tag.my_tag_float64_array"), Arrays.asList(12.34, 56.78)); span.setAttribute("appsignal.tag.my_tag_int", 1234); span.setAttribute(AttributeKey.longArrayKey("appsignal.tag.my_tag_int_array"), Arrays.asList(1234L, 5678L)); span.setAttribute("appsignal.tag.my_tag_int64", 1234); span.setAttribute(AttributeKey.longArrayKey("appsignal.tag.my_tag_int64_array"), Arrays.asList(1234L, 5678L)); ``` ### Limitations Tags that do not meet these limitations are dropped without warning. * The tag key must be a String. * The tagged value must be a String, Integer, Long, Double, or Boolean, or a list of these values. * The length of the tag value must be less than 256 characters. * Array values are flattened to comma separated values. * Nested object values (maps) are not supported for tags. ## PHP In PHP applications, to add an AppSignal tag to a span on a trace, use the `Appsignal::addTags()` helper method. ```php PHP theme={null} 'tag value', 'my_tag_string_slice' => ['abc', 'def'], 'my_tag_bool_true' => true, 'my_tag_bool_false' => false, 'my_tag_bool_slice' => [true, false], 'my_tag_float64' => 12.34, 'my_tag_float64_slice' => [12.34, 56.78], 'my_tag_int' => 1234, 'my_tag_int_slice' => [1234, 5678], 'my_tag_int64' => 1234, 'my_tag_int64_slice' => [1234, 5678], ]); ``` ### Limitations Tags that do not meet these limitations are dropped without warning. * The tag key must be a String. * The tagged value must be a String, Integer, Float, or Boolean, or a slice of these values. * The length of the tag value must be less than 256 characters. * Array values are flattened to comma separated values. * Nested object values (maps) are not supported for tags. ## See also * [User impersonation in Rails 8 authentication](/tutorials/ruby/impersonation): let an administrator view the application as another user. Tagging those requests with the administrator's own identity keeps support activity distinct from a customer's. # Attribute distributions Source: https://docs.appsignal.com/guides/tagging/attribute-distributions Attribute distributions can help you get to the source of an error by showing a distribution of errors per tag. ![Screenshot of Attributes Page](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/guides/custom-data/attributes-page.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=dcb7d2450dc1aa94f1fdb5b10d7e9bdc) This can help you show how many errors happened on frontend1 vs frontend2, for example. Or if a specific deploy caused more errors than another deploy. Attribute distributions work by looking at "special" tags in a trace. We extract the values from these special tags and compute the distributions from them. ## Tagging traces You can tag a trace with the following tags to get enriched distributions for them: * `hostname` To show distributions by hosts * `revision` To show distributions per deploy/revision * `country` (For front-end errors) to show which countries experience the most issues * `country_code` (For front-end errors) to show which countries experience the most issues * `browser` (For front-end errors) to show which browser is the cause The following tags are also accepted, but not enriched. They are shown as tagged: * `company` * `slug` * `user_id` * `account_id` * `customer_id` * `visitor_id` * `client_id` * `group_id` * `site_id` Most of the enriched tags are applied to traces automatically; our agent sets the `hostname` tag and if you use deploy tracking with ENV vars, we use the `revision` tag from that. For front-end errors we extract the `country` from the IP address that sent the error, as well as the `browser` tag. Tags we don't set automatically are the `user_id` and `company` tags. You can tag these yourself to get a better sense of which users have experienced an issue. If you'd like to use attributes not in this list, we're happy to add more. Please [contact support](mailto:support@appsignal.com). ## Notes to keep in mind We extract tags from traces, which means in some cases, if an enormous amount of errors are sent in a short timeframe, we don't get every tag from every trace, as these are throttled by our integrations. Tags are stored for the duration of your plan's retention. This can range from seven days to sixty days, depending on your plan. This means distributions can change over time, depending on how many error traces we still have in retention. # AppSignal Labs Source: https://docs.appsignal.com/labs Try experimental features early and help shape what we build next. Labs is where new ideas land first, before they make it into the rest of AppSignal. ## What to expect Three things to keep in mind about Labs features. > **Early access** > > Use features before they're generally available. > **Rough edges** > > Features may be incomplete or change without notice. Not covered by our SLA. > **Direct influence** > > Your feedback goes straight to the team building the feature. ## Stages Each Labs feature sits at one of three stages. The stage tells you how to get involved: * **In research:** We're exploring the problem and shaping the solution. You may see early pull requests, prototypes, or open calls for UX research sessions. Join a session to help us scope what we build. * **In beta:** We're rolling these out gradually as we polish the rough edges. Some beta features sit behind a feature flag and may need to be enabled by [Support](mailto:support@appsignal.com). Share what you run into in our [Discord](https://discord.gg/EjF6ykYx63) channel. * **In preview:** Closer to general availability. Self-serve and ready to try: turn it on yourself, explore what's there, and share your feedback in our [Discord](https://discord.gg/EjF6ykYx63) channel. ## Current Labs features > **Apdex** > > **In preview** > > Measure how satisfied your users are with your application's performance. Set **Satisfied** and **Tolerating** response time thresholds per namespace, and AppSignal generates `apdex` and `apdex_counts` metrics you can add to dashboards and anomaly detection triggers. Display them as a **single value** or **time series**, so you can see your current score at a glance. > > [Read the Apdex docs →](/metrics/apdex) > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) > **Log-based metrics** > > **In preview** > > Turn data from your logs into metrics without writing any new code or leaving the Logs page. Filter your logs to the events you care about (for example requests to `/api/orders`), select **Create a metric** from a log line, and AppSignal builds a Count, Gauge, or Measurement metric using the query, severity, and source you already had open. Use it on a dashboard or in a trigger. > > [Read the log-based metrics docs →](/logging/metrics) > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) > **Set up with AI** > > **In preview** > > Set up AppSignal in your application with an AI agent and send your first data. In your organization, select **Add app** and then **Set up with AI**, then paste the prompt into your agent. The prompt includes a provisioning token and points to AppSignal's agent instructions, so the agent can inspect your project, choose the right integration, and confirm details such as application name and environment before it changes files. Setup is complete when your first data reaches AppSignal. > > This works with agents that can read a URL and edit files, such as Claude Code, Cursor, or Codex. > > [Read the AI setup docs →](/guides/install-with-agents) > > [Browse the agent instruction files →](/guides/install-with-agents#agent-instruction-files) > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) > **Distributed tracing** > > **In preview** > > Follow a request as it travels across your services and applications. Distributed tracing is built on OpenTelemetry. Its trace timeline shows every span in a request, across service boundaries, so you can see where the time goes. When a trace crosses more than one service, a service map shows which services it reached and how long each call took. The service map is now available to everyone. > > Available for Python, Ruby, and PHP, and for any OpenTelemetry-instrumented application that reports to a hosted collector. We'd like to hear what works and what you'd want from it next. > > [Read the distributed tracing docs →](/distributed-tracing) > > [Set up distributed tracing →](/distributed-tracing#availability-and-setup) > > [Read the trace page docs →](/trace-page) > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) > **AppSignal CLI** > > **In beta** > > A command-line interface for AppSignal, built in Rust. Designed for both people and AI agents to query your AppSignal data from the terminal. Install it with Homebrew. > > We'll keep expanding the CLI toward feature parity with the AppSignal API. > > [Read the AppSignal CLI docs →](/cli) > > [Install the CLI →](https://github.com/appsignal/homebrew-appsignal-cli#install) > > [See the latest releases →](https://github.com/appsignal/homebrew-appsignal-cli/releases) > **Browser monitoring: front-end errors and Core Web Vitals** > > **In beta** > > Front-end monitoring for your browser apps, in its own Browser section. Front-end errors arrive with a breadcrumb trail of what the user did before them, collected without configuration. Core Web Vitals from real users (LCP, INP, CLS, FCP, and TTFB) are aggregated per route, so you can see which are slow and filter by app version to compare releases. Collection is handled by `@appsignal/browser`, a new standalone package that replaces `@appsignal/javascript`. > > [Read the browser monitoring docs →](/browser) > > [Install `@appsignal/browser` →](/browser/installation) > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) > **New Slack app** > > **In beta** > > Slack app is a newly rearchitected Slack integration with two-way sync. Supports actions to close, reopen incidents or change an assignee. Closing an incident in AppSignal UI will be reflected on the corresponding Slack notification. > > Add Slack from **Add new notifier** on the Notifications page. > > [Read the Slack integration docs →](/application/integrations/slack) > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) > **Responsive UI for mobile** > > **In beta** > > We're improving the responsive UI for mobile users, so you can read and act on your data from a phone. So far this covers: > > * Dashboards and the Discover AppSignal page > * The Logs page filters > * App and organization settings > * The time and date filter, and Time Detective > * Page titles and breadcrumbs > * Error breadcrumbs > * The trace timeline > > This work ships page by page, and each page is live for everyone once it lands. There's nothing to turn on. Tell us which screens you reach for on a phone, and what still doesn't work there. > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) > **GitHub bidirectional sync** > > **In beta** > > Today, **Send to GitHub** creates a GitHub issue from an incident. We're rebuilding the integration so changes in GitHub update the incident too. > > Already available: > > * An incident can link to more than one issue or pull request. Mention one in a note, and AppSignal links it. > * Each linked issue shows whether it is open, closed, or merged. AppSignal updates the status when it changes on GitHub. > * Status changes show in the incident's logbook, with who made them on GitHub. > > We're working toward: > > * Assignees match in AppSignal and GitHub > * An incident reopens when its GitHub issue reopens > * An incident closes when its linked pull request is merged and deployed > * GitHub issue comments show on the incident > * AppSignal adds labels to new issues based on the incident type > > The status sync needs new permissions on the AppSignal GitHub app. When AppSignal asks for them, an owner of your GitHub organization [approves them on GitHub](/application/integrations/github/link-to-repo#approve-new-permissions-on-github). **Send to GitHub** keeps working while we build. Tell us which of these you need most. > > [Read the GitHub integration docs →](/application/integrations/github) > > [Share feedback on Discord →](https://discord.gg/EjF6ykYx63) ## Get involved > **[UX research sessions](https://discord.gg/EjF6ykYx63)** > > 30-minute video calls where you share what's working and what isn't. > **[Feedback](https://discord.gg/EjF6ykYx63)** > > Use the in-feature feedback button or join us on Discord. ## FAQ > **Will Labs features affect my production data?** > > No. Labs features operate alongside your existing setup with explicit opt-in where needed. > **Can I disable a Labs feature?** > > Yes, at any time. Your configuration is preserved. > **What happens to my feedback?** > > The team building that feature reads every piece of feedback. # AppSignal Logging Source: https://docs.appsignal.com/logging AppSignal Logging stores, shows, and queries your application's logs. Supported integrations, best practices, log retention, and limitations. Having quick access to your application’s logs is crucial for troubleshooting issues and assessing the health of various components, from your database to your messaging queue. AppSignal Logging consolidates your application’s logs, enabling you to store, view, and query them, offering deeper insights into your application's performance and behavior. If you need to store logs for long retention periods, you can export them to an S3-compatible storage solution using the [Long-Term Log Storage add-on](#log-retention). ### AppSignal Logging helps you answer questions like ## Getting started Our documentation covers everything you need to know to get AppSignal Logging up and running with your application. * [How to configure logging](/logging/configuration) * [How to manage your logs](/logging/log-management) * [How to query your logs](/logging/query-syntax) * [How to export your logs with Long-term Log Storage](/logging/long-term-log-storage) * [How to create and manage triggers](/logging/triggers) * [How to troubleshoot issues](/logging/troubleshooting) ## Supported AppSignal Integrations The following AppSignal integrations feature out-of-the-box support for AppSignal Logging: * [Ruby](/logging/integrations/ruby) * [Elixir](/logging/integrations/elixir) * [Node.js](/logging/integrations/nodejs) * [Go](/logging/integrations/go) * [Java](/logging/integrations/java) * [PHP](/logging/integrations/php) * [Python](/logging/integrations/python) ## Best Practices To log or not to log, that can be a tricky question to answer. The best kinds of logs are descriptive, contextual, and concise. With AppSignal, you can get the most out of your logs by utilizing features like [custom attributes](/logging/formatting), which allow you to add additional, filterable data to your log lines. You can read our [Learning Center article on logging best practices](https://www.appsignal.com/learning-center/what-logs-should-i-store) for more information on properly utilizing your application logs. ## Log Retention > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). Retention will vary depending on your plan. You can find actual retention and pricing information on our [plans page](https://www.appsignal.com/plans). If you need to store logs for longer periods, you can export them to an S3-compatible storage solution using the [Long-Term Log Storage add-on](/support/business-add-ons#long-term-log-storage). This add-on allows you to retain your logs beyond the 30-day period AppSignal typically stores them, giving you greater control over your log data retention. For setup instructions, visit the [Long-Term Log Storage setup guide](/logging/long-term-log-storage). ## Limitations AppSignal Logging complements our APM features by capturing important events like slow database queries, admin activity, and outgoing API calls. However, there are some limitations: * We support up to **500k log lines per minute per app**. * Log lines can be up to **10,000 characters**, with any excess being truncated. * Deeply nested JSON payloads are not supported. For advanced monitoring and custom data tracking, we recommend using our [Errors](https://www.appsignal.com/tour/errors) and [Performance](https://www.appsignal.com/tour/performance) features, which are better suited for such use cases. # Configure Logging Source: https://docs.appsignal.com/logging/configuration Create a log source for a logging platform or endpoint and choose its message format. Not needed when you log from an AppSignal integration. This documentation will take you through all the necessary steps and additional information needed when adding a new log source to your application. ## Creating a Log Source > [!NOTE] > > ✨ You do not need to create a log source when sending logs directly from an > AppSignal integration. A log source will be automatically created for you. > Follow the instructions for [logging from AppSignal > integrations](/logging/integrations). To send logs to AppSignal, you'll first need to configure your log sources. Your application could have many log sources, like a database or app process. You will need to do this once per log source. For example, if you want to send MongoDB and NGINX logs to AppSignal, you'd need to create a source for each of these integrations. ![Screenshot of Logging Sources page](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/view-source.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=7b63838a05d0fee525cb5ecbe3a7a883) To do this, navigate to the Logging page in the AppSignal application and click on the `Add log source` button in the top right of the page. A pop-up will appear, prompting you to name your source. It's important to give your source a descriptive name like Redis or MongoDB so that you can successfully query these logs in the future. ![Add new Log Source form](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/add-new-source.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=a8fb34d76efb364eb9a4f0d6ecc37f97) ### Choose Your Platform > [!TIP] > > Are you setting up logging for Vercel? There are some additional steps > required when creating a Vercel log source. Read our [Vercel Configuration > documentation](/vercel/logs) for step-to-step setup instructions. We support sending logs to AppSignal from various sources and platforms and are hard at work to add support for more. You can find out more about the platforms supported in this documentation's [Platform Configuration](#platform-configuration) section. If your platform is not listed, you can send logs to [one of our endpoints](/logging/endpoints) directly. ### Choose The Message Format > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). Some sources are based on a third-party integration, where you can't control the format of the log line. In this case, you can choose the format of the log line that AppSignal will attempt to parse the `message` from. This allows you to add structure to your log lines, without controlling the surrounding log line format. For example, if you use the Netlify integration, which takes care of sending log lines to AppSignal in their own format, allowing us to extract the correct time and hostname, you can choose the `json` log format to add additional attributes to a log line. When we support parsing the log message, we support these formats: * [Plaintext](/logging/formatting#plaintext) * [Logfmt](/logging/formatting/logfmt) * [JSON](/logging/formatting/json) Read more about how to format your messages in the [Formatting Documentation](/logging/formatting). ### Create Source Once you've chosen the name and format of your new source is created, it will be listed in the Log Sources table on the Logs page, alongside a generated API key. ![Screenshot of Log Sources table pointing to API key](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/highlight-api.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=c14f61255f690cc8dfe4dfb2e3e7dbf9) You will now need to configure your application to send logs to AppSignal using one of the [platforms we support](#platform-configuration). ## Platform Configuration Once you've created a new source, you'll need to configure your application to send logs to AppSignal. This should be via the same platform you defined when creating your log source. ### Supported Logging Platforms * AWS CloudWatch logs through Amazon Data Firehose * [Manual setup](/logging/platforms/cloudwatch) * [CloudFormation setup](/logging/platforms/cloudwatch-cloudformation) * [Clever Cloud](/logging/platforms/clevercloud) * [Gigalixir Log Drain](/logging/platforms/gigalixir) * [Heroku](/logging/platforms/heroku) * [Netlify](/logging/platforms/netlify) * [Render](/logging/platforms/render) * [Scalingo](/logging/platforms/scalingo) * [Vector](/logging/platforms/vector) * [Vercel](/vercel/logs) ### Supported Logging Endpoints * [HTTP](/logging/endpoints/http) * [HTTP-JSON](/logging/endpoints/http-json) * [HTTP-Syslog](/logging/endpoints/http-syslog) * [Syslog](/logging/endpoints/syslog) ## Completing Setup > [!NOTE] > > As AppSignal only stores logs that are sent to it from your application, you > will only be able to see logs created **after** you've completed your > configuration. Once you've configured your chosen platform, you'll be able to view and query your logs from the `All logs` page in the AppSignal application. There's more information on how to manage, view, and query your logs in this guide's [next step](/logging/log-management). ![Screenshot of expanded log](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/all-logs.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=294a9482dd18a89b870da2f9f8f13055) ## Adding Long-Term Storage You can configure a source for storing logs with your own secure S3-compatible storage using AppSignal's Long-term Log Storage. This feature requires a paid Business Add-On. AppSignal will continue to retain your logs for 30 days. Learn more in our [Long-Term Log Storage documentation](/logging/long-term-log-storage). ## Troubleshooting and support If you've followed the above steps and cannot see any logs in AppSignal, you may want to read our [Troubleshooting Guide](/logging/troubleshooting) or [reach out to us for assistance](mailto:support@appsignal.com). # Drop logs after extracting metrics Source: https://docs.appsignal.com/logging/drop-logs-after-extracting-metrics Extract metric data from selected log lines before dropping them. Turn this on for a log-based metric, or set it up through AppSignal MCP. Suppose an online store writes a log entry each time a shopper searches its catalog. A single entry describes one search, while the number of entries over time can reveal broader changes. If search activity drops while overall store traffic remains steady, it may indicate that shoppers cannot reach or use the search feature. AppSignal can extract metric data from matching log lines before dropping them. The metric remains available for dashboards and triggers, but AppSignal does not store the matching lines. Turn on **Drop log line after metric extraction** when you create or edit a [log-based metric](/logging/metrics). AppSignal sets up the drop for you. You can also create the underlying actions through AppSignal MCP, as described in the [log processing workflow](/mcp/workflows#setting-up-log-processing). ## How it works When a new log line matches a saved log-based metric, AppSignal extracts the metric data before dropping the line. The metric remains available for dashboards and triggers, but the matching log line is not stored. The toggle creates a companion filter directly after the metrics action, using the same query and log sources. When you edit the metric in the AppSignal UI, AppSignal updates the filter as well. Disabling the toggle or deleting the metric removes the companion filter. > [!NOTE] > > This setting applies only to logs received after it takes effect. It does not remove logs that AppSignal has already stored. The **Data preview** in the metric form and the Logs page use stored log data. They can still show earlier matching lines, but they do not include lines dropped after metric extraction. Use a dashboard to confirm that the saved metric is receiving new data. ## Before you start * A log source that receives the lines you want to measure * A query that matches those lines * For the MCP route, [AppSignal MCP](/mcp-server) set up in your AI agent, with write access to the logging tools ## Turn it on with the toggle 1. On the **Logs** page, filter to the lines you want to measure and open one. 2. In the **Actions** section, select **Create a metric**. 3. Name the metric, choose its type, and check the **Data preview**. Turn on **Drop log line after metric extraction**, confirm with **Drop log lines**, and select **Create metric**. > [!NOTE] > > Before enabling the drop, use the **Data preview** to confirm that the query matches only the lines you intend to discard. You can also enable the setting for an existing metric: 1. Open the **Metrics** page from the **Logging** side menu. 2. Open the metric's three-dot menu and select **Edit**. 3. Turn on **Drop log line after metric extraction**, confirm with **Drop log lines**, and select **Update metric**. The three-dot menu also contains the **Add to dashboard**, **Create trigger**, and **Delete** actions. The metric now shows **Drop after match** in the **Action** column of the **Metrics** page. ## Set it up through AppSignal MCP The MCP tool does not expose the UI toggle. Your agent creates two independent actions instead: a metrics action followed by a filter with the same query and log sources. Because the actions are not linked, update both if you later change the query or sources. AppSignal processes log line actions in order. A filter prevents a matching line from reaching later actions, so the metrics action must run before the filter. ### Step 1: Record a metric from the lines Ask your agent to add a metrics action. For example, to count how often shoppers search your catalog: > On MyStore production, add a metrics log line action that counts log lines matching `message:"Type your message here"` as a counter named `log.catalog_searches`, scoped to the application log source. Your agent can call `manage_log_line_action` with: ```json theme={null} { "app_name": "MyStore", "app_environment": "production", "action": "upsert", "name": "Catalog search rate", "action_type": "metrics", "query": "message:"\"Type your message here\"", "source_ids": [""], "log_line_metrics": [ { "name": "log.catalog_searches", "metric_type": "counter" } ] } ``` For details about these fields, see the [`manage_log_line_action` reference](/mcp/reference#manage_log_line_action). ### Step 2: Check the metric before you drop anything After AppSignal receives matching lines, read the metric back: > Show me the `log.catalog_searches` counter for MyStore production over the last 15 minutes. > [!WARNING] > > Confirm that the counter is recording and that the query matches only the lines you intend to discard. AppSignal does not store dropped lines, so you cannot recover them from AppSignal. ### Step 3: Drop the matching lines Add a filter action with the same query: > On MyStore production, add a filter log line action that drops log lines matching `message:"Type your message here"`. ```json theme={null} { "app_name": "MyStore", "app_environment": "production", "action": "upsert", "name": "Drop catalog search logs", "action_type": "filter", "query": "message:\"Type your message here\"", "source_ids": [""] } ``` ### Step 4: Keep the metrics action before the filter New actions are added at the end of the order, so the filter already runs after the metrics action. Confirm the order: > List the log line actions on MyStore production, and keep the metrics action before the filter. Your agent can use `get_app_resources` to read the order, then call `manage_log_line_action` with `action: "reorder"` if the filter is ahead of the metrics action. If the filter ran first, it would drop the lines before the metrics action counted them. ## Verify it works After AppSignal applies the actions and receives new matching lines, verify the result: 1. Read the metric and confirm that it contains data from new matching lines. 2. Search your logs with the same query. Lines received after the filter took effect should not appear. If the metric has no new data, or matching lines continue to appear, check the query and action order. Then try again with new log lines. ## Behavior and limitations * **Actions are not retroactive.** Logs stored before you created the action stay as they are. * **UI edits keep companion actions aligned.** Editing the metric in the AppSignal UI updates its companion filter. Deleting the filter through MCP keeps the metric and disables dropping. * **Actions created through MCP are independent.** To measure and drop the same lines, give both actions the same query and log sources, and update both when their configuration changes. ## Related * [Log-based metrics](/logging/metrics), where the toggle lives * [AppSignal MCP](/mcp-server), the [MCP tool reference](/mcp/reference), and the [log processing workflow](/mcp/workflows#setting-up-log-processing) * [Ignore logs](/guides/filter-data/ignore-logs), to stop sending lines from your integration in the first place # Supported Log Endpoints Source: https://docs.appsignal.com/logging/endpoints ## Supported Log Endpoints When you can't use any of our [platforms](#supported-platforms) or [integrations](#supported-appsignal-integrations), you can send logs directly to one of our four endpoints available: * **[HTTP-JSON](/logging/endpoints/http-json)**: this endpoint expects NDJSON formatted log lines in the format described here. * **[HTTP-Syslog](/logging/endpoints/http-syslog)**: this endpoint expects Syslog-formatted log lines in the format described here. * **[HTTP](/logging/endpoints/http)**: this endpoint accepts plain-text log lines, that don't have any additional information. We use the time we received the log line as the timestamp, and other fields such as group and hostname are empty. In order to add additional information to a log line, you can format the log lines with one of the message formats described below. * **[Syslog](/logging/endpoints/syslog)**: this endpoint expects Syslog-formatted log lines in the format described here. You can use a specific format in the log message to override log information, or add additional attributes for a log line. ### Supported Platforms AppSignal Log Management supports the following platforms: * AWS CloudWatch logs through Amazon Data Firehose * [Manual setup](/logging/platforms/cloudwatch) * [CloudFormation setup](/logging/platforms/cloudwatch-cloudformation) * [Clever Cloud](/logging/platforms/clevercloud) * [Gigalixir Log Drain](/logging/platforms/gigalixir) * [Heroku](/logging/platforms/heroku) * [Netlify](/logging/platforms/netlify) * [Render](/logging/platforms/render) * [Scalingo](/logging/platforms/scalingo) * [Vector](/logging/platforms/vector) * [Vercel](/vercel/logs) ### Supported AppSignal Integrations The following AppSignal Integrations support AppSignal Logging: * [Ruby](/logging/integrations/ruby) * [Elixir](/logging/integrations/elixir) * [Node.js](/logging/integrations/nodejs) * [Go](/logging/integrations/go) * [Java](/logging/integrations/java) * [PHP](/logging/integrations/php) * [Python](/logging/integrations/python) # HTTP Configuration Source: https://docs.appsignal.com/logging/endpoints/http > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). The HTTP endpoint is the most flexible endpoint to send logs to AppSignal. You can format the message in multiple ways as described below. If you are using a language that has an integration library for AppSignal, we recommend using one of the [integration libraries](/logging/integrations) instead of the HTTP endpoint. If you are creating a custom integration, we recommend using the [HTTP-JSON](/logging/endpoints/http-json) endpoint to guarantee the messages are formatted exactly as intended. ## Endpoint You can `POST` logs to AppSignal. Your logs must be formatted in `JSON`, `Logfmt` or `Plaintext` and sent to the following endpoint: ```sh Shell theme={null} https://appsignal-endpoint.net/logs?api_key=YOUR_LOG_SOURCE_API_KEY ``` *Replace `YOUR_LOG_SOURCE_API_KEY` with the key provided when [creating a log source](/logging/configuration#creating-a-log-source).* We will use the time our servers receive the `POST` request as the log timestamp. The default severity will be `INFO`. You can send the `hostname`, `severity` and `group/appname` parameters by appending them to the URL, for example: ```sh Shell theme={null} https://appsignal-endpoint.net/logs?group=app&hostname=frontend1&severity=debug&api_key=YOUR_LOG_SOURCE_API_KEY ``` You can send multiple log lines by separating each log line with a-formatted message overrides the hostname newline character: `\n` ## Structured messages In order to add additional metadata to a log line, you can send a structured message. ### Plaintext By default the source is created with the `Plaintext` formatter selected, you can send any string as the message part of the log line, for example: ```shell Shell theme={null} This is a log message And this is another message ``` Will result in two log lines with the message `This is a log message` and `And this is another message` respectively. ### Logfmt When `Logfmt` is selected as the message format, you can send a log line with key-value pairs separated by a space, for example: ```shell Shell theme={null} This is a log message user_id=123 action=login This is another log message user_id=123 action=logout ``` Will result in two log lines with the message `This is a log message` and `This is another log message` respectively, and the following attributes: ```json JSON theme={null} { "user_id": 123, "action": "login" } ``` ```json JSON theme={null} { "user_id": 123, "action": "logout" } ``` ### JSON When `JSON` is selected as the message format, you can send a log line with a JSON object, for example: ```shell Shell theme={null} {"message": "This is a log message", "user_id": 123, "action": "login"} {"msg": "This is another log message", "user_id": 123, "action": "logout"} ``` We expect either a `msg` or `message` key for the log line message, and any other keys will be added as attributes. If no `msg` or `message` key is provided, we'll use the entire (unparsed) JSON object as the message. Attributes will still be parsed and added to this line. You can read more about the specifics of message formatting in our [formatting](/logging/formatting) documentation. # HTTP-JSON Configuration Source: https://docs.appsignal.com/logging/endpoints/http-json > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). ## Endpoint You can `POST` logs to AppSignal. Your logs must be formatted in [`NDJSON`](#ndjson) and sent to the following endpoint: ```shell Shell theme={null} https://appsignal-endpoint.net/logs/json?api_key=YOUR_LOG_SOURCE_API_KEY ``` ## NDJSON Our HTTP-JSON endpoint expects the logs to be sent in an `NDJSON` format to our endpoint. `NDJSON` stands for Newline Delimited JSON, which means that each log line is its own JSON object, for example: ```shell Shell theme={null} {"timestamp": "2022-06-02T04:17:25.783Z", "message": "foo", [...]} {"timestamp": "2022-06-02T04:17:26.000Z", "message": "bar", [...]} ``` ### Required Data Below is an example of a (prettified) `NDJSON` message. You can read more about the data AppSignal requires in the [Required Fields](#required-fields) section. #### Example message > [!WARNING] > > **Warning:** This is formatted using newlines for readability. Your client > **must** send the log line as a single line, without newlines. ```json JSON theme={null} { "timestamp": "2022-06-02T04:17:25.783Z", "group": "organisations", "severity": "warn", "message": "This is a test message", "hostname": "frontend1", "attributes": { "org": "appsignal", "step": 1, "seen_terms": true, "entries": 10.01 } } ``` #### Required Fields > [!WARNING] > > AppSignal will silently drop any message that does not contain the required > fields below or any incorrect values. The `NDJSON` payload you send to AppSignal must contain the following fields: #### timestamp A `RFC 3339` formatted timestamp with a 3-digit nanosecond precision. ```yaml YAML theme={null} YYYY-MM-DDThh:mm:ss.sss 2022-01-12T07:20:50.520Z ``` #### group One-word string that allows the user to separate log lines by a certain context (e.g., logs for a specific part of your application, group could be "admin", "payments", "database", or "background"). #### severity The severity field accepts the following values: `unknown`, `trace`, `debug`, `info`, `notice`, `warn`, `error`, `critical`, `alert` and `fatal`. #### message `Plaintext` message. #### hostname Hostname of the server sending the message. #### Optional fields The following fields are optional but recommended for richer log data: #### attributes Attributes that can be used to filter or search the message, with the following rules: * Attributes cannot be nested or contain arrays * The maximum key size is `50` characters * The maximum amount of attributes is `100` * The following primitives are accepted as values: * String: ideally used as "tags," e.g. one-word values, with a maximum of `100` characters * Integer: `10` * Double: `0.01` * Boolean: `true`/`false` #### format Overrides the log source's configured format when parsing the `message`. Accepts `plaintext`, `logfmt`, `json` or `autodetect`; unknown values are ignored. # HTTP Syslog Configuration Source: https://docs.appsignal.com/logging/endpoints/http-syslog > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). ## Endpoint You can `POST` logs to AppSignal. Your logs must be formatted in `Syslog` and sent to the following endpoint: ```bash Shell theme={null} https://appsignal-endpoint.net/logs/syslog?api_key=YOUR_LOG_SOURCE_API_KEY ``` *Replace `YOUR_LOG_SOURCE_API_KEY` with the key provided when [creating a log source](/logging/configuration#creating-a-log-source).* The Syslog lines should be separated by a newline character: `\n`. The log line should be sent in the syslog [RFC 5424](https://www.rsyslog.com/doc/master/configuration/modules/pmrfc5424.html) (Request For Comment) format: ```bash Shell theme={null} <%pri%>%protocol-version% %timestamp:::date-rfc3339% %HOSTNAME% %app-name% %procid% %msgid% %msg%\n" <14>1 2017-07-26T14:47:35.869952+05:30 my_hostname custom_appname 5678 some_unique_msgid - Some other message" ``` ## Structured messages The `message` part of a syslog message can be formatted either in `JSON`, `Logfmt` or `Plaintext`. Formatting the message in `JSON` or `Logfmt` allows you to add additional (structured) data attributes that can be used to find/filter messages on. For more information about the specifics of message formatting, see our [formatting](/logging/formatting) documentation. # Syslog Configuration Source: https://docs.appsignal.com/logging/endpoints/syslog > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). ## Install TLS Package To send logs to AppSignal via syslog, you'll need to have installed rsyslog's [TLS (Transport Layer Security)](/appsignal/terminology#tls) package. You can check to see if the package is already installed on your server using the below command: ```shell Shell theme={null} sudo apt list rsyslog-gnutls --installed ``` If the package is not installed, you can install it using the below command: ```shell Shell theme={null} sudo apt install rsyslog-gnutls ``` ## Setup Syslog AppSignal generates a Syslog code snippet for you, available on the source management page. To view this snippet, find the source you wish to configure from the Manage Sources overview and click "Manage source". You will be redirected to a page, that will look similar to the example below: ![Screenshot of Source Management](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/manage-source-full.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=6bc4766cffc3cf0a2a8c523d62965a44) On this page, you will be able to find the "Installation instructions" for your source. These instructions will include a code snippet you copy and use as your configuration file. You should save this file in the `etc/rsyslog.d` directory. Once you've created and saved your configuration, you will need to restart rsyslog so that it begins sending logs to AppSignal, using the restart command from a terminal with root access: ```shell Shell theme={null} /etc/rc.d/init.d/systemctl restart rsyslogd ``` If you are unsure about this step, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help you to get those logs flowing! ## Domain and Port Information Our domain and port are as follows: | Domain | Port | | - | - | | `appsignal-endpoint.net` | `6514` | ## Structured messages The `message` part of a syslog message can be formatted either in `JSON`, `Logfmt` or `Plaintext`. Formatting the message in `JSON` or `Logfmt` allows you to add additional (structured) data attributes that can be used to find/filter messages on. For more information about the specifics of message formatting, see our [formatting](/logging/formatting) documentation. # Log Formatting Source: https://docs.appsignal.com/logging/formatting ## Message Formatting > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). ### Supported Log Formats * [Plaintext](/logging/formatting#plaintext) * [Logfmt](/logging/formatting/logfmt) * [JSON](/logging/formatting/json) How you can format your logs will vary depending on which configuration you are using with Logging. The table below outlines the currently available configurations and the log formats which they support | Platform | [JSON][json-docs] | [Logfmt][logfmt-docs] | [Plaintext](#plaintext) | | - | - | - | - | | [AWS CloudWatch logs through Amazon Data Firehose](/logging/platforms/cloudwatch) | | | | | [Clever Cloud](/logging/platforms/clevercloud) | | | | | [Gigalixir Log Drain](/logging/platforms/gigalixir) | | | | | [Heroku Log Drain](/logging/platforms/heroku) | | | | | [HTTP](/logging/endpoints/http) | | | | | [Netlify](/logging/platforms/netlify) | | | | | [Render](/logging/platforms/render) | | | | | [Scalingo](/logging/platforms/scalingo) | | | | | [Syslog](/logging/endpoints/syslog) | | | | ## Fixed-format endpoint We have one special endpoint/source, and that's the `http-json` endpoint. This endpoint is intended for customers implementing their own log forwarding solution, or log implementation. This endpoint expects a specific NDJSON format, and will silently ignore any messages that do not match this format. ### Attributes When using [Logfmt][logfmt-docs] or [JSON][json-docs] as your log format, you can add searchable attributes to your logs. Attributes can be any of the following types: * string * integer (e.g. `10`) * double (e.g. `10.01`) * boolean (`true`/`false`) ### Plaintext When specifying Plaintext as your log format, the log line will be used as the message as-is, and AppSignal will not parse attributes from the log line. If you want to have searchable attributes in your application's logs, we recommend formatting your logs in [Logfmt][logfmt-docs] or [JSON][json-docs]. [json-docs]: /logging/formatting/json.html#json [logfmt-docs]: /logging/formatting/logfmt.html [syslog-info]: https://www.rsyslog.com/doc/master/configuration/modules/pmrfc5424.html # Log Attributes Source: https://docs.appsignal.com/logging/formatting/attributes > [!TIP] > > Want to get the most out of your logs? Read our [Learning Center article on > logging best > practices](https://www.appsignal.com/learning-center/what-logs-should-i-store) > for more information on properly utilizing your application logs. The best kinds of logs are descriptive, contextual, and concise. Attributes allow you to quickly store, query, and filter key contextual information from your application's logs. Attributes are supported with the [Logfmt][logfmt-docs], [JSON][json-docs], and [NDJSON][ndjson-docs] log formats. ## Formatting AppSignal will parse logs received from your source based on key-value pairs, storing each key and value as attributes on the log line, allowing you to filter log lines on these attributes. Formatting attributes with: * [Logfmt](#logfmt) * [JSON and NDJSON](#json-and-ndjson) ### Logfmt In Logfmt, attributes can be added to log lines: ```text Text theme={null} this is foo=bar a duration=10 message message="I am a message" ``` For example, the above log line will be parsed to a log line with the message `"I am a message"`, and the following attributes: ```json JSON theme={null} { "foo": "bar", "duration": 10 } ``` [Read more about Logfmt log formatting.](/logging/formatting/logfmt) ### JSON and NDJSON In JSON, attributes can be added in a hash under the key `attributes`: ```text Text theme={null} { "timestamp": "2022-06-02T04:17:25.783Z", "group": "organisations", "severity": "warn", "message": "This is a test message", "hostname": "frontend1", "attributes": { "org": "appsignal", "step": 1, "seen_terms": true, "entries": 10.01 } } ``` For example, the above log line will be parsed to a log line with the message `"This is a test message"`, and the following attributes: ```json JSON theme={null} { "org": "appsignal", "step": 1, "seen_terms": true, "entries": 10.01 } ``` [Read more about JSON/NDJSON log formatting.](/logging/formatting/json) ## Querying Attributes in AppSignal In AppSignal, you can search for logs that match specific attribute conditions. For example, the following query would return all logs with an `article_id` attribute that contains the value 7: ```text Text theme={null} attributes.article_id=7 ``` Read our [log management documentation](/logging/query-syntax) for a full explanation of our logging search syntax. When a log is expanded, attributes will be listed under the log message: ![Expanded log line with attribute table](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/formatting/expanded-log-line.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=e6626beedd58d340de11271b643d79d9) ## Formatting Rules Attribute values can be any of the following types: * string * integer (e.g. `10`) * double (e.g. `10.01`) * boolean (`true`/`false`) Attribute keys must follow the following rules: * Keys must be alphanumeric. * Keys cannot contain spaces but may contain full stops (.), underscores (\_), and hyphens (-). * Keys may not contain more than 50 characters * Values must not be longer than 255 characters * No more than 25 attributes per log message. In the event attribute keys and values do not follow the above rules, the following behavior can be expected: * If a key does not have a value, it will be appended to the message field. * If a key-value pair has a key with the name of msg or message, the value of this key will be parsed as the log message. * If no message/msg key is available, the entire log line will be considered the message. [json-docs]: /logging/formatting/json.html#json [logfmt-docs]: /logging/formatting/logfmt.html [ndjson-docs]: /logging/endpoints/http-json#ndjson # JSON Log Formatting Source: https://docs.appsignal.com/logging/formatting/json > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). This documentation explains how AppSignal supports log messages formatted in JSON. ## JSON If you specify JSON as your log format, AppSignal will parse incoming log `message` as key-value pairs. Each key-value pair will be stored as an attribute on the log line, allowing you to filter and search for specific log lines based on their attributes. ### Examples The following example shows how AppSignal parses a log `message` in the JSON format. ```json JSON theme={null} { "timestamp": "2022-06-02T04:17:25.783Z", "group": "organisations", "severity": "warn", "hostname": "frontend1", "message": "This is a test message", "org": "appsignal", "step": 1, "seen_terms": true, "entries": 10.01, "user": { "id": 1, "remote_id": "123" } } ``` #### Message The above JSON will be parsed with the message `"this is a test message"`. You can either use the `msg` or `message` key to override the message. If no `msg` or `message` key is available, the entire log line will be used as the message. #### Overrides The log attributes from the platform or integration (such as hostname, timestamp and group set by e.g. the Heroku platform) can be overridden with the values from the JSON message. | Attribute Key | Type | | - | - | | group | String | | severity | Severity | | hostname | String | | message | String | The `severity` can contain one of the following values: `unknown`, `trace`, `debug`, `info`, `notice`, `warn`, `error`, `critical`, `alert` and `fatal`. This is an excellent way to control the severity of your log lines from within application, regardless of the (usually defaulted `info`) severity set by the platform or integration. #### Attributes Any other key/value pair is added as a searchable attributes: | Attribute Key | Type | Value | | - | - | - | | org | String | "appsignal" | | step | Int | 1 | | seen\_terms | Bool | true | | entries | Double | 10.01 | | user.id | Int | 1 | | user.remote\_id | String | "123" | ## Formatting Rules > [!NOTE] > > Keys must be alphanumeric strings. Array values are not supported. **Key behavior:** * If a key-value pair has a key with the name of `msg` or `message` the value of this key will be parsed as the log message. * If no message/msg key is available, the entire log line will be considered the message. * Keys must be alphanumeric. * Keys cannot contain spaces, but may contain full stops (`.`), underscores (`_`) and hyphens (`-`). * Keys may not contain more than 50 characters **Value behavior:** * Values must not be longer than 255 characters * No more than 25 attributes per log message. * Values may contain nested Objects, but not Arrays. * Values may be of the following types: * String * Integer (e.g. `10`) * Double (e.g. `10.01`) * Boolean (`true`/`false`) * Object (e.g. `{ "foo": "bar" }`) For nested objects, the attributes will be flattened, separated by a `.` character. Key value pairs that do not follow these rules are appended to the message of a log, unless a `message` or `msg` key is provided. # Logfmt Log Formatting Source: https://docs.appsignal.com/logging/formatting/logfmt > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). Logfmt is a log format that is easy for humans to read and write, and is supported by AppSignal. It was initially used as the format for the [Heroku Logdrains](/logging/platforms/heroku), and is now used by many other logging providers. Most of our platforms and endpoints support the Logfmt message format, which we'll describe in more detail below. ## Format Logfmt is a key-value format, where each key-value pair is separated by a space. The key and value are separated by an equals sign (`=`). The key-value pairs are appended to the message at the end of the log line. Any key-value pairs that do not follow the Logfmt format are appended to the message of the log line. ### Examples The following examples show how AppSignal parses logs in the Logfmt format: #### Message with attributes ```shell Shell theme={null} this is foo=bar duration=10 a value="with spaces" message ``` This will be parsed to a log line with the message `"this is a message"`, and the following attributes: `{ "foo": "bar", "duration": 10, "value": "with spaces"}` #### Message with override ```shell Shell theme={null} this is foo=bar a duration=10 message message="I am a message" ``` This will be parsed to a log line with the message `"I am a message"`, and the following attributes: `{ "foo": "bar", "duration": 10 }`. The rest of the original message is ignored, in favor of the `message` key. #### Attributes only ```shell Shell theme={null} foo=bar duration=100 ``` This will be parsed to a log line with the message `"foo=bar duration=100"`, and the following attributes: `{ "foo": "bar", "duration": 100 }` ## Formatting Rules * Keys must be alphanumeric. * Keys cannot contain spaces, but may contain full stops (`.`), underscores (`_`) and hyphens (`-`). * Keys may not contain more than 50 characters * Values must start with an alphanumeric character, and may not be longer than 100 characters * No more than 25 attributes per log message. Key value pairs that do not follow these rules are appended to the message of a log. **Key behavior:** * If a key does not have a value, it will be appended to the message field. * If a key-value pair has a key with the name of `msg` or `message` the value of this key will be parsed as the log message. * If no message/msg key is available, the entire log line will be considered the message. # Logging from AppSignal Integrations Source: https://docs.appsignal.com/logging/integrations Send logs directly from AppSignal integrations without creating a log source, or send any process's output with appsignal-wrap. AppSignal supports logging directly from your application using the AppSignal integration. You do not need to create a log source to send logs using the AppSignal integration. An "application" log source will be created automatically. ## Supported AppSignal Integrations The following AppSignal integrations support logging: * [Ruby](/logging/integrations/ruby) * [Elixir](/logging/integrations/elixir) * [Node.js](/logging/integrations/nodejs) * [Go](/logging/integrations/go) * [Java](/logging/integrations/java) * [PHP](/logging/integrations/php) * [Python](/logging/integrations/python) ## Process monitoring with AppSignal Wrap You can also send the output of any process as logs to AppSignal, using our wrap tool: ```shell Shell theme={null} appsignal-wrap my-process-name -- /path/to/my/process ``` Learn more about how to use `appsignal-wrap` to send logs to AppSignal in our [Wrap documentation](/wrap#logging). # Logging from Elixir Source: https://docs.appsignal.com/logging/integrations/elixir This documentation outlines how to configure logging with the AppSignal for Elixir integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Elixir integration. An "application" log source will be created automatically. ### Logger Handler You can configure the Erlang `:logger` to use the `Appsignal.Logger.Handler` module as a handler, by calling the `Appsignal.Logger.Handler.add/2` function on your `Application.start/2` callback: ```elixir Elixir theme={null} @impl true def start(_type, _args) do Appsignal.Logger.Handler.add("phoenix") end ``` The given argument is the group name that describes where you are logging from. This group name can be used in AppSignal to filter your logs. ### Logger Backend > [!TIP] > > Starting with Elixir version 1.15, Elixir logger backends are no longer > recommended. See the [Logger Handler section](#logger-handler) above for the > recommended alternative. Instead of using an Elixir logger handler, you can configure the Elixir logger backend to use the `Appsignal.Logger.Backend` module as a backend by placing the code below in the `config/runtime.exs` file: ```elixir Elixir theme={null} config :logger, backends: [:console, {Appsignal.Logger.Backend, [group: "phoenix"]}] ``` The `group` option describes where you are logging from. This group name can be used in AppSignal to filter your logs. You can also add the backend using the `add_backend/2` function on your `Application.start/2` callback: ```elixir Elixir theme={null} @impl true def start(_type, _args) do Logger.add_backend(Appsignal.Logger.Backend, group: "phoenix") end ``` ### Elixir Logger To send logs to AppSignal without using the Elixir Logger backend, you can use one of `Appsignal.Logger`'s logging functions and provide it with a `groupname` that defines where you are logging from. For example, if we were logging from a helper for invoicing clients: ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", "Generating invoice for customer 129" ) ``` ## Usage ### Sending Logs Like the Elixir/Phoenix logger class, you can define the severity level of your logs by using `fatal`, `error`, `warning`, `info`, and `debug`: ```elixir Elixir theme={null} Appsignal.Logger.warning( "app", "Something's gone terribly wrong here" ) ``` You can pass custom attributes as the last argument, to send log information that can be used when filtering and querying logs: ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", "Generated invoice for customer #{customer.id}", %{ customer_id: customer.id, invoice_id: invoice.id } ) ``` You can query and filter on message contents and attribute values using our [query syntax](/logging/query-syntax). Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface. ## Formats ### Auto detected format The AppSignal for Elixir package will automatically detect the log line's format as JSON, Logfmt or plaintext by default, and parse attributes from it. You don't need to manually set the log format, unless it's not being detected properly. Please also [notify us](mailto:support@appsignal.com?subject=Log%20format%20auto%20detection%20not%20working) if this isn't working automatically. ```elixir Elixir theme={null} # Plaintext format Appsignal.Logger.info( "invoice_helper", "Generated invoice" ) # Logfmt format Appsignal.Logger.info( "invoice_helper", "Generated invoice invoice_id=A145 for customer customer_id=123" ) # JSON format Appsignal.Logger.info( "invoice_helper", ~s({"message": "Generated invoice for customer", "invoice_id": "A145", "customer_id": "123"}) ) ``` ### Logfmt The AppSignal Logger can be explicitly configured to expect the line to be formatted as Logfmt and parse attributes from it. Use this option when using an older AppSignal for Elixir package version, which does not support [automatic format detection](#auto-detected-format). The Logfmt format can be specified when the AppSignal logger is called by adding the `:logfmt` value as the last argument. ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", "Generated invoice invoice_id=A145 for customer customer_id=123", :logfmt ) ``` ### JSON The AppSignal Logger can be explicitly configured to expect the line to be formatted as JSON and parse attributes from it. Use this option when using an older AppSignal for Elixir package version, which does not support [automatic format detection](#auto-detected-format). The JSON format can be specified when the AppSignal logger is called by adding the `:json` value as the last argument. ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", ~s({"message": "Generated invoice for customer", "invoice_id": "A145", "customer_id": "123"}), :json ) ``` Only primitive non-nested values (numbers, strings, booleans and `null`) will be shown as log attributes. All other attributes will be discarded. ## Filtering Logs You can use [the `ignore_logs` configuration option](/elixir/configuration/options#option-ignore_logs) to ignore log lines based on their message. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Elixir application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging from Go Source: https://docs.appsignal.com/logging/integrations/go This documentation outlines how to configure logging with the AppSignal for Go integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Go integration. An "application" log source will be created automatically. The Go integration uses OpenTelemetry's logging capabilities to send logs to AppSignal. ### Stand-alone usage To use logging with OpenTelemetry in Go, you need to set up the logger using OpenTelemetry's logger provider. ```go Go theme={null} package main import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/log" ) func main() { // Get the logger from the global logger provider loggerProvider := otel.GetLoggerProvider() logger := loggerProvider.Logger("my-app") // Log a message logger.Emit(context.Background(), log.Record{ Severity: log.SeverityInfo, Body: log.StringValue("Log message line"), }) } ``` ### Usage with `slog` You can configure the standard `slog` package to send structured logs to AppSignal using the OpenTelemetry handler. ```go Go theme={null} package main import ( "context" "log/slog" "go.opentelemetry.io/contrib/bridges/otelslog" ) func main() { // Create an OpenTelemetry `slog` handler otelHandler := otelslog.NewHandler("my-app") // Create a `slog` logger with the OpenTelemetry handler logger := slog.New(otelHandler) // Use the logger logger.Info("Log message line") logger.With("user_id", 123).Info("User logged in") logger.Error("An error occurred", "error", "database connection failed") } ``` ## Usage ### Sending Logs Using the OpenTelemetry logger directly, you can define the severity level of your logs: ```go Go theme={null} package main import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/log" ) func main() { loggerProvider := otel.GetLoggerProvider() logger := loggerProvider.Logger("my-app") // Different severity levels logger.Emit(context.Background(), log.Record{ Severity: log.SeverityWarn, Body: log.StringValue("Something went wrong"), }) logger.Emit(context.Background(), log.Record{ Severity: log.SeverityInfo, Body: log.StringValue("Action completed"), }) logger.Emit(context.Background(), log.Record{ Severity: log.SeverityError, Body: log.StringValue("Database connection failed"), }) } ``` You can define custom attributes to send log information that can be used when filtering and querying logs: ```go Go theme={null} package main import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/log" ) func processInvoice(customerID string) { loggerProvider := otel.GetLoggerProvider() logger := loggerProvider.Logger("invoice_helper") logger.Emit(context.Background(), log.Record{ Severity: log.SeverityInfo, Body: log.StringValue("Generating invoice for customer"), Attributes: []log.KeyValue{ log.String("customer_id", customerID), }, }) invoice := generateInvoice(customerID) logger.Emit(context.Background(), log.Record{ Severity: log.SeverityInfo, Body: log.StringValue("Generated invoice for customer"), Attributes: []log.KeyValue{ log.String("customer_id", customerID), log.String("invoice_id", invoice.ID), }, }) } ``` You can query and filter on message contents and attribute values from within the [Log Management](/logging/log-management) tool. Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface. ## Filtering Logs You can use [the `ignore_logs` configuration option](/go/configuration/options#option-ignore_logs) to ignore log lines. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Go application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging from Java Source: https://docs.appsignal.com/logging/integrations/java This documentation outlines how to configure logging with the AppSignal for Java integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Java integration. An "application" log source will be created automatically. The Java integration uses OpenTelemetry's logging capabilities to send logs to AppSignal. ### Stand-alone usage To use logging with OpenTelemetry in Java, you need to set up the logger using the OpenTelemetry LoggerProvider. ```java Java theme={null} import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.logs.Severity; public class MyApplication { public void logMessages() { // Get the logger from the global logger provider LoggerProvider loggerProvider = GlobalOpenTelemetry.getLoggerProvider(); Logger logger = loggerProvider.get("my-app"); // Log a message logger.logRecordBuilder() .setSeverity(Severity.INFO) .setBody("Log message line") .emit(); } } ``` ### Usage with Log4j Log4j is automatically instrumented by the OpenTelemetry Java agent. Logs emitted using Log4j2 will automatically be sent to AppSignal. Context added using `ThreadContext` or within `StructuredDataMessage` logs will be shown as log tags in AppSignal. ```java Java theme={null} import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.message.StructuredDataMessage; public class MyService { private static final Logger logger = LogManager.getLogger(MyService.class); public void processOrder(String orderId) { // This will be shown as a tag in AppSignal for all log lines ThreadContext.put("order_id", orderId); logger.info("Processing order"); StructuredDataMessage structuredMessage = new StructuredDataMessage( "processing_items", // ID (not shown in AppSignal) String.format("Processing items in order"), // Message "order" // Type (not shown in AppSignal) ); // This will be shown as a tag in AppSignal for this log line structuredMessage.put("item_count", 123); logger.info(structuredMessage); ThreadContext.clearAll(); } } ``` ### Usage with `java.util.logging` Java's built-in logging framework, `java.util.logging`, is automatically instrumented by the OpenTelemetry Java agent. Logs emitted using `java.util.logging` will automatically be sent to AppSignal. ```java Java theme={null} import java.util.logging.Logger; import java.util.logging.Level; public class MyApplication { private static final Logger logger = Logger.getLogger(MyApplication.class.getName()); public void doSomething() { logger.info("Application started"); logger.log(Level.WARNING, "This is a warning message"); logger.severe("This is an error message"); } } ``` ## Usage ### Sending Logs Using the OpenTelemetry logger directly, you can define the severity level of your logs: ```java Java theme={null} import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.logs.Severity; public class MyApplication { public void sendLogs() { // Get the logger from the global logger provider LoggerProvider loggerProvider = GlobalOpenTelemetry.getLoggerProvider(); Logger logger = loggerProvider.get("my-app"); // Different severity levels logger.logRecordBuilder() .setSeverity(Severity.WARN) .setBody("Something went wrong") .emit(); logger.logRecordBuilder() .setSeverity(Severity.INFO) .setBody("Action completed successfully") .emit(); logger.logRecordBuilder() .setSeverity(Severity.ERROR) .setBody("Database connection failed") .emit(); } } ``` You can define custom attributes to send log information that can be used when filtering and querying logs: ```java Java theme={null} import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.logs.Severity; public class InvoiceService { public void generateInvoice(Customer customer) { LoggerProvider loggerProvider = GlobalOpenTelemetry.getLoggerProvider(); Logger logger = loggerProvider.get("invoice_helper"); logger.logRecordBuilder() .setSeverity(Severity.INFO) .setBody("Generating invoice for customer") .setAllAttributes(Attributes.of( AttributeKey.stringKey("customer_id"), customer.getId() )) .emit(); } } ``` You can query and filter on message contents and attribute values from within the [Log Management](/logging/log-management) tool. Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface. ## Filtering Logs You can use [the `ignore_logs` configuration option](/java/configuration/options#option-ignore_logs) to ignore log lines. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Java application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging from Node.js Source: https://docs.appsignal.com/logging/integrations/nodejs This documentation outlines how to configure logging with the AppSignal for Node.js integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Node.js integration. An "application" log source will be created automatically. ### Stand-alone usage To use the logger, you need to import AppSignal and set up the logger using the `.logger()` function. The `.logger()` function accepts two arguments: `group` and optionally `severityThreshold`. If `severityThreshold` is not provided, it will default to `info`. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); const logger = Appsignal.logger("app"); // with a severity threshold: const logger = Appsignal.logger("app", "info"); ``` There are six severity levels available `trace`, `debug`, `info`, `log`, `warn`, and `error`, each of them with its own function with the same name. These functions accept two arguments `message` and `attributes`. Attributes is used for metadata and is optional. Messages will only be logged if their severity level is above the severity threshold. ```javascript Node.js theme={null} logger.info("Log message line"); logger.debug("User logged in", { user_id: 123 }); ``` Note that if the message's severity is below the severity threshold set up when initializing the logger, it will not be sent to AppSignal. You can query and filter on message contents and attribute values using our [query syntax](/logging/query-syntax). #### Using multiple logging backends It's currently not possible to send logs to multiple backends using Node.js' standard logger. For more complex setups, we recommend using a logging library like Winston or Pino. ### Usage with Winston If you use Winston to log messages throughout your application, you can use our Winston transport to send those logs to AppSignal. After importing the transport from the AppSignal integration, add it to the list of transports in your Winston logger: ```javascript Node.js theme={null} const winston = require("winston"); const { WinstonTransport } = require("@appsignal/nodejs"); const logger = winston.createLogger({ transports: [new WinstonTransport({ group: "app" })], }); ``` #### Child Logger You can use a child logger to add additional tags to log messages. You define tags when creating the child logger constant or pass tags as metadata when writing a log message. Say we want greater context in our logs of the actions of a particular user within a specific session. In the below example, a child logger for the `background` group is used to add `sessionID` with the additional `drinkID`, and `paymentID` tags are provided as metadata when creating a log message, and if a group is given to the child, it'll override the one set up in the transport. ```javascript Node.js theme={null} const logger = winston.createLogger({...}); const sessionLogger = logger.child({ group: "background", sessionID: user.id, }); sessionLogger.debug("User logged in"); sessionLogger.info("User ordered coffee", { drinkID: 30, paymentID: 20082 }); sessionLogger.debug("User logged out"); ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, add another transport: ```javascript JavaScript theme={null} const winston = require("winston"); const { WinstonTransport } = require("@appsignal/nodejs"); const logger = winston.createLogger({ transports: [ new WinstonTransport({ group: "app" }), new winston.transports.Console(), ], }); ``` ### Usage with Pino If Pino is your preferred logging library, you can use the AppSignal Pino transport to send logs to AppSignal. The group argument will default to "app" if not provided. ```javascript Node.js theme={null} import pino from "pino"; const logger = pino({ transport: { targets: [ { target: "@appsignal/nodejs/pino", options: { group: "my-group" } } ], }, }); ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, add another target: ```javascript Node.js theme={null} import pino from "pino"; const logger = pino({ transport: { targets: [ { target: "@appsignal/nodejs/pino", options: { group: "my-group" } }, { target: 'pino/file', options: {destination: 1} } ], }, }); ``` ## Formats ### Auto detected format The AppSignal for Node.js package will automatically detect the log line's format as JSON, Logfmt or plaintext by default, and parse attributes from it. You don't need to manually set the log format, unless it's not being detected properly. Please also [notify us](mailto:support@appsignal.com?subject=Log%20format%20auto%20detection%20not%20working) if this isn't working automatically. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); // Plaintext format const logger = Appsignal.logger("app", "info"); logger.info("This is about the blog"); // Logfmt format const logger = Appsignal.logger("app", "info"); logger.info("category=blog This is about the blog"); // JSON format const logger = Appsignal.logger("app", "info"); logger.info('{"category": "blog", "message": "This is about the blog"}'); ``` ### Logfmt The AppSignal Logger can be explicitly configured to expect the line to be formatted as Logfmt and parse attributes from it. Use this option when using an older AppSignal for Node.js package version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the `"logfmt"` value as the third argument. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); const logger = Appsignal.logger("app", "info", "logfmt"); logger.info("category=blog this is about the blog"); ``` In the example above, a filterable category attribute with the value "blog" will be logged. ### JSON The AppSignal Logger can be explicitly configured to expect the line to be formatted as JSON and parse attributes from it. Use this option when using an older AppSignal for Node.js package version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the `"json"` value as the third argument. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); const logger = Appsignal.logger("app", "info", "json"); logger.info('{"category": "blog", "message": "this is about the blog"}'); ``` In the example above, a filterable category attribute with the value "blog" will be logged. ## Filtering Logs You can use [the `ignoreLogs` configuration option](/nodejs/3.x/configuration/options#option-ignorelogs) to ignore log lines based on their message. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Node.js application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging From PHP Source: https://docs.appsignal.com/logging/integrations/php This documentation outlines how to configure logging with the AppSignal for PHP package. ## Configure logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for PHP integration. An "application" log source will be created automatically. The AppSignal for PHP package uses OpenTelemetry's logging capabilities to send logs to AppSignal. ### Laravel If you're using the Laravel framework, the AppSignal for PHP package automatically sends your logs to AppSignal. You do not need to configure Monolog directly. ### Symfony If you're using the Symfony framework, the easiest way to send logs to AppSignal is by using the [`MonologBundle`](https://github.com/symfony/monolog-bundle). Install the Monolog auto-instrumentation package. ```shell Shell theme={null} composer require open-telemetry/opentelemetry-logger-monolog ``` Add a service definition for `'appsignal.monolog.handler'` that uses the `Appsignal\Integrations\Monolog\Handler` class. ```yml title="config/services.yaml" theme={null} services: # ... other services appsignal.monolog.handler: class: Appsignal\Integrations\Monolog\Handler factory: ['Appsignal\Integrations\Monolog\Handler', "withLevel"] arguments: ["info"] # configure log level that will reach AppSignal ``` Add `appsignal.monolog.handler` to the Monolog handler stack. ```yml title="config/packages/monolog.yaml" theme={null} monolog: handlers: # other handlers appsignal: type: service id: appsignal.monolog.handler channels: ["app", "event"] # configure which channels to send to AppSignal ``` ### Monolog [Monolog](https://github.com/Seldaek/monolog) is the most popular logging library for PHP. You can use Monolog directly to send logs to AppSignal. Install the Monolog auto-instrumentation package. ```shell Shell theme={null} composer require open-telemetry/opentelemetry-logger-monolog ``` Then add `Appsignal\Integrations\Monolog\Handler` to Monolog's handler stack. ```php PHP theme={null} use Appsignal\Integrations\Monolog\Handler; use Monolog\Logger; $logger = new Logger('app'); $logger->pushHandler(Handler::withLevel('info')); $logger->info('My log message'); ``` ### Stand-alone usage You can also send logs with the stand-alone logger using the `log` helper method from the `Appsignal` base class. This method doesn't require configuration. ```php PHP theme={null} use Appsignal\Appsignal; use Appsignal\Severity; // Log a message Appsignal::log( message: 'Log message line', severity: Severity::INFO, loggerName: 'my-app', attributes: [ 'customer_id' => $customer->id, ], ); ``` Configure Monolog with the OpenTelemetry handler to send logs to AppSignal: ```php PHP theme={null} use Appsignal\Integrations\Monolog\Handler; use Monolog\Logger; // Create Monolog logger with the AppSignal handler $logger = new Logger('app', [Handler::withLevel('info')]); ``` ## Sending logs ### Monolog Using Monolog, you can define the severity level of your logs: ```php PHP theme={null} $logger->warning("Something's gone terribly wrong here"); $logger->info('User action completed successfully'); $logger->error('Database connection failed'); // using Laravel's Log facade Log::warning("Something's gone terribly wrong here"); Log::info('User action completed successfully'); Log::error('Database connection failed'); ``` You can define custom attributes to send log information that can be used when filtering and querying logs: ```php PHP theme={null} $logger->info('Generating invoice for customer', ['customer_id' => $customer->id]); // using Laravel's Log facade Log::info('Generating invoice for customer', ['customer_id' => $customer->id]); ``` ### Stand-alone logger Using the stand-alone logger, you can define the severity level of your logs: ```php PHP theme={null} use Appsignal\Appsignal; use Appsignal\Severity; // Different severity levels Appsignal::log( message: "Something's gone terribly wrong here", severity: Severity::WARN, ); Appsignal::log( message: 'User action completed successfully', severity: Severity::INFO, ); Appsignal::log( message: 'Database connection failed', severity: Severity::ERROR, ); ``` You can define custom attributes to send log information that can be used when filtering and querying logs: ```php PHP theme={null} use Appsignal\Appsignal; use Appsignal\Severity; function processInvoice($customer) { Appsignal::log( message: 'Generating invoice for customer', severity: Severity::INFO, attributes: ['customer_id' => $customer->id], ); } ``` ## Filtering logs You can query and filter on message contents and attribute values from within the [Log Management](/logging/log-management) tool. Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface. ### Structured logging AppSignal supports structured logging out of the box. You can send structured data as log attributes: ```php PHP theme={null} use Appsignal\Appsignal; use Appsignal\Severity; Appsignal::log( message: 'User action completed', severity: Severity::INFO, attributes: [ 'user_id' => $userId, 'action' => 'purchase', 'product_id' => $productId, 'amount' => $amount, 'currency' => 'USD' ], ); // or using Monolog $logger->info('Generating invoice for customer', ['customer_id' => $customer->id]); // or using Laravel's Log facade Log::info('Generating invoice for customer', ['customer_id' => $customer->id]); ``` > [!NOTE] > > You can also configure AppSignal for PHP to ignore specific log lines using [the `ignore_logs` option](/php/configuration/options#option-ignore_logs). See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need help? After configuring your PHP application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging from Python Source: https://docs.appsignal.com/logging/integrations/python This documentation outlines how to configure logging with the AppSignal for Python integration. > [!WARNING] > > Logging is only available when using [collector > mode](/python/configuration/collector), which is an **experimental > feature**. ## Configure logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Python integration. An "application" log source will be created automatically. When using [collector mode](/python/configuration/collector), AppSignal automatically instruments Python's built-in `logging` module via OpenTelemetry, attaching a handler to the root logger. ### Which logs are captured AppSignal captures logs sent to the root logger and any logger that propagates to it. Propagation is controlled by the `propagate` attribute on each logger, which defaults to `True` in Python. Loggers with `propagate=False` will **not** have their messages captured by AppSignal. Some libraries and frameworks set this attribute on their own loggers. Django, for example, sets it on `django.server`, which [the Django section](#django) shows how to override. ### Set the log level Python's `logging` module defaults to the `WARNING` log level, meaning that `INFO` and `DEBUG` log messages won't be captured. To capture lower-severity messages, set the root logger level: ```python Python theme={null} import logging logging.root.setLevel(logging.INFO) ``` ### Send only specific loggers to AppSignal By default AppSignal captures everything that reaches the root logger. To send a chosen set of loggers instead, disable the automatic instrumentation with [the `disable_default_instrumentations` configuration option](/python/configuration/options#option-disable_default_instrumentations) and attach the handler yourself: ```python Python theme={null} # __appsignal__.py appsignal = Appsignal( # ... # Disable the automatic instrumentation disable_default_instrumentations=["logging"], ) ``` ```python Python theme={null} import logging from opentelemetry.instrumentation.logging.handler import LoggingHandler # Initialize the OpenTelemetry handler handler = LoggingHandler(level=logging.NOTSET, log_code_attributes=True) # Attach the handler to the chosen logger logging.getLogger("myapp").addHandler(handler) ``` Pass `log_code_attributes=True` to record the file, function, and line each log line came from, as the automatic instrumentation does. A handler you attach yourself is not protected against later reconfiguration the way the automatic instrumentation is. For Django, [adding it to the logging configuration itself](#django-attaching-handlers-manually) is the most reliable way to attach it. > [!WARNING] > > Disabling the automatic instrumentation is what keeps AppSignal from > attaching a handler of its own. Attaching your own handler without disabling > it sends every log line that reaches both handlers twice. ## Framework setup ### Celery Celery forks worker processes, so AppSignal must be started for each fork. Use the `worker_process_init` signal to reinitialize AppSignal and configure logging in each worker process. See the [Celery instrumentation page](/python/instrumentations/celery) for more details on instrumenting Celery tasks. ```python Python theme={null} # tasks.py import logging import appsignal from celery.signals import worker_process_init @worker_process_init.connect(weak=False) def init_worker_logging(*args, **kwargs): appsignal.start() logging.root.setLevel(logging.INFO) logging.getLogger("celery").propagate = True ``` ### Django Django sets `propagate=False` on its `django.server` logger, so its messages do not reach the root logger where AppSignal's handler is attached. Override it in your `LOGGING` setting: ```python Python theme={null} # settings.py LOGGING = { "version": 1, "disable_existing_loggers": False, "handlers": { "console": {"class": "logging.StreamHandler"}, }, "loggers": { "django.server": { "handlers": ["console"], "level": "INFO", "propagate": True, }, }, } ``` To [send only specific loggers to AppSignal](#specific-loggers), add the handler to your `LOGGING` setting rather than attaching it in code, so that it survives Django configuring the logging module: ```python Python theme={null} # settings.py import logging from opentelemetry.instrumentation.logging.handler import LoggingHandler LOGGING = { "version": 1, "handlers": { "console": {"class": "logging.StreamHandler"}, "appsignal": { "()": LoggingHandler, "level": logging.NOTSET, "log_code_attributes": True, }, }, "loggers": { "django.server": { "handlers": ["console", "appsignal"], "level": "INFO", }, "myapp": { "handlers": ["console", "appsignal"], "level": "INFO", }, }, } ``` > [!WARNING] > > For previous versions of AppSignal for Python, we recommended adding the > OpenTelemetry `LoggingHandler` to your `LOGGING` configuration. When > upgrading to AppSignal for Python 1.9.0, you should remove the OpenTelemetry > `LoggingHandler` from your configuration, as AppSignal will attach its own > handler, causing your handler to emit duplicate lines. ## Sending logs with OpenTelemetry You can also send logs directly using the OpenTelemetry logs API, without going through Python's `logging` module: ```python Python theme={null} from opentelemetry._logs import get_logger_provider, SeverityNumber logger = get_logger_provider().get_logger("my-app") logger.emit( body="Log message line", severity_number=SeverityNumber.INFO, severity_text="INFO", ) ``` Passing a dictionary as the body sends a structured log line. Its keys become attributes on the log line in AppSignal, and a `message` key becomes the log line's message: ```python Python theme={null} logger.emit( body={"message": "Order placed", "order_id": 1234}, severity_number=SeverityNumber.INFO, severity_text="INFO", ) ``` ## Filtering logs You can use [the `ignore_logs` configuration option](/python/configuration/options#option-ignore_logs) to ignore log lines. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need help? After configuring your Python application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging from Ruby Source: https://docs.appsignal.com/logging/integrations/ruby This documentation outlines how to configure logging with your AppSignal for Ruby integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Ruby integration. An "application" log source will be created automatically. ### Rails Logger You can configure the Rails framework to send logs to AppSignal in an initializer file like `config/initializers/logging.rb`: ```ruby Ruby theme={null} # config/initializers/logging.rb appsignal_logger = Appsignal::Logger.new("rails") Rails.logger = ActiveSupport::TaggedLogging.new(appsignal_logger) ``` #### Using multiple logging backends To send logs to both AppSignal's logger and Rails' default logger, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} # config/initializers/logging.rb appsignal_logger = Appsignal::Logger.new("rails") appsignal_logger.broadcast_to(Rails.logger) Rails.logger = ActiveSupport::TaggedLogging.new(appsignal_logger) ``` We do not recommend using Rails' built-in broadcast logger feature, due to compatibility issues when used alongside tagged logging. #### Tagged logging support The use of `ActiveSupport::TaggedLogging` in the above examples enables support for Rails' log tags. For example, if you wish to add the request ID tag to the log messages, add it to the `config.log_tags` array in the `config/application.rb` file: ```ruby Ruby theme={null} module TestApp class Application < Rails::Application config.log_tags = [:request_id] end end ``` #### Using Lograge > [!WARNING] > > This Lograge config is not a replacement for the Rails logger config. If you > want to report logs from `Rails.logger`, the [Rails logger config > steps](#rails-logger) also need to be followed. The [Lograge](https://github.com/roidrage/lograge) library is a popular solution for ingesting structured Rails *request* logs. After adding the `lograge` gem, you can configure it in `config/initializers/lograge.rb` to send logs to AppSignal: ```ruby Ruby theme={null} Rails.application.configure do config.lograge.enabled = true config.lograge.keep_original_rails_log = true config.lograge.logger = Appsignal::Logger.new( "rails", format: Appsignal::Logger::LOGFMT ) end ``` > [!TIP] > > Lograge does not support log levels. All logs emitted via Lograge will appear > with severity level `INFO` in the AppSignal Logging UI. ### Sinatra Logger You can configure Sinatra to send request logs to AppSignal using Rack's CommonLogger middleware. Configure it like shown below. Consider if request logs contain useful information for you, read our [what logs should I store](https://www.appsignal.com/learning-center/what-logs-should-i-store) learning center article. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("sinatra") use Rack::CommonLogger, logger ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("sinatra") logger.broadcast_to(Logger.new($stdout)) use Rack::CommonLogger, logger ``` ### Sidekiq Logger You can configure Sidekiq to send its logs to AppSignal, including the logs emitted by your background jobs: ```ruby Ruby theme={null} Sidekiq.configure_server do |config| config.logger = Appsignal::Logger.new("sidekiq") config.logger.formatter = Sidekiq::Logger::Formatters::WithoutTimestamp.new end ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} Sidekiq.configure_server do |config| config.logger = Appsignal::Logger.new("sidekiq") config.logger.broadcast_to(Logger.new($stdout)) config.logger.formatter = Sidekiq::Logger::Formatters::WithoutTimestamp.new end ``` ### Ruby Logger To send logs to AppSignal as you would with Ruby's `Logger` class, you will need to create an instance of `Appsignal::Logger` and provide it with a `groupname` that defines where you are logging from, for example, if we were logging from a helper for invoicing clients: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper") ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper") logger.broadcast_to(Logger.new($stdout)) ``` ### Semantic Logger The [Semantic Logger](https://logger.rocketjob.io/) library provides a comprehensive logging solution for Ruby and Rails applications. After adding the `semantic_logger` gem, you can configure it to send logs to AppSignal as follows: ```ruby Ruby theme={null} appsignal_logger = Appsignal::Logger.new("rails", format: Appsignal::Logger::LOGFMT) SemanticLogger.add_appender(logger: appsignal_logger, formatter: :logfmt) ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, add another appender using the `add_appender` method: ```ruby Ruby theme={null} appsignal_logger = Appsignal::Logger.new("rails", format: Appsignal::Logger::LOGFMT) SemanticLogger.add_appender(logger: appsignal_logger, formatter: :logfmt) SemanticLogger.add_appender(io: $stdout) ``` ## Usage ### Sending Logs Like the Ruby/Rails `Logger` class, you can define the severity level of your logs by using `fatal`, `error`, `warn`, `info`, and `debug`: ```ruby Ruby theme={null} logger.warn("Something went wrong") ``` You can define custom attributes to send log information that can be used when filtering and querying logs: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper") logger.info("Generating invoice for customer", { customer_id: @customer.id }) invoice = generate_invoice(@customer) logger.info("Generated invoice for customer", { customer_id: @customer.id, invoice_id: invoice.id }) ``` You can query and filter on message contents and attribute values using our [query syntax](/logging/query-syntax). Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface. ### Default Logger Attributes When initializing the AppSignal logger, you can provide default attributes that will be included in all log messages: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper", attributes: { customer_id: @customer.id }) ``` The attributes provided when initializing the logger will be included in all log messages sent from that logger instance. Attributes provided with the log message will be merged with the default logger attributes. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper", attributes: { customer_id: @customer.id }) # This log message will contain the `customer_id` attribute: logger.info("Generating invoice for customer") invoice = generate_invoice(@customer) # This log message will contain the `customer_id` and `invoice_id` attributes: logger.info("Generated invoice for customer", { invoice_id: invoice.id }) ``` When both the logger and the log message provide the same attribute, the log message's attribute will override the default logger attribute. ## Formats ### Auto detected format The AppSignal for Ruby gem will automatically detect the log line's format as JSON, Logfmt or plaintext by default, and parse attributes from it. You don't need to manually set the log format, unless it's not being detected properly. Please also [notify us](mailto:support@appsignal.com?subject=Log%20format%20auto%20detection%20not%20working) if this isn't working automatically. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("group") # Plaintext format logger.info("This is about the blog") # Logfmt format logger.info("category=blog This is about the blog") # JSON format logger.info('{"category": "blog", "message": "This is about the blog"}') ``` ### Logfmt The AppSignal Logger can be explicitly configured to expect the line to be formatted as Logfmt and parse attributes from it. Use this option when using an older AppSignal for Ruby gem version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the Logfmt constant in the format option. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("group", format: Appsignal::Logger::LOGFMT) logger.info("category=blog This is about the blog") ``` In the example above, a filterable category attribute with the value "blog" will be logged. ### JSON The AppSignal Logger can be explicitly configured to expect the line to be formatted as JSON and parse attributes from it. Use this option when using an older AppSignal for Ruby gem version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the JSON constant in the format option. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("group", format: Appsignal::Logger::JSON) logger.info('{"category": "blog", "message": "This is about the blog"}') ``` In the example above, a filterable category attribute with the value "blog" will be logged. ## Filtering Logs You can use [the `ignore_logs` configuration option](/ruby/configuration/options#option-ignore_logs) to ignore log lines. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Ruby application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Legacy Log Query Syntax Source: https://docs.appsignal.com/logging/legacy-query-syntax Log query syntax with the attributes. prefix and type suffixes, for accounts not yet migrated to the current syntax. > [!WARNING] > > This query syntax will be deprecated in the future. Go back to our [new query > syntax](/logging/query-syntax). If you like to switch to the new query syntax, > [contact support](mailto:support@appsignal.com). AppSignal's powerful log filtering system allows you to quickly search and filter through your application logs using an intuitive query syntax. Whether you need to find specific error messages, filter by severity levels, or search through custom attributes, our query language makes it easy to pinpoint exactly what you're looking for in your logs. Think of it like a search engine for your application's logs. Here's a simple example: If you want to find all error logs, you can use: `severity=error` Or if you want to find logs containing the word "timeout": `message:timeout` ![Screenshot of expanded log](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/all-logs.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=294a9482dd18a89b870da2f9f8f13055) AppSignal supports log filtering by: | Filter Field | Description | Example Query | | - | - | - | | `severity` | Log severity level. Accepted values are: error, warning, info, debug, and trace | `severity=error` | | `hostname` | Application Host (via search) | `hostname=appsignal` | | `group` | Namespaces defined for your application (via search) | `group=users` | | `message` | Log message contents (via search) | `message:error` | | `attributes` | Attributes defined in your logs (via search) | `attributes.duration_double>10.1` (see [Attribute Types](#attribute-types)) | ## Search Syntax Explained The below table explains the current AppSignal Logs search query syntax. Queries can be combined with a space between them (see Combined Queries in [Combining Multiple Queries](#combining-multiple-queries)). ### Search Query Overview | Query Name | AppSignal Syntax | Description | | - | - | - | | Wildcard | `Foo` | Returns all logs that contain a value like `Foo` | | Multiple Wildcards | `Foo Bar` | Returns all logs that contain a value like `Foo` and a value like `Bar` | | Wildcard For Words With Spaces | `"Foo Bar"` | Returns all logs that contain a value like `"Foo Bar"` | | Field Search | `hostname:foo` | Returns all logs where field hostname is like `Foo` | | Multiple Word Field Search | `hostname:"foo bar"` | Returns all logs where field hostname is like `"Foo Bar"` | | Exact Match | `hostname=foo` | Returns all logs where field hostname is `Foo` | | Exact Query Negation | `hostname!=foo` | Returns all logs where field hostname is not `Foo` | | Wildcard Query Negation | `hostname!:foo` | Returns all logs where field hostname is not like `Foo` | | Match any in list | `hostname=[\"frontend1\", frontend2]"` | Returns all logs that match any of the items in the list `["frontend1", "frontend2"]` | | Match not in list | `group!=[\"app\", unix]"` | Returns all logs that do not match any of the items in the list `["app", "unix"]` | | Attribute Specific Query | `attributes.attribute_name` | Queries log attributes. Replace `attribute_name` with the attribute you are querying (including its type suffix). You can use any legal AppSignal operator in this table to complete your query. | | Greater Than | `attributes.duration_double>100` | Returns all logs where `duration` is greater than 100 | | Less Than | `attributes.duration_double<100` | Returns all logs where `duration` is less than 100 | The wildcard queries above match the given text anywhere in the value. There is no wildcard character. An asterisk is searched for literally, so `hostname:web*` only matches hostnames that contain the text `web*`. ### Combining Multiple Queries You can combine multiple queries by adding them together with spaces. 1. Find logs containing "error": `message:error` 2. Add filtering for a specific group: `message:error group="background jobs"` 3. Exclude certain hostnames: `message:error group="background jobs" hostname!:test-server` ### Attribute Types When filtering on custom log attributes using comparison operators (`>`, `<`, `>=`, `<=`), you **must** include a type suffix in the attribute name. Without the correct type suffix, the query will fail. The supported type suffixes are: | Suffix | Type | Example | | - | - | - | | `_int` | Integer | `attributes.user_id_int>1000` | | `_double` | Float | `attributes.duration_double>5.65` | | `_bool` | Boolean | `attributes.success_bool=true` | | `_string` | String | `attributes.region_string=eu` | > [!WARNING] > > **Important:** Do not include spaces around comparison operators when querying > attributes. For example, use `attributes.duration_double>5.65` — **not** > `attributes.duration_double > 5.65`. Spaces will cause the query to fail. ### Common Use Cases 1. Find all errors from a specific server: `severity=error hostname=production-web-1` 2. Find slow database queries: `source=PostgreSQL attributes.duration_double>100.0` 3. Debug failed background jobs: `group="background jobs" message:failed` # Log Management Source: https://docs.appsignal.com/logging/log-management > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). ![Screenshot of expanded log](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/all-logs.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=294a9482dd18a89b870da2f9f8f13055) Once AppSignal Logging is successfully configured, you'll be able to see logs for all of your sources from within the AppSignal application. You can filter and query logs and expand specific logs for their trace data. When viewing your logs you can: * [Filter and Query Logs](#filter-and-query-logs) * [Copy Log Meta Data as JSON](#copy-log-meta-data-as-json) * [Share Log](#share-log) * [View What Happened Here](#what-happened-here) * [Time Detective](#time-detective) * [View Live Trail](#live-trail) #### Filter and Query Logs Use the "Source" drop down to filter which sources you see the logs for. Use the "Severity" drop down to filter the severity of logs Filtering and querying are further explained in the [Query Syntax](/logging/query-syntax) section of this guide. #### Copy Log Meta Data As JSON Expand a log by pressing the "+" button, click "Copy as JSON". Meta data will automatically be copied to your clipboard as a valid JSON object. #### Share Log Click "Copy link to log line" and a link to this log line will automatically be copied to your clipboard. > [!TIP] > > Only users within your AppSignal Organization will be able to access the logs > via this link #### What Happened Here Want to see a snapshot of your application's metric at the exact time the log line was written? Click "What Happened Here" #### Time Detective Use the "Time Detective" button to investigate application wide data at the time a log line was written. #### Live Trail Clicking "Go to live" will take you to a live trail of your logs. ## Managing Sources To modify a source go to AppSignal > Logging > Sources and click "Manage source" ![Screenshot of Source Management](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/view-source.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=7b63838a05d0fee525cb5ecbe3a7a883) When managing a source, you can: * [Edit Source](#edit-source) * [Remove Source](#remove-source) ### Edit Source To edit the source click "Edit source" in the top right corner of the screen. You can edit the following source attributes: * Name * Platform (currently limited to syslog) * Format Changing the log format only applies to new log lines. The attributes and message of existing log lines will not change. ### Remove Source Deletion is permanent and will revoke the API key used for that source. Before removing a log source, we recommend ensuring that the source is no longer sending logs to AppSignal so that your application is not making unnecessary calls to third parties. Before removing the log source in AppSignal, remove the rsyslog configuration file for this log source (located in `etc/rsyslog.d`) and restart rsyslog with the below command. ```bash Bash theme={null} /etc/rc.d/init.d/systemctl restart rsyslogd ``` ![Screenshot of confirm deletion alert](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/delete-source-confirmation.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=e9483919555fa0fe4a31f3e2f0ef36c9) To remove a source click "Remove source" from the Source Management page. When prompted to confirm removal read the dialogue box carefully and click "Yes, delete this". The source will be deleted. # Long-Term Log Storage Source: https://docs.appsignal.com/logging/long-term-log-storage > [!TIP] > > Long-Term Log Storage is a paid-for Business Add-On. Please [contact > us](mailto:support@appsignal.com) for more information, see our [Business > Add-Ons documentation](/support/business-add-ons). Long-term Log Storage allows you to export and store your AppSignal logs in S3-compatible storage. You need a paid-for Business Add-On to use this feature. AppSignal will continue to store your logs for 30 days. Follow the following steps to configure Long-Term Log Storage: 1. [Ensure you have all requirements](#requirements) 2. [Configure S3 Storage](#configure-s3-storage) 3. [Add storage to log source](#add-storage-to-log-source) ## Requirements To set up Long Term Log Storage you will need: * [The Long-Term Log Storage Business Add-On](/support/business-add-ons#long-term-log-storage) * S3-Compatible Storage ## Configure S3 Storage You will need S3-compatible storage to use Long-Term Log Storage. We have documented the steps for: * [AWS S3 Storage](#configuring-aws-s3-storage) * [DigitalOcean Spaces](#configuring-digitalocean-spaces) If you are using a different service, please read our [Configuring Other S3 Compatible Storage Service](#configuring-other-s3-compatible-storage-services) section. > [!TIP] > > If you plan to use the same bucket and credentials to export multiple log > sources, make sure to include a unique path for each log source. This will > prevent logs from different sources attempting to overwrite each other. ### Configuring AWS S3 Storage Follow the following steps to configure AWS S3 storage for Long Term Log Storage: 1. **[Create a new S3 bucket and retrieve it's URL.](https://s3.console.aws.amazon.com/s3/bucket/create)** You will need to provide AppSignal with the bucket's URL. You can generate this URL with the following pattern: `https://s3.[region-code].amazonaws.com/[bucket-name]`, replacing `[region]` and `[bucket-name]` respectively. 2. **[Create a new user with Programmatic access and `read/write` access to the bucket you intend to store logs in.](https://console.aws.amazon.com/iam/home#/users\$new?step=details)** You will need to provide AppSignal with the user's `access key ID` and `access secret key`. An example IAM policy is: ```json JSON theme={null} "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::", "arn:aws:s3:::/*" ] } ] ``` 3. **[Add storage to log source.](#add-storage-to-log-source)** ### Configuring DigitalOcean Spaces Follow the following steps to configure DigitalOcean Spaces for Long Term Log Storage: 1. **[Create a new space with `Restrict File Listing` and retrieve it's URL.](https://cloud.digitalocean.com/spaces/new)** You will need to provide AppSignal with the spaces' URL. You can generate this URL with the following pattern: `[region].digitaloceanspaces.com/[spacename]`, replacing `[region]` and `[spacename]` respectively. 2. **[Generate a new DigitalOcean API token key.](https://cloud.digitalocean.com/account/api/tokens)** You will need to provide AppSignal with the key's `access key` and `secret key`. 3. **[Add storage to log source.](#add-storage-to-log-source)** ### Configuring Other S3-Compatible Storage Services Follow the following steps to configure S3-compatible storage services for Long Term Log Storage: 1. **Create a new bucket and retrieve its URL.** You will need to provide AppSignal with the bucket's URL, see your S3 storage service's documentation for details on where to locate this. 2. **Create a new access key.** You will need to provide AppSignal with the key's `access key` and `secret key`, see your S3 storage service's documentation for details on how to generate this. 3. **[Add storage to log source.](#add-storage-to-log-source)** ## Add Storage To Log Source Before adding storage to a log source, make sure you've followed the storage set-up steps and have the following information: * Bucket URL * `access key` and `secret key` Once you have this information to hand, follow the following steps to add your S3 storage to your desired log source. 1. Navigate to Log Sources and click "Add storage" on the desired log source: ![Image of log sources with Add storage link](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/long-term-log-storage/logging-sources-add-source.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=37be34be71ca75dcd06abb54b3e24d7b) 1. Provide AppSignal with your `buckets URL`, `access key` and `secret key` and complete setup by clicking `Send long-term storage request`. ![Form for adding long term storage](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/long-term-log-storage/add-long-term-storage.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=c2c7ff93416f65ddc24a1fd08e3ad8bb) Once set-up is complete, AppSignal will enqueue a storage job to begin writing log data to your S3 bucket. Each job will create a file in your S3 bucket with the following filename and format: `/yyyy-mm/yyyy-mm-ddThhmmss-yyyy-mm-ddThhmmss.json.gz` For example: `https://s3.com/2015-01/2015-01-01T100000-2015-01-02T110000.json.gz` You can read more about storage jobs in the [Storage Jobs and Exceptions](#storage-jobs-and-exceptions) section. ## Storage Jobs and Exceptions In this section, you can learn more about the writing of logs to S3 storage via storage jobs, and how AppSignal handles job exceptions. ### Storage jobs Storage jobs are run every hour. Each job writes **one hour** of log data from **25 hours ago**. For example, a job that runs on `12/01/2024` at `10:00`, will write a file of logs from: `11/01/2024` that were created between `09:00` and `09:59:59` to your S3 storage. This ensures that any log lines, that may have been delayed, are included in the storage job. If a job is successful, a job for the next hour of data is enqueued and your source's long-term storage will have the status of "Running". You can view and manage storage jobs from the "Manage source" page. ![Source overview page](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/long-term-log-storage/source-overview-page.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=c4a7e8a0e0957f827398adfccd16e905) ### Exceptions If a storage job fails, AppSignal will attempt to re-run the storage job each hour, for 24 hours (so 24 attempts). If after 24 attempts AppSignal is unable to complete the storage job, we will notify you of a `failed` job. ### Restoring A Failed Job When a Log source has a storage job with a `failed` status, AppSignal will stop enqueueing new jobs. Clicking on the `failed` status will display the error AppSignal encountered when trying to run the storage job. ![Source storage job error message](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/long-term-log-storage/sync-error.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=a967667ab26645d87d5c5e0108df7f33) You will need to manually verify the Log source's settings to re-try the job, this can be done via the "Manage source" page. Once verified, AppSignal will re-try the job. If this succeeds, AppSignal will resume hourly storage jobs and your source's long-term storage will have the status of "Running". > [!WARNING] > > You have until 48 hours before your AppSignal log retention cut-off to store logs with your S3 storage. > > For example, with 30 days of retention, you would have until `10:00` on `29/01/2024` to store logs from `09:00-09:59:59` on `01/01/2024`. ## Removing storage To remove long-term storage from a source navigate to the source's "Manage source" page and click "Remove storage". Once confirmed AppSignal will remove the source's storage and delete the source's storage job history. Log data already stored in your storage will not be deleted. # Log-based metrics Source: https://docs.appsignal.com/logging/metrics Turn data from your logs into metrics you can chart, alert on, and group across your application. If you have indexed logs in AppSignal, you can generate metrics from them directly in the Explore view. Use these log-based metrics to track important signals over time, set up triggers, or add them to dashboards, all without changing your application code or leaving your log exploration workflow. Use log metrics to count how often an event happens, track the latest value of a numeric field, or follow its average and percentiles over time. When you spot something worth tracking in your logs, you can turn it into a metric without leaving the Logs page. The query and log source you've used to narrow your logs carry into the metric, so the filtering work you've already done is what defines what the metric tracks. Once the metric is saved, you can add it to a dashboard or use it in a trigger in the same flow. ## Create a metric from a log line The fastest way to create a metric is from a log line that already shows the data you want to track. 1. Open the **Logs** page for your app. 2. Use the query bar to filter the log lines that match the event you want to measure. 3. Select a log line in the table to open the **Log details** panel. 4. In the **Actions** section, select **Create a metric**. 5. The Create metric overlay opens with the **Log source** and **Query** fields prefilled from the log line. The query matches the line's severity, hostname, and group. ![Log details panel with the Create a metric action](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-from-log-line.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=5b493d4ccad3ee9d1147bfe17c813e5e) ## Configure the metric In the **Define metric** panel, fill in the fields that describe what you want to measure. As you change any field, the **Data preview** on the right updates so you can confirm the metric returns the data you expect. * **Metric name**: A unique name for the metric, used when you reference it on dashboards and triggers. See [metric naming](#metric-naming) for the rules and recommendations. * **Log source**: The log source the metric draws events from. * **Query**: The query string used to match log lines. Same syntax as the Logs page. To include only some severities, add them to the query. For example, `severity=error` matches only error log lines. * **Metric type**: Count, Gauge, or Measurement. See [metric types](#metric-types). * **Field to measure**: For Gauge and Measurement metrics, the numeric field to track — like the duration or size of each event, instead of counting occurrences. * **Group by tag**: Split the metric by a tag to get a separate series per unique value (for example, group by `hostname` to get one series per server). When you finish, select **Create metric** to save. ### Metric naming We recommend naming your metrics something easily recognizable. Metric names only support numbers, letters, dots and underscores (`[a-z0-9._]`) as valid characters. Any other characters will be replaced with an underscore by our processor. Some examples of good metric names are: * `database_size` * `account_count` * `users.count` * `notifier.failed` * `orders.request.duration` > [!WARNING] > > **Note**: We **do not** recommend adding dynamic values to your metric names > like so: `eu.database_size`, `us.database_size` and `asia.database_size`. This > creates multiple metrics that serve the same purpose. Instead we recommend > using **Group by tag** for this. ## Metric types The metric type defines how AppSignal aggregates the data over time. The **Field to measure** field appears for Gauge and Measurement only, since Count just counts matching log lines. ### Count The total number of matching events in a given time frame. Use this for events like errors, sign-ups, or job retries. Count does not require a **Field to measure** — it just counts every log line matching your query. ![Create metric overlay with the Count chart preview](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-count-chart.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=279cef379582fb30e011d5221067cbb6) ### Gauge The current value at the moment. Use this for values that move up and down, such as an active connection count. ![Create metric overlay with the Gauge chart preview](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-gauge-chart.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=07ea5df662d79360d3716c0f84ee609b) ### Measurement Averages, counts, and percentiles for a numeric field over time. Use this when the distribution matters, such as request duration. Measurement persists the mean, count, and 90th/95th percentiles of the **Field to measure** for each interval. ## Preview your metric The **Data preview** panel has two tabs that let you confirm the metric returns the data you expect before saving. ### Chart A live chart of the metric for the selected time range. The chart preview supports selecting multiple log sources, and updates as you change any field in the **Define metric** panel. Use the time-range selector below the chart to switch between **Last 24 hours**, **Last 48 hours**, and **Last 7 days**. ![Create metric overlay with the chart time-range selector open](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-time-range.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=14bef4e69eb8514c0bf366acb240c51b) ### Log lines The log lines that match your current query. When a **Field to measure** is set, that field is shown as a highlighted column so you can confirm the values before saving. ![Create metric overlay with the log lines preview](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-log-lines-preview.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=a76f02db5ac76bb0de2c927e9da20dff) ## Choose what to do next After you save a metric for the first time, AppSignal asks what you want to do with it: * **Add to dashboard**: Add the metric to a chart on an existing dashboard. * **Create a trigger**: Open the trigger creation flow with the metric prefilled. * **Edit metric**: Reopen the overlay to refine the configuration. For follow-up metrics, AppSignal shows a confirmation toast instead. You can still reach the same options from the **Metrics** page. A new metric may take a moment to start collecting data, so a dashboard or trigger created right after may briefly show a "no data yet" warning. ## Edit a metric 1. Open the **Metrics** page from the **Logging** side menu. 2. Find the metric and select **Edit** from the three-dot menu. 3. Adjust the **Query**, **Field to measure**, or **Group by tag** fields. 4. Select **Update metric** to save. The **Metric name** and **Metric type** are read-only when editing. To change either, create a new metric. From the row menu on the **Metrics** page, you can also add the metric to a dashboard, create a trigger from it, or delete it. The **Modified by** column shows who last updated each metric, so you can see at a glance which team member made the most recent change. ## Example: track request duration * **Metric name**: `orders.request.duration` * **Log source**: application * **Query**: `path=/api/orders` * **Metric type**: Measurement * **Field to measure**: `duration_ms` * **Group by tag**: `hostname` This metric reports the average, count, and percentiles of `duration_ms` for requests to `/api/orders`, with one series per host. # Migrating to the new query syntax Source: https://docs.appsignal.com/logging/migration We're about to migrate you to the new query syntax for logging. This will allow you to query your logs more efficiently. The new query syntax has impact on the following logging areas. Take a look at each of them to see the notable changes: * [Query language](#query-language) * [Saved views](#saved-views) * [Log triggers](#log-triggers) * [Long term storage](#long-term-storage) Make sure you are aware of all these changes, and [contact support](mailto:support@appsignal.com) to start the migration process. ## Query Language The query language changes in a few significant ways. Here are some of the most notable changes: 1. **No more `attributes.` prefix** — Custom attributes can now be queried directly. Instead of `attributes.user_id_int=12345`, simply use `user_id=12345`. 2. **No more type suffixes** — You no longer need to append `_int`, `_string`, or `_double` to attribute names. The query engine automatically determines the correct type based on the operator you use. 3. **Nested JSON support** — Query nested objects using dot notation: `user.email="user@example.com"` and array elements by index: `user.roles.0=admin`. 4. **OR logic and parentheses** — Build complex queries with explicit `OR` operators and parentheses for grouping: `severity=error AND (hostname=web-1 OR hostname=web-2)`. 5. **List syntax replaced** — The `field=[value1, value2]` syntax is replaced with OR statements, which is more flexible and supports all operators, not just exact matches. For example: **Old syntax:** ```sh Shell theme={null} message:"API request" attributes.user_id_int=12345 severity=[info, warn] ``` **New syntax:** ```sh Shell theme={null} message:"API request" user.id=12345 (severity=info OR severity=warn) ``` For complete details on the new syntax, see our [query syntax documentation](/logging/query-syntax). To reference the old syntax, see the [legacy query syntax documentation](/logging/legacy-query-syntax). ## Saved Views Your saved views will be updated to the new query syntax. After the migration, check the views for any issues. ## Log Triggers Your log triggers will be updated to the new query syntax. After the migration, check the triggers for any issues. Triggers that were open, will be closed, and you'll get new issues after the migration. ## Long Term Storage We're making a change to the output of the [long term storage](/logging/long-term-log-storage) exports. Instead of an attributes field that contains a 1-dimensional map of attribute key-values, we'll export a Stringified JSON object with all the attributes. For example: **Old output:** ```json JSON theme={null} { "timestamp": "1970-01-01 00:04:00.000", "source_id": "source-json", "hostname": null, "group": "group", "severity": "info", "message": null, "attributes": { "user.name": "alice", "user.id": "123", "request_id": "abc-123", "status_code": "200", "response_time": "45.67", "success": "true" } } ``` **New output:** ```json JSON theme={null} { "timestamp": "1970-01-01 00:04:00.000", "hostname": null, "group": "group", "severity": "info", "message": null, "source_id": "source-json", "attributes": "{\"user\": {\"name\":\"alice\", \"id\":\"123\"},\"request_id\":\"abc-123\",\"status_code\":200,\"response_time\":45.67,\"success\":true}" } ``` # Supported Platforms Source: https://docs.appsignal.com/logging/platforms ## Supported Platforms AppSignal Log Management supports the following platforms: * AWS CloudWatch logs through Amazon Data Firehose * [Manual setup](/logging/platforms/cloudwatch) * [CloudFormation setup](/logging/platforms/cloudwatch-cloudformation) * [Clever Cloud](/logging/platforms/clevercloud) * [Gigalixir Log Drain](/logging/platforms/gigalixir) * [Heroku](/logging/platforms/heroku) * [Netlify](/logging/platforms/netlify) * [Render](/logging/platforms/render) * [Scalingo](/logging/platforms/scalingo) * [Vector](/logging/platforms/vector) * [Vercel](/vercel/logs) ### Supported Log Endpoints If your platform is not listed, you can use one of the following endpoints to send log lines to AppSignal manually: * [HTTP](/logging/endpoints/http) * [HTTP-JSON](/logging/endpoints/http-json) * [HTTP-Syslog](/logging/endpoints/http-syslog) * [Syslog](/logging/endpoints/syslog) ### Supported AppSignal Integrations The following AppSignal Integrations support AppSignal Logging: * [Ruby](/logging/integrations/ruby) * [Elixir](/logging/integrations/elixir) * [Node.js](/logging/integrations/nodejs) * [Go](/logging/integrations/go) * [Java](/logging/integrations/java) * [PHP](/logging/integrations/php) * [Python](/logging/integrations/python) # Clever Cloud Source: https://docs.appsignal.com/logging/platforms/clevercloud AppSignal can automatically ingest logs via Clever Cloud Log Drain. To configure this, you will need to create a new logdrain in Clever Cloud's [CLI](https://www.clever-cloud.com/doc/getting-started/cli/). To set up your log drain, copy and paste the below command: ```shell Shell theme={null} clever drain create HTTP "https://appsignal-endpoint.net/logs/syslog?api_key=YOUR_LOG_SOURCE_API_KEY" ``` Replace `YOUR_LOG_SOURCE_API_KEY` with the key provided when [creating a log source](/logging/configuration#creating-a-log-source). When created, logs should appear in AppSignal. If you still cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. You can find more information on Clever Cloud's drains in their [Logs Management](https://www.clever-cloud.com/doc/administrate/log-management/#exporting-logs-to-an-external-tools) documentation. # Send CloudWatch logs to AppSignal through Amazon Data Firehose Source: https://docs.appsignal.com/logging/platforms/cloudwatch > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). Complete the following steps to send CloudWatch logs to AppSignal through Amazon Data Firehose (formerly Kinesis Data Firehose): 1. [Create a log source](#create-a-log-source) 2. [Set up an S3 bucket for failed deliveries](#set-up-an-s3-bucket-for-failed-deliveries) 3. [Set up an IAM role for Data Firehose](#set-up-an-iam-role-for-data-firehose) 4. [Create a Firehose delivery stream](#create-a-firehose-delivery-stream) 5. [Set up an IAM role for CloudWatch](#set-up-an-iam-role-for-cloudwatch) 6. [Create a CloudWatch log subscription](#create-a-cloudwatch-log-subscription) Before you start, have the following information ready: * Your log source's [API key](https://appsignal.com/redirect-to/app?to=logs/sources). If you do not have a log source yet, [create a new log source](/logging/configuration#creating-a-log-source) first. * AWS account ID * AWS region * S3 bucket name for failed delivery storage * Data Firehose stream name * IAM role name for the S3 bucket * IAM role name for the CloudWatch subscription ## Create a log source Create a log source before proceeding. See [Logging configuration](/logging/configuration#creating-a-log-source) for instructions. ## Set up an S3 bucket for failed deliveries Amazon Data Firehose requires an S3 bucket to store records that fail to deliver. Create an S3 bucket through the AWS Console or CLI before proceeding, you can't create a Firehose delivery stream without one. ## Set up an IAM role for Data Firehose Create an IAM role that allows Data Firehose to write to the S3 bucket and, optionally, to CloudWatch Logs for delivery error logging. Use the following trust policy: ```json JSON theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "firehose.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } ``` Assign the following permissions policy to the role as an inline policy. > [!NOTE] > > See [Adding IAM identity > permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html) > for instructions on creating inline policies for IAM roles. ```json JSON theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::", "arn:aws:s3:::/*" ] }, { "Effect": "Allow", "Action": ["logs:PutLogEvents"], "Resource": [ "arn:aws:logs:::log-group::*" ] } ] } ``` Replace the placeholders with your own values: * `` — your AWS account ID. * `` — the region your Firehose stream will run in. * `` — the S3 bucket you created in the previous step. * `` — the log group Firehose uses for **its own delivery error logs** (separate from the log group you want to stream to AppSignal). AWS uses the convention `/aws/kinesisfirehose/`, so decide your Firehose stream name now — you'll reuse it in the next step. If you don't plan to enable error logging on the Firehose stream, you can omit the `logs:PutLogEvents` statement entirely. > [!NOTE] > > See [Controlling access with Amazon Data > Firehose](https://docs.aws.amazon.com/firehose/latest/dev/controlling-access.html) > for more on the permissions Data Firehose requires. ## Create a Firehose delivery stream 1. Open the Amazon Data Firehose console and select **Create Firehose stream**. 2. Select **Direct PUT** as the source. 3. Select **HTTP Endpoint** as the destination. 4. Under "Transform records", leave data transformation turned off. 5. Enter the following URL as the **HTTP endpoint URL**: ```shell Shell theme={null} https://appsignal-endpoint.net/logs/aws-kinesis ``` 6. Enter your AppSignal log source API key from [creating a log source](/logging/configuration#creating-a-log-source) as the **Access key**. This is an AppSignal key, not an AWS access key. 7. Under "Content encoding", enable **GZIP**. 8. Under "Backup settings", select the S3 bucket you created in the previous step. 9. Under "Advanced settings > Service access", select **Choose existing IAM role** and choose the IAM role you created in the previous step. 10. (Optional) Under "Advanced settings > Amazon CloudWatch error logging", enable error logging to use the `logs:PutLogEvents` permission you granted in the previous step. 11. Use the same Firehose stream name you referenced when setting up the IAM role, then select **Create Firehose stream**. To verify the connection, you can use the **Test with demo data** button in the Firehose console. The stock-ticker JSON payloads it sends appear in AppSignal under **Logging** as individual log lines — a useful end-to-end check before you hook up real log groups. You can also watch `DeliveryToHttpEndpoint.Success` climb on the Firehose stream's **Monitoring** tab. ## Set up an IAM role for CloudWatch Create an IAM role that allows CloudWatch to send logs to the Firehose delivery stream. Use the following trust policy: ```json JSON theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "logs..amazonaws.com" }, "Action": "sts:AssumeRole" } ] } ``` Assign the following permissions policy to the role as an inline policy. > [!NOTE] > > See [Adding IAM identity > permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html) > for instructions on creating inline policies for IAM roles. ```json JSON theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["firehose:*"], "Resource": [ "arn:aws:firehose:::deliverystream/" ] } ] } ``` Replace ``, ``, and `` with your own values. ## Create a CloudWatch log subscription 1. In the CloudWatch console, navigate to the log group whose logs you want to stream. 2. Open the **Subscription filters** tab. 3. Select **Create Amazon Data Firehose subscription filter**. 4. Choose the Firehose delivery stream from [step 4](#create-a-firehose-delivery-stream) and the IAM role from [step 5](#set-up-an-iam-role-for-cloudwatch). 5. Enter a **Subscription filter name** and select **Start streaming**. After saving the subscription, logs appear in AppSignal under the log source you've configured above. If you see an error saving the subscription, verify that the IAM role in [step 5](#set-up-an-iam-role-for-cloudwatch) uses the correct region, account ID, and delivery stream name. If logs do not appear in AppSignal: * Open your Firehose stream's **Monitoring** tab and check `DeliveryToHttpEndpoint.Success`. The value should stay near 1; a drop or zero indicates AppSignal is rejecting records. * Check the S3 failure bucket from [step 2](#set-up-an-s3-bucket-for-failed-deliveries). Failed records land there, and each object contains the rejection reason. * If records are failing with an authorization error, verify that the **Access key** on the Firehose stream matches your AppSignal log source API key. If you're still stuck, [contact us](mailto:support@appsignal.com) for support. # Stream CloudWatch logs with CloudFormation Source: https://docs.appsignal.com/logging/platforms/cloudwatch-cloudformation > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You can automate the setup of CloudWatch logs streaming to AppSignal using an AWS CloudFormation template. This creates all the required resources in a single deployment instead of configuring each one manually through the AWS Console. If you prefer to set up each resource manually, see the [CloudWatch logs setup guide](/logging/platforms/cloudwatch). ## Before you start Have the following information ready: * Your log source's [API key](https://appsignal.com/redirect-to/app?to=logs/sources). If you do not have a log source yet, [create a new log source](/logging/configuration#creating-a-log-source) first. * The name of the existing CloudWatch log group you want to stream to AppSignal. * The AWS region where the log group lives. Deploy the stack in the same region and account as the log group. ## What the template creates The CloudFormation template creates the following resources: 1. An **S3 bucket** to store records that fail to deliver, with server-side encryption, public access blocked, a 30-day lifecycle expiration, and a retain-on-delete policy. 2. An **IAM role** that allows Amazon Data Firehose to write failed records to the S3 bucket and to write its own delivery error logs to CloudWatch. 3. A **Firehose delivery stream** that sends logs to the AppSignal endpoint over HTTPS. 4. An **IAM role** that allows CloudWatch Logs to write to the Firehose delivery stream. 5. A **CloudWatch log subscription filter** on your existing log group that forwards log events to the Firehose delivery stream. ## CloudFormation template Copy the following template and save it as `appsignal-cloudwatch-logs.yaml`: ```yaml YAML theme={null} AWSTemplateFormatVersion: 2010-09-09 Description: >- Configures a CloudWatch log subscription and Amazon Data Firehose delivery stream to send logs to AppSignal from an existing CloudWatch log group. It must be deployed in the same region and same account as the CloudWatch log group. Implements all the steps from AppSignal documentation all at once: https://docs.appsignal.com/logging/platforms/cloudwatch.html Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: AppSignal Configuration Parameters: - LogSourceApiKey - Label: default: CloudWatch Configuration Parameters: - CloudWatchLogGroupName ParameterLabels: LogSourceApiKey: default: "Log Source API Key (find at https://appsignal.com/redirect-to/app?to=logs/sources)" CloudWatchLogGroupName: default: "CloudWatch Log Group Name" Parameters: LogSourceApiKey: Type: String Description: Your AppSignal log source API key (39-character hexadecimal string). NoEcho: true MinLength: 39 MaxLength: 39 CloudWatchLogGroupName: Type: String Description: >- Name (not the ARN) of the CloudWatch log group to send to AppSignal. Group logs list: https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups MinLength: 1 Resources: S3FirehoseEventsBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain Properties: BucketName: !Join - "-" - - "appsignal-firehose" - !Ref AWS::StackName - !Ref AWS::AccountId - !Ref AWS::Region PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LifecycleConfiguration: Rules: - Id: ExpireFailedDeliveries Status: Enabled ExpirationInDays: 30 FirehoseRole: Type: AWS::IAM::Role Properties: Description: >- Role to allow firehose stream to put events into S3 backup bucket RoleName: !Join - "-" - - "appsignal-firehose" - !Ref AWS::StackName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - firehose.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyName: !Join - "-" - - "appsignal-firehose" - !Ref AWS::StackName PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "s3:AbortMultipartUpload" - "s3:GetBucketLocation" - "s3:GetObject" - "s3:ListBucket" - "s3:ListBucketMultipartUploads" - "s3:PutObject" Resource: - !GetAtt S3FirehoseEventsBucket.Arn - !Join ["", [!GetAtt S3FirehoseEventsBucket.Arn, "/*"]] - Effect: Allow Action: - "logs:PutLogEvents" Resource: - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/kinesisfirehose/appsignal-firehose-${AWS::StackName}:*" FirehoseDeliveryStream: Type: AWS::KinesisFirehose::DeliveryStream Properties: DeliveryStreamName: !Join - "-" - - "appsignal-firehose" - !Ref AWS::StackName DeliveryStreamType: DirectPut HttpEndpointDestinationConfiguration: RequestConfiguration: ContentEncoding: GZIP EndpointConfiguration: Name: AppSignal Url: "https://appsignal-endpoint.net/logs/aws-kinesis" AccessKey: !Ref LogSourceApiKey BufferingHints: IntervalInSeconds: 60 SizeInMBs: 1 RetryOptions: DurationInSeconds: 60 S3Configuration: CompressionFormat: GZIP BucketARN: !GetAtt S3FirehoseEventsBucket.Arn RoleARN: !GetAtt FirehoseRole.Arn RoleARN: !GetAtt FirehoseRole.Arn LogsStreamRole: Type: AWS::IAM::Role Properties: Description: Role to allow stream put into a firehose RoleName: !Join - "-" - - "appsignal-cloudwatch" - !Ref AWS::StackName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - !Sub "logs.${AWS::Region}.amazonaws.com" Action: - "sts:AssumeRole" Policies: - PolicyName: !Join - "-" - - "appsignal-firehose" - !Ref AWS::StackName PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "firehose:*" Resource: - !GetAtt FirehoseDeliveryStream.Arn SubscriptionFilter: Type: AWS::Logs::SubscriptionFilter Properties: LogGroupName: !Ref CloudWatchLogGroupName FilterName: "AppSignal" FilterPattern: "" DestinationArn: !GetAtt FirehoseDeliveryStream.Arn RoleArn: !GetAtt LogsStreamRole.Arn ``` > [!NOTE] > > The `logs:PutLogEvents` statement allows Firehose to write its own delivery error logs to CloudWatch. It targets the Firehose error log group (`/aws/kinesisfirehose/`), which is separate from the log group you want to stream to AppSignal. See [Controlling access with Amazon Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/controlling-access.html) for more details. ## Deploy the stack 1. Open the [AWS CloudFormation console](https://console.aws.amazon.com/cloudformation/). 2. Select **Create stack** and choose **With new resources (standard)**. 3. Under **Specify template**, select **Upload a template file** and upload `appsignal-cloudwatch-logs.yaml`. 4. Select **Next**. 5. Enter a stack name, for example `appsignal-cloudwatch-logs`. 6. For **LogSourceApiKey**, enter your log source's API key. 7. For **CloudWatchLogGroupName**, enter the exact name of the log group you want to stream. 8. Select **Next** twice, then check **I acknowledge that AWS CloudFormation might create IAM resources** and select **Submit**. The stack takes a few minutes to create. Once the status shows **CREATE\_COMPLETE**, CloudWatch begins streaming logs to AppSignal. ## Verify the deployment 1. In the AWS Console, search for "CloudFormation" and select **Stacks**. Open your stack and select the **Resources** tab to confirm all resources show **CREATE\_COMPLETE**. 2. In the AWS Console, search for "CloudWatch". In the left sidebar, open your log group and select the **Subscription filters** tab to confirm the `AppSignal` filter is listed. 3. In the AWS Console, search for "Firehose". Open the delivery stream and use the **Test with demo data** function to verify connectivity. 4. In AppSignal, open the [log management screen](/logging/log-management) and confirm log entries from your log group appear there. If logs do not appear after a few minutes, check the S3 bucket for failed delivery records. If you need help, [contact us](mailto:support@appsignal.com). ## Multi-region deployments The template must be deployed in the same region and account as the CloudWatch log group. If you have log groups in multiple regions, deploy a separate copy of this stack in each region. ## Clean up To remove all resources created by this template, delete the stack in the CloudFormation console. The S3 bucket for failed deliveries has a `DeletionPolicy` of `Retain`, so it is kept when the stack is deleted to avoid losing any failed delivery records. Failed delivery records in the bucket are automatically deleted after 30 days by the lifecycle rule. You can delete the bucket manually once you no longer need it. # Gigalixir Log Drain Source: https://docs.appsignal.com/logging/platforms/gigalixir > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). AppSignal can ingest logs via [Gigalixir Log Drain](https://gigalixir.readthedocs.io/en/latest/log.html#). Gigalixir logs use the `Plaintext` format, you can find more information on formatting in our [Log Formatting Documentation](/logging/formatting). ## Check For Existing Log Drains Before creating a new log drain for AppSignal, we recommend checking to see if a drain for AppSignal already exists. You can do so using the following command: ```shell Shell theme={null} gigalixir drains ``` You can remove any log drain you wish using the below command: ```shell Shell theme={null} gigalixir drains:remove LOG_DRAIN_ID ``` *Replace LOG\_DRAIN\_ID the log drain ID you are trying to remove.* ## Add new log drain Use the command below to create a new AppSignal log drain ```shell Shell theme={null} gigalixir drains:add "https://appsignal-endpoint.net/gigalixir?api_key=YOUR_LOG_SOURCE_API_KEY" ``` Replace `YOUR_LOG_SOURCE_API_KEY` with the key provided when creating a log source. When connected, logs should appear in AppSignal. If you still cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. # Heroku Logs Source: https://docs.appsignal.com/logging/platforms/heroku > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). ## Cedar (Legacy Platform) applications ### Remove old log drains > [!TIP] > > This Heroku log drain setup will send both logs and metrics to AppSignal. To > send only metrics to AppSignal, follow the Heroku log drain setup [in our > Heroku documentation](/heroku/setup) instead. Before creating a new log drain for AppSignal, you need to remove any pre-existing AppSignal log drains. You can check for any existing active log drains using the command below, where `myapp` is the name of your Heroku application: ```shell Shell theme={null} heroku drains -a myapp ``` If there are any active AppSignal log drains, you can remove them using the following command: ```shell Shell theme={null} heroku drains:remove -a myapp ``` *Replace `` above with the URL of the log drain you are trying to remove* ### Add new log drain Once any active log drains have been removed, [follow the instructions to create a Heroku log source](/logging/configuration#creating-a-log-source). Once you have created a log source, use the command below to create a new log drain. ```shell Shell theme={null} heroku drains:add "https://appsignal-endpoint.net/logplex?api_key=YOUR_LOG_SOURCE_API_KEY" ``` Replace `YOUR_LOG_SOURCE_API_KEY` with the key provided when creating a log source. When connected, logs should appear in AppSignal. If you still cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. ### Severity parsing By default, Heroku sends all logs with an INFO severity. And since the content of logdrain messages can depend on the source (add-ons, application, Heroku router etc.), there are a couple of ways to override the default severity. #### Log format Set a log format and override the severity. You can set the format of your log lines in the source to "logfmt" and emit the following string in your logline `severity=warning`. This will override the default `INFO` severity to `WARNING`. #### Severity parsing When adding a Heroku log source in AppSignal, there's a checkbox to enable "Severity parsing." When checked, we will attempt to parse any valid severity string from the log message. We only do this when the alternatives have not yielded any results (e.g., if you set the source log format to logfmt and emit a severity attribute, that is used instead of the parsed severity). The following strings are considered valid severities; they can be uppercase, lowercase, or mixed case: * TRACE * DEBUG * INFO * NOTICE * WARNING * WARN * ERR * ERROR * CRIT * CRITICAL * ALERT * EMERG * PANIC * FATAL We will not consider these strings a severity, if they are part of a word. Severities encased in blocks are considered severities, for example: These are parsed as severities: ```shell Shell theme={null} [oban] [error] invalid query ERROR - My app is broken error something went wrong [Error] this is a valid error severity ``` *Note that this means any lowercase severity string (info/debug/warning/trace/etc) anywhere in the log line will change the log severity.* These are not parsed as severities: ```shell Shell theme={null} ErrorClass error: something went wrong The doctor was panicking just as much as the patient ``` ## Fir applications To send logs from your Heroku Fir application to AppSignal, follow the [setup steps for Heroku Fir generation applications](/heroku/setup#fir-applications). AppSignal will automatically ingest logs from your application through OpenTelemetry HTTP exporters, or any logs from `stdout` and `stderr` via a [Heroku Telemetry Drain](https://devcenter.heroku.com/articles/log-drains). # Netlify Source: https://docs.appsignal.com/logging/platforms/netlify You can configure Netlify to send logs to a dedicated endpoint. Currently, Netlify only supports the exporting of function logs. To configure Netlify to send function logs to AppSignal, follow the steps outlined below: 1. Under **Site settings > Log Drains**, select "**Enable a log drain**". 2. Select "**General HTTP endpoint**" as the Log drain service. 3. Select only "**function logs**" as the **Log type**. 4. Enter the following URL for your endpoint: ```shell Shell theme={null} https://appsignal-endpoint.net/logs/netlify?api_key=YOUR_LOG_SOURCE_API_KEY ``` Replace `YOUR_LOG_SOURCE_API_KEY` with the key provided when [creating a log source](/logging/configuration#creating-a-log-source). 1. Select [`NDJSON`](/logging/endpoints/http-json#ndjson) as the **Log Drain Format**. 2. Once you've completed the steps above, select "**Connect**". When connected, logs should appear in AppSignal. If you still cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. You can find more information on Netlify's log drains in their [Log Drain](https://docs.netlify.com/monitor-sites/log-drains/#general-http-endpoint) documentation. # Render Logs Source: https://docs.appsignal.com/logging/platforms/render > [!TIP] > > Please note that when running multiple applications on Render, AppSignal will receive logs for all your applications and currently cannot automatically filter them. > > To avoid sending unnecessary logs, we recommend sending logs via [AppSignal for Ruby, Elixir, or Node](/logging/integrations) when running multiple apps on Render. You can configure a Log Stream with Render to send logs to AppSignal. Render logs will be in the [Syslog RFC 5424](/logging/formatting) format. To configure Render to send logs to AppSignal, follow the steps outlined below: 1. To open Render's Create Log Stream form, navigate to **Account/Team settings > Log Streams**, and select "**Add Log Stream**". 2. Enter the following URL in the Log Endpoint field: ```shell Shell theme={null} appsignal-endpoint.net:6514 ``` 1. In the Token field, add the key provided when [creating a log source](/logging/configuration#creating-a-log-source). 2. Once you've completed the steps above, select "**Create Log Stream**". When connected, Render logs should appear in AppSignal. If you still cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. You can find more information on Render's Log Streams in their [Log Streams](https://render.com/docs/log-streams) documentation. # Scalingo Log Drain Source: https://docs.appsignal.com/logging/platforms/scalingo > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). AppSignal can automatically ingest logs via [Scalingo Log Drain](https://doc.scalingo.com/platform/app/log-drain#appsignal). Scalingo log drains can be managed using Scalingo's [CLI](https://doc.scalingo.com/platform/cli/start). ## Check For Existing Log Drains Before creating a new log drain for AppSignal, we recommend checking to see if a drain for AppSignal already exists. You can do so using the following command: ```shell Shell theme={null} scalingo --app my-app log-drains ``` You can remove any log drain you wish using the below command: ```shell Shell theme={null} scalingo --app my-app log-drains-remove LOG_DRAIN_URL ``` *Replace LOG\_DRAIN\_URL with the log drain URL you are trying to remove.* ## Add New Log Drain Use the command below to create a new AppSignal log drain: ```shell Shell theme={null} scalingo --app my-app log-drains-add --type appsignal --token YOUR_LOG_SOURCE_API_KEY ``` Replace `YOUR_LOG_SOURCE_API_KEY` with the key provided when creating a log source. When connected, logs should appear in AppSignal. If you still cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. # Vector Source: https://docs.appsignal.com/logging/platforms/vector > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). AppSignal can ingest logs via your Vector instance. To send data from your Vector sources to AppSignal, you need to set up the AppSignal Vector sink in your Vector configuration and create a new Vector logging source. You can read more about AppSignal's Vector integration in our [Vector documentation](/vector). ## Configure Sink To do this, create a new Vector sink with the type `appsignal`. You can define your logging sources via the `inputs` attribute in this sink. To successfully send logging data to AppSignal, you must also provide your [app-level Push API Key](https://appsignal.com/redirect-to/app?to=api_keys\&key_tab=app) via the `push_api_key` attribute: ```toml TOML theme={null} # vector.toml example # Other config here # Add this AppSignal sink section [sinks.appsignal] type = "appsignal" inputs = [ "internal_logs", "your_log_source" ] push_api_key = "YOUR_APP_LEVEL_API_KEY" ``` ## Create Logging Source Once your Vector Sink is configured, create a new [logging source](/logging/configuration#creating-a-log-source) and select Vector as the platform. Once created, AppSignal Logging will begin to display the configured logs. If you cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. # Logs query autocomplete Source: https://docs.appsignal.com/logging/query-autocomplete Picture this: your Rails app logs under several groups, such as `rails`, `shop`, and `audit`. You want to see only the `shop` lines, but can't remember whether the field is called `group` or `namespace`. The Logs query bar suggests fields, operators, and severity values as you type. Use the suggestions to build a query without memorizing the syntax. You can also type a query directly and pick suggestions for the parts you don't remember. ## Build a query Select the query bar to open suggestions grouped under **Fields** and **Attributes**: * **Fields** are available on every log line: `severity`, `hostname`, `group`, and `message`. * **Attributes** are the keys AppSignal finds in the JSON of the log lines shown, such as `amount` or `cart_id`. The list shows five attributes until you type. Type part of a name to filter the list. ![Logs query bar containing a typed query that ends in AND, with a dropdown listing the fields severity, hostname, group, and message, then attributes such as amount, attempt, and cart\_id](https://mintcdn.com/appsignal-715f5a51/GKJqxbAmNvM75ywp/assets/images/screenshots/logging/logs-query-autocomplete.png?fit=max\&auto=format\&n=GKJqxbAmNvM75ywp\&q=85\&s=1d485a8dc03e051cafa87a0d26819463) Suggestions grouped under Fields and Attributes, shown after AND for the next filter Say a background job fails and you want every error-level line that mentions Active Job. Build `severity=error AND message:"ActiveJob"` from the suggestions: 1. Select `severity`. Severity skips the operator step and offers the severity levels, such as `error`, `warn`, and `info`. These suggestions insert text into the query but you can still type or edit them directly. 2. Select `error`. The bar now reads `severity=error`. 3. Type a space and select **AND** from the join suggestions, or type it yourself. 4. Select `message`, then choose an operator: **contains**, **is**, **is not**, or **does not contain**. Select **contains** and the bar reads `severity=error AND message:`. 5. Type `"ActiveJob"` and press Enter to run the query. Quotes are optional for one word and required once the value contains a space, such as `message:"Error performing"`. The page now shows only error-level lines whose message contains `ActiveJob`. Add `AND group=shop` to narrow it to one group. To match more than one severity, combine filters with OR, for example `(severity=error OR severity=warn)`. Use the arrow keys to highlight a suggestion and Enter to insert it. With no suggestion highlighted, Enter runs the query. Press Escape to close the suggestions. Select the clear button at the right of the bar to remove the query and show all logs. While the query bar has focus, live tailing pauses so the current lines stay in place. It resumes when you leave the bar. ## Type a query directly The query bar is a text field, so you can also type or paste a query. The full [Log Query Syntax](/logging/query-syntax) still works in the bar if you need more than the logs autocomplete suggestions offer. The same autocomplete is available in the query fields for log triggers and log metrics. In the metrics form, suggestions also include fields available for metric extraction and grouping. ![Logs query bar containing autocomplete field suggestions and preselected log source values in the log metrics form](https://mintcdn.com/appsignal-715f5a51/wxDkcl57NEpCWnZt/assets/images/screenshots/logging/trigger-metric-autocomplete.png?fit=max\&auto=format\&n=wxDkcl57NEpCWnZt\&q=85\&s=1af93251a5d3e9b9064928ba85710348) Autocomplete suggestions for a query typed directly into the query bar and preselected log source values in the log metrics form Once a query returns the lines you need, you can turn them into a [log-based metric](/logging/metrics) without leaving the page. Then, you can also create a [log trigger](/logging/triggers) to get notified when the query matches new lines. Logs query autocomplete is now generally available to all customers. Share your feedback on our [Discord server](https://discord.gg/sBWWGwYzfC). # Log Query Syntax Source: https://docs.appsignal.com/logging/query-syntax > [!TIP] > > This page describes our newest query syntax. For the syntax using > `attributes`, see our [legacy query syntax](/logging/legacy-query-syntax) AppSignal's log filtering system allows you to search and filter through your application logs using an intuitive query syntax. Whether you need to find specific error messages, filter by severity levels, or search through custom attributes, our query language makes it easy to pinpoint exactly what you're looking for. ![Screenshot of expanded log](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/logging/all-logs.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=294a9482dd18a89b870da2f9f8f13055) > [!NOTE] > > You don't have to type this syntax by hand. Select the logs search bar and [autocomplete](/logging/query-autocomplete) suggests fields, operators, and severity levels from your logs. Suggestions insert text into the query, and you press Enter to run it. The same autocomplete is available in the query fields for log triggers and log metrics. For the full flow, see [Logs query autocomplete](/logging/query-autocomplete). ## Quick Start Get started with these simple queries: ```sql SQL theme={null} timeout ``` Finds logs whose message contains "timeout". ```sql SQL theme={null} severity=error ``` Finds all error-level logs. ```sql SQL theme={null} severity=error hostname=production-web-1 ``` Finds errors from a specific server. ## Available Fields You can query the following fields in your logs: | Field | Description | Example | | - | - | - | | `severity` | Log level (error, warning, info, debug, trace) | `severity=error` | | `hostname` | Application host | `hostname=production-1` | | `group` | Namespace defined for your application | `group="background jobs"` | | `message` | Log message content | `message:timeout` | | Custom attributes | Any custom attribute defined in your logs | `duration>10.1` | If no field is provided, the query will search the message field. ## Query Operators ### Search Operators | Operator | Syntax | Description | Example | | - | - | - | - | | `:` | `field:value` | Contains value | `message:error` | | `!:` | `field!:value` | Does not contain value | `hostname!:test` | | `=` | `field=value` | Exact match | `severity=error` | | `!=` | `field!=value` | Not equal to | `severity!=info` | Use quotes for values with spaces: `group:"background jobs"` Compare a field with an empty string to filter empty and non-empty values: * `code=""` matches log lines where `code` is empty. * `code!=""` matches log lines where `code` has a non-empty value. ### Partial Matches and Wildcards The `:` operator matches when the value appears anywhere in the field. `message:timeout` finds "Request timeout" and "timeout after 30s". The match is case-sensitive, so it does not find "Timeout". There is no wildcard character. An asterisk is searched for literally, so `message:error*` only matches messages that contain the text `error*`. To find messages that contain "error", use `message:error`. The `%` and `_` characters are matched literally as well. Use `=` when the whole field has to match. Exact matches are case-sensitive too. ### Comparison Operators For numeric values: | Operator | Syntax | Description | Example | | - | - | - | - | | `>` | `attribute>value` | Greater than | `duration>100` | | `<` | `attribute=` | `attribute>=value` | Greater than or equal to | `duration>=100` | | `<=` | `attribute<=value` | Less than or equal to | `user_id<=1000` | ### Nested Attributes We'll use the following example JSON structure: ```json JSON theme={null} { "message": "User logged in", "group": "admin", "hostname": "production-1", "user": { "id": 123, "name": "John Doe", "emails": ["john@example.com", "john@work.com"], "location.country": "US" } } ``` Query nested JSON attributes using dot notation: ```sql SQL theme={null} user.id=123 ``` Access nested object properties. ```sql SQL theme={null} user.emails.0=john@example.com ``` Query array elements by index (zero-based). ```sql SQL theme={null} user.location\.country=US ``` Escape dots that are part of the field name itself using a backslash. ## Combining Queries ### AND Logic (Default) Space-separated queries are combined with AND: ```sql SQL theme={null} severity=error hostname=production-1 ``` Finds errors from production-1. ### OR Logic Use `OR` to match any condition: ```sql SQL theme={null} severity=error OR severity=warning ``` Finds errors or warnings. ### Grouping with Parentheses Use parentheses for complex queries: ```sql SQL theme={null} severity=error AND (hostname=web-1 OR hostname=web-2) ``` Finds errors from either web-1 or web-2. # Triggers Source: https://docs.appsignal.com/logging/triggers This documentation explains how to create triggers to alert you of specific logging behaviors. You can read our [Anomaly Detection documentation](/anomaly-detection) for more information on AppSignal's alerting functionality. ## Creating Triggers To create a new trigger, navigate to [Triggers](https://appsignal.com/redirect-to/app?to=logging/triggers) in the Logging Navigation, and click "Create a log trigger". You will then be requested to define the following trigger attributes: * [Name and Description](#name-and-description) * [Trigger Query](#trigger-query) * [Threshold](#threshold) * [Source](#trigger-source) * [Notifier](#trigger-notifier) ### Name & Description In the *Create new trigger* form, give your trigger a functional name and description, for example, "Slow Process Trigger". ### Trigger Query Logging triggers are query based, meaning an alert is triggered when the conditions of a logging query are met. For example, if we have a logging attribute called `duration` that records how long an API request takes to complete, and we want to be alerted when that attribute is greater than 50, we would create a trigger with the following query: ```bash Shell theme={null} attributes.duration > 50 ``` To match only some log levels, add a severity filter to the query. For example, this query matches error and fatal log lines: ```bash Shell theme={null} severity=error OR severity=fatal ``` Without a severity filter, the trigger matches log lines of every severity. You can read more about AppSignal's query syntax in our [query syntax documentation](/logging/query-syntax). ### Threshold You can define a threshold for your trigger to ensure you only receive alerts when necessary. Logging triggers can have the following thresholds: * Every Occurrence * First After Close * Nth in an hour * Nth in a day If you want to prevent a trigger from notifying you, you can select "Never Notify". The Never Notify threshold is mainly used for benign issues you want to keep track of but are not urgent enough to justify triggering an alert. You can read more about thresholds in our [Notification Settings documentation](/application/notification-settings#notification-options). ### Trigger Source Define which logging sources your query applies to. ### Trigger Notifier Define how you are notified once a trigger is triggered, for example, via email or Slack. Logging currently supports the following notifiers: * Discord * Email * Google Hangouts * Opsgenie * Pagerduty * Slack * MS Teams * Webhook You can read more about integrating AppSignal with notifiers in our [Integrations documentation](/application/integrations#available-notifiers). ### Save & Manage Triggers Once saved, if the conditions of your trigger are met, you will be alerted via your preferred notifier platform. You can manage your logging triggers from the Triggers page. If you are struggling with integrating a notifier or are not receiving alerts, you can [reach out to us support](mailto:support@appsignal.com), we're here to help! # Troubleshooting Source: https://docs.appsignal.com/logging/troubleshooting If you're having trouble with RSyslog you may wish to follow some of the troubleshooting information in this documentation. Alternatively, you can review the official [RSyslog Troubleshooting Documentation](https://docs.rsyslog.com/doc/troubleshooting/index.html). If that still doesn't solve your problems, you can [contact us](mailto:support@appsignal.com), and we'll help you figure things out! ### Check Installation To see if the RSyslog daemon is installed, you can run the following terminal command: ```sh Shell theme={null} command -v rsyslogd ``` If RSyslog is installed, the output of this command will be the path to the RSyslog binary. If nothing is returned by this command, rsyslog is probably not installed. For installation instructions, please refer to the official [RSyslog Installation Documentation](https://www.rsyslog.com/doc/master/installation.html). To see if the RSyslog daemon is running, you can run the following terminal command: ```sh Shell theme={null} pgrep rsyslogd ``` If RSyslog is running, the output of this command will be the process ID of the currently running RSyslog daemon process. If nothing is returned by this command, the RSyslog daemon is not running. In most RSyslog installations, the following command will start the RSyslog daemon: ```sh Shell theme={null} systemctl start rsyslog ``` ### Debugging If you run into issues, you may wish to inspect the behaviour of the RSyslog daemon. To do so, you can configure RSyslog to create a debug log. Add the following lines at the beginning of your `rsyslog.conf` file: ```text Text theme={null} $DebugFile /tmp/rsyslogd.log $DebugLevel 2 ``` A `DebugLevel` of `2` activates always-on debug mode, while a level of `0` turns debug mode off. For other debugging options, please refer to the [RSyslog Debug Log Documentation](https://www.rsyslog.com/doc/v8-stable/troubleshooting/howtodebug.html#how-to-create-a-debug-log). To apply the configuration changes, restart the RSyslog daemon process: ```sh Shell theme={null} systemctl restart rsyslog ``` You can now review the RSyslog debug logs at `/tmp/rsyslogd.log`. When you're done, make sure to deactivate debug mode by undoing the configuration changes and restarting RSyslog again. > [!NOTE] > > 🔎 For further information on troubleshooting and debugging with syslog please > refer to the official [RSyslog Troubleshooting > Documentation](https://www.rsyslog.com/doc/v8-stable/troubleshooting/). # Wrap process monitoring Source: https://docs.appsignal.com/logging/wrap-process-monitoring ## Logging By default, `appsignal-wrap` will send both the standard output and standard error of the process it monitors as logs to AppSignal. The logs will appear under the "application" source, and the name provided as the first argument will be used as the log group. ### Disable logging To disable sending either the standard output or standard error as logs, you can use the `--no-stdout` or `--no-stderr` command-line options respectively. To disable sending logs altogether, you can use the `--no-log` command-line option. ### Custom log group To send logs as a different log group, you can pass it as an argument to the `--log` command-line option. For example: ```sh Shell theme={null} appsignal-wrap mysql --log db -- mysqld ``` In the above example, `appsignal-wrap` will use `db` as the log group when sending logs to AppSignal, but will still use `mysql` as the name to identify the process when reporting process monitors and errors. ### Custom log source To send logs to a different log source, you can pass the log source's API key, which you obtain when [creating a log source](https://docs.appsignal.com/logging/configuration.html#creating-a-log-source), as an argument to the `--log-source` command-line option, or as the `APPSIGNAL_LOG_SOURCE_API_KEY` environment variable. For example: ```sh Shell theme={null} export APPSIGNAL_LOG_SOURCE_API_KEY=[LOG_SOURCE_API_KEY] appsignal-wrap mysql -- mysqld ``` # Organizations Source: https://docs.appsignal.com/organization Organizations group applications and billing in AppSignal. Create, rename, or leave an organization. Let's say you have your own startup but still do some freelance work for clients on the side. You'll want to have your own AppSignal billing setup for your startup, while still being part of the AppSignal organizations of your clients. This is easily done with "organizations" in AppSignal. Organizations are basically umbrellas for your applications, which we charge on the organization level. ## Creating a new organization Once you sign up for an AppSignal account you will need to create an Organization, except when you accept an invitation to another organization. If you already have an account you can [create a new organization][profile-organizations] from your user account settings. Because you'll probably work with new people and apps in this organization, you'll start a new 30 day trial period for this new organization. ## Renaming an organization In case you want to rename your organization contact us at [support@appsignal.com](mailto:support@appsignal.com), or through the in-app chat. Please ensure you're an owner of the organization otherwise we will have to decline your request. Please provide the following details in your message: 1. Tell us which organization you want to rename and what to rename it to. 2. If the organization's slug in the URL needs to be updated as well (`appsignal.com/your-organization-slug`), let us know what it needs to be changed to as well. **Note**: If the organization's URL slug has to be updated as well, the change will break all existing links in emails and other notifications. We will not put a redirect in place to link from the old organization slug to the new one. New notifications will use the updated organization slug. ## Leaving an organization In your user profile you can find a [list of all the organizations][profile-organizations] you have access to. If you're not the only owner of an organization you can leave it. Once you do that you will not have access to the organization anymore, the only way to undo this is asking the owner to invite you again. [profile-organizations]: https://appsignal.com/users/accounts # Performance / tracing Source: https://docs.appsignal.com/performance-tracing How traces and performance views relate in AppSignal. Follow a slow request or failed job through its spans, and add instrumentation where data is missing. In AppSignal, performance and tracing describe the same core flow from two sides. A trace shows what happened during a request, job, or script run. Performance views help you understand where that trace spent time and where it slowed down. When a trace is slow, you can use AppSignal to inspect the spans and events inside it. When a trace ends with an exception, that same trace becomes the context you use to debug the error. ## Follow the trace The Performance [trace page](/trace-page) list shows the stored traces. Select one to open its details, which shows that trace in full: its span timeline, tags, related logs, request data, and the triggers that alert you when the action gets slow. Use these guides when you want to investigate performance in more detail: * [Find slow requests](/guides/slow-requests) * [Find slow queries](/guides/slow-queries) * [Distributed tracing](/distributed-tracing) — follow one request across services and applications * [Errors](/errors) ## Add more instrumentation When the default instrumentation is not enough, add more detail to your traces with: * [Add additional OpenTelemetry Instrumentation](/guides/instrumentation/additional-opentelemetry-instrumentation) * [Custom instrumentation](/custom-instrumentation) # Services and integrations Source: https://docs.appsignal.com/services-integrations Browse all platforms, services, and integrations that work with AppSignal. Find setup guides for your hosting provider, log source, notification channel, and more. AppSignal works with the platforms, services, and tools you already use. Browse the sections below to find setup guides for your stack. ## Hosting and deploy platforms Set up deploy markers, host metrics, and log forwarding for your hosting provider. > **[Heroku](/heroku/setup)** > > Metrics, dashboards, deploy markers, and logs > **[Vercel](/vercel/overview)** > > Logs, Speed Insights, and traces > **[Kubernetes](/kubernetes/metrics)** > > Cluster and container metrics > **[Render](/render/setup)** > > Metrics, dashboards, deploy markers, and logs > **[Hatchbox](/application/markers/deploy-markers#hatchbox-support)** > > Deploy markers via connected account > **[Kamal](/application/markers/deploy-markers#kamal-support)** > > Automatic deploy markers > **[Docker](/application/markers/deploy-markers#docker-support)** > > Deploy markers for containerized apps > **[Clever Cloud](/logging/platforms/clevercloud)** > > Log forwarding > **[Gigalixir](/logging/platforms/gigalixir)** > > Log drain > **[Netlify](/logging/platforms/netlify)** > > Log forwarding > **[Scalingo](/logging/platforms/scalingo)** > > Log drain ## Cloud services and log sources Forward logs and metrics from cloud infrastructure to AppSignal. > **[AWS CloudWatch logs](/logging/platforms/cloudwatch)** > > Forward logs via Amazon Data Firehose > **[AWS CloudWatch logs (CloudFormation)](/logging/platforms/cloudwatch-cloudformation)** > > Automate log streaming setup with a CloudFormation template > **[AWS CloudWatch metrics](/metrics/cloudwatch)** > > Stream CloudWatch metrics via Amazon Data Firehose > **[AWS CloudWatch metrics (CloudFormation)](/metrics/cloudwatch-cloudformation)** > > Automate metric streaming setup with a CloudFormation template > **[Vector](/vector)** > > Forward logs from any Vector pipeline > **[NGINX](/metrics/nginx)** > > Collect NGINX metrics ## Notifications and incident management Send alerts and incidents from AppSignal to your team's communication and on-call tools. > **[Slack](/application/integrations/slack)** > > Receive alerts in Slack channels > **[Microsoft Teams](/application/integrations/teams)** > > Receive alerts in Teams channels > **[Discord](/application/integrations/discord)** > > Receive alerts in Discord channels > **[Google Chat](/application/integrations/hangouts)** > > Receive alerts in Google Chat spaces > **[PagerDuty](/application/integrations/pagerduty)** > > Trigger PagerDuty incidents from alerts > **[OpsGenie](/application/integrations/opsgenie)** > > Create OpsGenie alerts from incidents > **[Squadcast](/application/integrations/squadcast)** > > Route incidents to Squadcast > **[Webhooks](/application/integrations/webhooks)** > > Send alert data to any HTTP endpoint > **[All Quiet](https://docs.allquiet.app/integrations/inbound/appsignal)** > > Route AppSignal alerts via the All Quiet webhook > **[ilert](https://docs.ilert.com/inbound-integrations/appsignal)** > > Route AppSignal alerts via the ilert webhook > **[Zenduty](https://www.zenduty.com/docs/appsignal-integration/)** > > Route AppSignal alerts via the Zenduty webhook ## Issue tracking and source control Create issues and link backtraces to your codebase directly from AppSignal. > **[GitHub](/application/integrations/github)** > > Link repos, create issues, and link backtraces > **[GitLab](/application/integrations/gitlab)** > > Create GitLab issues from incidents > **[Jira](/application/integrations/jira)** > > Create Jira issues from incidents > **[Linear](/application/integrations/linear)** > > Create Linear issues from incidents > **[Asana](/application/integrations/asana)** > > Create Asana tasks from incidents > **[Trello](/application/integrations/trello)** > > Create Trello cards from incidents > **[Shortcut](/application/integrations/shortcut)** > > Create Shortcut stories from incidents ## Dashboards and reporting Push AppSignal data to external dashboards. > **[Geckoboard](/application/integrations/geckoboard)** > > Display AppSignal data in Geckoboard ## AppSignal tools Additional tools for sending data to AppSignal or extending your setup. > **[Collector](/collector)** > > Receive and forward OpenTelemetry data > **[Standalone agent](/standalone-agent/installation)** > > Monitor host metrics without an SDK > **[Wrap](/wrap)** > > Monitor any process with a wrapper script > **[AppSignal API](/api)** > > Access data and manage resources via REST API > **[MCP server](/mcp-server)** > > Query AppSignal from AI assistants *** Don't see what you need? AppSignal supports any tool or service that exports [OpenTelemetry](/opentelemetry) data. You can also reach out to [support@appsignal.com](mailto:support@appsignal.com). # Traces page Source: https://docs.appsignal.com/trace-page Inspect one trace: its service map, span timeline, span details, tags, related logs, triggers, the other traces for the same action, and the action's logbook. When a request is slow and you need to see where the time went, start with the ["Performance > Traces" page](https://appsignal.com/redirect-to/app?to=performance/traces). That page lists the actions AppSignal has stored traces for. Select the action you want to inspect, then select one of its stored traces at a specific time. The trace page shows that one recorded request, job, or task in detail: its services, spans, metadata, related errors and logs, and the related traces for the same action. Use the page to answer three practical questions: * Which service or span took the time? * Did the trace produce an error, and where did it start? * What request data or tags help explain this one run? The header shows the action name and its [namespace](/guides/namespaces), for example `run/shop.send_waitlist_notification` in `celery/background`. The tabs under the header switch between views of the same action: Summary, Traces, Charts, and Logbook. Browser errors show the same trace timeline, service map, and related log lines in their error inspector. ## Service map The service map shows the trace from the perspective of the services that took part in it: which services the request reached, and how long each call between them took. The service map appears only when a trace spans two or more services, for example when a request calls another service over HTTP or enqueues a background job. A request that stays inside one service has no map. * **One box per service**, grouped by `service_name`. Each box is labeled with the service name and the AppSignal application it reports to. Inside it, one row per call the service handled, so a service called twice in the same trace shows two rows. Select a row to open that service's own view of the trace. * **Hover over a row** to highlight its call chain: the calls that led to it and the calls it made. * **Edges are the calls between services**, labeled with their duration and landing on the action row they called. * **Hover over or focus a duration label** to see its breakdown, when the call spent time outside the called service: the total duration, the duration inside the called service, and the latency between the two services. * **Edge color rates each call** against the trace's own baseline, as fast, slow, or critical, so the slowest ones stand out without you reading every duration. A dashed edge marks a linked trace, and a dashed box marks a service from another trace. * **Errors mark the service they happened in**, not the service that called it. Select **Fullscreen** to inspect the whole map and its legend. ![Full-screen trace service map of a checkout request across gateway, pricing, catalog, payments, inventory, fulfillment, notifications, courier, and a linked ledger trace, with each call labeled by duration and colored by speed](https://mintcdn.com/appsignal-715f5a51/3emBf86oghNbNPRL/assets/images/screenshots/performance/trace-service-map.png?fit=max\&auto=format\&n=3emBf86oghNbNPRL\&q=85\&s=9337e68bc4fcc0c5939d7c355adb171d) The full-screen trace service map, showing the services in one trace, the calls between them, and the legend ## Errors From This Trace If the trace produced exception incidents, AppSignal shows an **Errors from this trace** table above the trace timeline. Use it to open the error trace view for that incident in the same trace, where you can inspect the error message, backtrace, and error causes. ## Trace timeline The timeline details the trace's spans over time, from the start of the trace to its end. The position of each bar shows when a span started, its width shows how long the span ran, and its color shows the span group it belongs to. When AppSignal detects an N+1 query, the timeline shows a short explanation above the spans and marks the representative span with a yellow badge. Select the badge to expand that span and inspect the repeated queries. The timeline follows the operation across services. Each service is labeled in the timeline, so you can see where one service hands work to the next. When the trace has more spans than the preview shows, select **All spans** at the top, or the **more in the fullscreen overlay** link at the bottom, to open the full timeline. The full timeline also fits a phone screen. In it, you can: * Search spans by name, attribute, or event. * Filter by event type: errors, queries, or events. * Filter by span group, such as web server, database and ORM, HTTP, or other. * Filter by service, or narrow the timeline to part of the trace's duration. * Expand and collapse nested spans. A badge shows how many child spans a span has, and a repeat badge such as `x6` shows how often the same span ran. * Hover over a span to preview its details, and select it to keep them open. * Drag the divider beside the span column to resize it, on a touch screen too. Scroll the column sideways to read long span names. ![Full-screen trace timeline showing spans across django, inventory, and audit services over time, with filters across the top and the selected SQL span's query and attributes on the right](https://mintcdn.com/appsignal-715f5a51/3emBf86oghNbNPRL/assets/images/screenshots/performance/trace-timeline.png?fit=max\&auto=format\&n=3emBf86oghNbNPRL\&q=85\&s=00eedfcb8e39143041e2ded0caa4b885) The full-screen trace timeline, with filters across the top and the details of the selected span on the right ### Span details The details panel names the span and shows its kind, such as `consumer`, its status, its start time, and its duration. Three tabs give the rest: * **Attributes**: the span attributes, such as `celery.task_name` and `messaging.destination`, and the resource attributes, such as `host.name` and `service.name`. Select **Show internal attributes** to also list the attributes AppSignal adds. The trace ID and the span ID are visible **only** while **Show internal attributes** is selected. * **Exceptions** or **Events**: the errors and other events recorded on the span. A span that raised an error also shows a summary at the top of the panel, with an action to view the exception. * **Related logs**: the log lines linked to the span. Select **View in logs** to continue in the [log explorer](/logging). The **Related logs** tab opens with its scope set to **This span**, so it searches only for the log lines of the span you selected. Set the scope to **Entire trace** to widen the search to every log line linked to the trace, across all of its spans and services. ### Trace breakdown The trace breakdown shows where the trace's time went, split by the libraries and code that did the work, such as `active_record`, `http_rb`, or `sidekiq`. The legend lists each one with its total, largest first. Some traces can also show an **Allocations** bar with how many objects each one allocated. ## Metadata The metadata section shows when the selected subtrace occurred and then groups that subtrace's metadata into tabs. Each tab appears only when AppSignal received that kind of data for the selected subtrace. When tags are present, the **Tags** tab appears first. * **Tags**: the AppSignal tags on the selected subtrace, plus its `revision` when present, such as `hostname`, `queue`, `message_id`, and `revision`. * **Request headers**: the HTTP headers AppSignal received for that subtrace. * **Environment**: other request values the integration reported for that subtrace. Depending on the integration, header-like values can appear here too. * **Request query parameters**: the query string parameters AppSignal received for that subtrace, when available. * **Request payload**: the request body AppSignal received for that subtrace, when available. * **Request session data**: the session values AppSignal received for that subtrace, when available. * **Custom data** and **Function parameters**: extra context your instrumentation added for that subtrace. Each tag has two actions: * **Filter** narrows the Traces list to the traces of this action that carry the same value. The value stays visible above the list, and **Reset** clears it. * **Search** opens an overview of everything AppSignal recorded with that value. You can narrow the overview by app, namespace, time range, and type, so you see only the errors or only the performance traces that share it. Select **Go to trace** on any result to open it. Two tags also link to a related page: * `hostname` has **View host metrics**, which opens the host's metrics around the time of the trace. In apps that report Kubernetes metrics, it is **View pod metrics** instead. * `revision` has **View deploy**, which opens the deploy for that revision. ![The Tags list on a trace, with the View host metrics tooltip on the icon next to the hostname tag and the View deploy tooltip on the icon next to the revision tag.](https://mintcdn.com/appsignal-715f5a51/8fn2fngWpUaYPpwU/assets/images/screenshots/performance/trace-tag-links.png?fit=max\&auto=format\&n=8fn2fngWpUaYPpwU\&q=85\&s=f09ae336b59e6018b01e4c88711cc842) The hostname and revision tags link to host metrics and the deploy Use [header filtering](/application/header-filtering), [parameter filtering](/application/parameter-filtering), and [session data filtering](/application/session-data-filtering) to control which request values your app sends. To turn a tag value into a link to your own application, use [link templates](/application/link-templates). To send more tags from your app, see [tagging](/application/tagging). ## Related logs The trace-level **Related logs** box shows the log lines AppSignal could link to this trace, with their time, severity, and message. Select **Open in the log view** to continue in the [log explorer](/logging). The panel reports when it finds no related log lines. AppSignal links a log line to a trace when the log line carries the trace's `request_id` or `trace_id` as an attribute, or contains that identifier in its message. The panel stays empty when the operation logged nothing, when your app does not send logs to AppSignal yet, or when no log line carries the identifier. See [configure logging](/logging/configuration) to send logs, and [link traces with logs](/guides/linking-traces-with-logs) for the identifiers. ## Breadcrumbs If your app records AppSignal breadcrumbs as `appsignal.breadcrumb` events, the page shows them in time order under **Breadcrumbs**. Each breadcrumb includes its time, category, action, and, when present, a message and metadata. Use them to see what led up to that trace without leaving the page. ## Perf. trends At the top of the right-hand column, **Perf. trends** shows the action's performance over the last 24 hours or 30 days. For performance traces, the chart plots the `P90` and the mean duration. Select `24H` or `30D` to change the time range, then select a point on the chart to jump the trace list to that time. ## Triggers Triggers alert you when this action gets slow. The panel lists the triggers that already exist for the action, such as `Mean > 200 ms`. If there are none yet, the box shows **No triggers yet** and an **Add new** link. Select **Add new** to open the trigger form with the namespace and action name filled in. In the form, you: * Choose the value to alert on, such as the mean, and the threshold above which AppSignal alerts, such as 200 ms. * Set an alert warm-up and an alert cooldown in minutes. * Add a description for the people who receive the alert. * Select the notifiers that receive it, such as email, Slack, PagerDuty, or OpsGenie. Existing triggers also show whether they have open alerts, when they last fired, and a menu to edit, duplicate, or delete them. For how alerts open, close, and repeat, see [anomaly detection](/anomaly-detection) and [warm-up and cooldown](/anomaly-detection#warm-up-and-cooldown). ## Actions The **Actions** box gives you two kinds of follow-up: * **Time detective**: review your application's data as it was at the time of the trace. * **JSON and Markdown exports**: download or copy the trace in either format. The Markdown export includes the trace summary, related errors, span tree, breakdown, shared metadata such as session data and environment, breadcrumbs, and context. ## Traces The Traces panel lists the other stored traces for this action, each with its timestamp and duration. Select any of them to open that trace. To find a specific trace: * Enter a value in the tag filter field, or use the **Filter** action on a tag, to keep only the traces that carry that value. * Open the date control to pick a date and time, or choose **Today**, **Yesterday**, **Last week**, or **Latest**. Select **Jump to date** or **Jump to latest** to update the list. * Select **Load newer traces** or **Load older traces** to move through the list. * Select **Reset** to clear the filters and see every stored trace again. A [deploy marker](/application/markers) between two traces shows where a new revision took over, which helps you compare traces from before and after a deploy. > [!NOTE] > > AppSignal does not store a trace for every request. It stores a representative set instead, so the list shows a sample of the action's traffic. A link to a trace that's no longer available opens the action's latest trace instead, under a **Specific trace could not be found** notice. A link to an error's trace opens that error's latest occurrence. ## Logbook Traces expire, and with them the context your team gathered while investigating one. The logbook keeps that context with the action instead. Every action on the ["Performance > Traces" page](https://appsignal.com/redirect-to/app?to=performance/traces) has one logbook, shared by all of its traces. A note you write today is still there when the next slow trace of that action arrives. To open the logbook, select the action on the "Performance > Traces" page. That opens the action's **Summary** tab, which holds a **Logbook** box with the note form and the notes so far. Write your note and select **Post note**. It appears in the box, under the pinned note if there is one. Select **Full logbook**, or the **Logbook** tab, to open the whole logbook on its own page. Notes support Markdown. You can pin any note to keep it at the top, and pinning another note replaces it. You can edit and delete only the notes you wrote. A trace logbook holds notes only. Unlike the previous incident's logbook, it does not record state changes or link GitHub issues. For an agent, the AppSignal MCP [`manage_note` tool](/mcp/reference#manage_note) adds and edits these notes by namespace and action name. The GraphQL API does the same with the [`createPerformanceTraceActionNote` mutation](/api/graphql/mutations#create-a-note-on-a-performance-trace-action). Once you have noted a fix, add a trigger in the [Triggers](#triggers) panel. AppSignal then alerts you if the action slows down again. # Your user account Source: https://docs.appsignal.com/user-account Sign up for AppSignal with GitHub or email, and manage your personal and notification settings. Whenever you use AppSignal your log in with your user account. A user can have access to one or more organizations that contain apps that are being monitored. ## Sign up When you are invited to an existing account or sign up, you can choose to sign up using GitHub or use an email / password combination. If you chose to sign up using an email / password combination, you can always link your GitHub account later on by visiting your [Profile & Settings](https://appsignal.com/users/edit) and scrolling down to GitHub section. ## Personal settings Once you're logged in you can navigate to your settings page by using the settings link at the top right of the screen. There are four personal setting screens. ### Personal In personal settings you can change your name and password. If you haven't linked your GitHub account during sign-up, you can still do so here. Connecting your GitHub account gives you additional features like direct links to commits and linked stack trace lines. You can also choose a theme for the AppSignal UI here. Switch the **Theme** toggle to **Dark** for a dark theme, **Light** to keep the default light theme, or **System** to follow your operating system's preference. ### Notifications You can have multiple email addresses associated with AppSignal. This could be useful if someone invites you on your personal email address while you prefer to use your company email address. It's also useful if you are part of multiple organizations within AppSignal. You can choose to have notifications sent to different email addresses per organization. ![Email addresses](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/user_emails.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=5bd0cbbc6467f5af5ed9a7560b49fa08) You can configure which email address AppSignal should use for notifications per organization. You can also choose whether you want to receive notifications per app. If you disable notifications you'll still be able to access the app. ![Notifications](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/user_notifications.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=7ea7cf6c1f24458046cfacf33c06c22a) # Vercel Logs Source: https://docs.appsignal.com/vercel/logs AppSignal can automatically ingest Vercel logs. This setup requires an additional authorization step outlined in this step-by-step documentation. Ensure you have access to your Vercel login credentials before creating a new Vercel logging source. ## Creating a Vercel Log Source Our configuration documentation covers log sources in greater detail. To create a new log source navigate to the Logging page in the AppSignal application and click on the Add log source button in the top right of the page. A pop-up will appear, prompting you to name your source. It's important to give your source a descriptive name like Redis or MongoDB so that you can successfully query these logs in the future. Once you've named your source, select "Vercel" as your log source's platform. A notification will appear below the source dropdown asking you to authorize AppSignal via Vercel. Click "Authenticate with Vercel". Vercel will open in a new browser tab. ![Screenshot of Add new source pop-up](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/platforms/vercel/vercel-logging-add-new-1.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=a0faa9158a8448dfe9960b5ccb263808) The pop-up contains the following fields: * **Source name** — a descriptive label for your source (e.g. "Vercel"). * **Choose your platform** — select "Vercel". * **Authenticate with Vercel** — required to use this source. * **Log format** — shown further down the form after authenticating; choose how AppSignal parses your log messages (e.g. `plaintext` or `JSON`). * **Create a new view with this source** — optional; opens a logging view tied to this source after creation. Vercel will ask you to add the AppSignal integration. Click "Add Integration". ![Screenshot of Logging Sources page](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/platforms/vercel/vercel-logging-auth.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=69b8e7d6494a15d4716a52a94c5e7fa7) Next, choose which Vercel Account you want to add AppSignal to. ![Screenshot of Logging Sources page](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/platforms/vercel/vercel-logging-auth-2.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=cbf56620027e79fffa97e99dd5b46331) Follow the steps on Vercel until you get to the final screen. Here you need to click "Add Integration": ![Screenshot of Logging Sources page](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/platforms/vercel/vercel-logging-auth-3.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=977c0b56e91355cc5117e5847b4f911c) Next, you will need to select which AppSignal organization you want to link Vercel to. ![Screenshot of Logging Sources page](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/platforms/vercel/vercel-logging-choose-org.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=4bdb027e3a4121f2db802d04bac07b8e) Now you can return to AppSignal. AppSignal will check with Vercel every 30 seconds to see if it has been authorized. Do not save your log source until authorization has completed, and display a dropdown of your Vercel projects: ![Screenshot of Logging Sources page](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/platforms/vercel/vercel-logging-add-new-2.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=0fb5f9be33adffa6cdbad478e4045b95) > [!NOTE] > > 🛟 If you get stuck on this step, please [get in > touch](mailto:support@appsignal.com) with us, and we'll help you get your > Vercel logs flowing! Select the project you wish to ingest logs from and click "Add log source" Once your new log source has been created, logs should appear in AppSignal. If you still cannot see any logs, please [contact us](mailto:support@appsignal.com) for support. # Customizing data collection Source: https://docs.appsignal.com/application/data-collection By default AppSignal gathers relevant data for errors and performance measurements to help you find the cause of the issue. Sometimes you need more information, app specific data or a custom request header your app uses. You can configure AppSignal to gather more, or less, information than it does by default by tagging your transactions and configuring the request headers, parameter filtering, etc. Ideally we receive as little metadata for traces as possible, and only data that is needed to debug an exception or performance issue. > [!TIP] > > 📖 Read our [filtering app data guide](/guides/filter-data/) about limiting what > (sensitive) data is collected by AppSignal. It will guide you through > configuring which parameters, session data and request headers to collect. ## Ignore actions By configuring the `ignore_actions` option it's possible to not record any data for the configured actions, requests, background jobs, etc. > [!NOTE] > > 📖 Read our [guide about ignoring > actions](/guides/filter-data/ignore-actions). ## Ignore errors By configuring the `ignore_errors` option it's possible to ignore errors matching the exact name of an error for the entire app. > [!NOTE] > > 📖 Read our [guide about ignoring > errors](/guides/filter-data/ignore-errors). ## Namespaces Namespaces allow grouping of [actions](/appsignal/terminology#actions). By default AppSignal uses the "web", "background" and "frontend" namespaces to group [transactions](/appsignal/terminology#transactions). It's possible to create a custom namespace such as "admin", "api" to group controllers in the same namespace. The grouped actions in the namespace can be configured with their own notification defaults, allowing a critical namespace to always notify about errors, while the "web" namespace does not. It's also possible to configure the AppSignal integration to ignore a namespace to ignore all transactional data from all actions in it. > [!NOTE] > > Read more about namespaces in the [namespaces > section](/application/namespaces). ## Tagging Our tagging system allows you to attach more metadata to traces, besides what we already collect. Things such as the ID of the user making the request or other data that can help you identify who made the request or specific conditions for the request. ## Queries By default we parse SQL queries and try and remove any parameters in the query string. We've created an open-source (Rust) package that is used by our integrations. You can find [the sql\_lexer project on GitHub](https://github.com/appsignal/sql_lexer). If you see any query params in our UI, please open an issue in that repository. MongoDB queries in the Ruby integration are sanitized by default. # Environment metadata Source: https://docs.appsignal.com/application/environment-metadata The AppSignal integrations and agent collect metadata about the host and app it is integrating with. The specifics about which metadata is collected is listed below. This metadata is used to: * enrich the data available on AppSignal.com (to provide a more complete picture of the host and app), * provide additional information for debugging purposes as a supplement to the diagnose command, * product improvement as part of an anonymous aggregated dataset. To disable this feature, set the `send_environment_metadata` config option to `false`: * [Ruby](/ruby/configuration/options#option-send_environment_metadata) * [Elixir](/elixir/configuration/options#option-send_environment_metadata) * [Node.js](/nodejs/3.x/configuration/options#option-sendenvironmentmetadata) * [Python](/python/configuration/options#option-send_environment_metadata) ## AppSignal metadata * AppSignal integration version * What package and version of AppSignal is installed. This is either the Ruby gem, Elixir package or the Node.js package. * AppSignal agent version * What version of the AppSignal agent is installed. This is used to recognize the version when [standalone mode] is used. * Agent release * Reports which architecture was installed, 32 or 64-bit. The AppSignal extension and agent are built for each architecture separately. * Reports whether the [musl build](/support/operating-systems#supported-versions) was installed. * Agent standalone mode enabled * If the agent is running in [standalone mode]. This is used for hosts that run systems such as databases, that still want to report host metrics for it. * Agent StatsD mode enabled * If the agent has [StatsD mode] enabled. * Optional enabled features * AppSignal integrations have some optional features that can be enabled, usually prefixed with the `enable_` name in the config options. It is reported only when they are enabled. ## App metadata * Integration language * What the integration language is (Ruby/Elixir/Node.js) and what version. * Integration language implementation * What the language implementation is, if any (MRI or JRuby), and what version. * Integration supported libraries * A list of which AppSignal supported libraries integrations are loaded and what version, e.g. Rails, Phoenix, Express. Only information of officially supported AppSignal packages is sent, but not any unsupported or private packages. ## Host metadata The host data is available for hosts in the [host metrics] feature, adding details to hosts in the overview. * Architecture * Whether the system is 32 or 64-bit architecture. * Operating System * Operating System, either Linux, macOS or Windows. * Operating System Distribution, for Linux this reports Ubuntu, Fedora, etc. * Operating System version, the version of the Operating System. * Kernel version, for Linux this reports the installed kernel version. * Containerized system * Is the host part of a container system such as Docker. On container system such as Docker the AppSignal agent is using a different method with which host metrics are reported. * Platform * If Heroku is detected as platform. Our integrations and agent use different settings on Heroku. [standalone mode]: /standalone-agent/installation.html [statsd mode]: /standalone-agent/statsd.html [host metrics]: /metrics/host-metrics.html # Request header collection Source: https://docs.appsignal.com/application/header-filtering AppSignal collects headers for HTTP requests by default for supported frameworks. This data may help track down errors or performance issues that were caused by requests header data a client is sending. To comply with [GDPR](/appsignal/gdpr) rules, collecting no user identifiable data, AppSignal collects a very limited amount of headers by default. To even further limit the request headers or collect more than the default list of headers, configure AppSignal which headers to collect. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). ## Configure headers An app's session data can be filtered by configuring keys in an *allowlist*. This allowlist system will filter out all the session data keys not in this list. All headers that are filtered out by these systems are not collected, neither the header name or value. > [!NOTE] > > 📖 Read our guide about [setting up request header collection and > filtering](/guides/filter-data/filter-headers) for your app. ## Filter all request headers To filter all request headers without individual header filtering, configure the allowlist to an empty list in the integration configuration. Without any header names in the list, it will not collect any request headers. * [Ruby `request_headers` config option documentation](/ruby/configuration/options#option-request_headers) * [Elixir `request_headers` config option documentation](/elixir/configuration/options#option-request_headers) * [Node.js `requestHeaders` config option documentation](/nodejs/3.x/configuration/options#option-requestheaders) * [Python `request_headers` config option documentation](/python/configuration/options#option-request_headers) * [Go `request_headers` config option documentation](/go/configuration/options#option-request_headers) * [PHP `request_headers` config option documentation](/php/configuration/options#option-request_headers) ## Recommended headers to filter A non-exhaustive list of request header names that may be used by an application. Do not include these headers, and those like it, in the integrations "request headers" allowlist unless absolutely necessary. * Any personal identifiable headers: * IP Addresses * `Forwarded` * Browser type and versions headers * `User-Agent` * Referrer * `Referer` * Passwords and tokens * `Authorization` * `Proxy-Authorization` * Any custom API token headers. ## See also * [Data filtering guide](/guides/filter-data) - Filter app data in AppSignal integrations # Limits Source: https://docs.appsignal.com/application/limits > [!TIP] > > This page is about the **Limits** view in your application's settings. It is > not about reducing your billable request count. For that, see [Limiting > requests](/support/limiting-requests). The **Limits** page shows the top-10 custom metrics in your app by unique key count from the last recorded minute. Above the table, it also shows your app's total unique keys and the recorded time for that minute. [Open the Limits page](https://appsignal.com/redirect-to/app?to=limits) in your app. A unique key is one custom metric name plus one combination of tag values. Two limits apply to unique keys: * **Storage:** AppSignal stores up to 10,000 unique keys per minute for each app and drops the rest. The total on this page never goes above 10,000. Reaching it means your app hit the limit in that minute. See [why custom metrics get dropped](/faq#why-are-my-custom-metrics-being-dropped). * **Queries:** the [Public API (V2)](/api/v2/metrics#high-cardinality-custom-metrics) processes up to 100 series per timeseries query and 1,000 per list page. Dashboard charts use the same API. Each field counts as a separate series. A custom metric has high cardinality when a query on it matches more series than the query limits allow. ## What the page shows For each of the top 10 custom metrics, the page lists: * **Metric name:** the name of the custom metric. * **Unique keys:** how many distinct tag combinations were seen in the last recorded minute, and the share of your app's total. * **Tag examples:** up to 10 tag combinations the metric reported in the last hour. The page shows five; select **+ N more** to show the rest. Use this column to spot tags with many different values. ## When to use this page If you're seeing gaps in your custom dashboards, use this page to find custom metrics with many unique keys. The counts on this page cover one minute. A query through the Public API (V2) matches every series active in its time range. When tag values change over time, a metric can match more series in a day than this page shows. To reduce the number of unique keys, review the tags on that metric and use a limited range of tag values when possible. ## See also * [Custom metrics](/metrics/custom) * [Metric tags](/metrics/custom#metric-tags) # Link templates Source: https://docs.appsignal.com/application/link-templates AppSignal supports tagging of requests, as described in our [tagging guide][tagging-guide]. These tags make it possible to generate URLs to your own application to deep link to pages in your own system, such as related user profiles or blog posts. ## Tagging requests For link templates to work AppSignal needs to have the data necessary to create the links. Start by adding tags to request in your application. Add the following code in a location where it's executed for the related request, such as a `before_action` block in a Ruby on Rails application or using Plug in the Elixir Phoenix framework. ```ruby Ruby theme={null} # Ruby example Appsignal.tag_request( :user_id => current_user.id, :account_id => current_account.id ) ``` ```elixir Elixir theme={null} # Elixir example Appsignal.Span.set_sample_data( Appsignal.Tracer.root_span, "tags", %{ locale: "en", user_id: user_id, stripe_customer_id: stripe_customer_id, locale: locale, default_locale: default_locale } ) ``` > [!NOTE] > > 📖 For more information about tagging requests, please read the \[tagging > guide]\[tagging-guide]. ## Log attributes AppSignal can also generate links based on log attributes. For more information about logging and how to add log attributes see our [logging documentation](/logging) ## Creating a link template Link templates can be defined on AppSignal.com per application. The "Link templates" configuration can be found in the ["App settings" section](https://appsignal.com/redirect-to/app?to=edit) in the left-hand side navigation. ![link templates](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/application/link_templates/link-templates.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=41a6b8f078d4995d0b99c076c6959a07) Link templates can contain variables, defined by wrapping them in percentage signs `%%`. For example, the `user_id` tag can be used in a link like so: ```shell Shell theme={null} https://yourapp.com/backend/users/%user_id% ``` A link can contain as many variables as you like, but in order for a link to be generated, all variables need to be present in the tags of a request. After adding tags in your app and defining link templates, links will be generated for each request in the "Overview" section. ![link templates](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/application/link_templates/link-templates-result.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=0bf6e6c15c99b1c4b132e1d151e5d3f9) ### Customizing link names By default the tags and links table will increment links, e.g. "Link 1", "Link 2", "Link 3". If you want to use more descriptive link names you can do so with this format: ```shell Shell theme={null} [Backend]https://yourapp.com/backend/users/%user_id% ``` [tagging-guide]: /guides/tagging.html # Markers Source: https://docs.appsignal.com/application/markers Markers are little icons used in graphs on AppSignal.com to indicate a change. This can be a code deploy using a "Deploy marker" or a special event with a "Custom marker". Deploy markers can be used to indicate a change in application version that's deployed, grouping together errors and performance issue per deploy. To list only the errors a deploy introduced, use the [New errors filter](/errors#see-the-errors-a-deploy-introduced). Custom markers can be used for anything from scaling operations, to sudden spikes in traffic and infrastructure issues such as when a database was acting up. # Custom markers Source: https://docs.appsignal.com/application/markers/custom-markers Markers are little icons used in graphs on AppSignal.com to indicate a change. This can be a code deploy using a ["Deploy marker"](/application/markers/deploy-markers) or a special event with a "Custom marker". Custom markers can be used for anything from scaling operations, to sudden spikes in traffic and infrastructure issues such as when a database was acting up. See also our announcement posts about Custom markers: * [Introducing custom markers](https://blog.appsignal.com/2016/10/28/custom-markers.html) * [Add custom markers from any graph](https://blog.appsignal.com/2016/11/28/custom-markers-from-any-graph.html) ## Creating a custom marker A custom marker can be created in two ways. Through the UI on AppSignal.com on the graphs or with a request to our API. ### Using the Graph UI When on AppSignal.com open a page with a graph on it, any graph. Hover over a space in a graph and you will be presented with a "Add marker" button. In the "Add marker" lightbox, select an icon, set a message and create your marker. To edit or delete a marker, click on the icon and you will be brought back to the editor. ### Using the AppSignal API There are two APIs to report custom markers to AppSignal. These two APIs use different authentication methods. Choose the one that's most convenient, there is no other difference. * [Markers API endpoint documentation](/api/markers): authenticate using Personal Access Token. This authentication method has read and write access to all data. * [Public endpoint markers API endpoint documentation](/api/public-endpoint/custom-markers): authenticate using a Push API key + app name and environment, or using a Front-end API key. This authentication method is write only. # Deploy markers Source: https://docs.appsignal.com/application/markers/deploy-markers Markers are little icons used in graphs on AppSignal.com to indicate a change. This can be a code deploy using a "Deploy marker" or a special event with a ["Custom marker"](/application/markers/custom-markers). Deploy markers can also be found in the ["Deploys" section](https://appsignal.com/redirect-to/app?to=markers) in the app navigation which provides a performance overview per deploy. A deploy marker indicates a change in the deployed version of an application. This can be used to group together occurrences of errors and performance issues within a certain time frame. From when the version was deployed until a newer version was deployed. Deploy markers are also required to enable [backtrace links](/application/backtrace-links) for an app. When a new deploy is detected, the list of incidents is empty for the newest deployment version. When an error, or any other issue, is reported by AppSignal in your application it gets listed for the newest deploy as well. On the trace page for an incident you can see in which deployments an incident occurred with the help of the rocket (🚀) separator icon. > [!NOTE] > > 📖 Also read our guide on [how to set up deploy > markers](/guides/deploy-markers). ![Deploy markers in traces list](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/app_incident_samples_list.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=31ed7e05907d0d6ce1102810a22993a5) ## Deploy methods There are two methods of notifying AppSignal of a new deploy. These two methods cannot be used together. 1. Using the `revision` config option, and; 2. Creating a deploy notification manually with the AppSignal Push API. The first method (`revision` config option) is our recommended approach, because it's the most reliable method and works better for applications with more than one host. We detect the revision from the application itself so we know which instance is running what version. The second approach (creating a deploy marker manually) is a method only really useful for small applications that use one host. It creates a new deploy marker at a specific time, regardless of the version the application is actually running. This also means it's more error prone. ## Revision config option The recommended approach of letting AppSignal know a new version of your application is deployed is by using the `revision` config option or the `APP_REVISION` environment variable (see the [deploy markers configuration guide](/guides/deploy-markers#configurations-per-language) for more information). This is automatically detected for [Heroku apps](#heroku-support) using the dyno metadata lab feature. This config option is set per instance of an application which has the benefit of every version of an application running at the same time reporting the errors under the correct deploy, rather than the latest deploy that [has been reported](#manually-create-a-deploy-marker) to AppSignal. For example: If one machine is still running an older version of the application all the errors from that instance are reported under the previous deploy marker rather than the last known deploy marker. AppSignal will create a new deploy marker when it receives [transaction data](/appsignal/terminology#transactions). When the revision config option is set for your app, the revision is stored on a transaction that tracks a web request / background job. When our processor on the AppSignal servers detects a new revision it will create a new deploy marker for the parent app with the revision from the transaction. ### Choosing a revision value Set the revision to a single value that identifies the deployed version of your app, without spaces or characters that need escaping in a URL: * `abc0123`: a short Git commit SHA (recommended) * `abcdef0123456789abcdef0123456789abcdef01`: a full Git commit SHA * `1.2.3` or `v1.2.3`: a version number or Git tag AppSignal builds links to your source code from this value. [Backtrace links](/application/backtrace-links) and the link that compares two deploys only resolve when the revision is a reference your Git host knows, such as a commit SHA or a tag. AppSignal still creates a deploy marker for a value such as `1.2.3 - abc0123`, and still groups your data per deploy. It also still builds source code links from that value, but they point at a revision your Git host cannot find. AppSignal shortens revisions longer than 25 characters when it displays them. ### Config option The `revision` config option can be used in any integration to report the app's current deploy. See the [deploy markers guide](/guides/deploy-markers) for how to set it per language, and [choosing a revision value](#choosing-a-revision-value) for which values to use. ```ruby Ruby theme={null} AppSignal.configure do |config| config.revision = "abcdef12" end ``` If you're running a version in which this config option is not available we recommend using the [`APP_REVISION` environment variable](#system-environment-variable) instead. ### System environment variable Set `APP_REVISION` to the value you use to indicate a version, following [choosing a revision value](#choosing-a-revision-value). For example, a Git commit SHA `cf8bc42` or a version number `1.4.2`. The revision value should be set in the application's system environment and updated during a deploy of the application. ```bash Bash theme={null} export APP_REVISION="cf8bc42" # Start your application # bundle exec rackup app.rb ``` ### Heroku support When using Heroku with the [Heroku Labs: Dyno Metadata](https://devcenter.heroku.com/articles/dyno-metadata) enabled, Heroku will populate the `HEROKU_BUILD_COMMIT` and `HEROKU_SLUG_COMMIT` environment variables with the SHA of the git commit being deployed. AppSignal will automatically set the `revision` config option to the value of the `HEROKU_BUILD_COMMIT` or `HEROKU_SLUG_COMMIT` system environment variables. This will automatically report new deploys when the Heroku app is deployed. ### Render support When deploying an application using Render, it will populate the `RENDER_GIT_COMMIT` environment variable with the SHA of the git commit being deployed. AppSignal will automatically set the `revision` config option to the value of the `RENDER_GIT_COMMIT` system environment variable. This will automatically report new deploys when the Render app is deployed. ### Hatchbox support To use deploy markers with Hatchbox, first connect your Hatchbox account to AppSignal: 1. In Hatchbox, go to your profile settings and navigate to [**Connected accounts**](https://app.hatchbox.io/user/connected_accounts). 2. On the "Connected accounts" page, select **Sign in with AppSignal**. 3. In the AppSignal window that opens, authorize Hatchbox to access your AppSignal organization by selecting **Allow access**. When deploying an application using Hatchbox, it will add a `REVISION` file in the release folder with the SHA of the Git commit being deployed. AppSignal will automatically set the `revision` config option to the value of the `REVISION` file. This will automatically report new deploys when the Hatchbox app is deployed. ### Kamal support When deploying an application using Kamal, it will populate the `KAMAL_VERSION` environment variable within the container with the SHA of the git commit being deployed. AppSignal will automatically set the `revision` config option to the value of the `KAMAL_VERSION` system environment variable. This will automatically report new deploys when the app is deployed using Kamal. ### Scalingo support When deploying an application using Scalingo, it will populate the `CONTAINER_VERSION` environment variable with the SHA of the git commit being deployed. AppSignal will automatically set the `revision` config option to the value of the `CONTAINER_VERSION` system environment variable. This will automatically report new deploys when the Scalingo app is deployed. ### Docker support If your application runs in a Docker container, follow the instructions below to set your application's revision and create a deploy marker. First, add the following instructions to your Dockerfile, directly after the last `FROM` instruction: ```bash Bash theme={null} ARG COMMIT ENV APP_REVISION=$COMMIT ``` Once added you need to include your application's revision when building your Docker image: ```bash Bash theme={null} docker build --build-arg COMMIT=$(git rev-parse HEAD) -t image:latest ``` > [!TIP] > > When using Fly.io to deploy your application, the `COMMIT` build argument is > provided automatically during the build. This will set the `APP_REVISION` environment variable for your application and allow the AppSignal integration to use the revision as a deploy marker. ### GitLab support When deploying from a GitLab CI/CD pipeline, set the `APP_REVISION` environment variable in your deploy job to the commit SHA so AppSignal picks it up when the app starts: ```yaml YAML theme={null} deploy:production: stage: deploy variables: APP_REVISION: $CI_COMMIT_SHA script: - ./bin/deploy.sh ``` `CI_COMMIT_SHA` is one of GitLab's [predefined CI/CD variables](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html) and resolves to the commit being deployed. If your stack does not include an AppSignal integration, see the [GitLab CI/CD example](#gitlab-cicd-example) instead. ## Manually create a deploy marker > [!WARNING] > > This method of reporting deploy markers is **deprecated** and may be removed at any time in the future. > > Set the [`revision` config option](/application/markers/deploy-markers#revision-config-option) instead, so AppSignal creates deploy markers from the version your application is running. > > Reporting deploy markers using this method is only useful for small applications that use one application instance. It creates a new deploy marker at a specific time, regardless of the version the application is actually running. This also means it's more error prone to group data that shouldn't belong to it under the deploy. This method of reporting new deploys to AppSignal requires that you send a POST request to the AppSignal Push API markers endpoint. This can be done with a manual HTTP POST request for other languages. When the deploy marker create/notify request is received by the AppSignal servers, all data that is processed by our servers after that time is tracked under the newly created deploy. To create a Deploy marker with a HTTP POST request you can use curl or some other tool like it. The payload of the request is a JSON object with data about the marker, such as the revision, user who deployed it and the application's repository. Read more about how to create Deploy markers with our API in our [API endpoint](/api/markers) documentation. ### GitLab CI/CD example If you can't use the [`revision` config option](#revision-config-option) — for example, because your stack does not include an AppSignal integration — you can call the Markers API from a separate GitLab CI/CD job after your deploy succeeds. First, store your AppSignal credentials as masked CI/CD variables in your GitLab project's **Settings → CI/CD → Variables**: * `APPSIGNAL_API_TOKEN` — your personal API token (Profile → Account settings → Personal → API). * `APPSIGNAL_APP_ID` — the AppSignal app ID for the environment you're deploying. Find it in the AppSignal URL: `https://appsignal.com//sites//...`. Then add a deploy-marker job to your `.gitlab-ci.yml`: ```yaml YAML theme={null} stages: - deploy - notify deploy:production: stage: deploy script: - ./bin/deploy.sh rules: - if: '$CI_COMMIT_BRANCH == "main"' appsignal:deploy_marker: stage: notify image: curlimages/curl:latest needs: ["deploy:production"] rules: - if: '$CI_COMMIT_BRANCH == "main"' script: - | curl --fail --silent --show-error \ -H "Content-Type: application/json" \ -X POST "https://appsignal.com/api/${APPSIGNAL_APP_ID}/markers.json?token=${APPSIGNAL_API_TOKEN}" \ -d "{ \"marker\": { \"kind\": \"deploy\", \"repository\": \"${CI_PROJECT_URL}.git\", \"revision\": \"${CI_COMMIT_SHA}\", \"user\": \"${GITLAB_USER_LOGIN}\" } }" ``` > [!TIP] > > GitLab webhooks cannot be used to call the Markers API directly — GitLab > webhook payloads have a fixed format that does not match the Markers API > request body, and GitLab does not let you transform the payload before > sending. #### Troubleshooting If the marker job fails with `401 Unauthorized`, re-check `APPSIGNAL_API_TOKEN`. It must be a personal API token from **Profile → Account settings → Personal → API**, not the Push API key. Confirm the variable is not restricted by Environment scope to a different environment than the job runs in. If the marker job fails with `404 Not Found`, the `APPSIGNAL_APP_ID` is wrong or belongs to a different organization. Copy it from the AppSignal app's URL (`https://appsignal.com//sites//...`). [backtrace links]: /application/backtrace-links.html # Metadata Source: https://docs.appsignal.com/application/metadata You can supply extra context on errors and performance traces using metadata. This can help to add information that is not already part of the request parameters, session data or request headers. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). > [!NOTE] > > 📖 Also read our guides on how to set up [metadata](/guides/custom-data) and how to [filter](/guides/filter-data) this metadata. ## Types of metadata To add more complex data structures to error and performance traces, different types of metadata can be used. Some of these are set by our instrumentations automatically and can be overwritten if needed. These are the kind of extra data that can be set. 1. [Request parameters](/guides/custom-data/request-parameters) * If you are using a supported web framework or library, AppSignal will store the request query parameters, request payload body or background job arguments for you automatically. 2. [Request session data](/guides/custom-data/request-session-data) * If you are using a supported web framework, AppSignal will store the request session data for you automatically. 3. [Request headers](/guides/custom-data/request-headers) * If you are using a supported web framework, AppSignal will store the request headers for you automatically. 4. [Function parameters](/guides/custom-data/function-parameters) * Function parameters are the parameters that background jobs or scripts start with. 5. [Custom data](/guides/custom-data/custom-data) * You can use custom data if additional details you want to send are not related to the above three types. AppSignal does not automatically save anything in custom data unless you specifically tell it. # Namespaces Source: https://docs.appsignal.com/application/namespaces Namespaces are a way to group error incidents, traces and metrics from [actions](/appsignal/terminology#actions). [By default](#default-namespaces) AppSignal provides three namespaces: the "web", "background" and "frontend" namespaces. You can add your own namespaces to separate parts of your app like the API or Admin panel with [custom namespaces](#custom-namespaces). > [!TIP] > > 📖 Read our guide on \[how to set up namespaces]\[guide]. ## What can you do with namespaces? Let's start first with the things we can use namespaces for: * Group [error incidents](https://appsignal.com/redirect-to/app?to=exceptions) and [performance measurements](https://appsignal.com/redirect-to/app?to=performance) per namespace. Create overviews of the most important namespaces and fix those incidents first. * Track and graph metrics per namespace ([error rate, error count](https://appsignal.com/redirect-to/app?to=exceptions/graphs), [throughput, response times, queue times](https://appsignal.com/redirect-to/app?to=performance/graphs), and more). * Receive [Anomaly detection alerts per namespace](/anomaly-detection/). * Score how satisfied users are with your response times per namespace with [Apdex](/metrics/apdex). * Set up [notifications settings per namespace](/application/notification-settings). ![App Graphs Namespaces](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/namespaces/graphs.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=044f86ecbea3baac50432a8337ae69b2) Example graphs with multiple namespaces, splitting out a GraphQL API and the web namespace. On the left a drop down with the namespace filter. ## Default namespaces The "web" namespace holds all data for HTTP requests while the "background" namespace contains metrics from background job libraries and tasks. The "frontend" namespace is created by the [JavaScript front-end integration](/front-end). You can add your own namespaces to separate parts of your app like the API and Admin panel. ## Custom namespaces > [!NOTE] > > 📖 The custom namespaces feature was introduced in AppSignal for Ruby gem version > 2.3.0 and AppSignal for Elixir package version 1.3.0. Using more than one namespace makes it easier to group metrics belonging to the same part of an application together. In AppSignal we use custom namespaces to accomplish this. The advantage of custom namespaces is the ability to group together error incidents and traces from separate parts of the same application. Think of an administration panel, public homepage versus private back-end, etc. The metrics from these three parts in one namespace can clutter the "web" namespace with incidents of varying importance. For example, when something in the administration panel breaks it's not as big of a problem when the sign up page breaks on the public front-end. The metrics from separate parts of an application can be grouped together in their own namespace. By using the AppSignal instrumentation helpers for setting a namespaces it's possible to assign [transactions](/appsignal/terminology#transactions) to a certain namespace. Once the namespace is configured and the application is sending data to the AppSignal, the new namespace will appear in the navigation on AppSignal.com. Note: Data previously reported for the same action is not moved to the new namespace. > [!NOTE] > > 📖 To set up custom namespaces in your app, read our guide to \[setting up > namespace with our integrations]\[guide]. > [!TIP] > > Only letters and underscores are accepted for namespace names. ## Namespace limitations Namespaces are great to split out certain parts of your application, but there are a few limits to namespaces. For optimal performance it's recommended to not have more than **10-15** namespaces maximum. While we don't have a hard-limit on this number, we cannot guarantee performance when more than **15** namespaces are used. ## Ignoring namespaces Sometimes you have a certain part of an application that does not need to be monitored by AppSignal. The most common use case is an administration panel that you use internally which doesn't need constant monitoring. By ignoring an entire namespace AppSignal will ignore all transactional data from all actions in the configured namespaces. To ignore a namespace first make sure to configure AppSignal to report all actions you want to ignore under a certain namespace, as described in the [namespaces guide][guide]. Then configure AppSignal in your app to ignore the namespace, see our [ignore namespaces guide][ignore guide]. After restarting/deploying your app the actions in the selected namespace should no longer be reported on AppSignal.com. > [!NOTE] > > 📖 To configure AppSignal to ignore namespaces in your app, read our guide to > \[ignoring namespace with our integrations]\[ignore guide]. ## Deleting namespaces If you created a namespace that is no longer active you can delete it from the [namespaces](https://appsignal.com/redirect-to/app?to=namespaces) screen under app settings. > [!NOTE] > > We do not automatically delete a namespace if it is no longer receiving data. [guide]: /guides/namespaces.html [ignore guide]: /guides/filter-data/ignore-namespaces.html # Notification settings Source: https://docs.appsignal.com/application/notification-settings Whenever AppSignal detects a new error, it opens an incident. You can find incidents in the [Errors](https://appsignal.com/redirect-to/app?to=exceptions) section. AppSignal can send notifications when it detects a new incident or a new occurrence of an existing incident. Notifications can be sent by email or by one of our [many notifiers](/application/integrations/). > [!NOTE] > > These settings apply to error incidents. Performance is not alerted on through incidents. To be notified when an action gets slow, set up a trigger as described in the [performance alerting](#performance-alerting) section. Anomaly detection trigger alerts are routed by the notifiers selected on each trigger. ## Notification options Whenever AppSignal creates a new incident, it inherits the [app's notification defaults](#app-notification-defaults). After AppSignal creates an [Error](#error-incident-notification-settings) incident, you can change its notification settings on the incident page. If an incident was closed, it will be reopened when a new notification is sent out. There are six notification options available: * [Every Occurrence](#every-occurrence) * [First in Deploy](#first-in-deploy) * [First After Close](#first-after-close) * [Never Notify](#never-notify) * [Every Nth per Hour](#every-nth-per-hour-or-day) * [Every Nth per Day](#every-nth-per-hour-or-day) New error incidents default to **First in Deploy**. ### Every Occurrence A notification is sent every time an incident is triggered. This option has a cooldown of 5 minutes. This means that if an incident is triggered 20 times a minute, for 20 minutes, you'll receive a notification on minute 0, 5, 10, 15 and 20. ### First in Deploy A notification is sent on the first occurrence of an incident after a new deploy marker is received. You'll need to set up [deploy markers](/application/markers/deploy-markers) for AppSignal to detect a deploy and know when an incident occurred for the first time in a deploy. ### First After Close A notification is sent at the first occurrence of an incident after the incident was previously closed. You can open and close incidents from the sidebar on the incident detail page. This option works well for incidents that are caused by an outside source, such as a third-party connection issue, and cannot be resolved by deploying a new version of the app. ### Never Notify No notification is sent when the incident is triggered. Because an incident is only reopened when AppSignal sends a notification, an incident set to **Never Notify** stays closed even when it occurs again. Use this for errors that will continue to happen and that you want to track but not fix soon. If you do not want to receive the incident at all, [ignoring the action](/application/data-collection#ignore-actions) or [ignoring the error](/application/data-collection#ignore-errors) may help. ### Every Nth per Hour or Day A notification is sent every nth time an incident occurs within an hour, or within a day, depending on your preferences. There are many scenarios where this may be beneficial: * **Billing Error:** Imagine a billing error occurring now and then, outside of your control. It happens a maximum of 5 times a day, and you want to know when this suddenly increases. Setting it to "every 10th time a day" will send you an alert on every 10th, 20th, 30th occurrence, etc. * **API Error:** You might have an API that many people use. When experimenting with an API, making mistakes that trigger errors is common. You might only want to be alerted when the number of errors reaches a threshold. You could, for instance, set it to notify you every 1000th time an hour, which might indicate that the API is failing for different reasons. * **During Incident:** Imagine something is severely broken. Hundreds of errors an hour are happening, but you're on top of it. It might not be a good idea to ignore all alerts completely, but getting each one of them will drown you in notifications. This is the perfect moment to manage the number of notifications you receive by temporarily setting your errors to Nth/hour. ![Visualization of notifications every 100th per hour](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/application/notifications/every-nth-alert.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=b13d2bbc75dd9fce7a0ab55203b82aac) The visualization shows when you would receive alerts. In this scenario, notifications are set to "Every 100th per hour". > [!NOTE] > > AppSignal counts occurrences in UTC. The hourly counter resets on the hour, and the daily counter resets at 00:00 UTC. This is the same for everyone. No account, organization, or personal time zone setting changes it. > > AppSignal shows timestamps in your own time zone, and so do its notifications, so a reset can fall at a local time you would not expect. In summer, the daily count starts over at 02:00 in Berlin and at 17:00 the previous day in Los Angeles. Notifications never state the count or the threshold, so you cannot tell from a notification where you are in the counting window. How AppSignal counts occurrences for these two options: * The count resets at the start of each period. Occurrences that almost reach the threshold before a period ends do not carry over into the next one. * Passing the threshold subtracts it from the count instead of clearing the count, so a remainder still counts towards the next notification within the same period. * Both options have a cooldown of 5 minutes. You receive at most one notification every 5 minutes, however far the count runs past the threshold in the meantime. * Occurrences arrive in batches, and AppSignal checks the threshold once per batch. The notification is sent by the first batch that takes the count past the threshold, which can be slightly later than the exact nth occurrence. ## Error incident notification settings Error incidents are identified by the error (class)name, such as `ActiveRecord::RecordNotFound` and if the error happened inside of an action, the action name. (e.g. `StandardError` in `BlogpostsController#show`). ![Error incident notification options](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/application/notifications/notification-frequency.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=b23511c49fccb780bcbaac9bea99642c) ## Performance alerting The notification options described in the previous sections apply to error incidents. Performance uses [triggers](/anomaly-detection) instead. Errors are binary: they either happen or they don't, which is what makes an option like **First in Deploy** meaningful for them. Performance behaves differently. If your database is overloaded, deploying new code will not change the response time, and a notification about a single slow trace says little about the health of your app. Performance problems play out over a timeframe, which is what a trigger measures. ### Create a trigger for a slow action Open the performance action you want to watch, such as `run/shop.send_waitlist_notification`, then select **Add new** in the **Triggers** panel. ![Triggers panel on a performance action, with an option to add a new trigger](https://mintcdn.com/appsignal-715f5a51/YsDILhZQbsytsqZr/assets/images/screenshots/application/notifications/performance-action-triggers.png?fit=max\&auto=format\&n=YsDILhZQbsytsqZr\&q=85\&s=f2da079f05993a9a779ab7474d1a3425) A **Slow action** trigger form opens, with **Namespace** and **Action Name** already filled in. In the form you set: * **Alert me when**: the value to alert on, such as the mean duration, and in **Is above** the threshold it has to pass. The default is 200 ms. For actions that are expected to be slow because they interact with third parties, set a higher threshold than you would for your homepage. * **Alert warm-up** and **Alert cooldown**: how long the condition has to hold before an alert opens, and how long to wait before closing it. See [warm-up and cooldown](/anomaly-detection#warm-up-and-cooldown). * **Description** and **Notify me through**: a note explaining what the trigger watches, and the notifiers to alert through. A chart preview beside the form shows recent values for the action, which helps you choose a threshold that matches its normal behavior. Select **Save trigger** to create it. Triggers you create this way are listed with your other triggers in the [Anomaly detection](/anomaly-detection) section, where you can also edit them later. ## Organization and app namespace defaults Notification settings on an incident can only be changed after it has occurred at least once. This can be an issue if you never want to be notified. It's possible to configure notification defaults [per app namespace](#app-notification-defaults) or even [for the entire organization](#organization-notification-defaults). This will make it easier to apply the desired notification settings to all new incidents and all existing incidents, for which the notification settings haven't been customized. ### App notification defaults Each application has its own [namespace defaults][app notifications] for notification settings. A new incident in the specified namespace will inherit the default settings set on this page. For more information, see the [notification defaults inheritance](#notification-defaults-inheritance) section. It's recommended to split up the application in [namespaces](/application/namespaces) that group potential incidents by severity. This way you can configure notification settings for a group of incidents and there's no need to configure each incident separately. For example, for an app's admin panel you could create a namespace called `admin` with a default notification setting of "Never notify" as errors that occur in this namespace have less priority. ### Organization notification defaults It's also possible to set up notification defaults on your organization. These defaults will be used when AppSignal detects and creates a new application. When it creates the new app it will apply the organization's notification defaults as the app's app notification defaults. Changes to the organization notification defaults do not apply to already existing apps. For more information, see the [notification defaults inheritance](#notification-defaults-inheritance) section. These organization level [notification defaults][org notifications] can be set up in the organization's admin panel. It's possible to configure defaults for each namespace detected in any of the current applications in your organization. ## Notification defaults inheritance The notification settings bubble up from the incident settings to the app's namespace settings. If the notification settings for an incident aren't changed the app's namespace defaults are used. This means you can also change all the incident notification settings for incidents that haven't customized their notification settings by changing the app defaults. * When a new app is detected by AppSignal, the [organization's namespace defaults][org notifications] are applied. * When organization namespace notification defaults are changed, they only apply to new apps. * When an [app's namespace notification defaults][app notifications] are changed, they apply to all new incidents and existing incidents without customized notification settings. * When a new incident is detected by AppSignal, the [app's namespace defaults][app notifications] are used. * When an incident's notification settings are customized, the incident's customized notification settings are used from then on. [app notifications]: https://appsignal.com/redirect-to/app?to=notifications [org notifications]: https://appsignal.com/redirect-to/organization?to=admin/notifications/edit # Parameter filtering Source: https://docs.appsignal.com/application/parameter-filtering For every request made on a web app, AppSignal collects the parameters that were sent with the request. This includes form data (POST), query parameters and keys in routes, e.g. `/user/:id/` in some frameworks. Data sent to applications that is sensitive or personally identifiable information should not leave the application. To prevent AppSignal from storing this data the integrations need to be configured to not send this data at all or filter out specific values. Parameter filtering ensures that no passwords, email addresses, two-factor authentication token, API tokens, sent to your application are stored in AppSignal. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). ## Integration parameter filtering All AppSignal integrations have a parameter filtering system. A list of parameter keys can be configured to be filtered out, e.g. email, password, two factor authentication API tokens, etc. This way the data is filtered out before it's sent to the AppSignal servers. Any parameter values that are filtered out by these systems will be replaced with a `[FILTERED]` value. This way the list of parameters in the app data on AppSignal.com still includes the parameter key, but not the value. Making it easier to see that a value was sent, but the potentially sensitive data was filtered out. > [!NOTE] > > 📖 Read our guide about [setting up parameter > filtering](/guides/filter-data/filter-parameters) for your app. ### Filter all parameters To filter all parameters without individual parameter filtering, set "send parameters" config option to "false" in the integration configuration. * [Ruby `send_params` config option documentation](/ruby/configuration/options#option-send_params) * [Elixir `send_params` config option documentation](/elixir/configuration/options#option-send_params) * [Node.js `sendParams` config option documentation](/nodejs/3.x/configuration/options#option-sendparams) * [Python `send_params` config option documentation](/python/configuration/options#option-send_params) * Go [`send_request_query_parameters` config option](/go/configuration/options#option-send_request_query_parameters) and [`send_request_payload` config option](/go/configuration/options#option-send_request_payload) documentation * PHP [`send_request_query_parameters` config option](/php/configuration/options#option-send_request_query_parameters) and [`send_request_payload` config option](/php/configuration/options#option-send_request_payload) documentation ## Processor parameter filtering When some sensitive parameters are still sent by your app to AppSignal, we will filter these out during processing. This means the data was sent to our servers, where we received and temporarily store this "pre-processing data". AppSignal filters out [a list of keys](#processor-filtered-keys) from the parameters during processing. These keys are not customizable. These filtered values are replaced with `[REMOVED]` (rather than `[FILTERED]`) to indicate these values were filtered in our processors rather than in your app. Only after this processing, your data is viewable on AppSignal.com. Before that, none of the potentially sent sensitive data is visible to any member of your organization on AppSignal.com. The pre-processing data is removed shortly after processing. This step should **not** be relied upon. If a parameter value is shown as `[REMOVED]` on AppSignal.com, the app's config should be updated to filter out the parameter instead. This way sensitive data does not leave your app. *We always use SSL to encrypt data being sent between your apps and our servers. Any app data containing values that are removed by the processor is deleted shortly after processing.* ### Processor filtered keys The current list of filtered parameter keys by the processor: * `password` * `password_confirmation` ## Recommended keys to filter A non-exhaustive list of parameter keys that may be used by an application. Pick those keys that are relevant for your applications. * Names * `name` * `full_name` * `first_name` * `last_name` * Email addresses * `email` * `email_address` * Passwords * `password` * `password_confirmation` * `confirm_password` * (API) tokens * `token` * `api_token` * Addresses * `street` * `city` * `country` * `post_code` * User information * `phone_number` ## Managing PII and HIPAA Requirements If your app processes Personal Health Information (PHI) and you're a HIPAA-covered entity, you can sign a Business Associate Agreement (BAA) with AppSignal to ensure HIPAA compliance. More information about this can be found in our [Business Add-Ons documentation](/support/business-add-ons). ## See also * [Data filtering guide](/guides/filter-data) - Filter app data in AppSignal integrations # Session data filtering Source: https://docs.appsignal.com/application/session-data-filtering AppSignal gathers session data for HTTP requests by default for supported frameworks. This data may help track down errors or performance issues that were caused by some session data an app is using. Some of this session data may contain sensitive user information though which should not be sent to the AppSignal servers. Use session data filtering to [filter out specific keys](#filter-session-data) or [disable the feature entirely](#filter-all-session-data). > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). ## Filter session data An app's session data can be filtered by configuring keys in a *denylist*. This denylist system will filter out all the session data keys configured in this list. Any session data values that are filtered out by these systems will be replaced with a `[FILTERED]` value. This way the list of session data in the app data on AppSignal.com still includes the session data key, but not the value. Making it easier to see that a value was present, but the potentially sensitive data was filtered out. > [!NOTE] > > 📖 Read our guide about [setting up session data > filtering](/guides/filter-data/filter-session-data) for your app. ## Filter all session data To filter all session data without individual key filtering, set the "send session data" config option to "false" in the integration configuration. * [Ruby `send_session_data` config option documentation](/ruby/configuration/options#option-send_session_data) * [Elixir `send_session_data` config option documentation](/elixir/configuration/options#option-send_session_data) * [Node.js `sendSessionData` config option documentation](/nodejs/3.x/configuration/options#option-sendsessiondata) * [Python `send_session_data` config option documentation](/python/configuration/options#option-send_session_data) * [Go `send_request_session_data` config option documentation](/go/configuration/options#option-send_request_session_data) * [PHP `send_request_session_data` config option documentation](/php/configuration/options#option-send_request_session_data) ## Recommended keys to filter A non-exhaustive list of session data keys that may be used by an application. Pick those keys that are relevant for your applications. * Email addresses * `email` * `email_address` * Tokens * `token` * `api_token` * `sign_up_token` * `reset_password_token` ## Managing PII and HIPAA Requirements If your app processes Personal Health Information (PHI) and you're a HIPAA-covered entity, you can sign a Business Associate Agreement (BAA) with AppSignal to ensure HIPAA compliance. More information about this can be found in our [Business Add-Ons documentation](/support/business-add-ons). ## See also * [Data filtering guide](/guides/filter-data) - Filter app data in AppSignal integrations # Application settings Source: https://docs.appsignal.com/application/settings All settings for an application can be found by clicking the "App Settings" link in the main menu after you've navigated to an application. ## General If your app is not connected to a repository on GitHub you can connect it. If it is connected you can change the linked repository. You need to authenticate with GitHub to use this feature. You can either do this by signing in via GitHub, or by linking your GitHub account in your [user settings](/user-account). An application linked to GitHub gives you additional features like direct links to commits. [Visit the "General" page for your app](https://appsignal.com/redirect-to/app?to=edit) ## Notifications AppSignal can send alert for a number of events. Configure when a notification is sent on this page. See the [application integrations page](/application/integrations) to configure where the notification is sent to. [Visit the Notifications page for your app](https://appsignal.com/redirect-to/app?to=notifiers) ## Team permissions This page gives an overview of the teams and people that have access to an application. You can change the owners and permissions by editing clicking on the "Manage owners|this team" link. Read more about [team management](/organization/team/members) in the Organization topic. [Visit the Team permissions page for your app](https://appsignal.com/redirect-to/app?to=teams) ![App settings teams](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/app_teams.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=f01fc448187b4654ba596b1d3d97e968) ## Push & Deploy On the "Push & Deploy" page you can find your application's "Push API Key" and some snippets to set up deploy notifications. [Visit the Push & Deploy page for your app](https://appsignal.com/redirect-to/app?to=info) # Process Monitoring Source: https://docs.appsignal.com/check-ins Learn how to set up and manage AppSignal Process Monitoring AppSignal Process Monitoring provides visibility into the state of background processes such as cron jobs. Process Monitoring helps answer questions like: Once configured, AppSignal will track the execution of background processes and scheduled jobs, giving insights into individual runs and notifying you if a process doesn't notify us of completion. You can configure two kinds of process monitors with AppSignal: **cron process monitors** and **heartbeat process monitors**. Use cron process monitors to track the execution of processes scheduled to run at a specific time, such as cron jobs. Use heartbeat process monitors to track the uptime of a process that should run continuously, such as a server application or a background job processor. ## Getting started First, [create a process monitor in AppSignal](/check-ins/create#create-a-process-monitor), setting the expected schedule for your cron job, or the expected interval between heartbeat process monitor events. For example, you can have a process monitor for a scheduled job that should run every hour for at most 20 minutes, or a background job processor that should report a heartbeat process monitor event at most every 5 minutes. Then, [configure your scheduled job or background process to send process monitor events to AppSignal](/check-ins/configuration). A cron job should send a process monitor event at the start and end of each occurrence, while a background job should send a process monitor event at regular intervals. AppSignal will then [track the process monitor events it receives and compare them to the expected occurrences](/check-ins/occurrences). When AppSignal expects a process monitor event but doesn't receive one in time, it will notify you as configured in the process monitor, helping you ensure that your application's vital processes are working as expected. # Sending process monitor events to AppSignal Source: https://docs.appsignal.com/check-ins/configuration Send cron and heartbeat process monitor events from an AppSignal integration, with AppSignal Wrap, or over the HTTP API. In order to receive events for your AppSignal Process Monitoring, you must configure your application to send process monitor events to AppSignal. ## AppSignal integrations If your application is already using an AppSignal integration library, such as our Ruby gem or our Elixir, Node.js and Python packages, you can use the provided helper methods to send process monitor events. Follow the instructions in the [integration process monitor helpers documentation](/check-ins/configuration/integrations) for your integration. ## Process monitoring with AppSignal Wrap If the application you wish to send process monitors from is not using an AppSignal integration library, for example, if you wish to send cron process monitors when a process starts or finishes, or heartbeat process monitors while a process runs, you can send process monitor events using our wrap tool: ```shell Shell theme={null} appsignal-wrap my-process-name --cron -- /path/to/my/process appsignal-wrap my-process-name --heartbeat -- /path/to/my/process ``` Learn more about how to use `appsignal-wrap` to send process monitors to AppSignal in our [AppSignal Wrap documentation](/wrap#process-monitoring). ## HTTP API You can also send process monitors from any application using our HTTP API. Follow the instructions in the [process monitor events API documentation](/check-ins/configuration/api). # Sending process monitor events using the AppSignal API Source: https://docs.appsignal.com/check-ins/configuration/api Before sending process monitor events to AppSignal, you must first [create a process monitor in AppSignal](/check-ins/create#create-a-process-monitor). You can send process monitor events to AppSignal by performing HTTP POST requests to the AppSignal API, using any HTTP client. The examples in this page provide a sample cURL command, as well as the raw HTTP method and URL to use with any HTTP client of your choice. In the examples below, replace `YOUR-APP-LEVEL-API-KEY` with the AppSignal app-level push API key for your app, which can be found in [your application's "Push & Deploy" settings](https://appsignal.com/redirect-to/app?to=api_keys\&key_tab=app), and `YOUR-PROCESS-MONITOR-IDENTIFIER` with the identifier of the process monitor you wish to send events to. > [!NOTE] > > The Process Monitoring API still uses `check_ins` in endpoint URLs for > compatibility with existing integrations. ## Sending cron process monitor events Cron process monitors are used to monitor the execution of scheduled jobs, such as cron jobs. AppSignal will expect to receive a finish cron process monitor event according to its configured schedule, and will notify you if no finish cron process monitor event is received within its configured maximum duration. Additionally, you can send start cron process monitor events to AppSignal to notify that a cron process monitor event has started, allowing you to measure the duration of your cron jobs. ### Finish cron process monitor To notify AppSignal that a cron job has finished successfully, send a POST request to the AppSignal API with the following URL query parameters: ```curl Curl theme={null} curl -D - -X POST -G 'https://appsignal-endpoint.net/check_ins/cron' \ -d 'api_key=YOUR-APP-LEVEL-API-KEY' \ -d 'identifier=YOUR-PROCESS-MONITOR-IDENTIFIER' ``` ```http HTTP theme={null} POST https://appsignal-endpoint.net/check_ins/cron ?api_key=YOUR-APP-LEVEL-API-KEY &identifier=YOUR-PROCESS-MONITOR-IDENTIFIER ``` AppSignal will notify you if no finish cron process monitor event is received within the cron process monitor's configured maximum duration. ### Start cron process monitor Sending a start cron process monitor event is entirely optional. Doing so allows you to measure the duration of your cron jobs. To notify AppSignal that a cron job has started, send a POST request to the AppSignal API with the following URL query parameters: ```curl Curl theme={null} curl -D - -X POST -G 'https://appsignal-endpoint.net/check_ins/cron' \ -d 'api_key=YOUR-APP-LEVEL-API-KEY' \ -d 'identifier=YOUR-PROCESS-MONITOR-IDENTIFIER' \ -d 'kind=start' ``` ```http HTTP theme={null} POST https://appsignal-endpoint.net/check_ins/cron ?api_key=YOUR-APP-LEVEL-API-KEY &identifier=YOUR-PROCESS-MONITOR-IDENTIFIER &kind=start ``` #### Sending a digest When sending a start cron process monitor, we recommend sending a digest for both the start and finish events. The digest is an arbitrary value that is used to correlate the start and finish cron process monitor events. It should be the same for both the start and finish events, and it should be unique for each pair of start and finish events. Sending a digest is optional, but it is highly recommended when sending a start cron process monitor event, as it ensures that the start and finish events are correlated correctly. ```curl Curl theme={null} curl -D - -X POST -G 'https://appsignal-endpoint.net/check_ins/cron' \ ... \ -d 'digest=abc123' ``` ```http HTTP theme={null} POST https://appsignal-endpoint.net/check_ins/cron ... &digest=abc123 ``` ## Sending heartbeat process monitor events Heartbeat process monitors are used to monitor the uptime of a process that should run continuously, such as a server application or a background job processor. AppSignal will expect to receive heartbeat process monitor events continuously, and will notify you if no heartbeat process monitor event is received within its configured maximum duration. To send a heartbeat process monitor event to AppSignal, send a POST request to the AppSignal API with the following URL query parameters: ```curl Curl theme={null} curl -D - -X POST -G 'https://appsignal-endpoint.net/check_ins/heartbeats' \ -d 'api_key=YOUR-APP-LEVEL-API-KEY' \ -d 'identifier=YOUR-PROCESS-MONITOR-IDENTIFIER' ``` ```http HTTP theme={null} POST https://appsignal-endpoint.net/check_ins/heartbeats ?api_key=YOUR-APP-LEVEL-API-KEY &identifier=YOUR-PROCESS-MONITOR-IDENTIFIER ``` # Sending process monitor events using the AppSignal integrations Source: https://docs.appsignal.com/check-ins/configuration/integrations Send cron and heartbeat process monitor events with the helpers in the AppSignal Ruby, Elixir, Node.js, and Python integrations. The AppSignal integrations for [Ruby](/ruby), [Elixir](/elixir), [Node.js](/nodejs) and [Python](/python) offer helper methods and functions that allow you to easily send process monitor events to AppSignal. > [!NOTE] > > The integration helpers still use `CheckIn`, `checkIn`, and `check_in` in code > for compatibility with existing applications. ## Cron process monitor events To notify AppSignal that a cron job has finished successfully, use the `cron` helper function, passing the name of the cron process monitor as an argument. ```ruby Ruby theme={null} def send_invoices # ... your code here ... Appsignal::CheckIn.cron("send_invoices") end ``` ```elixir Elixir theme={null} def send_invoices do # ... your code here ... Appsignal.CheckIn.cron("send_invoices") end ``` ```javascript Node.js theme={null} import { checkIn } from "@appsignal/nodejs"; function sendInvoices() { // ... your code here ... checkIn.cron("send_invoices"); } ``` ```python Python theme={null} from appsignal.check_in import cron def send_invoices(): # ... your code here ... cron("send_invoices") ``` It is safe to call the `cron` helper function many times in a short period, as the helper will only send a finish event to AppSignal at most once every ten seconds. ### Monitoring the job's duration To monitor the duration of a cron job, you can use the `cron` helper function with a block or function that contains the code you want to monitor. This will send events to AppSignal both when the job starts and when it finishes. ```ruby Ruby theme={null} def send_invoices() Appsignal::CheckIn.cron("send_invoices") do # ... your code here ... end end ``` ```elixir Elixir theme={null} def send_invoices do Appsignal.CheckIn.cron("send_invoices", fn -> # ... your code here ... end) end ``` ```javascript Node.js theme={null} import { checkIn } from "@appsignal/nodejs"; function sendInvoices() { checkIn.cron("send_invoices", () => { // ... your code here ... }); } // If the function passed to `cron` returns a promise, the finish event // will be reported to AppSignal if the promise resolves, allowing you // to track the duration of async functions: async function sendInvoices() { await checkIn.cron("send_invoices", async () => { // ... your async code here ... }); } // If the promise is rejected, or if it never resolves, the finish event // will not be reported to AppSignal. ``` ```python Python theme={null} from appsignal.check_in import Cron def send_invoices(): with Cron("send_invoices"): # ... your code here ... ``` If an exception is raised within the function or method being monitored, the finish event will not be reported to AppSignal, triggering a missing process monitor notification. The exception will be re-raised. If the context in which the exception is raised is an AppSignal-monitored context, then the exception will be reported to AppSignal. Otherwise, if you wish to report the exception to AppSignal, you can use our exception handling helpers for [Ruby](/ruby/instrumentation/exception-handling#appsignal-report_error), [Elixir](/elixir/instrumentation/exception-handling#appsignal-send_error/3), [Node.js](/nodejs/3.x/instrumentation/exception-handling#send-error) or [Python](/python/instrumentation/exception-handling#send_error). ## Heartbeat process monitor events To send a heartbeat process monitor event to AppSignal, use the `heartbeat` helper function, passing the name of the heartbeat process monitor as an argument. It is safe to call `heartbeat` many times, as the helper will only send a heartbeat event to AppSignal at most every ten seconds. ```ruby Ruby theme={null} loop do Appsignal::CheckIn.heartbeat("job_processor") # ... your code here ... end ``` ```elixir Elixir theme={null} def job_processing_loop do Appsignal.CheckIn.heartbeat("job_processor") # ... your code here ... job_processing_loop() end ``` ```javascript Node.js theme={null} import { checkIn } from "@appsignal/nodejs"; while (true) { checkIn.heartbeat("job_processor"); // ... your code here ... } ``` ```python Python theme={null} from appsignal.check_in import heartbeat while True: heartbeat("job_processor") # ... your code here ... ``` ### Sending heartbeats continuously To send heartbeat process monitors continuously, you can pass the `{ continuous: true }` option to the `heartbeat` helper function. This is useful to monitor the lifetime of the process itself. The helper will send a heartbeat event to AppSignal every thirty seconds. ```ruby Ruby theme={null} Appsignal::CheckIn.heartbeat("job_processor", continuous: true) ``` ```elixir Elixir theme={null} # This call spawns a new Elixir process, linked to the current process. # If the current process exits, the heartbeat process will also exit. Appsignal.CheckIn.heartbeat("job_processor", continuous: true) # It is also possible to add a continuous heartbeat sending process # to a supervision tree. This will ensure that the process is restarted # alongside the rest of the supervised children. Supervisor.start_link([ {Appsignal.CheckIn.Heartbeat, "job_processor"}, # ... other children processes ... ], strategy: :one_for_one) ``` ```javascript Node.js theme={null} import { checkIn } from "@appsignal/nodejs"; checkIn.heartbeat("job_processor", { continuous: true }); ``` ```python Python theme={null} from appsignal.check_in import heartbeat heartbeat("my_app", continuous=True) ``` ## Reviewing process monitor occurrences in AppSignal Once configured, AppSignal will begin to display information about occurrences for your process monitors. You can read more about occurrences in our [process monitor occurrences documentation](/check-ins/occurrences). # Creating and managing process monitors Source: https://docs.appsignal.com/check-ins/create ## Create a process monitor To create a process monitor, navigate to the [Process Monitoring page](https://appsignal.com/redirect-to/app?to=check_ins) and click "Add process monitor". On the side, you can select whether to create a cron process monitor or a heartbeat process monitor. The following options can be set: * **Identifier:** A name to uniquely identify this process monitor in your application. You will use this name later when [configuring your application to send process monitor events](/check-ins/configuration). * **Schedule:** The schedule at which AppSignal expects to receive cron process monitor events, specified using crontab syntax. You can learn more about crontab syntax in our [Crontab Learning Center article](https://www.appsignal.com/learning-center/how-can-i-use-the-cron-syntax-to-schedule-cron-jobs). * **Server timezone:** The timezone to use to interpret the cron process monitor schedule. If you're using `cron` to run your scheduled jobs, then this should match your server's configured timezone, as that is the timezone `cron` will use. When in doubt, **we recommend leaving this configuration option on its default value of UTC.** * **Maximum duration:** The maximum run-time of your job in minutes. If a cron process monitor event is not received between the start time determined by the schedule and the end of the maximum job duration, or if a heartbeat process monitor event is not received within this duration from the last heartbeat process monitor event, it will be reported as failing. * **Description:** An optional description of what this process monitor monitors. * **Notify me through:** The channels that AppSignal should use to notify you of any missed or late process monitor occurrences. ![Screenshot of cron process monitors form](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/check-ins/check-ins-form.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=ecc71a89680e62a6a3a368b796af6a74) For a cron process monitor, a finish process monitor event will be expected for each of the occurrences defined by the schedule, before the maximum duration has passed. For a heartbeat process monitor, heartbeat events will be expected continuously, before the maximum duration since the last heartbeat event has passed. When this expectation isn't met, the process monitor occurrence will be considered failed, and AppSignal will notify you as configured. Once created, you need to [configure your application to send process monitor events](/check-ins/configuration) to AppSignal. ## View all process monitors To view all of your app's process monitors, go to [the process monitors overview page](https://appsignal.com/redirect-to/app?to=check_ins). You can get there from the AppSignal app navigation sidebar: ![Screenshot of Process Monitoring overview](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/check-ins/check-ins-overview.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=d29d0b8c94425ad0b2d8b13bbcbcded6) Clicking on the process monitor name will take you to the [process monitor's occurrence overview](/check-ins/occurrences). ### Edit a process monitor To edit a process monitor's settings, navigate to [the process monitors overview page](https://appsignal.com/redirect-to/app?to=check_ins) in the AppSignal app, click on the name of the process monitor you want to change the settings of, then click "Edit" to modify the process monitor's settings. See the [Create a process monitor](#create-a-process-monitor) section for more information on the settings. ### Remove a process monitor To remove a process monitor, click on the name of the process monitor you want to remove, then click "Remove" and follow the on-screen instructions. # Process monitor occurrences Source: https://docs.appsignal.com/check-ins/occurrences You'll be able to begin monitoring your process monitors in AppSignal after: * [Creating a process monitor in AppSignal](/check-ins/create) * [Configuring your application to send process monitors to AppSignal](/check-ins/configuration) A process monitor consists of occurrences which can succeed or fail. For a cron process monitor, an occurrence is a time at which, according to its configured schedule, AppSignal expects to receive a start and finish event for this process monitor. A cron process monitor's occurrence succeeds if it receives a finish event during its maximum duration. For a heartbeat process monitor, an occurrence is a time at which AppSignal has received a heartbeat event, and an occurrence succeeds if it receives another heartbeat event during its maximum duration. ## Viewing process monitors To view all of your app's process monitors, click on the Process Monitoring overview via the AppSignal app navigation: ![Screenshot of Process Monitoring overview](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/check-ins/check-ins-overview.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=d29d0b8c94425ad0b2d8b13bbcbcded6) Here, you will have an overview of your process monitors with the following columns: | Column name | Description | | - | - | | Identifier and type | The identifier of your process monitor and its type. | | Schedule | The schedule of your process monitor: the crontab syntax for cron process monitors, or the maximum duration between heartbeats for heartbeat process monitors. | | Last failure | The last time a process monitor occurrence failed. | | Last success | The last time a process monitor occurrence succeeded. | | Last occurrence | The status of the last process monitor occurrence. | ## Statuses The state of a process monitor will be that of its last occurrence. Process monitor occurrences will have one of the following statuses: | Status | Description | | - | - | | New | No events have yet been received for this process monitor. | | Success | The process monitor occurrence has been completed within its maximum duration. | | Late | The process monitor occurrence has been completed *after* its maximum duration. | | Missed | The process monitor occurrence has not been completed. | | Running | A start cron process monitor event has been received, or a previous heartbeat's maximum duration has not yet passed. | Late or missed process monitor occurrences are considered to have failed, and AppSignal will notify you that the process monitor has failed according to your process monitor's settings. ## Process monitor summary Clicking on the identifier of a process monitor will take you to an overview of: * **The last five occurrences:** The timestamps for the last five occurrences for the process monitor alongside their status. * **The last five failed occurrences:** The timestamps for the last five missed or late process monitor occurrences. ![Screenshot of Process Monitoring summary](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/check-ins/check-ins-summary.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=048fe6d110685685f69999e0e8e04cd9) # Wrap process monitoring Source: https://docs.appsignal.com/check-ins/wrap-process-monitoring ## Process Monitoring > [!TIP] > > [Read our Process Monitoring documentation](/check-ins) for more information on how > AppSignal Process Monitoring works. By default, `appsignal-wrap` will not send any process monitor events. You can use the `--cron` or `--heartbeat` command-line options to enable cron or heartbeat process monitors respectively. The `appsignal-wrap` tool will use the name provided as the first argument as the process monitor identifier. For example, to report cron process monitor events with `backup-script` as the process monitor identifier: ```sh Shell theme={null} appsignal-wrap backup-script --cron -- bash /var/app/backup.sh ``` ### Cron process monitors When using `--cron` to send cron process monitors, `appsignal-wrap` will send a start cron process monitor event when the process starts, and a finish cron process monitor event if the process finishes successfully. If the process exits with a failure exit status, `appsignal-wrap` will not send a finish cron process monitor event. ### Heartbeat process monitors When using `--heartbeat` to send heartbeat process monitors, `appsignal-wrap` will send heartbeat process monitor events continuously during the lifetime of the process. ### Custom identifier To send process monitor events to AppSignal with an identifier different from the name provided as the first argument, you can pass a different identifier as an argument to the `--cron` or `--heartbeat` command-line options. For example: ```sh Shell theme={null} appsignal-wrap backup --cron daily-backup -- bash /var/app/backup.sh ``` In the above example, `appsignal-wrap` will send cron process monitor events with `daily-backup` as the process monitor identifier, but will still use `backup` as the name to identify the process when reporting logs and errors. # Heroku host metrics Source: https://docs.appsignal.com/heroku/host-metrics Learn how to set up host metrics for Heroku dyno's for AppSignal using Heroku's logplex system. ## Cedar (Legacy Platform) applications > [!NOTE] > > Make sure a working [Heroku Logplex Log Drain](/heroku/setup) is setup before continuing with this section. Heroku provides a service to retrieve host metrics from a Dyno through their [Logplex system](https://devcenter.heroku.com/articles/logplex). AppSignal provides an endpoint to read these metrics from your app's logs. This is the only way to receive accurate host metrics in AppSignal for Heroku apps. The AppSignal [host metrics](/metrics/host-metrics) feature does not work reliably on Heroku as it doesn't directly expose runtime metrics for LXC containers in which their Dynos run. Using the normal host metrics collection your Heroku apps will report the host metrics for the parent system on which many Heroku apps run rather than metrics limited to your Dynos. From the Logplex system we're able to receive the following metrics from your apps per dyno: * Load average * Memory total limit * Memory used To setup AppSignal to receive these metrics, please follow the guide below. ### Update the AppSignal integration. First update the Ruby gem to version 2.6.0 or newer. For Elixir, please update to version 1.6.0 or newer of the AppSignal integration. We switched from using the dyno's UUID to the name (e.g. `web.1`), to make sure we can match the metrics we get from the Logplex drain with the data we receive from the integration, please make sure to run `2.6.x` or better. ### Enable host runtime metrics on Heroku The Heroku host [runtime metrics](https://devcenter.heroku.com/articles/log-runtime-metrics) feature will log the host metrics for your dynos at set intervals to your app's log. To enable this feature on your Heroku app, run the following command on your console. ```bash Bash theme={null} heroku labs:enable log-runtime-metrics heroku restart ``` After restarting the app you should see the following appear in your logs every now and then. ```bash Bash theme={null} $ heroku logs --tail source=web.1 dyno=heroku.2808254.d97d0ea7-cf3d-411b-b453-d2943a50b456 sample#load_avg_1m=2.46 sample#load_avg_5m=1.06 sample#load_avg_15m=0.99 source=web.1 dyno=heroku.2808254.d97d0ea7-cf3d-411b-b453-d2943a50b456 sample#memory_total=21.00MB sample#memory_rss=21.22MB sample#memory_cache=0.00MB sample#memory_swap=0.00MB sample#memory_pgpgin=348836pages sample#memory_pgpgout=343403pages ``` Please see the [Heroku Logplex documentation](https://devcenter.heroku.com/articles/log-runtime-metrics) for more information on how to set this up if you run into problems. After adding the labs feature, host metrics for your app will appear after a few minutes in the ["host metrics" section](https://appsignal.com/redirect-to/app?to=host_metrics). ## Fir applications Heroku Fir platform provides [dyno runtime metrics](https://devcenter.heroku.com/articles/heroku-opentelemetry-signals-and-attributes-reference#dyno-runtime-metrics) through its OpenTelemetry signals that you can configure by following the [Fir setup guide](/heroku/setup#fir-applications). Once you have completed the initial setup, no additional steps are required. Your application's [host metrics](/metrics/host-metrics) will appear in AppSignal in a few minutes. # Log-based metrics Source: https://docs.appsignal.com/logging/metrics Turn data from your logs into metrics you can chart, alert on, and group across your application. If you have indexed logs in AppSignal, you can generate metrics from them directly in the Explore view. Use these log-based metrics to track important signals over time, set up triggers, or add them to dashboards, all without changing your application code or leaving your log exploration workflow. Use log metrics to count how often an event happens, track the latest value of a numeric field, or follow its average and percentiles over time. When you spot something worth tracking in your logs, you can turn it into a metric without leaving the Logs page. The query and log source you've used to narrow your logs carry into the metric, so the filtering work you've already done is what defines what the metric tracks. Once the metric is saved, you can add it to a dashboard or use it in a trigger in the same flow. ## Create a metric from a log line The fastest way to create a metric is from a log line that already shows the data you want to track. 1. Open the **Logs** page for your app. 2. Use the query bar to filter the log lines that match the event you want to measure. 3. Select a log line in the table to open the **Log details** panel. 4. In the **Actions** section, select **Create a metric**. 5. The Create metric overlay opens with the **Log source** and **Query** fields prefilled from the log line. The query matches the line's severity, hostname, and group. ![Log details panel with the Create a metric action](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-from-log-line.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=5b493d4ccad3ee9d1147bfe17c813e5e) ## Configure the metric In the **Define metric** panel, fill in the fields that describe what you want to measure. As you change any field, the **Data preview** on the right updates so you can confirm the metric returns the data you expect. * **Metric name**: A unique name for the metric, used when you reference it on dashboards and triggers. See [metric naming](#metric-naming) for the rules and recommendations. * **Log source**: The log source the metric draws events from. * **Query**: The query string used to match log lines. Same syntax as the Logs page. To include only some severities, add them to the query. For example, `severity=error` matches only error log lines. * **Metric type**: Count, Gauge, or Measurement. See [metric types](#metric-types). * **Field to measure**: For Gauge and Measurement metrics, the numeric field to track — like the duration or size of each event, instead of counting occurrences. * **Group by tag**: Split the metric by a tag to get a separate series per unique value (for example, group by `hostname` to get one series per server). When you finish, select **Create metric** to save. ### Metric naming We recommend naming your metrics something easily recognizable. Metric names only support numbers, letters, dots and underscores (`[a-z0-9._]`) as valid characters. Any other characters will be replaced with an underscore by our processor. Some examples of good metric names are: * `database_size` * `account_count` * `users.count` * `notifier.failed` * `orders.request.duration` > [!WARNING] > > **Note**: We **do not** recommend adding dynamic values to your metric names > like so: `eu.database_size`, `us.database_size` and `asia.database_size`. This > creates multiple metrics that serve the same purpose. Instead we recommend > using **Group by tag** for this. ## Metric types The metric type defines how AppSignal aggregates the data over time. The **Field to measure** field appears for Gauge and Measurement only, since Count just counts matching log lines. ### Count The total number of matching events in a given time frame. Use this for events like errors, sign-ups, or job retries. Count does not require a **Field to measure** — it just counts every log line matching your query. ![Create metric overlay with the Count chart preview](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-count-chart.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=279cef379582fb30e011d5221067cbb6) ### Gauge The current value at the moment. Use this for values that move up and down, such as an active connection count. ![Create metric overlay with the Gauge chart preview](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-gauge-chart.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=07ea5df662d79360d3716c0f84ee609b) ### Measurement Averages, counts, and percentiles for a numeric field over time. Use this when the distribution matters, such as request duration. Measurement persists the mean, count, and 90th/95th percentiles of the **Field to measure** for each interval. ## Preview your metric The **Data preview** panel has two tabs that let you confirm the metric returns the data you expect before saving. ### Chart A live chart of the metric for the selected time range. The chart preview supports selecting multiple log sources, and updates as you change any field in the **Define metric** panel. Use the time-range selector below the chart to switch between **Last 24 hours**, **Last 48 hours**, and **Last 7 days**. ![Create metric overlay with the chart time-range selector open](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-time-range.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=14bef4e69eb8514c0bf366acb240c51b) ### Log lines The log lines that match your current query. When a **Field to measure** is set, that field is shown as a highlighted column so you can confirm the values before saving. ![Create metric overlay with the log lines preview](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/logging/create-metric-log-lines-preview.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=a76f02db5ac76bb0de2c927e9da20dff) ## Choose what to do next After you save a metric for the first time, AppSignal asks what you want to do with it: * **Add to dashboard**: Add the metric to a chart on an existing dashboard. * **Create a trigger**: Open the trigger creation flow with the metric prefilled. * **Edit metric**: Reopen the overlay to refine the configuration. For follow-up metrics, AppSignal shows a confirmation toast instead. You can still reach the same options from the **Metrics** page. A new metric may take a moment to start collecting data, so a dashboard or trigger created right after may briefly show a "no data yet" warning. ## Edit a metric 1. Open the **Metrics** page from the **Logging** side menu. 2. Find the metric and select **Edit** from the three-dot menu. 3. Adjust the **Query**, **Field to measure**, or **Group by tag** fields. 4. Select **Update metric** to save. The **Metric name** and **Metric type** are read-only when editing. To change either, create a new metric. From the row menu on the **Metrics** page, you can also add the metric to a dashboard, create a trigger from it, or delete it. The **Modified by** column shows who last updated each metric, so you can see at a glance which team member made the most recent change. ## Example: track request duration * **Metric name**: `orders.request.duration` * **Log source**: application * **Query**: `path=/api/orders` * **Metric type**: Measurement * **Field to measure**: `duration_ms` * **Group by tag**: `hostname` This metric reports the average, count, and percentiles of `duration_ms` for requests to `/api/orders`, with one series per host. # Apdex Source: https://docs.appsignal.com/metrics/apdex Score how satisfied your users are with your app's response times, per namespace. Apdex (Application Performance Index) turns response times into a single score between 0 and 1. A score of 1 means every request was fast enough. A score of 0 means every request was too slow. You decide what "fast enough" means by setting two thresholds per [namespace](/application/namespaces). AppSignal reports the score as a metric and charts it on the Apdex page. ## How Apdex rates requests Apdex rates each request as satisfied, tolerating, or frustrated, based on the thresholds you set: | Rating | Response time | Weight | | - | - | - | | Satisfied | At or below the satisfied threshold | 1 | | Tolerating | Above the satisfied threshold, up to the tolerating threshold | 0.5 | | Frustrated | Above the tolerating threshold | 0 | The score is the weighted average of these counts. You set the satisfied and tolerating thresholds. Frustrated covers everything slower. ## Configure Apdex for a namespace 1. Open the [Apdex page](https://appsignal.com/redirect-to/app?to=performance/apdex) under Performance for your app. 2. Select a namespace without a configuration in the namespace filter. 3. Select **Configure Apdex**. 4. Choose the **Namespace** you want to score. The list holds every namespace that does not have a configuration yet. 5. Enter the **Satisfied threshold** and **Tolerating threshold** in milliseconds. 6. Select **Create configuration**. ![The New Apdex configuration form, with the namespace, the two thresholds, and a response time preview for the selected namespace](https://mintcdn.com/appsignal-715f5a51/TSsaLF1LsyefYzNP/assets/images/screenshots/metrics/apdex/apdex-configuration.png?fit=max\&auto=format\&n=TSsaLF1LsyefYzNP\&q=85\&s=6fcf625e8123a638d7a292b845ed6535) The form previews the namespace's mean, 90th percentile, and 95th percentile response times over the last seven days, and draws a line for each threshold as you enter it. Use it to set thresholds against the response times you already have. Change the preview's time range to read a shorter or longer period. Each namespace can have one configuration. Repeat this for every namespace you want to score. To change the thresholds later, select **Edit configuration**, then **Update**. The namespace is fixed when you edit a configuration. When a namespace has no configuration, the page lists the other namespaces that do. This tells you whether Apdex is unconfigured for this namespace only, or for the whole app. ## The Apdex page ![The Apdex page, charting the score, the score over time, counts, and throughput for one namespace](https://mintcdn.com/appsignal-715f5a51/TSsaLF1LsyefYzNP/assets/images/screenshots/metrics/apdex/apdex-page.png?fit=max\&auto=format\&n=TSsaLF1LsyefYzNP\&q=85\&s=22c29c992dac49fed2ed7a8d3c126433) The Apdex page charts one namespace at a time. Use the filters to choose the namespace, set the time range, and switch between a one and two column layout. The namespace filter lists every namespace in your app, not only the ones with Apdex configured. Selecting a namespace without a configuration shows the empty state, where you can configure it. For a namespace with a configuration, the page charts: * The latest Apdex score for the selected time range. * The Apdex score over time. * **Counts** — how many requests were satisfied, tolerating, and frustrated. * **Throughput** — request throughput for the namespace. * **Response time** — mean, 90th percentile, and 95th percentile response times for the namespace. Throughput and response time are the same namespace metrics you see elsewhere in Performance. They are included here so you can read a score against the traffic and latency behind it. ## Apdex metrics Once a namespace has a configuration, AppSignal reports two metrics for it: * `apdex` — the score for the namespace, between 0 and 1. * `apdex_counts` — how many requests were satisfied, tolerating, and frustrated. These are the numbers the score is calculated from. Both metrics are reported per namespace. Charting `apdex_counts` gives you one series per rating, each named after the namespace it belongs to: `web - satisfied`, `web - tolerating`, and `web - frustrated`. You can use both metrics like any other metric, on your own [dashboards](/metrics/dashboards) and in [anomaly detection triggers](/anomaly-detection). ## Remove an Apdex configuration Select the namespace in the filter, select **Edit configuration**, then **Delete configuration** and confirm. AppSignal stops scoring the namespace. The `apdex` and `apdex_counts` metrics stop being reported for it, and the charts on the Apdex page fall back to the empty state. # AWS Intelligence dashboards Source: https://docs.appsignal.com/metrics/aws-dashboards AppSignal creates an Intelligence dashboard for each AWS service it detects metrics from, such as EC2, Lambda, ECS, and EKS. AppSignal automatically creates Intelligence dashboards for AWS services when it detects their metrics. Each AWS service gets its own dashboard with pre-built charts, so you get useful monitoring of your AWS infrastructure without building dashboards from scratch. These dashboards appear in **Dashboards** grouped under **AWS**, with a separate dashboard for each service (for example, `AWS/Lambda`, `AWS/RDS`, or `AWS/SQS`). The metrics that power them currently arrive through [CloudWatch Metric Streams](/metrics/cloudwatch-overview). ## How AWS dashboards are created When AppSignal receives metrics from an AWS service, it matches the metric names against its list of supported services. If there is a match, AppSignal creates a dashboard for that service in your app. Each chart uses wildcard tag filters to show all resources of a given type as separate lines. For example, the Lambda Errors chart shows a line for each function, tagged by `FunctionName`. You can narrow the view using the tag filters in the chart options. ## Setup To start receiving AWS metrics in AppSignal, set up a CloudWatch Metric Stream that sends data through Amazon Data Firehose to AppSignal's HTTP endpoint. There are two ways to do this: * [Console setup](/metrics/cloudwatch) — create each resource manually in the AWS Console. * [CloudFormation](/metrics/cloudwatch-cloudformation) — deploy a single template that creates all required resources in one step. See the [AWS CloudWatch metrics overview](/metrics/cloudwatch-overview) for details on metric naming, tags, filtering, multi-region setups, and troubleshooting. ### Beta dashboards Dashboards marked with a **beta** label are recently added and may receive changes to their chart layout and metrics based on feedback. Once a dashboard is stable, the beta label is removed. If you have feedback on any dashboard, [let us know](mailto:support@appsignal.com). ## Dashboard design Every AWS dashboard is designed to help you answer common operational questions quickly: 1. **Is anything broken?** Health indicators and error rates appear first, so a quick glance at the top of the dashboard tells you whether something needs attention. 2. **Why is it slow or failing?** Performance metrics like latency, queue depth, and throttle counts help you narrow down the cause. 3. **Do I need to scale?** CPU, memory, and capacity metrics show whether you are approaching resource limits. Charts are ordered by urgency of signal, not by resource type. Health and stability metrics come first, followed by resource pressure, then operational context like network throughput and storage I/O. Chart descriptions explain what values indicate a problem and what to do about it, rather than restating the metric name. For example, a Lambda Throttles chart tells you that non-zero values mean requests are being dropped and suggests increasing reserved concurrency. ## Supported services The following sections list all AWS services with Intelligence dashboards, grouped by category. Each section includes the service, its CloudWatch namespace (used for [filtering which metrics to stream](/metrics/cloudwatch-cloudformation#filter-specific-aws-services)), and the charts in its dashboard. ## Compute ### EC2 **Namespace:** `AWS/EC2` Monitor Amazon EC2 instance performance including CPU, network, disk, and EBS metrics. Charts: * CPU Utilization * Network In vs Out * Network Packets In vs Out * Disk Read vs Write Ops * Disk Read vs Write Bytes * EBS Read vs Write Ops * EBS Read vs Write Bytes * Status Checks * CPU Credit Balance vs Usage ### Lambda **Namespace:** `AWS/Lambda` Monitor AWS Lambda function invocations, errors, throttles, duration, and concurrency. Charts: * Errors * Throttles * Dead Letter Errors vs Destination Delivery Failures * Invocations * Duration * ConcurrentExecutions vs UnreservedConcurrentExecutions * ClaimedAccountConcurrency * AsyncEventsReceived vs AsyncEventsDropped * AsyncEventAge * Iterator Age ### ECS **Namespace:** `AWS/ECS` Monitor Amazon ECS service-level CPU and memory utilization. Charts: * CPU Utilization * Memory Utilization ### EKS Nodes **Namespace:** `ContainerInsights` Monitor EKS node-level CPU, memory, filesystem, and network metrics across the cluster. Charts: * Node CPU Utilization * Node Memory Utilization * Node Filesystem Utilization * Node Network Traffic * Running Pods per Node * Running Containers per Node * Cluster Node Count ### EKS Pods **Namespace:** `ContainerInsights` Monitor EKS pod-level CPU, memory, network, and container restart metrics. Charts: * Container Restarts * Pod CPU Utilization * Pod Memory Utilization * Pod Network Rx vs Tx ### Auto Scaling **Namespace:** `AWS/AutoScaling` Monitor Auto Scaling group capacity, instance lifecycle states, and scaling activity. Charts: * Scaling Overview * Instance Lifecycle * Total Instances ### App Runner **Namespace:** `AWS/AppRunner` Monitor AWS App Runner service performance including requests, latency, HTTP status codes, and resource utilization. Charts: * HTTP 2xx vs 4xx vs 5xx * Requests * Request Latency * CPU Utilization * Memory Utilization * Active Instances * Concurrency ## Databases ### RDS **Namespace:** `AWS/RDS` Monitor Amazon RDS database instance performance including CPU, connections, storage, I/O, and replication metrics. Charts: * Replica Lag * CPU Utilization * Freeable Memory * Free Storage Space * Database Connections * Read IOPS vs Write IOPS * Read Latency vs Write Latency * Read Throughput vs Write Throughput * Disk Queue Depth * Swap Usage * Network Receive vs Transmit Throughput * Burst Balance ### Aurora **Namespace:** `AWS/RDS` Monitor Amazon Aurora cluster-specific metrics including replica lag, volume I/O, serverless capacity, and backup storage. Charts: * Aurora Replica Lag * Aurora Replica Lag (Max vs Min) * CPU Utilization * Database Connections * Freeable Memory * Buffer Cache Hit Ratio * Volume Read vs Write IOPs * Volume Bytes Used * Serverless Database Capacity * Backup Storage Used ### DynamoDB **Namespace:** `AWS/DynamoDB` Monitor Amazon DynamoDB table performance including capacity consumption, throttling, latency, and errors. Charts: * Read vs Write Throttle Events * System Errors vs User Errors * Consumed Read vs Write Capacity * Provisioned Read vs Write Capacity * Successful Request Latency * Conditional Check Failed Requests * Returned Item Count * Time To Live Deleted Item Count * Replication Latency * Transaction Conflict ### ElastiCache Redis **Namespace:** `AWS/ElastiCache` Monitor Amazon ElastiCache Redis cluster performance including cache hits/misses, CPU, memory, connections, and replication. Charts: * Cache Hits vs Misses * Cache Hit Rate * Engine CPU Utilization * Current Connections * Evictions * Bytes Used for Cache * Database Memory Usage Percentage * Freeable Memory * Network In vs Out * Replication Lag * Current Items * Commands: Get vs Set * Host CPU Utilization * Memory Fragmentation Ratio ### ElastiCache Memcached **Namespace:** `AWS/ElastiCache` Monitor Amazon ElastiCache Memcached cluster performance including get/set commands, hit rates, CPU, memory, and connections. Charts: * Get Hits vs Misses * Commands: Get vs Set * CPU Utilization * Current Connections * Evictions * Bytes Used for Cache Items vs Freeable Memory * Network In vs Out * Current Items ### OpenSearch **Namespace:** `AWS/ES` Monitor OpenSearch cluster health, resource utilization, search and indexing performance, and HTTP response codes. Charts: * Cluster Status * Nodes * CPU Utilization * Free Storage Space * JVM Memory Pressure * Search vs Indexing Latency * Search vs Indexing Rate * HTTP Response Codes * Threadpool Search * Threadpool Write * Cluster Index Writes Blocked * Automated Snapshot Failure * Master CPU vs JVM Memory Pressure ### Redshift **Namespace:** `AWS/Redshift` Monitor Redshift cluster health, CPU, disk usage, query performance, and I/O throughput. Charts: * Health Status * CPU Utilization * Disk Space Used * Database Connections * Query Throughput * Read vs Write Latency * Read vs Write IOPS * Network Throughput ### DocumentDB **Namespace:** `AWS/DocDB` Monitor Amazon DocumentDB cluster performance including CPU, connections, IOPS, latency, memory, and storage. Charts: * CPU Utilization * Database Connections * Read vs Write IOPS * Read vs Write Latency * Freeable Memory * Volume Bytes Used * Buffer Cache Hit Ratio * Replica Lag ## Networking and content delivery ### ALB (Application Load Balancer) **Namespace:** `AWS/ApplicationELB` Monitor Application Load Balancer request counts, response times, HTTP status codes, host health, and connection metrics. Charts: * HTTP ELB 4xx vs 5xx * Healthy vs Unhealthy Hosts * Target Connection Errors * Rejected Connections * Request Count * Target Response Time * HTTP Target 2xx vs 3xx vs 4xx vs 5xx * Active vs New Connections * Processed Bytes * Consumed LCUs ### Classic ELB **Namespace:** `AWS/ELB` Monitor Classic Elastic Load Balancer request counts, latency, HTTP status codes, host health, and queue metrics. Charts: * HTTP ELB 4xx vs 5xx * Healthy vs Unhealthy Hosts * Backend Connection Errors * Request Count * Latency * HTTP Backend 2xx vs 3xx vs 4xx vs 5xx * Surge Queue Length vs Spillover Count ### CloudFront **Namespace:** `AWS/CloudFront` Monitor Amazon CloudFront distribution request counts, data transfer, error rates, and cache hit rates. Charts: * Total Error Rate * 4xx vs 5xx Error Rate * Requests * Bytes Downloaded vs Uploaded * Cache Hit Rate * Origin Latency ### NLB (Network Load Balancer) **Namespace:** `AWS/NetworkELB` Monitor Network Load Balancer target health, connection flow, throughput, TCP resets, and TLS errors. Charts: * Target Health * TLS Negotiation Errors * Active Connections * New Connections * Processed Bytes * TCP Resets * Consumed LCUs ### NAT Gateway **Namespace:** `AWS/NATGateway` Monitor NAT Gateway throughput, connections, port allocation errors, and packet drops. Charts: * Errors and Drops * Byte Throughput * Packet Throughput * Connections * Peak Utilization ### Route 53 **Namespace:** `AWS/Route53` Monitor Route 53 health check status, endpoint latency, and DNS query volume. Charts: * Health Check Status * Health Check Percentage Healthy * Endpoint Latency * DNS Query Volume ### API Gateway **Namespace:** `AWS/ApiGateway` Monitor Amazon API Gateway request counts, latency, and error rates. Charts: * 4XX Errors * 5XX Errors * Request Count * Latency vs Integration Latency * Cache Hit vs Miss ## Storage ### S3 **Namespace:** `AWS/S3` Monitor Amazon S3 bucket storage size, object counts, request metrics, errors, and latency. Charts: * 4xx vs 5xx Errors * Bucket Size * Number of Objects * All Requests * Request Types * First Byte Latency vs Total Request Latency * Bytes Downloaded vs Uploaded ### EBS **Namespace:** `AWS/EBS` Monitor EBS volume throughput, IOPS, queue length, latency, and burst credit balance. Charts: * Volume Status Check * Read vs Write Bytes * Read vs Write Ops * Queue Length * Read vs Write Time * Idle Time * Burst Balance ### EFS **Namespace:** `AWS/EFS` Monitor EFS throughput, I/O limits, burst credits, client connections, and storage usage. Charts: * Throughput * Permitted Throughput * I/O Limit * Burst Credit Balance * Client Connections * Storage ## Messaging and streaming ### SQS **Namespace:** `AWS/SQS` Monitor Amazon SQS queue message throughput, queue depth, message age, and message size. Charts: * Age of Oldest Message * Queue Depth (Visible vs Not Visible vs Delayed) * Messages Sent vs Received vs Deleted * Sent Message Size * Empty Receives ### SNS **Namespace:** `AWS/SNS` Monitor Amazon SNS topic message publishing, delivery, filtering, and message size. Charts: * Notifications Delivered vs Failed * Messages Published * Notifications Filtered Out * Publish Size ### EventBridge **Namespace:** `AWS/Events` Monitor Amazon EventBridge event matching, rule invocations, failures, dead-letter delivery, and latency. Charts: * Failed Invocations * Dead Letter Invocations * Throttled Rules * Matched Events vs Triggered Rules * Invocations * Ingestion to Invocation Start Latency ### Kinesis Data Streams **Namespace:** `AWS/Kinesis` Monitor Amazon Kinesis Data Streams throughput, iterator age, put/get operations, and provisioned throughput limits. Charts: * GetRecords Iterator Age * Read vs Write Throughput Exceeded * Incoming Records * Incoming Bytes * GetRecords Records vs Bytes * PutRecord vs PutRecords Success * PutRecord vs PutRecords Latency * GetRecords Latency ### Data Firehose **Namespace:** `AWS/Firehose` Monitor Firehose delivery stream ingestion, S3 delivery throughput, data freshness, and delivery success. Charts: * Delivery to S3 - Success * Delivery to S3 - Data Freshness * Incoming Bytes * Incoming Records * Delivery to S3 - Bytes * Delivery to S3 - Records ### MSK (Kafka) **Namespace:** `AWS/Kafka` Monitor MSK cluster health, partition replication, throughput, and resource utilization. Charts: * Cluster Health * Under-Replicated Partitions * Under Min ISR Partitions * Consumer Max Lag * Throughput * Messages In * CPU Usage * Disk Usage ### MQ ActiveMQ **Namespace:** `AWS/AmazonMQ` Monitor Amazon MQ ActiveMQ broker health including CPU, heap, storage, connections, and message throughput. Charts: * Store Usage * CPU Utilization * Heap Usage * Connections * Producers vs Consumers * Total Messages * Enqueue vs Dequeue * Network In vs Out ### MQ RabbitMQ **Namespace:** `AWS/AmazonMQ` Monitor Amazon MQ RabbitMQ broker health including CPU, memory, disk, connections, and message throughput. Charts: * Disk Free vs Limit * Memory Used vs Limit * CPU Utilization * Connections vs Channels * Publish vs Ack Rate * Queue Depth * Consumer Count * Network In vs Out ## Application integration ### Step Functions **Namespace:** `AWS/States` Monitor AWS Step Functions state machine executions, outcomes, throttling, and execution duration. Charts: * Executions Succeeded vs Failed * Executions Aborted vs Timed Out * Execution Throttled * Executions Started * Execution Time ### AppSync **Namespace:** `AWS/AppSync` Monitor AWS AppSync GraphQL API performance including requests, latency, errors, and real-time subscriptions. Charts: * Client Errors vs Server Errors * Requests * Latency * Tokens Consumed * WebSocket Connections * Active Connections vs Subscriptions * Subscription Messages ## Security ### WAF **Namespace:** `AWS/WAFV2` Monitor WAF request filtering decisions including allowed, blocked, and counted requests. Charts: * Request Decisions * Passed Requests ### Cognito **Namespace:** `AWS/Cognito` Monitor Cognito user pool authentication activity and token operations. Charts: * Authentication * Token & Federation ## AI and machine learning ### SageMaker **Namespace:** `AWS/SageMaker` Monitor SageMaker endpoint invocations, errors, and latency. Charts: * Invocation Errors * Invocations * Latency ### Bedrock **Namespace:** `AWS/Bedrock` Monitor Amazon Bedrock model invocations, latency, errors, throttles, and token usage. Charts: * Invocation Errors * Throttles * Invocations * Invocation Latency * Input vs Output Tokens * Output Images ## Developer tools ### CodeBuild **Namespace:** `AWS/CodeBuild` Monitor CodeBuild project build counts, success/failure rates, and build phase durations. Charts: * Builds * Build Duration * Queue Duration * Provisioning & Source Download ### CloudWatch Logs **Namespace:** `AWS/Logs` Monitor CloudWatch Logs ingestion volume, log event counts, subscription forwarding, and delivery errors. Charts: * Delivery Errors vs Throttling * Incoming Data * Incoming Log Events * Forwarded Bytes * Forwarded Log Events ## Email ### SES **Namespace:** `AWS/SES` Monitor SES email delivery, bounces, complaints, and sender reputation rates. Charts: * Bounces vs Complaints * Email Sending * Reputation Rates ## Analytics ### Athena **Namespace:** `AWS/Athena` Monitor Athena query execution times, query phase durations, and data scanned. Charts: * Query Execution Time * Query Phases * Data Scanned ### Glue **Namespace:** `AWS/Glue` Monitor Glue ETL job duration, task completion, data throughput, and JVM heap usage. Charts: * Job Duration * Tasks * Bytes Read * JVM Heap * JVM Heap Usage ## Management and monitoring ### Billing **Namespace:** `AWS/Billing` Monitor estimated AWS charges broken down by service. Charts: * Estimated Charges ### CloudTrail **Namespace:** `AWS/CloudTrail` Monitor CloudTrail API event volume. Charts: * Events # Stream AWS CloudWatch metrics through the AWS Console Source: https://docs.appsignal.com/metrics/cloudwatch This guide walks through setting up CloudWatch metrics streaming to AppSignal by creating each resource manually in the AWS Console. For an automated alternative, see [Stream AWS CloudWatch metrics with CloudFormation](/metrics/cloudwatch-cloudformation). For an overview of CloudWatch metrics in AppSignal, including Intelligence dashboards and metric naming, see [AWS CloudWatch metrics](/metrics/cloudwatch-overview). Complete the following steps to send CloudWatch metrics to AppSignal through Amazon Data Firehose: 1. [Set up an S3 bucket for failed deliveries](#set-up-an-s3-bucket-for-failed-deliveries) 2. [Set up an IAM role for Data Firehose](#set-up-an-iam-role-for-data-firehose) 3. [Create a Firehose stream](#create-a-firehose-stream) 4. [Create a CloudWatch metric stream](#create-a-cloudwatch-metric-stream) Before you start, have the following information ready: * Your app's App-level Push API key. To find it, open the [API keys settings page](https://appsignal.com/redirect-to/app?to=api_keys\&key_tab=app), or navigate to your organization settings and select **Dev zone > API keys**. * The AWS region you want to stream metrics from. * AWS permissions to create Firehose streams, CloudWatch metric streams, S3 buckets, and IAM roles. ## Set up an S3 bucket for failed deliveries Amazon Data Firehose requires an S3 bucket to store records that fail to deliver. Create an S3 bucket through the AWS Console or CLI before proceeding. ## Set up an IAM role for Data Firehose Create an IAM role that allows Data Firehose to write to the S3 bucket. Use the following trust policy: ```json JSON theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "firehose.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } ``` Assign the following permissions policy to the role as an inline policy. > [!NOTE] > > See [Adding IAM identity > permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html) > for instructions on creating inline policies for IAM roles. ```json JSON theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::", "arn:aws:s3:::/*" ] } ] } ``` Replace `` with the name of the S3 bucket you created in the previous step. ## Create a Firehose stream 1. Open the Amazon Data Firehose console and select **Create Firehose stream**. 2. Select **Direct PUT** as the source. 3. Select **HTTP Endpoint** as the destination. 4. Under "Transform records", leave data transformation turned off. The data must be delivered as-is. 5. Enter the following URL as the **HTTP endpoint URL**: ```shell Shell theme={null} https://appsignal-endpoint.net/metrics/aws-cloudwatch ``` 6. Enter your app's App-level Push API key as the **Access key**. This is not an AWS access key. It is the key AppSignal uses to identify your app. 7. Under "Content encoding", select **GZIP**. 8. Under "Buffer hints", set the buffer size to **1 MB** and the buffer interval to **60 seconds** for the lowest latency. Higher values reduce cost but increase delivery delay. 9. Under "Backup settings", set source record backup to **Failed data only** and select the S3 bucket you created in the previous steps. 10. Under "Advanced settings > Service access", select **Choose existing IAM role** and choose the IAM role you created in the previous steps. 11. Select **Create Firehose stream**. ## Create a CloudWatch metric stream 1. In the CloudWatch console, go to **Metrics > Streams**. 2. Select **Create metric stream**. 3. Select **Custom setup with Firehose**. Under **Select your Amazon Data Firehose stream**, choose the Firehose stream you created in the previous step. 4. Choose which metrics to stream: * **All metrics** streams everything from all AWS services. This is the simplest option, but may increase costs. * **Selected namespaces** lets you include or exclude specific namespaces, such as `AWS/EC2`, `AWS/Lambda`, or `AWS/RDS`. See the [Intelligence dashboards](/metrics/aws-dashboards) page for the services AppSignal supports. 5. Select **OpenTelemetry 1.0** as the output format. 6. For **Service access**, let the AWS Console create or update the IAM role for you, or choose an existing role with permission to write to the Firehose stream. 7. Select **Create metric stream**. You can create multiple metric streams if you need to send metrics to different destinations or filter metrics differently for separate use cases. ## Verify the setup After completing the setup, allow 5 to 10 minutes for metrics to begin appearing in AppSignal. To verify data is flowing: 1. Check the **Monitoring** tab on your Firehose stream in the AWS Console. Look for non-zero **Incoming records** and **HTTP endpoint - Success** metrics. 2. Confirm the metric stream state shows **Running** in the CloudWatch console under **Metrics > Streams**. If no data appears, enable CloudWatch Logs error logging on the Firehose stream and check for delivery errors. > [!NOTE] > > Some AWS metrics, such as S3 daily storage metrics, are reported with > timestamps older than two hours and do not appear in metric streams. See the > [AWS CloudWatch Metric Streams > documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Metric-Streams.html) > for details on metric reporting frequencies. ## CloudWatch metrics in AppSignal After setup, AppSignal receives metrics from any AWS service that emits metrics through CloudWatch. AppSignal automatically creates [Intelligence dashboards](/metrics/aws-dashboards) for supported AWS services when it detects their metrics. These dashboards appear in **Dashboards** with pre-built charts for the most important metrics of each service. You can also build your own views using [custom dashboards](/metrics/dashboards). In the **Metric** field, type `aws_` to browse the CloudWatch metrics AppSignal has received. AppSignal normalizes CloudWatch metric names to lowercase with underscores. For example, `AWS/Firehose` `DeliveryToS3.Success` becomes `aws_firehose_delivery_to_s3_success`. It can take a few minutes after setup for the first metrics to appear. If the list is empty, wait a few minutes and refresh. If you need help, [contact us](mailto:support@appsignal.com). # Stream AWS CloudWatch metrics with CloudFormation Source: https://docs.appsignal.com/metrics/cloudwatch-cloudformation Use an AWS CloudFormation template to set up CloudWatch metrics streaming to AppSignal. The template creates all required resources in a single deployment, instead of configuring each one manually through the AWS Console. For an overview of CloudWatch metrics in AppSignal, including Intelligence dashboards and metric naming, see [AWS CloudWatch metrics](/metrics/cloudwatch-overview). If you prefer to set up each resource manually, see the [console setup guide](/metrics/cloudwatch). ## Before you start Have the following information ready: * Your app's App-level Push API key. To find it, open the [API keys settings page](https://appsignal.com/redirect-to/app?to=api_keys\&key_tab=app), or navigate to your organization settings and select **Dev zone > API keys**. * The AWS region where you want to deploy the stack ## What the template creates The CloudFormation template creates the following resources: 1. An **S3 bucket** to store records that fail to deliver, with a 30-day lifecycle expiration and a retain-on-delete policy. 2. An **IAM role** that allows Amazon Data Firehose to write failed records to the S3 bucket. 3. A **Firehose delivery stream** that sends metrics to the AppSignal endpoint over HTTPS. 4. An **IAM role** that allows CloudWatch Metric Streams to write to the Firehose delivery stream. 5. A **CloudWatch metric stream** that exports metrics in OpenTelemetry 1.0 format. ## CloudFormation template Copy the following template and save it as `appsignal-cloudwatch-metrics.yaml`: ```yaml YAML theme={null} AWSTemplateFormatVersion: "2010-09-09" Description: > Stream CloudWatch metrics to AppSignal using Amazon Data Firehose. Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: AppSignal Configuration Parameters: - AppLevelPushApiKey ParameterLabels: AppLevelPushApiKey: default: "App-level Push API Key (find at https://appsignal.com/redirect-to/app?to=api_keys&key_tab=app)" Parameters: AppLevelPushApiKey: Type: String NoEcho: true Description: > Your App-level Push API key from AppSignal. Resources: # 1. S3 bucket for failed deliveries FailedDeliveryBucket: Type: AWS::S3::Bucket DeletionPolicy: Retain Properties: BucketName: !Sub "appsignal-firehose-${AWS::StackName}-${AWS::AccountId}-${AWS::Region}" PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LifecycleConfiguration: Rules: - Id: ExpireFailedDeliveries Status: Enabled ExpirationInDays: 30 # 2. IAM role for Firehose to write to S3 FirehoseS3Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: firehose.amazonaws.com Action: "sts:AssumeRole" Policies: - PolicyName: FirehoseS3Access PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:AbortMultipartUpload" - "s3:GetBucketLocation" - "s3:GetObject" - "s3:ListBucket" - "s3:ListBucketMultipartUploads" - "s3:PutObject" Resource: - !GetAtt FailedDeliveryBucket.Arn - !Sub "${FailedDeliveryBucket.Arn}/*" # 3. Firehose delivery stream MetricsDeliveryStream: Type: AWS::KinesisFirehose::DeliveryStream Properties: DeliveryStreamType: DirectPut HttpEndpointDestinationConfiguration: EndpointConfiguration: Url: "https://appsignal-endpoint.net/metrics/aws-cloudwatch" AccessKey: !Ref AppLevelPushApiKey Name: AppSignal RequestConfiguration: ContentEncoding: GZIP BufferingHints: IntervalInSeconds: 60 SizeInMBs: 1 S3BackupMode: FailedDataOnly S3Configuration: BucketARN: !GetAtt FailedDeliveryBucket.Arn RoleARN: !GetAtt FirehoseS3Role.Arn RoleARN: !GetAtt FirehoseS3Role.Arn # 4. IAM role for CloudWatch Metric Streams to write to Firehose MetricStreamRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: streams.metrics.cloudwatch.amazonaws.com Action: "sts:AssumeRole" Policies: - PolicyName: MetricStreamFirehoseAccess PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "firehose:PutRecord" - "firehose:PutRecordBatch" Resource: !GetAtt MetricsDeliveryStream.Arn # 5. CloudWatch metric stream CloudWatchMetricStream: Type: AWS::CloudWatch::MetricStream Properties: FirehoseArn: !GetAtt MetricsDeliveryStream.Arn RoleArn: !GetAtt MetricStreamRole.Arn OutputFormat: "opentelemetry1.0" Outputs: DeliveryStreamName: Description: Name of the Firehose delivery stream. Value: !Ref MetricsDeliveryStream MetricStreamName: Description: Name of the CloudWatch metric stream. Value: !Ref CloudWatchMetricStream FailedDeliveryBucketName: Description: S3 bucket for failed delivery records. Value: !Ref FailedDeliveryBucket ``` ## Deploy the stack 1. Open the [AWS CloudFormation console](https://console.aws.amazon.com/cloudformation/). 2. Select **Create stack** and choose **With new resources (standard)**. 3. Under **Specify template**, select **Upload a template file** and upload `appsignal-cloudwatch-metrics.yaml`. 4. Select **Next**. 5. Enter a stack name, for example `appsignal-cloudwatch-metrics`. 6. For **AppLevelPushApiKey**, enter your app's App-level Push API key. 7. Select **Next** twice, then check **I acknowledge that AWS CloudFormation might create IAM resources** and select **Submit**. The stack takes a few minutes to create. Once the status shows **CREATE\_COMPLETE**, CloudWatch begins streaming metrics to AppSignal. ## Filter specific AWS services By default, the template streams metrics from all AWS services in the account. To stream only specific services, add `IncludeFilters` to the `CloudWatchMetricStream` resource: ```yaml YAML theme={null} CloudWatchMetricStream: Type: AWS::CloudWatch::MetricStream Properties: FirehoseArn: !GetAtt MetricsDeliveryStream.Arn RoleArn: !GetAtt MetricStreamRole.Arn OutputFormat: "opentelemetry1.0" IncludeFilters: - Namespace: AWS/EC2 - Namespace: AWS/RDS - Namespace: AWS/ELB ``` Replace the namespaces with the AWS services you want to monitor. See the [AWS services that publish CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html) for a full list of available namespaces. ## Verify the deployment 1. In the AWS Console, search for "CloudFormation" and select **Stacks**. Open your stack and select the **Resources** tab to confirm all resources show **CREATE\_COMPLETE**. 2. In the AWS Console, search for "CloudWatch". In the left sidebar, go to **Metrics > Streams** and confirm the metric stream status is **Running**. 3. In the AWS Console, search for "Firehose". Open the delivery stream and use the **Test with demo data** function to verify connectivity. 4. In AppSignal, open your [app's dashboard](https://appsignal.com/redirect-to/app?to=dashboard) and check that CloudWatch metrics appear on your [custom dashboard](/metrics/dashboards). If metrics do not appear after a few minutes, check the S3 bucket for failed delivery records. If you need help, [contact us](mailto:support@appsignal.com). ## Multi-region deployments The template deploys all resources in a single AWS region. If you run workloads in multiple regions, deploy a separate copy of this stack in each region. This keeps data transfer within each region and avoids cross-region transfer fees. ## Clean up To remove all resources created by this template, delete the stack in the CloudFormation console. The S3 bucket for failed deliveries has a `DeletionPolicy` of `Retain`, so it is kept when the stack is deleted to avoid losing any failed delivery records. Failed delivery records in the bucket are automatically deleted after 30 days by the lifecycle rule. You can delete the bucket manually once you no longer need it. # AWS CloudWatch metrics Source: https://docs.appsignal.com/metrics/cloudwatch-overview AppSignal can receive and visualize metrics from your AWS infrastructure through CloudWatch Metric Streams. Once connected, AppSignal automatically creates [Intelligence dashboards](/metrics/aws-dashboards) for the AWS services you use, giving you pre-built charts for the metrics that matter most. ## How it works AWS CloudWatch collects metrics from services running in your AWS account. A CloudWatch Metric Stream exports those metrics through Amazon Data Firehose to AppSignal's HTTP endpoint in OpenTelemetry format. The data flow looks like this: **AWS services** → **CloudWatch** → **Metric Stream** → **Data Firehose** → **AppSignal** Once metrics arrive, AppSignal normalizes the metric names, applies tags from CloudWatch dimensions, and stores them as time series data. When AppSignal detects metrics from a supported AWS service, it creates a Intelligence dashboard with pre-built charts for that service. ## Set up CloudWatch metrics There are two ways to connect CloudWatch metrics to AppSignal: ### Console setup Follow the instructions to create a Firehose delivery stream, an S3 backup bucket, and a CloudWatch Metric Stream through the AWS Console. See [Stream AWS CloudWatch metrics through the AWS Console](/metrics/cloudwatch). ### CloudFormation Deploy a single CloudFormation template that creates all the required resources in one step. This is the fastest way to get started and the easiest to reproduce across AWS accounts or regions. See [Stream AWS CloudWatch metrics with CloudFormation](/metrics/cloudwatch-cloudformation). ## Intelligence dashboards AppSignal automatically creates dashboards when it detects CloudWatch metrics from a supported AWS service. Each dashboard is designed to answer common operational questions: is anything broken, why is it slow, and do I need to scale? Dashboards put health and error indicators first, followed by resource utilization, then operational context. Chart descriptions explain what values indicate a problem and what to do about it, so you do not need to be an AWS monitoring expert to interpret your data. AppSignal supports 46 Intelligence dashboards for AWS services across compute, databases, networking, storage, messaging, and more. See [AWS Intelligence dashboards](/metrics/aws-dashboards) for the full list of supported services and their charts. ## Choose which metrics to stream CloudWatch Metric Streams can send metrics from all AWS services in your account or a filtered subset. Streaming all metrics is the simplest option. If you only need specific services, filter by namespace to limit the data sent through Firehose. To filter, add `IncludeFilters` to the Metric Stream resource, specifying the CloudWatch namespaces you want (such as `AWS/EC2`, `AWS/Lambda`, or `AWS/RDS`). See the [AWS Intelligence dashboards](/metrics/aws-dashboards) page for the namespace of each supported service. For filtering configuration examples, see the [CloudFormation setup guide](/metrics/cloudwatch-cloudformation#filter-specific-aws-services). ## Metric naming AppSignal normalizes CloudWatch metric names to lowercase with underscores. The format is the normalized namespace followed by the `snake_case` metric name. For example, `AWS/Lambda` `Duration` becomes `aws_lambda_duration`, and `AWS/Firehose` `DeliveryToS3.Success` becomes `aws_firehose_delivery_to_s3_success`. You can use these normalized names when building [custom dashboards](/metrics/dashboards) or setting up [anomaly detection](/metrics/dashboards) in AppSignal. ## Tags and dimensions CloudWatch dimensions (such as `FunctionName`, `DBInstanceIdentifier`, or `ServiceName`) become tags in AppSignal. Use these tags to filter charts by specific resources. Intelligence dashboards use wildcard tag filters to show all resources of a given type as separate lines on the same chart. You can also use these tags in custom dashboards for more focused views. ## Multi-region and multi-account setups CloudWatch Metric Streams operate within a single AWS region. If you run workloads in multiple regions, deploy a separate Metric Stream and Firehose delivery stream in each region. The [CloudFormation template](/metrics/cloudwatch-cloudformation) can be deployed once per region to set this up. For multi-account setups, create a Metric Stream in each account. Use the same App-level Push API key to send all metrics to a single AppSignal app, or use different keys to separate metrics across apps. ## Troubleshooting If metrics do not appear in AppSignal after setup: 1. Check the **Monitoring** tab on your Firehose delivery stream in the AWS Console. Look for non-zero **Incoming records** and **HTTP endpoint - Success** metrics. 2. Verify the Metric Stream state shows **Running** in the CloudWatch console under **Metrics > Streams**. 3. Check the S3 backup bucket for failed delivery records. 4. Confirm the output format is set to **OpenTelemetry 1.0**. Other formats are not supported. Some AWS metrics (such as S3 daily storage metrics) are reported with timestamps older than two hours and do not appear in Metric Streams. See the [AWS documentation on CloudWatch Metric Streams](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Metric-Streams.html) for details on metric reporting frequencies. If you need help, [contact us](mailto:support@appsignal.com). # Custom metrics Source: https://docs.appsignal.com/metrics/custom Custom metrics let you track anything meaningful in your application — from the number of active users at a given moment, to how many invoices were generated in the last hour, to the current size of your database. By sending custom metrics to AppSignal, you can create graphs in your dashboards that relate this data to critical signals like error rates and response times, giving you the context to quickly identify and resolve issues. Additionally, custom metrics help you work proactively rather than reactively. While logging helps you debug issues after they occur, custom metrics let you spot trends and potential problems before your customers notice. You can concentrate on data that matters to your business — such as active user counts, KPIs, or sales volumes — without sifting through log lines or incident lists. You can also set triggers on custom metrics to warn you when values fall outside expected ranges. Custom metrics are not a replacement for [custom instrumentation](/ruby/instrumentation/instrumentation), but a complementary tool for making specific application data visible and measurable over time. AppSignal offers three custom metric types: | Type | Best for | Example use case | | - | - | - | | [Gauge](#gauge) | Absolute values that change over time | Active users, database size, disk usage | | [Measurement](#measurement) | Ranges and distributions of values | Response times, job durations, cart values | | [Counter](#counter) | Counting occurrences over time | Invoices created, logins, errors triggered | You can track custom metrics in [graphs](#graphing-custom-metrics) in your AppSignal dashboards. ### Gauge A gauge records a value at a specific point in time. If you report multiple gauges with the same key within the same time window, only the last value is persisted. **Use gauges when** you want to know the current state of something — the number of items that exist right now, or the current size of a resource. All AppSignal [host metrics](/metrics/host-metrics) are stored as gauges. Gauges are often used with [minutely probes](/ruby/instrumentation/minutely-probes) to periodically report a snapshot value, such as querying the number of recently active shopping carts or open database connections every minute. **Examples:** active user count, database size, disk usage, number of open connections. ```ruby Ruby theme={null} # The first argument is a string, the second argument a number # Appsignal.set_gauge(metric_name, value) Appsignal.set_gauge("database_size", 100) Appsignal.set_gauge("database_size", 10) # Will create the metric "database_size" with the value 10 ``` ```elixir Elixir theme={null} # The first argument is a string, the second argument a number # Appsignal.set_gauge(metric_name, value) Appsignal.set_gauge("database_size", 100) Appsignal.set_gauge("database_size", 10) # Will create the metric "database_size" with the value 10 ``` ```javascript Node.js theme={null} const meter = Appsignal.client.metrics(); // The first argument is a string, the second argument a number // meter.setGauge(metric_name, value) meter.setGauge("database_size", 100); meter.setGauge("database_size", 10); // Will create the metric "database_size" with the value 10 ``` ```python Python theme={null} # Import the AppSignal metric helper from appsignal import set_gauge # The first argument is a string, the second argument a number (int/float) # set_gauge(metric_name, value) set_gauge("database_size", 100) set_gauge("database_size", 10) # Will create the metric named "database_size" with the value 10 ``` ```php PHP theme={null} [!TIP] > > Starting from version 3.1.0, the Node.js integration allows you to set gauges and counters using the OpenTelemetry metrics provider. You must enable the agent's OpenTelemetry HTTP server to report these metrics to AppSignal; you can do this by setting the [enableOpentelemetryHttp](/nodejs/3.x/configuration/options#option-enableopentelemetryhttp) option to `true`. > > The Java and Go integrations also use OpenTelemetry metrics to report custom metrics to AppSignal. > > You can read more about OpenTelemetry metrics in the [OpenTelemetry metrics documentation](https://opentelemetry.io/docs/concepts/metrics/). For Node.js, see the [OpenTelemetry JS metrics documentation](https://opentelemetry.io/docs/languages/js/instrumentation/#metrics) for more information. ### Measurement A measurement tracks a spread of values over time. AppSignal stores the average and count for each time window, letting you graph things like average duration, 90th/95th percentile, and throughput. **Use measurements when** you are recording a value that varies across individual events and you want to understand its distribution — not just its current value. For example, you can track the duration of a critical background job (such as order confirmation emails) to spot slowdowns before they affect your users. A measurement metric creates several metric fields: * **Count:** how many times the helper was called. Useful for throughput graphs. * **Mean:** the average metric value for the point in time. * **90th percentile:** the 90th percentile of the metric value for the point in time. * **95th percentile:** the 95th percentile of the metric value for the point in time. **Examples:** HTTP response times, background job durations, user cart values, query execution times. ```ruby Ruby theme={null} # The first argument is a string, the second argument a number # Appsignal.add_distribution_value(metric_name, value) Appsignal.add_distribution_value("memory_usage", 100) Appsignal.add_distribution_value("memory_usage", 110) # Will create a metric "memory_usage" with the mean field value 105 # Will create a metric "memory_usage" with the count field value 2 ``` ```elixir Elixir theme={null} # The first argument is a string, the second argument a number # Appsignal.add_distribution_value(metric_name, value) Appsignal.add_distribution_value("memory_usage", 100) Appsignal.add_distribution_value("memory_usage", 110) # Will create a metric "memory_usage" with the mean field value 105 # Will create a metric "memory_usage" with the count field value 2 ``` ```javascript JavaScript theme={null} const meter = Appsignal.client.metrics(); // The first argument is a string, the second argument a number // meter.addDistributionValue(metric_name, value) meter.addDistributionValue("memory_usage", 100); meter.addDistributionValue("memory_usage", 110); // Will create a metric "memory_usage" with the mean field value 105 // Will create a metric "memory_usage" with the count field value 2 ``` ```python Python theme={null} # Import the AppSignal metric helper from appsignal import add_distribution_value # The first argument is a string, the second argument a number (int/float) # add_distribution_value(metric_name, value) add_distribution_value("memory_usage", 100) add_distribution_value("memory_usage", 110) # Will create a metric "memory_usage" with the mean field value 105 # Will create a metric "memory_usage" with the count field value 2 ``` ```php PHP theme={null} [!TIP] > > **Gauge vs. Counter:** Use a gauge to track *how many of something exist right > now* (e.g., currently active users). Use a counter to track *how many times > something happened* in a given period (e.g., new logins in the last minute). ```ruby Ruby theme={null} # The first argument is a string, the second argument a number # Appsignal.increment_counter(metric_name, value) Appsignal.increment_counter("login_count", 1) Appsignal.increment_counter("login_count", 1) # Will create the metric "login_count" with the value 2 for a point in the minutely/hourly resolution ``` ```elixir Elixir theme={null} # The first argument is a string, the second argument a number # Appsignal.increment_counter(metric_name, value) Appsignal.increment_counter("login_count", 1) Appsignal.increment_counter("login_count", 1) # Will create the metric "login_count" with the value 2 for a point in the minutely/hourly resolution ``` ```javascript JavaScript theme={null} const meter = Appsignal.client.metrics(); // The first argument is a string, the second argument a number // meter.incrementCounter(metric_name, value) meter.incrementCounter("login_count", 1); meter.incrementCounter("login_count", 1); // Will create the metric "login_count" with the value 2 for a point in the minutely/hourly resolution ``` ```python Python theme={null} # Import the AppSignal metric helper from appsignal import increment_counter # The first argument is a string, the second argument a number (int/float) # increment_counter(metric_name, value) increment_counter("metric_name", 1) # Increase the value by one increment_counter("metric_name", 1) increment_counter("metric_name", -1) # Decrease the value by one # Will create the metric named "metric_name" with the value 2 for a point in the minutely/hourly resolution ``` ```php PHP theme={null} [!WARNING] > > **Note**: In AppSignal, counters are designed to store integer values only. > While the API accepts float values to facilitate integration, these values are internally converted to integers. > > Decimal values are rounded down to the nearest integer. > The value 0.0001 becomes 0, and 1.2, 1.5, and 1.7 become 1. ## Metric naming We recommend naming your metrics something easily recognizable that describes what you measure, such as `checkout_duration` or `invoice_count`. While you can wildcard parts of the metric name for dashboard creation, we recommend you only use this for small grouping. Do not put IDs, email addresses, URLs, or customer names in metric names. Each distinct value creates a separate metric, which makes graphs hard to read and queries slow. Metric names only support numbers, letters, dots and underscores (`[a-z0-9._]`) as valid characters. Any other characters will be replaced with an underscore by our processor. You can find the list of metrics as processed on the ["Add Dashboard"](https://appsignal.com/redirect-to/app?to=dashboard\&overlay=dashboardForm). Some examples of good metric names are: * `database_size` * `account_count` * `users.count` * `notifier.failed` * `notifier.perform` * `notifier.success` By default AppSignal already tracks metrics for your application, such as [host metrics](/metrics/host-metrics). See the metrics list on the ["Add Dashboard"](https://appsignal.com/redirect-to/app?to=dashboard\&overlay=dashboardForm) page for the metrics that are already available for your app. > [!WARNING] > > **Note**: We **do not** recommend adding dynamic values to your metric names > like so: `eu.database_size`, `us.database_size` and `asia.database_size`. This > creates multiple metrics that serve the same purpose. Instead we recommend > using [metric tags](#metric-tags) for this. ## Metric values Metrics only support numbers as valid values. Any other value will be silently ignored or will raise an error as triggered by the implementation language number parser. For Ruby and Elixir we support a [double](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) and [integer](https://en.wikipedia.org/wiki/Integer) as valid values: ```ruby Ruby theme={null} # Integer Appsignal.increment_counter("login_count", 1) # Double Appsignal.increment_counter("assignment_completed", 0.12) ``` ```elixir Elixir theme={null} # Integer Appsignal.increment_counter("login_count", 1) # Double Appsignal.increment_counter("assignment_completed", 0.12) ``` ```javascript JavaScript theme={null} const meter = Appsignal.client.metrics(); // Integer meter.incrementCounter("login_count", 1); // Double meter.incrementCounter("assignment_completed", 0.12); ``` ```python Python theme={null} from appsignal import increment_counter # Integer increment_counter("login_count", 1) # Double increment_counter("assignment_completed", 0.12) ``` ```php PHP theme={null} [!TIP] > > Custom metric tags require the following AppSignal package/gem version or > higher: > >
    >
  • Ruby gem version `2.6.0`
  • >
  • Elixir package `1.6.0`
  • >
  • Node.js package `1.0.0`
  • >
  • Python package `0.3.0`
  • >
A single metric can consist of various groups of data; for example, a 'total\_orders' custom metric could consist of pending and processed orders. You can add multiple tags to metrics for deeper insights into the metric data AppSignal is reporting. Each tag will be represented by its line on an AppSignal graph. By default, the AppSignal metric helpers do not set tags on a custom metric. How you can use tags in AppSignal graphs: Tags can "label" a line in the graph legend, making it easier to see what each line represents when you hover your mouse over them. Filtering with tags can show the same metric in different contexts on different graphs. To get the most out of metric tags, we advise the following: * **Be consistent with tagging:** For optimal tracking and graph legibility, we advise against reporting a custom metric both with and without tags. Reporting the same metric in different ways can create confusion and make it difficult to interpret the data accurately. The exception is a metric with high-cardinality tags. Report it without tags too, so its total is a single series that stays within the [query limits](/api/v2/metrics#high-cardinality-custom-metrics). See [Rendering metric with and without tags](#rendering-metric-with-and-without-tags). * **Always use the same metric tags when:** We recommend using the same combination of tags whenever you report a metric. For example, if a metric uses tags A and B in one area of your app, it should use them in all areas. Avoid changing the tags, as consistent tagging will make graphing easier. * **Use a limited range of values for metric tags:** To avoid overly complex or illegible graphs, we recommend using a limited range of tags on your custom metrics, such as regions (EU, US, and Asia), plans, or worker queues. You can perform a broader analysis of your app's metric data when using a limited and precise range of tags for all of your app metric data. Avoid high-cardinality tags, which have many distinct values, such as a user ID, request ID, or full URL. In general when implementing metric tagging, consider developing a robust tagging strategy that can be applied consistently across your application and will need little to no adjustments in the long term. > [!WARNING] > > AppSignal stores each unique combination of tag values as a separate series. A tag like `order_id` creates a new one for almost every event, which gives the metric high cardinality. Past the [per-minute limit](/faq#why-are-my-custom-metrics-being-dropped), AppSignal drops some series. [Querying high-cardinality metrics through the API](/api/v2/metrics#high-cardinality-custom-metrics) can also return partial results. The [Limits](/application/limits) page shows which metrics have the most combinations in the last minute. ```ruby Ruby theme={null} Appsignal.set_gauge("database_size", 100, :region => "eu") Appsignal.set_gauge("database_size", 50, :region => "us") Appsignal.set_gauge("database_size", 200, :region => "asia") # Multiple tags per metric Appsignal.set_gauge("my_metric_name", 100, :tag_a => "a", :tag_b => "b") Appsignal.set_gauge("my_metric_name", 10, :tag_a => "a", :tag_b => "b") Appsignal.set_gauge("my_metric_name", 200, :tag_a => "b", :tag_b => "c") ``` ```elixir Elixir theme={null} Appsignal.set_gauge("database_size", 100, %{region: "eu"}) Appsignal.set_gauge("database_size", 50, %{region: "us"}) Appsignal.set_gauge("database_size", 200, %{region: "asia"}) # Multiple tags per metric Appsignal.set_gauge("my_metric_name", 100, %{tag_a: "a", tag_b: "b"}) Appsignal.set_gauge("my_metric_name", 10, %{tag_a: "a", tag_b: "b"}) Appsignal.set_gauge("my_metric_name", 200, %{tag_a: "b", tag_b: "c"}) ``` ```javascript JavaScript theme={null} const meter = Appsignal.client.metrics(); meter.setGauge("database_size", 100, { region: "eu" }); meter.setGauge("database_size", 50, { region: "us" }); meter.setGauge("database_size", 200, { region: "asia" }); // Multiple tags per metric meter.setGauge("my_metric_name", 100, { tag_a: "a", tag_b: "b" }); meter.setGauge("my_metric_name", 10, { tag_a: "a", tag_b: "b" }); meter.setGauge("my_metric_name", 200, { tag_a: "b", tag_b: "c" }); ``` ```python Python theme={null} from appsignal import set_gauge set_gauge("database_size", 100, {"region": "eu"}) set_gauge("database_size", 50, {"region": "us"}) set_gauge("database_size", 200, {"region": "asia"}) # Multiple tags per metric set_gauge("my_metric_name", 100, {"tag_a": "a", "tag_b": "b"}) set_gauge("my_metric_name", 10, {"tag_a": "a", "tag_b": "b"}) set_gauge("my_metric_name", 200, {"tag_a": "b", "tag_b": "c"}) ``` ```php PHP theme={null} 'eu']); Appsignal::setGauge('database_size', 50, ['region' => 'us']); Appsignal::setGauge('database_size', 200, ['region' => 'asia']); // Multiple tags per metric Appsignal::setGauge('my_metric_name', 100, ['tag_a' => 'a', 'tag_b' => 'b']); Appsignal::setGauge('my_metric_name', 10, ['tag_a' => 'a', 'tag_b' => 'b']); Appsignal::setGauge('my_metric_name', 200, ['tag_a' => 'b', 'tag_b' => 'c']); ``` ```java Java theme={null} import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.DoubleGauge; import io.opentelemetry.api.metrics.Meter; public void recordTaggedMetrics() { Meter meter = GlobalOpenTelemetry.getMeter("my-app"); DoubleGauge gauge = meter.gaugeBuilder("database_size").build(); // Record gauge values with attributes (tags) gauge.set(100, Attributes.of( AttributeKey.stringKey("region"), "eu" )); gauge.set(50, Attributes.of( AttributeKey.stringKey("region"), "us" )); gauge.set(200, Attributes.of( AttributeKey.stringKey("region"), "asia" )); // Multiple tags per metric DoubleGauge myGauge = meter.gaugeBuilder("my_metric_name").build(); myGauge.set(100, Attributes.of( AttributeKey.stringKey("tag_a"), "a", AttributeKey.stringKey("tag_b"), "b" )); myGauge.set(10, Attributes.of( AttributeKey.stringKey("tag_a"), "a", AttributeKey.stringKey("tag_b"), "b" )); myGauge.set(200, Attributes.of( AttributeKey.stringKey("tag_a"), "b", AttributeKey.stringKey("tag_b"), "c" )); } ``` ```go Go theme={null} package main import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) func recordTaggedMetrics() { meter := otel.Meter("my-app") gauge, _ := meter.Float64Gauge("database_size") // Record gauge values with attributes (tags) gauge.Record(context.Background(), 100, metric.WithAttributes( attribute.String("region", "eu"), )) gauge.Record(context.Background(), 50, metric.WithAttributes( attribute.String("region", "us"), )) gauge.Record(context.Background(), 200, metric.WithAttributes( attribute.String("region", "asia"), )) // Multiple tags per metric myGauge, _ := meter.Float64Gauge("my_metric_name") myGauge.Record(context.Background(), 100, metric.WithAttributes( attribute.String("tag_a", "a"), attribute.String("tag_b", "b"), )) myGauge.Record(context.Background(), 10, metric.WithAttributes( attribute.String("tag_a", "a"), attribute.String("tag_b", "b"), )) myGauge.Record(context.Background(), 200, metric.WithAttributes( attribute.String("tag_a", "b"), attribute.String("tag_b", "c"), )) } ``` ## Rendering metric with and without tags If you created a custom metric and you have multiple tags associated with it, you can render the metric with and without the tag at the same time in a graph. ```ruby Ruby theme={null} Appsignal.increment_counter("sign_ups", 1, region: "eu") Appsignal.increment_counter("sign_ups", 1) ``` ```elixir Elixir theme={null} Appsignal.increment_counter("sign_ups", 1, %{region: "eu"}) Appsignal.increment_counter("sign_ups", 1) ``` ```javascript JavaScript theme={null} const meter = Appsignal.client.metrics(); meter.incrementCounter("sign_ups", 1, { region: "eu" }); meter.incrementCounter("sign_ups", 1); ``` ```python Python theme={null} from appsignal import increment_counter increment_counter("sign_ups", 1, {"region": "eu"}) increment_counter("sign_ups", 1) ``` ```php PHP theme={null} 'eu']); Appsignal::incrementCounter('sign_ups', 1); ``` ```java Java theme={null} import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; public void recordMixedMetrics() { Meter meter = GlobalOpenTelemetry.getMeter("my-app"); LongCounter counter = meter.counterBuilder("sign_ups").build(); counter.add(1, Attributes.of( AttributeKey.stringKey("region"), "eu" )); counter.add(1); } ``` ```go Go theme={null} package main import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) func recordMixedMetrics() { meter := otel.Meter("my-app") counter, _ := meter.Int64Counter("sign_ups") counter.Add(context.Background(), 1, metric.WithAttributes( attribute.String("region", "eu"), )) counter.Add(context.Background(), 1) } ``` ## Graphing Custom Metrics Once you've started recording custom metrics, you can track them in custom graphs using the Graph Builder. Navigate to an existing dashboard or use the "Add dashboard" button in the Dashboard navigation to create a new one, then click "Add graph". ![Graph Builder](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/metrics/custom/graph-builder.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=095f9711aa9531e138596c955b6a81c2) When creating a graph, you can select which metrics and tags you want to chart and configure your graph's legends and labels. Once created, the graph will be added to the dashboard and display all recorded custom metric data for the specified period of time. You can read more about dashboards and graphs in our [Dashboard documentation](/metrics/dashboards). # Dashboards Source: https://docs.appsignal.com/metrics/dashboards Custom dashboards built from any metric your app reports, and how number, line, and area charts handle NULL values. This page provides more detailed information about how some dashboard charts options work. For all other options, please see the help icon with attached tooltip for more information. AppSignal has two kinds of dashboard: * **Custom dashboards** that you build. Select **Add dashboard** in the app's sidebar to create one, then **Add chart** to add charts to it. Any metric your app reports can go on a chart, including [custom metrics](/metrics/custom), and the **Metric** field suggests the names your app currently reports. * **[Intelligence dashboards](/metrics/intelligence-dashboards)** that AppSignal creates the first time it recognizes metrics from a supported integration, such as Sidekiq, NGINX, Kubernetes, or an AWS service. They carry an **Intelligence** badge, and when AppSignal improves one, the dashboard offers you the [update](/metrics/intelligence-dashboards#dashboard-updates). [Open the dashboard and chart builder](https://appsignal.com/redirect-to/app?to=dashboard\&overlay=dashboardForm) in your app. ## Charts types Some data is better understood if the chart is rendered in a different way. We provide the following display options: * Number chart * Line graph * Area graph * Relative area graph Charts load their data from the [Public API (V2)](/api/v2/metrics#high-cardinality-custom-metrics). A chart shows at most 100 series, counting each field separately, and does not indicate when series are left out. ### Number chart The number chart, also called a Big Number, shows the value of a metric as a large number. This is useful for metrics that represent a single value, such as error count or request count. ![Big Number Value chart example](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/big-number-value-chart.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=e0154ecd303f043a66f54cf025e38506) A number chart takes one metric and one aggregation across the time range selected on the dashboard or preview: * **Metric** — The metric name to be shown in this chart. Use the full metric name to select one metric, or a wildcard (`*`) to select several at once: `db_users_document_count`, `db_*_size`. See [metric naming](/metrics/custom#metric-naming) for the full rules. * **Aggregation type** — How the value on the chart is selected or calculated from the metric data in the selected time frame: * `Maximum value` — the highest metric value * `Minimum value` — the lowest metric value * `Average value` — the average of the metric values * `Total value` — the combined value of the metric values * `First value` — the first metric value * `Last value` — the last metric value * **Data format** — The value format used to display values in the chart and chart legends. See [value formatting](/metrics/custom#metric-values-value-formatting) for the available formats. * **Tags** *(optional)* — Which tags of the metric to display in the chart. When empty, every variation of a tag gets its own entry. Enter tags to filter for certain tag values; in that case, all tags of the metric need to be specified, either with a value or a wildcard. See [metric tags](/metrics/custom#metric-tags) for the full reference. ![Number chart setup in the chart builder](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/mcp/mcp-big-number-config.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=8d2c96289e2b0b5ac01538922ba70f31) You can also create a number chart from an AI agent instead of the chart builder. See [`create_dashboard_visual`](/mcp/reference#create_dashboard_visual) in the MCP tool reference. ### Line, area, and relative area graphs When selecting the "Line graph", the default graph type is "Line graph". Use "Area graph" to render areas beneath the lines and "Relative area graph" to render a graph with the relative values of each data point. This renders a percentage for each data point from 0–100 and fills out the graph accordingly. This can be used to easily show the relation between data points in a graph. The image below shows the same metric in all three graph types. In the Line and Area graph you can see that the amount of data has increased, but the Relative area graph at the bottom shows that the relation between transmitted/received has not changed over time. ![Graph display example](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/custom_metrics_graph_display.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=a4ff4e1a677efdeace84292d21268278) ## NULL values Not always does every point in time have a value for a metric, yet the value is not `0`. In our system we do not record a value for this time and treat this point as `NULL` rather than `0`. This means no value is present and can be interpreted in two ways. Either it was actually `0` or it retains the value of the last known data point in the graph. The "NULL values" option ("Draw NULL as 0" by default) allows for the configuration of the draw behavior for a graph. If set to "Draw NULL as 0" it will treat the `NULL` value as `0`. If set to "Repeat last known value" it will repeat the last known value until a later point in time specifies a new value. See the difference in the graph below. With "Draw NULL as 0" the graph makes a sharp drop to `0` every time the app stopped reporting data. With "Repeat last known value" the graph looks less volatile in terms of lines moving up and down. ![Draw NULL as 0 option graph comparison screenshot](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/draw_null_as_zero.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=05980225ab9c14c071b212646611b395) The app used to generate these graphs: ```ruby Ruby theme={null} # app.rb # gem install "appsignal" require "appsignal" Appsignal.configure("development") do |config| config.active = true config.name = "My app" config.push_api_key = "00000000-0000-0000-0000-000000000000" end Appsignal.start [ [5, 1], [7, 1], [3, 3], [5, 2], [2, 5], [10, 2], [8, 1], [4, 2] ].each do |(value, pause)| puts "set_gauge random_number #{value}" Appsignal.set_gauge("random_numbers", value) pause_in_minutes = pause * 60 puts "Sleeping #{pause} minute(s)" sleep pause_in_minutes end Appsignal.stop ``` # Host metrics Source: https://docs.appsignal.com/metrics/host-metrics The AppSignal agent collects various system metrics, which allows you to correlate performance issues and errors to abnormal host metrics. This data is available in the [Host metrics](https://appsignal.com/redirect-to/app?to=host_metrics) section in the app overview, which allows you to inspect and [compare multiple hosts](https://blog.appsignal.com/2018/02/20/comparing-hosts.html). We also show a host metrics overview on the trace detail page. For a preview of how host metrics look in the AppSignal interface, please see our [host metrics](https://www.appsignal.com/tour/hosts) tour page. > [!TIP] > > **Note**: This feature is available in these packages: > > * Ruby: gem version `1.2` and newer. Enabled by default since version `1.3`. > * Elixir: package version `0.10.0` and newer. Enabled by default since > version `0.10.0`. > * Node.js: all package versions. > * JavaScript for Front-end: none package versions. > [!TIP] > > **Note**: This feature is not available on the following architectures: > > * macOS/OSX (`darwin`) > * FreeBSD > > A list of supported Operating Systems is available on the [Supported > Operating Systems](/support/operating-systems) page. ## Collected host metrics The following host metrics are collected by the AppSignal agent for every minute on your system. | Metric | Description | | - | - | | CPU usage | User, nice, system, idle and iowait in percentages. Read more about [CPU metrics](https://blog.appsignal.com/2018/03/06/understanding-cpu-statistics.html)  in our academy article. | | Load average | 1 minute load average on the host. | | Memory usage | Available, free and used memory. Also includes swap total and swap used. | | Disk usage | Percentage of every disk used. | | Disk I/O | Throughput of data read from and written to every disk. | | Network traffic | Throughput of data received and transmitted through every network interface. | These host metrics are collected by default. To disable it, use the `enable_host_metrics` configuration option, for: * [Ruby](/ruby/configuration/options#option-enable_host_metrics) * [Elixir](/elixir/configuration/options#option-enable_host_metrics) * [Node.js](/nodejs/3.x/configuration/options#option-enablehostmetrics) * [Python](/python/configuration/options#option-enable_host_metrics) * [Collector](/collector/configuration/options#option-enable_host_metrics) for [OpenTelemetry](/opentelemetry) * [Standalone agent](/standalone-agent/configuration/options#option-enable_host_metrics) ### Environment metadata The AppSignal agent reports the following information of the host. Once received this metadata is shown on the [host metrics index page](https://appsignal.com/redirect-to/app?to=host_metrics) per host to provide more detail of all hosts running an app. Use this metadata to spot any differences between hosts that could cause differences in behavior. * Host architecture, 32 or 64-bit. * Operating System, either Linux, macOS or Windows. * Operating System Distribution, for Linux this reports Ubuntu, Fedora, etc. * Operating System version, the version of the Operating System. * Kernel version, for Linux this reports the installed kernel version. This metadata is collected by default. To disable it, use the `send_environment_metadata` configuration option, for: * [Ruby](/ruby/configuration/options#option-send_environment_metadata) * [Elixir](/elixir/configuration/options#option-send_environment_metadata) * [Node.js](/nodejs/3.x/configuration/options#option-sendenvironmentmetadata) * [Python](/python/configuration/options#option-send_environment_metadata) ## Heroku support To use host metrics on Heroku, head to the [Heroku host metrics][heroku support] page. ## Render support To use host metrics on Render, head to the [Render host metrics][render support] page. ## Docker/container support To use host metrics on (Docker) containers, head to the [container host metrics](/metrics/host-metrics/containers) page. ## Dokku support > [!TIP] > > **Note**: Dokku support is available in packages Ruby gem 3.0.13, Elixir > package 2.2.0, Node.js package 2.0.0 and newer. [Dokku](https://github.com/dokku/dokku) has host metrics enabled by default as long as your Dokku application has the `DOKKU_ROOT` environment variable set up. [heroku support]: /heroku/host-metrics.html [render support]: /render/host-metrics [container support]: /metrics/host-metrics/containers.html # Container host metrics Source: https://docs.appsignal.com/metrics/host-metrics/containers Host metrics for containerized systems are fully supported. > [!WARNING] > > **Warning**: To get accurate metrics from your containers, container limits > are required for your monitored containers. See the [container > limits](#container-limits) section for more information. > [!TIP] > > **Note**: While Heroku also runs on a containerized system (LXC), we do not > support host metrics in the same way. Instead, please see the \[Heroku > support]\[heroku support] section. > [!TIP] > > **Note**: This page is part of the [host metrics > section](/metrics/host-metrics). ## Container limits For container host metrics to be accurate, limits need to be set for every container. This means, configuring your container to have a limited number of CPUs and memory allocated to it. Without these limits the container reports the maximum possible value of these metrics, resulting in the host reporting Terabytes of available memory for example. A container without swap configured, or unsupported on the host system, will report a `0` value. For more information on how to limit your container's CPU and memory, please read the documentation on: * Docker * [CPU](https://docs.docker.com/config/containers/resource_constraints/#cpu) * [memory](https://docs.docker.com/config/containers/resource_constraints/#memory) * Kubernetes * [CPU](https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/) * [memory](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/) ## Supported metrics On systems that expose the `/sys/fs` virtual file system the following metrics are supported. | Metric | Description | | - | - | | CPU usage | User and system in percentages. Read more about [CPU metrics](https://blog.appsignal.com/2018/03/06/understanding-cpu-statistics.html)  in our academy article. | | Load average | 1 minute load average on the host. | | Memory usage | Available, free and used memory. Also includes swap total and swap used. | | Disk usage | Percentage of every disk used. | | Disk IO | Throughput of data read from and written to every disk. | | Network traffic | Throughput of data received and transmitted through every network interface. | ### About CPU metrics In short: * AppSignal reports the same metrics as the [`docker stats`](https://docs.docker.com/engine/reference/commandline/stats/) command, but reported as an average on a minutely basis. * The reported CPU usage can go above 100%. 100% is equal to 1 full virtual CPU core. * [Container limits](#container-limits) are recommended to properly balance the available CPU resources between containers. * When multiple containers on the same host system share CPU resources, even with [container limits](#container-limits), containers that use more CPU can negatively impact the reported CPU usage for other containers. The container CPU metrics work a little differently than [normal CPU metrics](/metrics/host-metrics). They are affected by [container limits](#container-limits) and how many other containers are active on the system. This is because they share the container system's resources. Unlike normal host metrics the CPU usage can go above 100%. This is because a container can have more than 1 virtual CPU core available to it. Every full core amounts to 100%. If a container has three cores for example, the maximum is 300%. Other containers on the system can impact the total CPU time available to the container. [Limits](#container-limits) will help maintain a better balance of CPU usage between containers so the averages fluctuate less depending on busy neighbors. If all containers share all the host system's CPU resources, the usage on one host can negatively impact the available virtual CPU cores on another. For example: We have a Docker system on our host machine that has 3 virtual CPU cores available. We then start containers A, B and C without any specific CPU limits. * In the scenario of container A maxing out its available CPU cores, and the other containers B and C idling at 0%, it will be reported as 300% CPU usage for container A. Which is the total CPU time available on the host's container system. * When the three containers are all maxing out their available CPU cores it will be reported as 100% CPU usage for every container, as the resources are shared amongst them evenly. [heroku support]: /heroku/host-metrics.html # Intelligence dashboards Source: https://docs.appsignal.com/metrics/intelligence-dashboards AppSignal creates Intelligence dashboards when it detects metrics from a supported integration. Lists every dashboard by integration. AppSignal automatically creates dashboards when it detects metrics from a supported integration. These Intelligence dashboards give you pre-built charts for the most important metrics of each integration, without any manual setup. Dashboards you build and arrange yourself are covered in [dashboards](/metrics/dashboards). Intelligence dashboards appear in the **Dashboards** section of your app. They are created the first time AppSignal receives metrics from a supported source. If you remove the integration or stop sending the metrics, the dashboard stays in place so you can reference historical data. ## How Intelligence dashboards work Each integration sends specific metrics to AppSignal. When AppSignal receives the trigger metric of a known integration, it creates a dashboard with charts tailored to that integration. Dashboards are created per app environment, so a staging and a production environment each get their own. An Intelligence dashboard carries an **Intelligence** badge in its header. In the sidebar, a wand icon marks a type of Intelligence dashboard you have not opened yet. Dashboards that are still being refined carry a **beta** badge as well; their charts and metrics may change. The first time AppSignal creates a type of dashboard for you, it emails the members of the app. You can turn these emails off in your [notification settings](https://appsignal.com/users/notifications). Dashboards are designed to answer common operational questions quickly. Health and error indicators appear first, followed by resource utilization, then operational context. Chart descriptions explain what values indicate a problem and what to do about it. ## Customizing an Intelligence dashboard An Intelligence dashboard works like any other dashboard. You can add charts, edit the existing ones, rename it, and delete it. Renaming does not count as a customization. Deleting an Intelligence dashboard is permanent for that app environment. AppSignal does not create it again when it sees the metrics later. ## Dashboard updates AppSignal improves Intelligence dashboards over time: charts are added, metrics change, and descriptions are refined. When a newer version of a dashboard is available, the dashboard shows the message **A dashboard update is available** with three options: * **Update this dashboard** replaces the charts with the latest version. Any customizations you made are overwritten; the dashboard's name is kept. * **Create a new dashboard instead** creates a fresh Intelligence dashboard next to your current one. Your current dashboard keeps its charts, gets a "(custom)" suffix, and no longer receives updates. * **Skip for now** hides the message until the next version is available. ## Available Intelligence dashboards Intelligence dashboards are available for the following integrations, grouped by category. Each link leads to the integration's setup instructions and dashboard details. ### AWS CloudWatch AppSignal supports 46 Intelligence dashboards for AWS services through [CloudWatch Metric Streams](/metrics/cloudwatch-overview). Each AWS service gets its own dashboard with charts ordered by urgency of signal. Services with more than one flavor, such as EKS, ElastiCache, and Amazon MQ, get one dashboard per flavor. An **AWS/CloudWatch** dashboard tracks the health of the metric stream itself: metric updates sent and the publish error rate. These dashboards currently carry the **beta** badge. See [AWS Intelligence dashboards](/metrics/aws-dashboards) for the full list of supported services and their charts. ### Ruby The following integrations create Intelligence dashboards when AppSignal detects their metrics in a Ruby app: * [Active Job](/ruby/integrations/active-job#intelligence-dashboard) — job duration, job status per queue, and throughput per job class. * [Sidekiq](/ruby/integrations/sidekiq#intelligence-dashboard) — worker duration, queue latency, queue length, job status, Redis memory usage, and connection counts. * [Puma](/ruby/integrations/puma#intelligence-dashboard) — thread pool capacity, connection backlog, and worker status. * [MongoDB](/ruby/integrations/mongodb#intelligence-dashboard) — query throughput and query duration per database. * [Ruby VM](/ruby/integrations/ruby-vm#intelligence-dashboards) — garbage collection counts and time, heap slots, allocated objects, Ruby VM statistics, and thread count. * [Global VM Lock](/ruby/integrations/global-vm-lock#intelligence-dashboards) — GVL wait time and waiting thread count. * Action Mailer — deliveries per mailer and action, as a total and as a percentage of all deliveries. * Karafka — consumed messages and batches, lag, errors and dead letter queue, connection stability, and process and thread counts. ### Elixir * [Oban](/elixir/integrations/oban#metrics) — job duration, queue wait time, and job counts broken down by worker, queue, and status. * [Ecto](/elixir/integrations/ecto#metrics) — query time, throughput, total time, decode time, queue time, and idle time per repo. * [Erlang VM](/elixir/integrations/erlang#intelligence-dashboard) — I/O, schedulers, processes, memory, atoms, scheduler utilization, and run queue length. ### Node.js * [Heap statistics](/nodejs/3.x/integrations/core#heap-statistics-minutely-probe) — V8 heap size, used heap, malloced memory, and native and detached context counts. ### General * Process Memory — average and 95th percentile RSS memory usage per host and process type. Available for Ruby and Elixir apps. ### Infrastructure * [NGINX](/metrics/nginx#intelligence-dashboard) — request time, throughput, status codes, connections, and upstream proxy metrics. * [Kubernetes](/metrics/kubernetes-0.x) — two dashboards: node CPU, memory, swap, disk, inodes, and network; pod CPU, memory, and swap. Only AppSignal for Kubernetes 0.x creates these dashboards. Version 1.x shows node and pod metrics on the [Cluster Metrics](/kubernetes/metrics#cluster-metrics) page instead. ### Heroku Heroku creates several Intelligence dashboards from Log Drain or Telemetry Drain data: * [Status codes](/heroku/dashboards#status-code-dashboard) — HTTP status code breakdown (Cedar generation only). * [Redis](/heroku/dashboards#redis-dashboard) — connections, hit rate, evictions, memory, load average, and I/O. * [PostgreSQL](/heroku/dashboards#postgresql-dashboard) — database size, connections, cache hit rates, memory, load average, I/O, WAL usage, and follower lag (Standard and Premium plans). ### Render Render creates Intelligence dashboards from a [Metrics Stream](/render/setup): * [HTTP](/render/dashboards#http-dashboard) — request volume and latency per service. * [Postgres](/render/dashboards#postgres-dashboard) — connections, storage size, transactions, table scans, locks, and replication lag. * [Key Value](/render/dashboards#key-value-dashboard) — connections against the connection limit. ### Vector AppSignal creates dashboards from metrics collected through [Vector](/vector) sources: * [PostgreSQL](/vector/postgresql) — row operations, transactions, deadlocks, connected backends, and temporary file writes. * [MongoDB](/vector/mongodb) — three dashboards covering status (memory, connections, operations), WiredTiger storage engine internals, and replication health. ### Vercel * [Speed Insights](/vercel/speed-insights) — the Web Vitals dashboard: TTFB, FCP, LCP, FID, and CLS from real-user measurements. # NGINX metrics Source: https://docs.appsignal.com/metrics/nginx The AppSignal integrations and the AppSignal stand-alone agent can generate metrics from your NGINX server's access logs. After configuring your NGINX server to send metrics to AppSignal, a Intelligence dashboard with metrics related to your NGINX server will appear. ## Configuring AppSignal First, you must configure your AppSignal integration or stand-alone agent to receive metrics from NGINX. > [!TIP] > > Enabling NGINX metrics will open a server for NGINX to send metrics to. By default, this server is bound to `localhost` and listens on port `27649`. You can modify these settings using the `bind_address` and `nginx_port` configuration options. > > If you are running several AppSignal-instrumented applications at a time in the same server, you can configure each application to listen on a different port using the `nginx_port` configuration option. If you configure your AppSignal integration with environment variables, you must set `APPSIGNAL_ENABLE_NGINX_METRICS` to true. If you configure your AppSignal integration with configuration files, or you use the stand-alone agent, you can follow the relevant instructions below on how to enable NGINX metrics for your application: * [Ruby configuration](#ruby) * [Elixir configuration](#elixir) * [Node.js configuration](#nodejs) * [Stand-alone Agent configuration](#stand-alone-agent) ### Ruby > [!TIP] > > Support for NGINX metrics was added in version `3.3.4` of the Ruby > integration. Add `enable_nginx_metrics: true` to the desired environment in your application's`config/appsignal.yml` file, for example the production environment: ```yaml YAML theme={null} production: enable_nginx_metrics: true # ... ``` ### Elixir > [!TIP] > > Support for NGINX metrics was added in version `2.5.2` of the Elixir > integration. Add `enable_nginx_metrics: true` to your AppSignal configuration block, usually located at `config/config.exs`: ```elixir Elixir theme={null} config :appsignal, :config, enable_nginx_metrics: true, # ... ``` ### Node.js > [!TIP] > > Support for NGINX metrics was added in version `3.0.8` of the Node.js > integration. Add `enableNginxMetrics: true` to your `appsignal.cjs` file: ```javascript Node.js theme={null} new Appsignal({ enableNginxMetrics: true, // ... }); ``` ### Stand-alone agent > [!TIP] > > Support for NGINX metrics was added in version `0.0.24` of the stand-alone > agent. Add `enable_nginx_metrics = true` to your `/etc/appsignal-agent.conf` configuration file: ```toml TOML theme={null} enable_nginx_metrics = true ``` ## Configuring NGINX The next step is configuring your NGINX server to send metrics to AppSignal. In most Linux distributions, the default NGINX configuration will include configuration files from a configuration folder, often located in `/etc/nginx/conf.d`. Save the following configuration to that folder as `appsignal-metrics.conf`: ```nginx NGINX theme={null} map '' $appsignal_group { default 'http'; } log_format appsignal_metrics '1|g=$appsignal_group;s=$status;rqt=$request_time;rql=$request_length;bs=$bytes_sent;ua=$upstream_addr;uct=$upstream_connect_time;uht=$upstream_header_time;urst=$upstream_response_time;us=$upstream_status;ucs=$upstream_cache_status;ca=$connections_active;cr=$connections_reading;cwr=$connections_writing;cwa=$connections_waiting'; access_log syslog:server=127.0.0.1:27649,tag=appsignal_nginx appsignal_metrics; ``` > [!NOTE] > > Replace `127.0.0.1:27649` with the host and port where your AppSignal integration or stand-alone agent is listening for NGINX metrics. If your NGINX configuration does not include configuration files as described above, you can include it yourself from within the `http` block of your `nginx.conf` file: ```nginx NGINX theme={null} http { include '/path/to/appsignal-metrics.conf'; ... } ``` Note that if a `server` or `location` block contains an `access_log` directive, metrics for requests to that server or location will not be reported to AppSignal. To report metrics to AppSignal for those requests, you will need to add the following line inside the block: ```sh Shell theme={null} access_log syslog:server=127.0.0.1:27649,tag=appsignal_nginx appsignal_metrics; ``` > [!NOTE] > > Replace `127.0.0.1:27649` with the host and port where your AppSignal integration or stand-alone agent is listening for NGINX metrics. The existing `access_log` directive inside the block will continue to work as before. ### Configuring request groups By changing the value of the `$appsignal_group` variable within a `location` or `server` block in your NGINX configuration, you can differentiate between different kinds of requests handled by your NGINX server: ```nginx NGINX theme={null} location /admin { set $appsignal_group 'admin'; ... } ``` Metrics related to requests will be segmented by their group, and the different groups will be tracked independently in the Intelligence dashboard graphs for those metrics. ### Disabling metrics You can use the `access_log off` directive to disable all access logs within a `location` or `server` block. Note that this will disable *all* access logs configured, not just those that are sent to AppSignal as metrics. To only report metrics from specific `location` or `server` blocks, remove the following line from the `appsignal-metrics.conf` file, then add it only inside the specific `location` or `server` blocks that you would like to report metrics to AppSignal from: ```nginx NGINX theme={null} access_log syslog:server=127.0.0.1:27649,tag=appsignal_nginx appsignal_metrics; ``` > [!NOTE] > > Replace `127.0.0.1:27649` with the host and port where your AppSignal integration or stand-alone agent is listening for NGINX metrics. Doing this will implicitly disable all access logs from `access_log` directives in the surrounding `server` or `http` block. To enable those access logs again, repeat their corresponding `access_log` directive inside the `location` or `server` block that you added the above line to: ```nginx NGINX theme={null} server { access_log /var/log/nginx/access.log main; location /app { # this line enables AppSignal NGINX metrics for this location # but it also disables the access log declared in the server block access_log syslog:server=127.0.0.1:27649,tag=appsignal_nginx appsignal_metrics; # this line enables the access log declared in the server block again access_log /var/log/nginx/access.log main; } } ``` ## Intelligence dashboard ![The NGINX Intelligence dashboard](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/metrics/nginx/magic-dashboard.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=bda393b093aadf54c20c18df9d09a0b0) The [metrics sent to AppSignal by your NGINX server](#metrics) will be used to create a Intelligence dashboard. In this dashboard, you will be able to see graphs representing useful metrics over time, such as: * **Request time:** the time taken by your NGINX server to respond to a request, as a per-minute mean and 95th percentile. * **Throughput:** a count of the requests handled by your NGINX server. * **Request length:** the length in bytes of the request received from the client by your NGINX server, as a per-minute mean and 95th percentile. * **Response length:** the length in bytes of the response sent to the client by your NGINX server, as a per-minute mean and 95th percentile. * **Status codes:** a count of the status codes of the responses sent by your NGINX server. * **Connections:** a gauge of the connections currently being handled by your NGINX server, measured once per minute and segmented by the status of the connection. * **Upstream status codes:** a count of the status codes of the responses sent by the upstream servers that your NGINX server proxies from. * **Upstream response time:** the time taken to respond to a request by the upstream servers that your NGINX server proxies from, as a per-minute mean and 95th percentile. * **Upstream cache status:** the status of the cache (such as `HIT` or `MISS`) when handling a cached request proxied from an upstream server. Most of these graphs are segmented by [the request group](#configuring-request-groups), the hostname or the relevant upstream, if any. You can, however, dive in to the graph editor and pick a different segmentation that provides a more useful view into your data. See the section below for a detailed breakdown of the metrics sent from your NGINX server. ## Metrics The following metrics will be sent to AppSignal from your NGINX server: * **`nginx_status`**: A counter incrementing for each request handled by your NGINX server. Tagged by: * `status`: The status code of the response. * `group`: The request group, as [configured in your NGINX server](#configuring-request-groups). * `hostname`: The hostname of the server that handled the request. * **`nginx_request_time`**: A distribution of the time taken to respond to each request. Tagged by: * **`group`**: The request group, as [configured in your NGINX server](#configuring-request-groups). * **`hostname`**: The hostname of the server that handled the request. * `nginx_request_length`: A distribution of the bytes received in the request from the client, for each request. Tagged by: * **`group`**: The request group, as [configured in your NGINX server](#configuring-request-groups). * **`hostname`**: The hostname of the server that handled the request. * `nginx_bytes_sent`: A distribution of the bytes sent in the response to the client, for each request. Tagged by: * **`group`**: The request group, as [configured in your NGINX server](#configuring-request-groups). * **`hostname`**: The hostname of the server that handled the request. If the request is handled by proxying from an upstream using the `proxy_pass` NGINX directive, the following metrics will also be present: * `nginx_upstream_time`: A distribution of the time it took to communicate with the upstream server. Tagged by: * **`group`**: The request group, as [configured in your NGINX server](#configuring-request-groups). * **`hostname`**: The hostname of the server that handled the request. * **`upstream`**: The upstream server that the request was proxied to. * **`measurement`**: The specific time measured: * `connect`: The time it took for the connection to be established. * `header`: The time it took for the response header to be sent. * `response`: The time it took for the full response to be sent. * `nginx_upstream_status`: A counter incrementing for each request proxied to an upstream. Tagged by: * **`status`**: The status code of the response. * **`group`**: The request group, as [configured in your NGINX server](#configuring-request-groups). * **`hostname`**: The hostname of the server that handled the request. * **`upstream`**: The upstream server that the request was proxied to. If the request proxied from an upstream is cached using the `proxy_cache` NGINX directive, the following metric will also be present: * `nginx_upstream_cache_status`: A counter incrementing for each request proxied to an upstream with caching enabled. Tagged by: * **`status`**: The [cache status](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_cache_status) for the request. * **`group`**: The request group, as [configured in your NGINX server](#configuring-request-groups). * **`hostname`**: The hostname of the server that handled the request. If your NGINX server has been built with the `ngx_http_stub_status_module` NGINX module enabled (as provided by most Linux distributions) then the following metric will also be present: * `nginx_connections`: The number of connections that your NGINX server is currently handling. Tagged by: * **`hostname`**: The hostname of the server that handled the request. * **`measurement`**: The specific number of connections measured: * `active`: The number of active connections. * `reading`: The number of connections where the request is being read. * `writing`: The number of connections where the response is being written. * `waiting`: The number of idle connections. The connections metric always refers to the hostname as a whole, not to a specific group. Its value is updated once per minute. > [!TIP] > > The server hostname used for the metrics is not the NGINX hostname value, but > the hostname value configured for the AppSignal integration or standalone > agent. This value is usually configured automatically, and can be overriden by > the `hostname` configuration option. ## Support If you are experiencing any difficulties configuring your application's NGINX metrics, [contact support](mailto:support@appsignal.com), and we'll help you get your metrics flowing. # Render host metrics Source: https://docs.appsignal.com/render/host-metrics Learn how AppSignal reports host metrics for your Render services. After you complete the [Render setup](/render/setup), Render reports the resource usage of your services to AppSignal. No further action is required. Your services' [host metrics](/metrics/host-metrics) will appear in AppSignal in a few minutes. AppSignal receives the following [host metrics](/metrics/host-metrics#collected-host-metrics) per Render service: * CPU usage * Memory usage * Disk usage * Disk I/O * Network traffic interface These appear in the ["host metrics" section](https://appsignal.com/redirect-to/app?to=host_metrics), alongside host metrics from any other source. [Render Key Value](https://render.com/docs/key-value) services report the same metrics, so their resource usage appears here rather than on the [Key Value dashboard](/render/dashboards#key-value-dashboard). ![Screenshot of AppSignal's host metrics page showing Render services](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/render/host-metrics.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=979b0870c40c3bf7bb2503670137a62c) Render service metrics shown on AppSignal's host metrics page. # AppSignal for Ruby Source: https://docs.appsignal.com/ruby AppSignal for Ruby monitors Ruby and Rails applications. Start here for configuration, integrations, custom instrumentation, command line tools, and supported Ruby versions. > [!NOTE] > > **New in AppSignal for Ruby 5.0**: AppSignal for Ruby now supports [distributed tracing](/distributed-tracing). > > Distributed tracing is only available when using [collector mode](/ruby/configuration/collector) to send data to the AppSignal hosted collector. > > Collector mode is in beta. Upgrading from 4.x requires no changes unless you enable collector mode. AppSignal supports the [Ruby language][ruby-lang] with a [Ruby gem][appsignal-gem]. The gem supports many frameworks and gems out-of-the-box, but some gems and frameworks might require custom instrumentation. It's also possible to add custom instrumentation to your application to gain even more insights into the performance of your code. ## Configuration In this topic, we'll explain how to configure AppSignal. You'll learn what can be configured in the Ruby gem, what's the minimal configuration needed, and how the configuration is loaded. See our [configuration](/ruby/configuration) documentation for the complete configuration documentation of the AppSignal gem. ## Integrations The AppSignal Ruby gem integrates with many frameworks, including Rails, Sinatra, Padrino, Grape, and more: * [Action Cable](/ruby/integrations/action-cable) * [Active Job](/ruby/integrations/active-job) * [Capistrano](/ruby/integrations/capistrano) * [DataMapper](/ruby/integrations/datamapper) * [Delayed::Job](/ruby/integrations/delayed-job) * [Elasticsearch](/ruby/integrations/elasticsearch) * [Excon](/ruby/integrations/excon) * [Faraday](/ruby/integrations/faraday) * [Garbage Collection](/ruby/integrations/garbage-collection) * [Global VM Lock](/ruby/integrations/global-vm-lock) * [Grape](/ruby/integrations/grape) * [GraphQL](/ruby/integrations/graphql) * [Hanami](/ruby/integrations/hanami) * [HTTP.rb](/ruby/integrations/http) * [MongoDB](/ruby/integrations/mongodb) * [Multiple Rack libraries](/ruby/integrations/rack-libraries) * [Net::HTTP](/ruby/integrations/net-http) * [Padrino](/ruby/integrations/padrino) * [Puma](/ruby/integrations/puma) * [Que](/ruby/integrations/que) * [Rack](/ruby/integrations/rack) * [Rake](/ruby/integrations/rake) * [Redis](/ruby/integrations/redis) * [Resque](/ruby/integrations/resque) * [ROM](/ruby/integrations/rom) * [Ruby on Rails](/ruby/integrations/rails) * [Ruby VM](/ruby/integrations/ruby-vm) * [Sequel](/ruby/integrations/sequel) * [Shoryuken](/ruby/integrations/shoryuken) * [Sidekiq](/ruby/integrations/sidekiq) * [Solid Queue](/ruby/integrations/solidqueue) * [Sinatra](/ruby/integrations/sinatra) * [ViewComponent](/ruby/integrations/view-component) * [Webmachine](/ruby/integrations/webmachine) ## Custom instrumentation Add custom instrumentation to your application, or create your own integrations with AppSignal. See the [instrumentation](/ruby/instrumentation) topic for more details. ## Command line tools The AppSignal Ruby gem ships with several command line tools. These tools make it easier to install AppSignal in an application, send deploy notifications, and diagnose any problems with the installation. See our [command line tools](/ruby/command-line) documentation for a full list of all the available commands. ## Ruby and Rails tutorials We publish [Ruby and Rails tutorials](/tutorials) with [GoRails](https://gorails.com). Each tutorial pairs a screencast with a written walkthrough. They cover background jobs, debugging, parameters, authentication, Markdown, and local CI, with links to the related AppSignal features. ## Ruby implementation support ### Ruby (MRI) We currently support [Ruby `2.7.0+` and higher](/support/maintenance-policy). If you require support for older versions of Ruby, you can use an older version of the AppSignal gem. However, note that we do not provide full support for older versions of the gem. For help upgrading, see [planning an upgrade from an older version](/support/maintenance-policy#planning-an-upgrade-from-an-older-version). ### JRuby JRuby support is [available](https://blog.appsignal.com/2018/02/14/ruby-gem-2-5.html) in version `2.5.0` and higher of the AppSignal Ruby gem. To use JRuby on Alpine Linux, make sure to upgrade to Ruby gem `2.8.0` or newer. Also, check if your [Operating System is supported](/support/operating-systems) in combination with JRuby. [ruby-lang]: https://www.ruby-lang.org/ [appsignal-gem]: https://rubygems.org/gems/appsignal # AppSignal Ruby configuration Source: https://docs.appsignal.com/ruby/configuration Set the minimal required configuration for AppSignal for Ruby, choose a configuration method, and see how AppSignal loads it. This documentation explains the default AppSignal for Ruby configuration. Use it after installation to set the minimal required configuration, choose where to store it, and understand how AppSignal loads it. See also [collector mode](/ruby/configuration/collector) to configure Ruby to send data through the AppSignal collector, which enables [distributed tracing](/distributed-tracing). ## Minimal required configuration For applications to report data to AppSignal the following configuration is required. All other configuration is optional. * Application name - [name option](/ruby/configuration/options#option-name) * Application environment - [environment](/ruby/configuration/options#option-appsignal_app_env) (automatically detected or set with an environment variable) * Application push API key - [push\_api\_key option](/ruby/configuration/options#option-push_api_key) * AppSignal to be active - [active option](/ruby/configuration/options#option-active) For Rails apps you do not have to configure your application name, AppSignal will use the name of your application by default. If you use a framework that is aware of environments and [is supported by the AppSignal gem](/ruby/integrations), the environment is detected automatically. ```ruby Ruby theme={null} # config/appsignal.rb Appsignal.configure do |config| config.activate_if_environment(:development, :staging, :production) config.name = "My app" config.push_api_key = "1234-1234-1234" end ``` ```bash Bash theme={null} # Environment variables export APPSIGNAL_APP_NAME="My app" export APPSIGNAL_APP_ENV="production" export APPSIGNAL_PUSH_API_KEY="1234-1234-1234" ``` ```yaml YAML theme={null} # config/appsignal.yml # Legacy config method production: active: true name: "My app" push_api_key: "1234-1234-1234" ``` ## Configuration methods There are several different configuration methods available in our Ruby gem. To see in which order they're loaded and which configuration method overrides values from other sources, see our [configuration load order](/ruby/configuration/load-order) page. ### Ruby configuration file The AppSignal Ruby gem can be configured using a Ruby configuration file. When selected, the installer automatically creates a `config/appsignal.rb` file. This file includes default configuration settings that can be customized to meet your application's specific needs. This configuration file is read when `Appsignal.start` is called, which is called automatically for most of our [integrations](/ruby/integrations). Please read the [integrating AppSignal instructions](/ruby/instrumentation/integrating-appsignal) if `Appsignal.start` is not automatically called. The configuration file configures our Ruby gem using [the `Appsignal.configure` helper](#appsignal-configure-helper). Please read the [the `Appsignal.configure` helper](#appsignal-configure-helper) section for more details on how to use it. The [YAML configuration file](#yaml-configuration-file) will not be read when this file is present. ```ruby Ruby theme={null} Appsignal.configure do |config| # Enable AppSignal for the following environments config.activate_if_environment(:development, :staging, :production) # Ignore this action for all environments config.ignore_actions << "My global action" # Ignore this action for only the production environment if config.env?(:production) config.ignore_actions << "My production action" end # Ignore this action for only the staging environment if config.env?(:staging) config.ignore_actions << "My staging action" end end ``` ### `Appsignal.configure` helper The `Appsignal.configure` helper can be used to configure AppSignal using Ruby code. The [Ruby configuration file](#ruby-configuration-file) uses this helper and it can also be used directly in your application. If your app uses `Appsignal.configure` outside the `config/appsignal.rb` file, like a Rails initializer, please read [this section on the differences in behavior](#using-the-appsignal-configure-helper-in-your-application) this has. Set configuration options inside the `Appsignal.configure` block by calling the writer methods on the `config` object. [Configuration options](/ruby/configuration/options) can be set using the "Config file key" listed for the configuration options. For example, the [`send_params` option](/ruby/configuration/options#option-send_params) can be set using: `config.send_params = false`. ```ruby Ruby theme={null} # Some examples on how to configure config options Appsignal.configure do |config| # Enable AppSignal for the following environments config.activate_if_environment(:development, :staging, :production) # Configure String config options config.name = "My app name" # Read a value from an environment variable config.hostname = ENV.fetch("HOSTNAME", "default hostname value") # Append values to Array config options config.ignore_actions += ["My ignored action", "My other ignored action"] config.request_headers << "MY_HTTP_HEADER" # Configure Boolean config options config.send_params = true config.enable_host_metrics = false end ``` Read the rest of this section for more details on how the `Appsignal.configure` helper works and what other helpers it has. #### String config options Configuration options of the type String can be set using both Strings and Symbols. When set, we will convert Symbols to Strings. ```ruby Ruby theme={null} Appsignal.configure do |config| config.activejob_report_errors = :discard config.activejob_report_errors # => "discard" end ``` #### Array config options Configuration options of the type Array can be modified as a normal array: * Use an assignment to override defaults and previously read values from environment variables. * For example: `config.array_option = ["value 1", "value 2"]` * Option value: `["value 1", "value 2"]` * Use the *addition assignment operator* `+=` to merge a new array of values with the defaults and previously read values from environment variables. * For example: `config.array_option += ["value 1", "value 2"]` * Option value: `["DUMMY default value", "value 1", "value 2"]` * Use the *append operator* `<<` to append a single value to the list of the defaults and previously read values from environment variables. * For example: `config.array_option << "value 1"` * Option value: `["DUMMY default value", "value 1"]` #### Automatic environment detection The AppSignal Ruby gem detects the application's environment automatically. We integrate with gems like Rails, Sinatra, Rack, and others to detect which environment the application has started in. For this reason, it should not be necessary to configure the environment manually. If you need to configure the application environment manually, pass the environment name as the first argument to the `Appsignal.configure` helper. This argument will override the [`APPSIGNAL_APP_ENV` environment variable value](/ruby/configuration/options#option-appsignal_app_env) and the automatic environment detection. ```ruby Ruby theme={null} # Configure the application environment explicitly to be "production" Appsignal.configure(:production) do |config| # Some config end ``` #### `activate_if_environment` helper The `Appsignal.configure` helper has a helper to configure which environments should be active and report data to AppSignal.com. Call the `activate_if_environment` with a list of environments (Strings and/or Symbols). AppSignal detects the environment when the `Appsignal.configure` helper is called without an environment argument. It will then check if the environment matches any of the given values, and if so, set the [active config option](/ruby/configuration/options#option-active) to `true`. ```ruby Ruby theme={null} Appsignal.configure do |config| # Enable AppSignal for the following environments config.activate_if_environment(:development, :staging, :production) end ``` The `activate_if_environment` helper is a convenience helper to prevent applications from having to add their own checks on when AppSignal should be active, like: ```ruby Ruby theme={null} Appsignal.configure do |config| # Example of a manual check for which environments AppSignal should be active config.active = Rails.env.development? || Rails.env.staging? || Rails.env.production? end ``` #### `env?` helper The `Appsignal.configure` helper has a helper to check which environment AppSignal has detected. Use this helper to check which environment is active to set the configuration options that should only apply to this environment. Call the `env?` helper with an environment name (String or Symbol), and it will return `true` if the environment name matches the currently active environment. ```ruby Ruby theme={null} Appsignal.configure do |config| # Add this configuration only for the staging environment if config.env?(:staging) config.ignore_actions << "My staging action" end end ``` #### Using the `Appsignal.configure` helper in your application We recommend configuring the AppSignal Ruby gem using the [Ruby configuration file](#ruby-configuration-file) at `config/appsignal.rb`. If a Rails initializer or inline configuration is preferred, please read this section for the changes in behavior this has. If the `Appsignal.configure` helper is called before the `config/appsignal.rb` Ruby config file is read when `Appsignal.start` is called, it will not read the Ruby configuration file. In Rails apps, make sure to [configure the AppSignal gem to start after Rails is initialized](/ruby/integrations/rails#configure-appsignal-in-an-initializer), otherwise the config set with `Appsignal.configure` is ignored when called in a Rails initializer like `config/initializers/appsignal.rb`. > [!WARNING] > > In Ruby gem version 3.12 and newer, if a [YAML configuration file](#yaml-configuration-file) is present, it will be read when `Appsignal.configure` is called in a Rails initializer or inline in an application. This is deprecated behavior. Please move all configuration to the `Appsignal.configure` helper. > > We will remove this behavior in the next major version of the Ruby gem. Example Rails initializer: ```ruby Ruby theme={null} # Example file: config/initializers/appsignal.rb # WARNING: In this example the `config/appsignal.rb` config file is not read! Appsignal.configure do |config| # Set some config end ``` Example inline configuration: ```ruby Ruby theme={null} # Example file: app.rb require "appsignal" require "web_framework" # WARNING: In this example the `config/appsignal.rb` config file is not read! Appsignal.configure do |config| # Set some config end Appsignal.start run WebFramework.app ``` ### System environment variables AppSignal can also be configured using system environment variables on the host the application AppSignal is monitoring. This is common on platforms such as Heroku. Make sure these environment variables are configured in the way that's compatible with your Operating System and that the values get loaded before your app with AppSignal is started. ```sh Shell theme={null} export APPSIGNAL_APP_NAME="My app" ``` ### YAML configuration file > [!TIP] > > This configuration method is a legacy method and will be removed in the next major version of the Ruby gem. > > Please use the [Ruby configuration file](#ruby-configuration-file) instead. The AppSignal Ruby gem can be configured with a YAML configuration file. During installation the Ruby gem will create a `config/appsignal.yml` file, if selected. In this file some default configuration is supplied and can be modified to fit your application's needs. This `config/appsignal.yml` file supports ERB tags so that system environment variables can also be loaded in this file. The `config/appsignal.yml` configuration examples shown for configuration options will use the `default` YAML anchor. The AppSignal installer will create an `config/appsignal.yml` file with this anchor by default. If not present, make sure you add the config option to the correct environment. ```yaml YAML theme={null} # config/appsignal.yml # Define the "defaults" anchor default: &defaults name: "My app" # Supports ERB push_api_key: "<%= ENV['APPSIGNAL_PUSH_API_KEY'] %>" production: # Loads the defaults in the production environment by referencing the anchor <<: *defaults # production environment specific configuration active: true ``` #### Multiple app environments Multiple app environments can be configured in this file using root-level keys. ```yaml YAML theme={null} # Example: config/appsignal.yml development: # Development app environment active: true production: # Production app environment active: true test: # Testing app environment active: false # Disabled for test environment ``` To avoid having to repeat the configuration for every app environment, we can use YAML anchors to extend YAML objects. ```yaml YAML theme={null} # Example: config/appsignal.yml default: &defaults active: true development: # Development app environment <<: *defaults production: # Production app environment <<: *defaults test: # Testing app environment <<: *defaults active: false # Overwrites the inherited active config option from "defaults" ``` It's not possible to only configure a `defaults` anchor and have it apply to all environments automatically. Every environment needs to be configured in the YAML file with a root-level key and extend from this `defaults` anchor. #### Example YAML configuration file Here's an example of an `appsignal.yml` configuration file. It's recommended you only add the configuration you need to your configuration file. For the full list of options, please see the [configuration options](/ruby/configuration/options) page. ```yaml YAML theme={null} # config/appsignal.yml default: &defaults # Your Push API Key, it is possible to set this dynamically using ERB. Required push_api_key: "<%= ENV['APPSIGNAL_PUSH_API_KEY'] %>" # Your app's name as reported on AppSignal.com. Required name: "My App" # Your server's hostname. Optional, auto detected hostname: "frontend1.myapp.com" # Add default instrumentation of net/http. Default: true instrument_net_http: true # Skip session data, if it contains private information. Default: false skip_session_data: true # Ignore these errors (Optional) ignore_errors: - SystemExit # Ignore these actions, used by our Loadbalancer. Optional ignore_actions: - IsUpController#index # Enable allocation tracking for memory metrics. Default: true enable_allocation_tracking: true # Configuration per environment, leave out an environment or set active # to false to not push metrics for that environment. development: <<: *defaults active: true # Set the severity level of AppSignal's internal logger. Optional # Supported values are error, warning, info, debug, trace log_level: debug staging: <<: *defaults # Configure AppSignal to be active for this environment. Required active: true production: <<: *defaults # Configure AppSignal to be active for this environment. Required active: true # Set different path for the log file. Optional, auto detected log_path: "/home/my_app/app/shared/log" # Set AppSignal working dir. Optional, auto detected working_directory_path: "/tmp/appsignal" # When it's not possible to connect to the outside world without a proxy. # Optional http_proxy: "proxy.mydomain.com:8080" ``` # AppSignal Ruby Collector Configuration Source: https://docs.appsignal.com/ruby/configuration/collector Send AppSignal for Ruby data through an AppSignal Collector, with gem 5.0 and Ruby 3.1 or later. Distributed tracing needs a hosted collector. Use collector mode to send data to AppSignal through the [AppSignal Collector](/collector). [Distributed tracing](/distributed-tracing) is only supported when sending data through an AppSignal hosted collector. By the end of this page, your app will report to the collector you choose, and each service will identify itself with its own service name. This page assumes that you have already followed [the installation instructions](/ruby/installation). ## Requirements Collector mode requires **Ruby 3.1 or newer**. On older Ruby versions the `collector_endpoint` option is ignored. Collector mode does not support **JRuby**. It depends on how Ruby handles forking, which JRuby does something different with. ## Installing the OpenTelemetry gems Collector mode sends data using OpenTelemetry. The `appsignal` gem does not install the OpenTelemetry gems, so add `appsignal-opentelemetry` next to the `gem "appsignal"` line already in your `Gemfile`: ```ruby title="Gemfile" theme={null} gem "appsignal" gem "appsignal-opentelemetry" ``` Then run `bundle install`. The `appsignal-opentelemetry` gem does nothing on its own. It only installs the OpenTelemetry gem versions that collector mode supports, so you do not have to track them yourself. Its version matches the `appsignal` gem, so `appsignal-opentelemetry` 5.0.0 pairs with `appsignal` 5.0.0. If those gems are missing or their versions are unsupported, AppSignal logs a warning at startup and does not enter collector mode. ## Deploying a collector You can have AppSignal host a collector for you using the ["Hosted Collector"](https://appsignal.com/redirect-to/organization?to=admin/hosted_collectors) page in your organization's settings. ## Configuring the collector Set [the `collector_endpoint` configuration option](/ruby/configuration/options#option-collector_endpoint) to your collector's base URL. When using a hosted collector, copy the "Collector URL" from the "Hosted Collector" settings page. Set [the `service_name` option](/ruby/configuration/options#option-service_name) to identify this application in traces. Use a different value for each service, such as `web-server` or `background-worker`. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| # ... other settings ... config.collector_endpoint = "https://collector.example" config.service_name = "web-server" end ``` ```sh title="Environment variables" theme={null} APPSIGNAL_COLLECTOR_ENDPOINT="https://collector.example" APPSIGNAL_SERVICE_NAME="web-server" ``` AppSignal for Ruby now sends its traces, metrics, and logs to the configured collector. To check that AppSignal loaded these settings, run `bundle exec appsignal diagnose --no-send-report` and confirm that the `Configuration` section lists the expected `collector_endpoint` and `service_name`. Then send a request or run a job and confirm its trace appears in AppSignal. AppSignal builds its traces out of OpenTelemetry spans when it reports to a collector. Read [AppSignal for Ruby and OpenTelemetry](/ruby/instrumentation/opentelemetry) for how to describe those spans yourself, and how AppSignal works together with instrumentation you write with the OpenTelemetry SDK. ## Migrating to collector mode Most configuration options have the same behavior in agent mode and collector mode. In collector mode, some data that was sent in agent mode as a single kind of data is split between multiple data types. Some configuration options that controlled whether that data was sent and how it was filtered have changed: | Agent mode | Collector mode | | - | - | | [`request_headers`](/ruby/configuration/options#option-request_headers) | [`keep_request_headers`](/ruby/configuration/options#option-keep_request_headers), [`keep_request_environment`](/ruby/configuration/options#option-keep_request_environment) | | [`filter_parameters`](/ruby/configuration/options#option-filter_parameters) | [`filter_request_payload`](/ruby/configuration/options#option-filter_request_payload), [`filter_function_parameters`](/ruby/configuration/options#option-filter_function_parameters), [`filter_request_query_parameters`](/ruby/configuration/options#option-filter_request_query_parameters) | | [`send_params`](/ruby/configuration/options#option-send_params) | [`send_request_payload`](/ruby/configuration/options#option-send_request_payload), [`send_function_parameters`](/ruby/configuration/options#option-send_function_parameters), [`send_request_query_parameters`](/ruby/configuration/options#option-send_request_query_parameters) | When the collector mode options are not set, the agent mode option is used to derive a value for it, so an application that configured these config options for agent mode will still report the same data in collector mode. You can set the collector mode options to report each kind of data differently, such as filtering a background job's arguments but not a request's payload. AppSignal logs which values to set to keep reporting the same data, and [`appsignal diagnose`](/ruby/command-line/diagnose) shows them as loaded from `derived`: ```yaml Diagnose output theme={null} keep_request_headers: ["accept"] Sources: default: ["accept", "accept-charset", "accept-encoding", "accept-language", "cache-control", "connection", "content-length", "range"] derived: ["accept"] ``` ### Request headers `request_headers` lists [Rack environment](https://rack.github.io/) keys, and only some of those keys hold a request header. Collector mode reports the two separately, each under the names its own kind of value goes by: * `keep_request_headers` lists request headers, lowercase and dash-separated, as OpenTelemetry names them. `HTTP_ACCEPT` becomes `accept`. * `keep_request_environment` lists the rest, as Rack names them. `QUERY_STRING` stays `QUERY_STRING`. The trace view shows the first in its **Request headers** panel and the second in its **Environment** panel. ### Parameters Collector mode reports three kinds of parameters, each with its own filter and send option: * The **request payload**: an incoming HTTP request's parameters, such as a form body. * The **function parameters**: the arguments a background job was given. * The **request query parameters**: an incoming HTTP request's parsed query string. Read [request parameters](/guides/custom-data/request-parameters) for more information on how to report parameters. # AppSignal for Ruby load order Source: https://docs.appsignal.com/ruby/configuration/load-order The AppSignal Ruby gem can be configured in a couple different ways. Through an initializer, with a configuration file or through environment variables. > [!WARNING] > > In Ruby gem version 2.0 the load order changed! Step 4 and 5 were swapped, > making sure that environment variables are loaded after the `appsignal.yml` > configuration file. Read more about it in the [Pull Request on > GitHub](https://github.com/appsignal/appsignal-ruby/pull/180). The configuration is loaded in a five step process. Starting with the gem defaults and ending with reading environment variables. The configuration options can be mixed without losing configuration from a different option. Using an initializer, a configuration file and environment variables together will work. ## Config sources * 1. [Gem defaults - `default`](#1-gem-defaults) * 2. [System detected settings - `system`](#2-system-detected-settings) * 3. [Initial configuration - `initial`](#3-initial-configuration-given-to-config-initializer) * 4. [`appsignal.yml` config file - `file`](#4-appsignal-yml-config-file) * 5. [Environment variables - `env`](#5-environment-variables) * 6. [`appsignal.rb` config file - `dsl`](#appsignal-rb-config-file) * 7. [`Appsignal.configure` - `dsl`](#configure-helper) ## Gem defaults The AppSignal gem starts with loading its default configuration, setting paths and enabling certain features. The agent defaults can be found in the [gem source](https://github.com/appsignal/appsignal-ruby/blob/main/lib/appsignal/config.rb) as `Appsignal::Config::DEFAULT_CONFIG`. This source is listed as `default` in the [diagnose](/ruby/command-line/diagnose) output. ## System detected settings The gem detects what kind of system it's running on and configures itself accordingly. For example, when it's running inside a container based system (such as Docker and Heroku) it sets the configuration option `:running_in_container` to `true`. This source is listed as `system` in the [diagnose](/ruby/command-line/diagnose) output. ## Initial configuration given to `Config` initializer > [!WARNING] > > This configuration method has been deprecated since Ruby gem 3.12 and removed in Ruby gem 4.0.0 in favor of [`Appsignal.configure`](#configure-helper). When manually creating a `Appsignal::Config` class you can pass in the initial configuration you want to apply. This is a hash of any of the options described below. ```ruby Ruby theme={null} Appsignal.config = Appsignal::Config.new(Dir.pwd, "production", { active: true, name: "My app!", push_api_key: "e55f8e96-62df-4817-b672-d10c8d924065" }) ``` This step will override all given options from the defaults or system detected configuration. This source is listed as `initial` in the [diagnose](/ruby/command-line/diagnose) output. ## `appsignal.yml` config file > [!WARNING] > > This configuration method will be removed in the next major version of the Ruby gem. > We recommend using the [`appsignal.rb` config file](#appsignal-rb-config-file) instead. A way to configure your application is using the `appsignal.yml` file. When you use the `appsignal install` command the gem will create one for you. The path of this configuration file is `{project_root}/config/appsignal.yml`. This step will override all given options from the defaults, system detected and initializer configuration. Read [the `appsignal.yml` config file](/ruby/configuration#yaml-configuration-file) documentation for more information on how this configuration method works. This source is listed as `file` in the [diagnose](/ruby/command-line/diagnose) output. ## Environment variables AppSignal will look for its configuration in environment variables. When found these will override all given configuration options from previous steps. ```bash Bash theme={null} export APPSIGNAL_APP_NAME="my custom app name" # start your app here ``` Read [the system environment variables](/ruby/configuration#system-environment-variables) documentation for more information on how this configuration method works. This source is listed as `env` in the [diagnose](/ruby/command-line/diagnose) output. ## `appsignal.rb` config file A way to configure your application is using the `appsignal.rb` file. The path of this configuration file is `{project_root}/config/appsignal.rb`. This load path cannot be customized. This step will override all given options from the defaults, system detected and environment variables. If both an [`appsignal.yml` config file](#4-appsignal-yml-config-file) and a `appsignal.rb` config file are present, only the `appsignal.rb` config file is loaded. Read [the `appsignal.rb` config file](/ruby/configuration#ruby-configuration-file) documentation for more information on how this configuration method works. This source is listed as `dsl` in the [diagnose](/ruby/command-line/diagnose) output. ## Appsignal.configure helper > [!WARNING] > > In version 3 and 4 of the Ruby gem, calling the `Appsignal.configure` helper will also load the `appsignal.yml` file, if present. > This behavior will *removed* in the next major version of the Ruby gem. > Please only use the [`appsignal.rb` config file](#appsignal-rb-config-file) or [`Appsignal.configure` helper](#configure-helper). Lastly, the Ruby gem can be configured using the `Appsignal.configure` helper in the application. When called, any config options configured using this helper will overwrite all given configuration options from previous sources. If a `config/appsignal.rb` config file is also present in the project, it will **not be loaded** if the `Appsignal.configure` helper is called first in your application. Read [the `Appsignal.configure` helper](/ruby/configuration#appsignal-configure-helper) documentation for more information on how this configuration method works. This source is listed as `dsl` in the [diagnose](/ruby/command-line/diagnose) output. # Ruby gem configuration options Source: https://docs.appsignal.com/ruby/configuration/options The following list includes all configuration options with the name of the environment variable and the name of the key in the configuration file. For more information on how to configure AppSignal with a configuration file or system environment variables, see our [Configuration](/ruby/configuration) topic. ## Available options * Required options * [`active`](#option-active) * [`APPSIGNAL_APP_ENV`](#option-appsignal_app_env) * [`name`](#option-name) * [`push_api_key`](#option-push_api_key) * Options * [`activejob_report_errors`](#option-activejob_report_errors) * [`bind_address`](#option-bind_address) * [`ca_file_path`](#option-ca_file_path) * [`collector_endpoint`](#option-collector_endpoint) * [`cpu_count`](#option-cpu_count) * [`debug`](#option-debug) * [`default_tags`](#option-default_tags) * [`dns_servers`](#option-dns_servers) * [`enable_active_support_event_log_reporter`](#option-enable_active_support_event_log_reporter) * [`enable_allocation_tracking`](#option-enable_allocation_tracking) * [`enable_at_exit_hook`](#option-enable_at_exit_hook) * [`enable_at_exit_reporter`](#option-enable_at_exit_reporter) * [`enable_frontend_error_catching`](#option-enable_frontend_error_catching) * [`enable_gvl_global_timer`](#option-enable_gvl_global_timer) * [`enable_gvl_waiting_threads`](#option-enable_gvl_waiting_threads) * [`enable_host_metrics`](#option-enable_host_metrics) * [`enable_job_enqueue_instrumentation`](#option-enable_job_enqueue_instrumentation) * [`enable_minutely_probes`](#option-enable_minutely_probes) * [`enable_nginx_metrics`](#option-enable_nginx_metrics) * [`enable_rails_error_reporter`](#option-enable_rails_error_reporter) * [`enable_rake_performance_instrumentation`](#option-enable_rake_performance_instrumentation) * [`enable_statsd`](#option-enable_statsd) * [`endpoint`](#option-endpoint) * [`files_world_accessible`](#option-files_world_accessible) * [`filter_attributes`](#option-filter_attributes) * [`filter_function_parameters`](#option-filter_function_parameters) * [`filter_metadata`](#option-filter_metadata) * [`filter_parameters`](#option-filter_parameters) * [`filter_request_payload`](#option-filter_request_payload) * [`filter_request_query_parameters`](#option-filter_request_query_parameters) * [`filter_session_data`](#option-filter_session_data) * [`host_role`](#option-host_role) * [`hostname`](#option-hostname) * [`http_proxy`](#option-http_proxy) * [`ignore_actions`](#option-ignore_actions) * [`ignore_errors`](#option-ignore_errors) * [`ignore_logs`](#option-ignore_logs) * [`ignore_namespaces`](#option-ignore_namespaces) * [`instrument_active_job`](#option-instrument_active_job) * [`instrument_code_ownership`](#option-instrument_code_ownership) * [`instrument_delayed_job`](#option-instrument_delayed_job) * [`instrument_excon`](#option-instrument_excon) * [`instrument_faraday`](#option-instrument_faraday) * [`instrument_http_rb`](#option-instrument_http_rb) * [`instrument_mongo`](#option-instrument_mongo) * [`instrument_net_http`](#option-instrument_net_http) * [`instrument_ownership`](#option-instrument_ownership) * [`instrument_que`](#option-instrument_que) * [`instrument_redis`](#option-instrument_redis) * [`instrument_resque`](#option-instrument_resque) * [`instrument_sequel`](#option-instrument_sequel) * [`instrument_shoryuken`](#option-instrument_shoryuken) * [`instrument_sidekiq`](#option-instrument_sidekiq) * [`keep_request_environment`](#option-keep_request_environment) * [`keep_request_headers`](#option-keep_request_headers) * [`log`](#option-log) * [`log_level`](#option-log_level) * [`log_path`](#option-log_path) * [`logging_endpoint`](#option-logging_endpoint) * [`nginx_port`](#option-nginx_port) * [`ownership_set_namespace`](#option-ownership_set_namespace) * [`request_headers`](#option-request_headers) * [`response_headers`](#option-response_headers) * [`revision`](#option-revision) * [`running_in_container`](#option-running_in_container) * [`send_environment_metadata`](#option-send_environment_metadata) * [`send_function_parameters`](#option-send_function_parameters) * [`send_params`](#option-send_params) * [`send_request_payload`](#option-send_request_payload) * [`send_request_query_parameters`](#option-send_request_query_parameters) * [`send_session_data`](#option-send_session_data) * [`service_name`](#option-service_name) * [`sidekiq_report_errors`](#option-sidekiq_report_errors) * [`skip_session_data`](#option-skip_session_data) * [`statsd_port`](#option-statsd_port) * [`transaction_debug_mode`](#option-transaction_debug_mode) * [`working_dir_path`](#option-working_dir_path) * [`working_directory_path`](#option-working_directory_path) ## active | Field | Value | | - | - | | Config file key | `active` | | System environment key | `APPSIGNAL_ACTIVE` | | Required | yes | | Type | Boolean (`true` / `false`) | | Default value | `false` / detected by system | | Available since version | `0.3.0` | | |
  • `0.11.6`: Support added for the environment variable option.
| ### Description > [!NOTE] > > **Note**: When the [`APPSIGNAL_PUSH_API_KEY`](#option-push_api_key) > environment variable is set, this defaults to `true`. This can be overridden > by setting the `APPSIGNAL_ACTIVE` system environment variable to `false`: > `APPSIGNAL_ACTIVE=false`. Configure AppSignal to be active or not for a given environment. Most commonly used in the [file configuration](/ruby/configuration) per environment. ## APPSIGNAL\_APP\_ENV | Field | Value | | - | - | | System environment key | `APPSIGNAL_APP_ENV` | | Required | yes | | Type | `String` | | Default value | `""` / detected by system | | Available since version | `0.11.8` | | |
  • `1.3.0`: Support added for Padrino.
  • `1.3.6`: Support added for Sinatra.
  • `2.0.4`: Standardizes the behavior for all configuration.
| ### Description The environment of the app to be reported to AppSignal. This config option will be automatically detected in Rails apps. For Rails apps the `RAILS_ENV` variable is used to detect the environment. For apps using other frameworks or none at all, the `RACK_ENV` environment variable is used. To override this automatic detection, set the `APPSIGNAL_APP_ENV` environment variable. ```sh Shell theme={null} export APPSIGNAL_APP_ENV=staging rackup ``` This option will be used to load the configuration from the [config files](/ruby/configuration) in which the AppSignal configuration is stored. The environment variable option is commonly used on platforms where apps run in the `production` environment by default, such as Heroku. This setting allows an override to set the environment to `staging`, for example. ```sh Shell theme={null} heroku config:set APPSIGNAL_APP_ENV=staging ``` If the environment is set using the [`Appsignal.configure` helper](/ruby/configuration/load-order#configure-helper), it will override the `APPSIGNAL_APP_ENV` environment variable. > [!NOTE] > > **Note**: Changing the [name](#option-name) or environment of an existing app > will create a new app on AppSignal.com. > [!NOTE] > > **Note**: This config option has no config file key equivalent. To set the > environment on AppSignal initialization, you'll need to [initialize the > configuration > manually](/ruby/instrumentation/integrating-appsignal#configuration-file). #### Custom environments in config file There is no `env` key available in the `config/appsignal.yml` file. If you wish to dynamically set the environment name for an app in the config file it's possible to customize your config file to use the environment to create an environment. ```yaml YAML theme={null} # config/appsignal.yml <%= ENV["APPSIGNAL_APP_ENV"] %>: active: true ``` If you use another environment variable than `APPSIGNAL_APP_ENV` make sure that matches the value is any of the auto detected environment variable names (`RAILS_ENV` and `RACK_ENV`) or the value given to [`Appsignal.configure`](/ruby/configuration#ruby-configuration-file). > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## name | Field | Value | | - | - | | Config file key | `name` | | System environment key | `APPSIGNAL_APP_NAME` | | Required | yes | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `1.0.0` | ### Description Name of your application as it should be displayed on AppSignal.com. If you use Ruby on Rails the gem will auto-detect the name and you can leave this empty. For other frameworks setting this is mandatory. > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## push\_api\_key | Field | Value | | - | - | | Config file key | `push_api_key` | | System environment key | `APPSIGNAL_PUSH_API_KEY` | | Required | yes | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.1.0` | ### Description The organization-level authentication key to authenticate with our Push API. Read more about the [AppSignal Push API key](/appsignal/terminology#push-api-key). > [!NOTE] > > **Note**: When the [`APPSIGNAL_PUSH_API_KEY`](#option-push_api_key) system > environment variable is set, the [`active`](#option-active) option will > default to `true` instead of `false`. This means AppSignal will be consider > active for the loaded environment even if `active` is set to `false` in the > config file. For more information see the [`active`](#option-active) option. ## activejob\_report\_errors | Field | Value | | - | - | | Config file key | `activejob_report_errors` | | System environment key | `APPSIGNAL_ACTIVEJOB_REPORT_ERRORS` | | Required | no | | Type | `String` | | Default value | `all` | | Available since version | `3.6.1` | | |
  • `3.7.3`: The `discard` value was added.
  • `3.9.0`: Support added for the `APPSIGNAL_ACTIVEJOB_REPORT_ERRORS` environment variable.
| ### Description Configure the reporting of errors that occur in [Active Job](/ruby/integrations/active-job) jobs. This option allows the disabling of error reporting for Active Job jobs, to allow for custom error reporting to be added. Accepted values: * `all`: Report all errors for every execution of jobs, including retries. * `discard`: Report errors when the job is discarded due to the error. Use this option to only report errors when all job retries have been exhausted. * `none`: Report no errors for jobs, including retries. > [!NOTE] > > **Note**: The `discard` option only works on Active Job 7.1 and newer. On > lower versions `discard` is read as `all`. ## bind\_address | Field | Value | | - | - | | Config file key | `bind_address` | | System environment key | `APPSIGNAL_BIND_ADDRESS` | | Required | no | | Type | `String` | | Default value | `127.0.0.1` | | Available since version | `3.4.8` | ### Description A valid IPv4 address the AppSignal agent uses as a binding for its TCP and UDP servers. Use a specific address if you only want the agent to listen to requests made to that address. Set this option to `0.0.0.0` to allow to receive requests from hosts using any IP address. By default it only listens to requests made on the same host. This option is applied to all the agent servers (StatsD, OpenTelemetry and NGINX). ## ca\_file\_path | Field | Value | | - | - | | Config file key | `ca_file_path` | | System environment key | `APPSIGNAL_CA_FILE_PATH` | | Required | no | | Type | `String` | | Default value | Packaged `cacert.pem` file path. | | Available since version | `1.3.5` | ### Description Configure the path of the SSL certificate file. By default this points to the AppSignal [vendored `cacert.pem` file](https://github.com/appsignal/appsignal-ruby/blob/4eed259e122d10df66655098ad0aa8a362f3297d/resources/cacert.pem) in the gem itself. Use this option to point to another certificate file if there's a problem connecting to our API. > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. ## collector\_endpoint | Field | Value | | - | - | | Config file key | `collector_endpoint` | | System environment key | `APPSIGNAL_COLLECTOR_ENDPOINT` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `5.0.0` | ### Description The address of an externally deployed [AppSignal Collector](/collector). When set, OpenTelemetry traces, metrics, and logs are sent to the collector at this address. > [!NOTE] > > This is an **experimental** configuration option. > [Distributed tracing](/distributed-tracing) is > **only available** when using the AppSignal hosted collector. Collector mode requires Ruby 3.1 or newer, does not support JRuby, and needs the OpenTelemetry gems, which are optional and must be added to your application's `Gemfile`. See [the collector configuration guide](/ruby/configuration/collector) for the required gems and minimum versions. On older Ruby versions, or when the gems are missing or too old, this option is ignored. ## cpu\_count | Field | Value | | - | - | | Config file key | `cpu_count` | | System environment key | `APPSIGNAL_CPU_COUNT` | | Required | no | | Type | `Float` | | Default value | `undefined` | | Available since version | `3.6.3` | ### Description The available CPU capacity of the host, in number of CPUs. This is used to calculate the CPU usage percentage in the host metrics. If not set, the agent will attempt to automatically detect this from cgroups. The number of CPUs can be a fraction, e.g. `0.5`. ## debug | Field | Value | | - | - | | Config file key | `debug` | | System environment key | `APPSIGNAL_DEBUG` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `1.0.0` | | |
  • `3.0.16`: Deprecated in favor of the [`log_level` config option](#option-log_level).
  • `4.0.0`: Removed from the gem. Use the [`log_level` config option](#option-log_level) instead.
| ### Description > [!WARNING] > > **Warning**: This config option was removed in Ruby gem 4.0.0. Setting it in > Ruby gem 4.0.0 and newer has no effect. Please use the > [`log_level`](#option-log_level) option instead. Enable debug logging, this is usually only needed on request from support. With this option enabled AppSignal will log a lot more information about decisions that are made during metrics collection and when data is sent to AppSignal.com servers. Enabling debug logging could have a slight impact on the disk usage and IO, especially on high-traffic sites. CPU overhead is minimal with the debug option enabled. > [!NOTE] > > This option sets the severity level of AppSignal's internal logger. This > configuration option does not affect the [logging feature](/logging). ## default\_tags | Field | Value | | - | - | | Config file key | `default_tags` | | System environment key | `APPSIGNAL_DEFAULT_TAGS` | | Required | no | | Type | `Hash[String, (String \| Symbol \| Integer \| Boolean)]` | | Default value | `{}` | | Available since version | `4.8.3` | ### Description Default tags that will be added to all transactions. Transaction-specific tags set with [`Appsignal.add_tags`](/guides/tagging#ruby) will override default tags with the same key. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| config.default_tags = { "region" => "europe", "shard" => "shard-1" } end ``` ```yaml title="config/appsignal.yml" theme={null} default: &defaults default_tags: region: europe shard: shard-1 ``` When using the environment variable, provide a comma-separated list of key-value pairs. ```bash Shell theme={null} export APPSIGNAL_DEFAULT_TAGS="region=europe,shard=shard-1" ``` Tag values must be a String, Symbol, Integer, or Boolean. Tags with other value types will be ignored. Read more about [tagging](/guides/tagging). ## dns\_servers | Field | Value | | - | - | | Config file key | `dns_servers` | | System environment key | `APPSIGNAL_DNS_SERVERS` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `2.2.0.beta.1` | | |
  • `2.11.0`: Support added for the system environment option.
| ### Description Configure DNS servers for the AppSignal agent to use. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| config.dns_servers = ["8.8.8.8", "8.8.4.4"] end ``` ```yaml title="config/appsignal.yml" theme={null} default: &defaults dns_servers: - 8.8.8.8 - 8.8.4.4 ``` ```sh title="Environment variables" theme={null} # In the host environment export APPSIGNAL_DNS_SERVERS="8.8.8.8,8.8.4.4" ``` If you're affected by our [DNS timeouts](/support/known-issues/dns-timeouts), try setting a DNS server manually using this option that doesn't use more than **4** dots in the server name. * Acceptable values: `8.8.8.8`, `my.custom.local.server`. * Not acceptable values: `foo`, `my.awesome.custom.local.dns.server`. If the DNS server cannot be reached the agent will fall back on the host's DNS configuration and output a message in the `appsignal.log` file: `A problem occurred while setting DNS servers`. ## enable\_active\_support\_event\_log\_reporter | Field | Value | | - | - | | Config file key | `enable_active_support_event_log_reporter` | | System environment key | `APPSIGNAL_ENABLE_ACTIVE_SUPPORT_EVENT_LOG_REPORTER` | | Required | no | | Type | `Boolean` | | Default value | `false` | | Available since version | `4.8.0` | | |
  • `4.8.1`: The integration is opt-in. It was enabled by default in `4.8.0`.
| ### Description Enables the `ActiveSupport::EventReporter` [structured event reporting](https://edgeapi.rubyonrails.org/classes/ActiveSupport/EventReporter.html) integration. When enabled, the AppSignal integration subscribes to events emitted by `ActiveSupport::EventReporter`, and report them as logs. ## enable\_allocation\_tracking | Field | Value | | - | - | | Config file key | `enable_allocation_tracking` | | System environment key | `APPSIGNAL_ENABLE_ALLOCATION_TRACKING` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.0.0` | ### Description Set this option to `false` to disable tracking of the number of allocated objects in Ruby. ## enable\_at\_exit\_hook | Field | Value | | - | - | | Config file key | `enable_at_exit_hook` | | System environment key | `APPSIGNAL_ENABLE_AT_EXIT_HOOK` | | Required | no | | Type | `String` | | Default value | 'on\_error' / 'always' on containers | | Available since version | `4.5.8` | ### Description Configure how AppSignal shuts down when the application shuts down. This will determine if it calls `Appsignal.stop` automatically, which will flush the data to the extension and the agent. This option has three possible values: * `always`: Always call `Appsignal.stop` when the program exits. On (Docker) containers it's automatically set to this value. * `never`: Never call `Appsignal.stop` when the program exits. The default value when the program doesn't run on a (Docker) container. * `on_error`: Call `Appsignal.stop` when the program exits with an error. For more information, see our [instrumentation for scripts and background jobs page](/ruby/instrumentation/background-jobs). ## enable\_at\_exit\_reporter | Field | Value | | - | - | | Config file key | `enable_at_exit_reporter` | | System environment key | `APPSIGNAL_ENABLE_AT_EXIT_REPORTER` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.0.0` | ### Description Set to `true` to report the last error that caused the process to quit. The reported error is usually the error that crashes the process. If the Ruby gem already reported the error, it will not report it again. Errors reported via this mechanism are added to the "unhandled" namespace. Add this code to the start of the application on short-lived containers and serverless functions to ensure the error gets flushed before the system shuts down. ```ruby Ruby theme={null} at_exit { sleep 5 } ``` ## enable\_frontend\_error\_catching | Field | Value | | - | - | | Config file key | `enable_frontend_error_catching` | | System environment key | `APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `1.0.0` | | |
  • `3.0.0`: Removed from the gem. See our [upgrade guide](/ruby/installation/upgrade-from-2-to-3) for more information.
| ### Description Enable the experimental front-end error catching system. This will add a route to your app on `/appsignal_error_catcher` that can be used to catch JavaScript error and send them to AppSignal. You can configure this route with `frontend_error_catching_path`. ## enable\_gvl\_global\_timer | Field | Value | | - | - | | Config file key | `enable_gvl_global_timer` | | System environment key | `APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `3.3.9` | ### Description Set this option to `false` to disable the [GVL global timer instrumentation](/ruby/integrations/global-vm-lock#global-timer-graph). This configuration option has no effect if GVLTools is not installed. ## enable\_gvl\_waiting\_threads | Field | Value | | - | - | | Config file key | `enable_gvl_waiting_threads` | | System environment key | `APPSIGNAL_ENABLE_GVL_WAITING_THREADS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `3.3.9` | ### Description Set this option to `false` to disable the [GVL waiting threads instrumentation](/ruby/integrations/global-vm-lock#waiting-threads-graph). This configuration option has no effect if GVLTools is not installed. ## enable\_host\_metrics | Field | Value | | - | - | | Config file key | `enable_host_metrics` | | System environment key | `APPSIGNAL_ENABLE_HOST_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | \`\`true` / detected by system` | | Available since version | `1.2.0` | ### Description Set this option to `false` to disable [host metrics](/metrics/host-metrics) collection. On Heroku and Dokku host metrics are disabled by default. This is done because these systems will report inaccurate metrics from within the containers. Host metrics collection on these systems cannot be enabled. For Heroku, use the [Heroku log drain](/heroku/host-metrics) instead. ## enable\_job\_enqueue\_instrumentation | Field | Value | | - | - | | Config file key | `enable_job_enqueue_instrumentation` | | System environment key | `APPSIGNAL_ENABLE_JOB_ENQUEUE_INSTRUMENTATION` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable recording an event when a background job is enqueued. When enabled, enqueuing a job from within an active transaction records an enqueue event on that transaction's event timeline. This applies to the enqueue instrumentation for each background job integration: * [Sidekiq](/ruby/integrations/sidekiq#enqueue-instrumentation) * [Que](/ruby/integrations/que#enqueue-instrumentation) * [Resque](/ruby/integrations/resque#enqueue-instrumentation) * [Shoryuken](/ruby/integrations/shoryuken#enqueue-instrumentation) * [Delayed::Job](/ruby/integrations/delayed-job#enqueue-instrumentation) * [Active Job](/ruby/integrations/active-job#enqueue-instrumentation) Setting this to `false` stops these enqueue events from being recorded, without affecting the instrumentation of the jobs themselves. Enabled by default. ## enable\_minutely\_probes | Field | Value | | - | - | | Config file key | `enable_minutely_probes` | | System environment key | `APPSIGNAL_ENABLE_MINUTELY_PROBES` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.3.0` | | |
  • `2.9.0`: Default value was changed to `true`.
| ### Description Enables the [minutely probes](/ruby/instrumentation/minutely-probes) system. ## enable\_nginx\_metrics | Field | Value | | - | - | | Config file key | `enable_nginx_metrics` | | System environment key | `APPSIGNAL_ENABLE_NGINX_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `3.3.4` | ### Description Set to `true` to enable the NGINX metrics server. [See the NGINX metrics documentation for details.](/metrics/nginx) When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 27649. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## enable\_rails\_error\_reporter | Field | Value | | - | - | | Config file key | `enable_rails_error_reporter` | | System environment key | `APPSIGNAL_ENABLE_RAILS_ERROR_REPORTER` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `3.4.1` | ### Description Set to `false` to disable the Rails error reporter subscriber. [See the Rails documentation for details.](/ruby/integrations/rails) ## enable\_rake\_performance\_instrumentation | Field | Value | | - | - | | Config file key | `enable_rake_performance_instrumentation` | | System environment key | `APPSIGNAL_ENABLE_RAKE_PERFORMANCE_INSTRUMENTATION` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `3.10.0` | ### Description Enable performance instrumentation for Rake tasks. By default, the [Rake instrumentation](/ruby/integrations/rake) only reports errors. ## enable\_statsd | Field | Value | | - | - | | Config file key | `enable_statsd` | | System environment key | `APPSIGNAL_ENABLE_STATSD` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `3.0.14` | ### Description Enables the [StatsD server](/standalone-agent/statsd) in the AppSignal agent. When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 8125. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## endpoint | Field | Value | | - | - | | Config file key | `endpoint` | | System environment key | `APPSIGNAL_PUSH_API_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://push.appsignal.com` | | Available since version | `0.1.0` | | |
  • `1.0.0`: Support for system environment variable added.
| ### Description Configure the endpoint to send data to AppSignal. This setting will not have to be changed. ## files\_world\_accessible | Field | Value | | - | - | | Config file key | `files_world_accessible` | | System environment key | `APPSIGNAL_FILES_WORLD_ACCESSIBLE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.3.6` | ### Description If this is set to `true` the [AppSignal working directory](/appsignal/how-appsignal-operates#working-directory) that is created is accessible for all users (Unix permissions `0666`). This is often necessary because processes for the same app run under a different user. Set to `false` to disable this behaviour (Unix permissions `0644`). ## filter\_attributes | Field | Value | | - | - | | Config file key | `filter_attributes` | | System environment key | `APPSIGNAL_FILTER_ATTRIBUTES` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `5.0.0` | ### Description List of OpenTelemetry span attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_function\_parameters | Field | Value | | - | - | | Config file key | `filter_function_parameters` | | System environment key | `APPSIGNAL_FILTER_FUNCTION_PARAMETERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `5.0.0` | ### Description List of function parameter attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). Until this option is set, its value is derived from the [`filter_parameters`](#option-filter_parameters) configuration option. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_metadata | Field | Value | | - | - | | Config file key | `filter_metadata` | | System environment key | `APPSIGNAL_FILTER_METADATA` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `3.4.5` | ### Description The AppSignal Ruby gem stores metadata about requests and background jobs on traces by default, like request path, request method, request id, background queue, job id and job retry count. These metadata values will be shown in the tags box. If any of these metadata values contain PII or other senstive data, use this config option to filter out metadata by key. Set the `filter_metadata` option to a list of metadata keys that should be filtered out. You can configure this with a list of keys in the configuration file. When filtered the metadata will not be visible in the AppSignal UI. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| config.filter_metadata += ["path", "request_id"] end ``` ```yaml title="config/appsignal.yml" theme={null} default: &defaults filter_metadata: - path - request_id ``` ## filter\_parameters | Field | Value | | - | - | | Config file key | `filter_parameters` | | System environment key | `APPSIGNAL_FILTER_PARAMETERS` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `1.3.0` | | |
  • `2.3.0`: This config option is also used for argument filtering in background job integrations.
| ### Description List of parameter keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. You can configure this with a list of keys in the configuration file. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| config.filter_parameters += ["password", "email", "api_token", "token"] end ``` ```yaml YAML theme={null} # config/appsignal.yml default: &defaults filter_parameters: - password - email - api_token - token ``` Read more about [parameter filtering](/application/parameter-filtering). > [!NOTE] > > **Agent only:** when using [an external collector](#option-collector_endpoint), this configuration option sets the default for the options below and has no other effect. > > Set the following configuration options to control how request payloads, request query parameters and function parameters are filtered: > > * [`filter_function_parameters`](#option-filter_function_parameters) > * [`filter_request_payload`](#option-filter_request_payload) > * [`filter_request_query_parameters`](#option-filter_request_query_parameters) ## filter\_request\_payload | Field | Value | | - | - | | Config file key | `filter_request_payload` | | System environment key | `APPSIGNAL_FILTER_REQUEST_PAYLOAD` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `5.0.0` | ### Description List of request payload attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). Until this option is set, its value is derived from the [`filter_parameters`](#option-filter_parameters) configuration option. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_request\_query\_parameters | Field | Value | | - | - | | Config file key | `filter_request_query_parameters` | | System environment key | `APPSIGNAL_FILTER_REQUEST_QUERY_PARAMETERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `5.0.0` | ### Description List of request query parameter attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). Until this option is set, its value is derived from the [`filter_parameters`](#option-filter_parameters) configuration option. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_session\_data | Field | Value | | - | - | | Config file key | `filter_session_data` | | System environment key | `APPSIGNAL_FILTER_SESSION_DATA` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `2.6.0` | | |
  • `2.6.1`: An upgrade to this version or higher is recommended.
| ### Description List of session data keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. You can configure this with a list of keys in the configuration file. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| config.filter_session_data += ["name", "email", "api_token", "token"] end ``` ```yaml YAML theme={null} # config/appsignal.yml default: &defaults filter_session_data: - name - email - api_token - token ``` Read more about [session data filtering](/application/session-data-filtering). ## host\_role | Field | Value | | - | - | | Config file key | `host_role` | | System environment key | `APPSIGNAL_HOST_ROLE` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `3.4.11` | ### Description Group hosts by role and generate metrics based on this role. One such metric is the `reporting_hosts` counter metric. A good role indicates what the main role of the server is, like "webserver", "processor", "api", "database", "loadbalancer", etc. ## hostname | Field | Value | | - | - | | Config file key | `hostname` | | System environment key | `APPSIGNAL_HOSTNAME` | | Required | no | | Type | `String` | | Default value | detected from system | | Available since version | `1.3.6` | ### Description This overrides the server's hostname. Useful for when you're unable to set a custom hostname or when a nondescript id is generated for you on hosting services. ## http\_proxy | Field | Value | | - | - | | Config file key | `http_proxy` | | System environment key | `APPSIGNAL_HTTP_PROXY` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.11.13` | ### Description If you require the agent to connect to the Internet via a proxy set the complete proxy URL in this configuration key. ## ignore\_actions | Field | Value | | - | - | | Config file key | `ignore_actions` | | System environment key | `APPSIGNAL_IGNORE_ACTIONS` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `0.10.0` | ### Description With this config option you can specify a list of actions that will be ignored by AppSignal. Everything that happens including exceptions will not be transmitted to AppSignal. This can be useful to ignore health check endpoints or other actions that you don't want to monitor. Read more about [ignoring actions](/guides/filter-data/ignore-actions). ## ignore\_errors | Field | Value | | - | - | | Config file key | `ignore_errors` | | System environment key | `APPSIGNAL_IGNORE_ERRORS` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `0.1.0` | ### Description List of error classes that will be ignored. Any exception raised with this error class will not be transmitted to AppSignal. Read more about [ignoring errors](/guides/filter-data/ignore-errors). ## ignore\_logs | Field | Value | | - | - | | Config file key | `ignore_logs` | | System environment key | `APPSIGNAL_IGNORE_LOGS` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `3.7.0` | ### Description List of log messages that will be ignored. Any log message containing any of the elements of the list will not be transmitted to AppSignal. A small subset of regex syntax is supported, read more about it in our [Ignore Logs](/guides/filter-data/ignore-logs) guide. ## ignore\_namespaces | Field | Value | | - | - | | Config file key | `ignore_namespaces` | | System environment key | `APPSIGNAL_IGNORE_NAMESPACES` | | Required | no | | Type | `Array` | | Default value | `[]` | | Available since version | `2.3.0` | ### Description List of namespaces that will be ignored. Any error raised or slow request that occurs in this namespace will not be send to AppSignal. Read more about [namespaces](/application/namespaces). ## instrument\_active\_job | Field | Value | | - | - | | Config file key | `instrument_active_job` | | System environment key | `APPSIGNAL_INSTRUMENT_ACTIVE_JOB` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for [Active Job](/ruby/integrations/active-job). Setting this to `false` turns off the integration entirely, including both the job instrumentation and the enqueue instrumentation. Enabled by default. ## instrument\_code\_ownership | Field | Value | | - | - | | Config file key | `instrument_code_ownership` | | System environment key | `APPSIGNAL_INSTRUMENT_CODE_OWNERSHIP` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.7.1` | ### Description Whether to automatically instrument the [CodeOwnership gem](/ruby/integrations/code-ownership), can be `true` or `false`. ## instrument\_delayed\_job | Field | Value | | - | - | | Config file key | `instrument_delayed_job` | | System environment key | `APPSIGNAL_INSTRUMENT_DELAYED_JOB` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for [Delayed::Job](/ruby/integrations/delayed-job). Setting this to `false` turns off the integration entirely, including both the job instrumentation and the enqueue instrumentation. Enabled by default. ## instrument\_excon | Field | Value | | - | - | | Config file key | `instrument_excon` | | System environment key | `APPSIGNAL_INSTRUMENT_EXCON` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for [Excon](/ruby/integrations/excon). Setting this to `false` turns off the integration entirely. Enabled by default. ## instrument\_faraday | Field | Value | | - | - | | Config file key | `instrument_faraday` | | System environment key | `APPSIGNAL_INSTRUMENT_FARADAY` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for the [Faraday](/ruby/integrations/faraday) gem. Setting this to `false` turns off the integration entirely. Enabled by default. ## instrument\_http\_rb | Field | Value | | - | - | | Config file key | `instrument_http_rb` | | System environment key | `APPSIGNAL_INSTRUMENT_HTTP_RB` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `3.2.0` | ### Description Enable or disable the instrumentation for the [http.rb Ruby gem](https://github.com/httprb/http). Enabled by default. ## instrument\_mongo | Field | Value | | - | - | | Config file key | `instrument_mongo` | | System environment key | `APPSIGNAL_INSTRUMENT_MONGO` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the [MongoDB instrumentation](/ruby/integrations/mongodb), which covers the Mongo Ruby Driver and Mongoid. Setting this to `false` turns off the integration entirely. Enabled by default. ## instrument\_net\_http | Field | Value | | - | - | | Config file key | `instrument_net_http` | | System environment key | `APPSIGNAL_INSTRUMENT_NET_HTTP` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `0.9.0` | ### Description Whether to add instrumentation for `net/http` calls, can be `true` or `false`. ## instrument\_ownership | Field | Value | | - | - | | Config file key | `instrument_ownership` | | System environment key | `APPSIGNAL_INSTRUMENT_OWNERSHIP` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.3.3` | ### Description Whether to automatically instrument the [Ownership gem](/ruby/integrations/ownership), can be `true` or `false`. ## instrument\_que | Field | Value | | - | - | | Config file key | `instrument_que` | | System environment key | `APPSIGNAL_INSTRUMENT_QUE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for [Que](/ruby/integrations/que). Setting this to `false` turns off the integration entirely, including both the job instrumentation and the enqueue instrumentation. Enabled by default. ## instrument\_redis | Field | Value | | - | - | | Config file key | `instrument_redis` | | System environment key | `APPSIGNAL_INSTRUMENT_REDIS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.0.0` | ### Description Whether to enable the instrumentation for Redis queries using the [Redis gem](https://rubygems.org/gems/redis), can be `true` or `false`. ## instrument\_resque | Field | Value | | - | - | | Config file key | `instrument_resque` | | System environment key | `APPSIGNAL_INSTRUMENT_RESQUE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for [Resque](/ruby/integrations/resque). Setting this to `false` turns off the integration entirely, including both the job instrumentation and the enqueue instrumentation. Enabled by default. ## instrument\_sequel | Field | Value | | - | - | | Config file key | `instrument_sequel` | | System environment key | `APPSIGNAL_INSTRUMENT_SEQUEL` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.0.0` | ### Description Whether to add instrumentation for `sequel` queries using the [Sequel gem integration](/ruby/integrations/sequel), can be `true` or `false`. ## instrument\_shoryuken | Field | Value | | - | - | | Config file key | `instrument_shoryuken` | | System environment key | `APPSIGNAL_INSTRUMENT_SHORYUKEN` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for [Shoryuken](/ruby/integrations/shoryuken). Setting this to `false` turns off the integration entirely, including both the job instrumentation and the enqueue instrumentation. Enabled by default. ## instrument\_sidekiq | Field | Value | | - | - | | Config file key | `instrument_sidekiq` | | System environment key | `APPSIGNAL_INSTRUMENT_SIDEKIQ` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `4.9.0` | ### Description Enable or disable the instrumentation for [Sidekiq](/ruby/integrations/sidekiq). Setting this to `false` turns off the integration entirely, including both the job instrumentation and the enqueue instrumentation. Enabled by default. ## keep\_request\_environment | Field | Value | | - | - | | Config file key | `keep_request_environment` | | System environment key | `APPSIGNAL_KEEP_REQUEST_ENVIRONMENT` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `5.0.0` | ### Description List of [Rack environment](https://rack.github.io/) values to report that are not HTTP request headers, such as `REMOTE_ADDR` and `QUERY_STRING`. Rack environment keys are uppercase and underscore-separated. This config option is an *allowlist*, so only the values it lists are reported. Set it to an empty list to report no environment values. Use [`keep_request_headers`](#option-keep_request_headers) for the request headers. Until this option is set, its value is derived from the [`request_headers`](#option-request_headers) configuration option. Read our [request header collection](/guides/filter-data/filter-headers) guide for more information. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [request\_headers](#option-request_headers) configuration > option for the request headers and Rack environment values to report when using > the agent. ## keep\_request\_headers | Field | Value | | - | - | | Config file key | `keep_request_headers` | | System environment key | `APPSIGNAL_KEEP_REQUEST_HEADERS` | | Required | no | | Type | `list(String)` | | Default value | `["accept", "accept-charset", "accept-encoding", "accept-language", "cache-control", "connection", "content-length", "range"]` | | Available since version | `5.0.0` | ### Description List of HTTP request headers to report. Header names are lowercase and dash-separated, as OpenTelemetry names them: report the `X-Hub-Signature` header by adding `x-hub-signature` to this list. This config option is an *allowlist*, so only the headers it lists are reported. Set it to an empty list to report no request headers. Use [`keep_request_environment`](#option-keep_request_environment) for the [Rack environment](https://rack.github.io/) values that are not request headers. Until this option is set, its value is derived from the [`request_headers`](#option-request_headers) configuration option. Read our [request header collection](/guides/filter-data/filter-headers) guide for more information. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [request\_headers](#option-request_headers) configuration > option for the request headers and Rack environment values to report when using > the agent. ## log | Field | Value | | - | - | | Config file key | `log` | | System environment key | `APPSIGNAL_LOG` | | Required | no | | Type | `String` | | Default value | `file` | | Available since version | `2.0.0` | ### Description > [!NOTE] > > This option configures what logger that AppSignal's internal logging > functionality will use and does not affect the [logging feature](/logging). > > **Note**: The [AppSignal agent](/appsignal/how-appsignal-operates), > which is used by the integration, will always write to the "appsignal.log" file. Select which logger the AppSignal integration will use. Accepted values are `file` and `stdout`. See also the `log_path` configuration. * `file` (default) * Write all AppSignal logs to the file system. * `stdout` (default on [Heroku](https://heroku.com)) * Print AppSignal logs in the parent process' STDOUT instead of to a file. Useful with hosting solutions such as container systems and Heroku. ## log\_level | Field | Value | | - | - | | Config file key | `log_level` | | System environment key | `APPSIGNAL_LOG_LEVEL` | | Required | no | | Type | `String` | | Default value | `info` | | Available since version | `3.0.16` | ### Description > [!NOTE] > > This option sets the severity level of AppSignal's internal logger and does > not affect the [logging feature](/logging). Set the severity level of AppSignal's internal logger. If it is configured to "info" it will log all error, warning and info messages, but not log the debug messages. Setting it to the levels "debug" or "trace" is usually only needed on request from support. Setting the level to "debug"/"trace" could have a slight impact on the disk usage and IO, especially on high-traffic sites. CPU overhead is minimal with the debug option enabled. Accepted values: * error * warning * info * debug * trace ## log\_path | Field | Value | | - | - | | Config file key | `log_path` | | System environment key | `APPSIGNAL_LOG_PATH` | | Required | no | | Type | `String` | | Default value | `./log` | | Available since version | `1.0.0` | ### Description > [!NOTE] > > This option configures the location of AppSignal's internal logging file and > does not affect the [logging feature](/logging). > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. Override the location of the path (directory) where the `appsignal.log` file can be written to. ## logging\_endpoint | Field | Value | | - | - | | Config file key | `logging_endpoint` | | System environment key | `APPSIGNAL_LOGGING_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://appsignal-endpoint.net` | | Available since version | `3.2.0` | ### Description Configure the endpoint AppSignal sends logs and check-ins to. This setting will not have to be changed. ## nginx\_port | Field | Value | | - | - | | Config file key | `nginx_port` | | System environment key | `APPSIGNAL_NGINX_PORT` | | Required | no | | Type | `Integer` | | Default value | `27649` | | Available since version | `4.5.15` | ### Description Configure the port on which the NGINX metrics server is exposed. When AppSignal receives NGINX metrics, it listens on a `localhost`-bound server, by default on port 27649. If you're running several AppSignal-instrumented applications in the same server with NGINX metrics enabled, use this option to configure each application to listen on a different port. ## ownership\_set\_namespace | Field | Value | | - | - | | Config file key | `ownership_set_namespace` | | System environment key | `APPSIGNAL_OWNERSHIP_SET_NAMESPACE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `4.3.3` | ### Description Whether the [Ownership gem instrumentation](/ruby/integrations/ownership) should set the namespace of a trace to its owner, can be `true` or `false`. ## request\_headers | Field | Value | | - | - | | Config file key | `request_headers` | | System environment key | `APPSIGNAL_REQUEST_HEADERS` | | Required | no | | Type | `Array` | | Default value | `["HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_CACHE_CONTROL", "HTTP_CONNECTION", "CONTENT_LENGTH", "PATH_INFO", "HTTP_RANGE", "REQUEST_METHOD", "REQUEST_PATH", "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL"]` | | Available since version | `2.6.0` | | |
  • `2.6.1`: An upgrade to this version or higher is recommended.
  • `3.5.6`: `REQUEST_URI` is no longer included by default, `REQUEST_PATH` is included instead.
| ### Description > [!NOTE] > > **Agent only:** when using [an external collector](#option-collector_endpoint), this configuration option sets the default for the options below and has no other effect. > > In collector mode, we recommend using these configuration options instead: > > * [`keep_request_environment`](#option-keep_request_environment) > * [`keep_request_headers`](#option-keep_request_headers) The `request_headers` config option contains a list of [Rack environment](https://rack.github.io/) keys which are read and stored by the AppSignal Ruby gem. Some of those keys hold an HTTP request header, and some hold a value that describes the request, such as its method or the host it was sent to. This `request_headers` config option is an *allowlist*, which means that it will only report the Rack environment keys specified by this config option. If this config option is unset it will use the AppSignal default. Read our [request header collection](/guides/filter-data/filter-headers) guide for how Rack names a header's key. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| # Add a request header config.request_headers << "PATH_INFO" # Remove a request header config.request_headers.delete("PATH_INFO") end ``` ```yaml title="config/appsignal.yml" theme={null} # To add an additional request header it's necessary to list all default headers too default: &defaults request_headers: - HTTP_ACCEPT - HTTP_ACCEPT_CHARSET - HTTP_ACCEPT_ENCODING - HTTP_ACCEPT_LANGUAGE - HTTP_CACHE_CONTROL - HTTP_CONNECTION - CONTENT_LENGTH - PATH_INFO - HTTP_RANGE - REQUEST_METHOD - REQUEST_PATH - SERVER_NAME - SERVER_PORT - SERVER_PROTOCOL ``` Rack reports the key as your app or framework gave it, which may not match what the browser or client sent. To configure AppSignal to not store any HTTP request headers on AppSignal transactions, configure the option with an empty array. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| config.request_headers = [] end ``` ```yaml title="config/appsignal.yml" theme={null} default: &defaults request_headers: [] ``` ## response\_headers | Field | Value | | - | - | | Config file key | `response_headers` | | System environment key | `APPSIGNAL_RESPONSE_HEADERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `5.0.0` | ### Description The `response_headers` config option contains a list of HTTP response headers which are read and stored by the AppSignal for Ruby gem. This `response_headers` config option is an *allowlist*, which means that it will only report headers as specified by this config option. It names no headers by default, so no response headers are reported until it does. To customize this list, add the config option with *all headers* you want reported. All header names should be written in lowercase characters. If the header name is `X-Custom-Header`, add it to this list as `x-custom-header`. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). ## revision | Field | Value | | - | - | | Config file key | `revision` | | System environment key | `APP_REVISION` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `2.6.0` | | |
  • `2.6.1`: An upgrade to this version or higher is recommended.
  • `2.9.13`: Auto detection for Heroku deploys with the Dyno Metadata labs feature enabled.
  • `2.9.14`: Do not use this release if you depend on the Heroku dyno metadata detection.
  • `3.4.7`: Auto detection for Render deploys.
  • `3.7.5`: Auto detection for Kamal deploys.
  • `4.1.3`: Auto detection for Scalingo deploys.
  • `4.6.0`: Auto detection for Capistrano deploys.
  • `4.6.0`: Auto detection for Hatchbox.io deploys.
  • `5.0.2`: The Heroku, Render, Kamal and Scalingo revisions take precedence over the `REVISION` file.
  • `5.0.5`: Reads the `HEROKU_BUILD_COMMIT` environment variable.
| ### Description Set the app revision to report the currently running version of your app. AppSignal will create a deploy marker when this value changes, and tag all incoming data with the current revision. The AppSignal integration automatically detects the deployed Git commit and uses it as the revision when you deploy using the following tools or providers: * Kamal * Render * Scalingo * Heroku, when the [Heroku Labs: Dyno Metadata](https://devcenter.heroku.com/articles/dyno-metadata) feature is enabled Set the `revision` config option to override the detected revision. Use a single value without spaces, such as a Git commit SHA (`abc0123`) or a version number (`1.2.3`). AppSignal builds links to your source code from this value. Read more about [choosing a revision value](/application/markers/deploy-markers#choosing-a-revision-value). Read more about deploy markers in the [deploy markers topic](/application/markers/deploy-markers). When more than one source sets the revision, the Ruby gem uses the first one in this list that is set: 1. The `revision` config option or the `APP_REVISION` environment variable. 2. The environment variable set by Heroku (`HEROKU_BUILD_COMMIT` or `HEROKU_SLUG_COMMIT`), Render (`RENDER_GIT_COMMIT`), Kamal (`KAMAL_VERSION`), or Scalingo (`CONTAINER_VERSION`), in that order. 3. The `REVISION` file in the application's root directory. ## running\_in\_container | Field | Value | | - | - | | Config file key | `running_in_container` | | System environment key | `APPSIGNAL_RUNNING_IN_CONTAINER` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | detected by agent | | Available since version | `1.0.0` | | |
  • `2.0`: Detected automatically.
| ### Description AppSignal expects to be running on the same machine between different deploys. Set this key to `true` if the application is running in a container, such as with Docker. Newer versions of the AppSignal integration automatically detect its container environment, so no manual configuration is necessary. If you're having trouble with the automatic detection, please [contact support](mailto:support@appsignal.com). This option is set to `true` automatically on [Heroku](http://heroku.com/). ## send\_environment\_metadata | Field | Value | | - | - | | Config file key | `send_environment_metadata` | | System environment key | `APPSIGNAL_SEND_ENVIRONMENT_METADATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.11.0` | ### Description Send environment metadata about the app. For more information please read about [environment metadata](/application/environment-metadata). ## send\_function\_parameters | Field | Value | | - | - | | Config file key | `send_function_parameters` | | System environment key | `APPSIGNAL_SEND_FUNCTION_PARAMETERS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `5.0.0` | ### Description Whether to send function parameters to AppSignal. Until this option is set, its value is derived from the [`send_params`](#option-send_params) configuration option. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [send\_params](#option-send_params) configuration > option for sending data when not using the agent. ## send\_params | Field | Value | | - | - | | Config file key | `send_params` | | System environment key | `APPSIGNAL_SEND_PARAMS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `0.9.0` | | |
  • `1.3.0`: Support added for the system environment option.
| ### Description Whether to skip sending request parameters to AppSignal. For more information please read about [send\_params](/application/parameter-filtering) in filtering request parameters. > [!NOTE] > > **Agent only:** when using [an external collector](#option-collector_endpoint), this configuration option sets the default for the options below and has no other effect. > > Set the following configuration options to control whether request payloads, request query parameters and function parameters are reported: > > * [`send_function_parameters`](#option-send_function_parameters) > * [`send_request_payload`](#option-send_request_payload) > * [`send_request_query_parameters`](#option-send_request_query_parameters) ## send\_request\_payload | Field | Value | | - | - | | Config file key | `send_request_payload` | | System environment key | `APPSIGNAL_SEND_REQUEST_PAYLOAD` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `5.0.0` | ### Description Whether to send request payload to AppSignal. Until this option is set, its value is derived from the [`send_params`](#option-send_params) configuration option. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [send\_params](#option-send_params) configuration > option for sending data when not using the agent. ## send\_request\_query\_parameters | Field | Value | | - | - | | Config file key | `send_request_query_parameters` | | System environment key | `APPSIGNAL_SEND_REQUEST_QUERY_PARAMETERS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `5.0.0` | ### Description Whether to send request query parameters to AppSignal. Until this option is set, its value is derived from the [`send_params`](#option-send_params) configuration option. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [send\_params](#option-send_params) configuration > option for sending data when not using the agent. ## send\_session\_data | Field | Value | | - | - | | Config file key | `send_session_data` | | System environment key | `APPSIGNAL_SEND_SESSION_DATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `3.0.20` | ### Description Set this option to `false` to not send any session data with exception and performance traces. For more information please read about [request session data filtering](/application/session-data-filtering). ## service\_name | Field | Value | | - | - | | Config file key | `service_name` | | System environment key | `APPSIGNAL_SERVICE_NAME` | | Required | no | | Type | `String` | | Default value | \`\` | | Available since version | `5.0.0` | ### Description The service name helps AppSignal recognize different services for traces and groups the traces automatically in a namespace based on the service name. Choose a name that fits your application, such as `web-server`, `background-worker`, `email-service` or `authentication-service`. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). ## sidekiq\_report\_errors | Field | Value | | - | - | | Config file key | `sidekiq_report_errors` | | System environment key | `APPSIGNAL_SIDEKIQ_REPORT_ERRORS` | | Required | no | | Type | `String` | | Default value | `all` | | Available since version | `3.9.0` | ### Description Configure the reporting of errors that occur in [Sidekiq](/ruby/integrations/sidekiq) jobs. Accepted values: * `all`: Report all errors for every execution of jobs, including retries. * `discard`: Report errors when the job is discarded due to the error. Use this option to only report errors when all job retries have been exhausted. * `none`: Report no errors for jobs, including retries. Useful for custom error reporting. > [!NOTE] > > **Note**: The `discard` option only works on Sidekiq 5.1 and newer. On lower > versions `discard` is read as `all`. ## skip\_session\_data | Field | Value | | - | - | | Config file key | `skip_session_data` | | System environment key | `APPSIGNAL_SKIP_SESSION_DATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `0.11.0` | | |
  • `3.0.20`: Deprecated in favor of [`send_session_data`](#option-send_session_data).
  • `4.0.0`: Removed from the gem. Use [`send_session_data`](#option-send_session_data) instead.
| ### Description > [!WARNING] > > **Warning**: This config option was removed in Ruby gem 4.0.0. Setting it in > Ruby gem 4.0.0 and newer has no effect. Please use the > [`send_session_data`](#option-send_session_data) option instead. ## statsd\_port | Field | Value | | - | - | | Config file key | `statsd_port` | | System environment key | `APPSIGNAL_STATSD_PORT` | | Required | no | | Type | `Integer` | | Default value | `8125` | | Available since version | `3.4.3` | ### Description Set this option to configure the StatsD HTTP server port of the AppSignal agent process. Configure this port if another process is already running on the machine that is also using this port to avoid conflicts. ## transaction\_debug\_mode | Field | Value | | - | - | | Config file key | `transaction_debug_mode` | | System environment key | `APPSIGNAL_TRANSACTION_DEBUG_MODE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `2.9.18` | | |
  • `3.0.16`: Deprecated in favor of the [`log_level` config option](#option-log_level).
  • `4.0.0`: Removed from the gem. Use the [`log_level` config option](#option-log_level) instead.
| ### Description > [!WARNING] > > **Warning**: This config option was removed in Ruby gem 4.0.0. Setting it in > Ruby gem 4.0.0 and newer has no effect. Please use the > [`log_level`](#option-log_level) option instead. Enable transaction debug mode. This enables very detailed logging of transactions and events which is useful when developing integrations or when events aren not tracked as expected. The log is only written if the general `debug` option is on as well. > [!NOTE] > > This option sets the severity level of AppSignal's internal logger and does > not affect the [logging feature](/logging). ## working\_dir\_path | Field | Value | | - | - | | Config file key | `working_dir_path` | | System environment key | `APPSIGNAL_WORKING_DIR_PATH` | | Required | no | | Type | `String` | | Default value | detected by agent | ### Description > [!WARNING] > > **Warning**: This config option was removed in Ruby gem 4.0.0. Setting it in > Ruby gem 4.0.0 and newer has no effect. Please use the > [`working_directory_path`](#option-working_directory_path) option instead. > [!NOTE] > > Override the location where AppSignal for Ruby creates a working directory. > See > [`working_directory_path`](#option-working_directory_path) > for the behavior it is applicable. This config option appends `/appsignal` to > the specified path, where > [`working_directory_path`](#option-working_directory_path) > does not. > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. ## working\_directory\_path | Field | Value | | - | - | | Config file key | `working_directory_path` | | System environment key | `APPSIGNAL_WORKING_DIRECTORY_PATH` | | Required | no | | Type | `String` | | Default value | detected by agent | | Available since version | `2.7.0` | | |
  • `2.10.12`: Support added for the system environment option.
  • `2.7.0`: Renamed from [`working_dir_path`](#option-working_dir_path).
| ### Description Override the location where AppSignal for Ruby can store temporary files. Use this option if the default location is not suitable. See our [how AppSignal operates](/appsignal/how-appsignal-operates) page for more information about the purpose of this working directory. If you are running multiple applications using AppSignal on the same server, use this configuration option to select different working directories for every AppSignal instance, otherwise the two instances could conflict with one another. For more information on this scenario see our [running multiple applications on one host](/guides/application/multiple-applications-on-one-host) documentation. ```ruby title="config/appsignal.rb" theme={null} Appsignal.configure do |config| config.working_directory_path = "/tmp/project_1/" end ``` ```yaml title="config/appsignal.yml" theme={null} default: &defaults working_directory_path: "/tmp/project_1/" ``` > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. # Distributed tracing for Ruby Source: https://docs.appsignal.com/ruby/distributed-tracing The Ruby HTTP clients, HTTP servers, and background job libraries that carry a trace between services with AppSignal for Ruby. > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. [Distributed tracing](/distributed-tracing) shows a request as one trace across every service it passed through. AppSignal for Ruby does this for the integrations below. You do not have to pass anything between your services. ## HTTP clients Requests made with these libraries carry the current trace to the service being called: * [Excon](/ruby/integrations/excon) * [Faraday](/ruby/integrations/faraday) * [HTTP.rb](/ruby/integrations/http) * [Net::HTTP](/ruby/integrations/net-http) ## HTTP servers Requests that arrive carrying a trace continue it: * [Grape](/ruby/integrations/grape) * [Hanami](/ruby/integrations/hanami) * [Padrino](/ruby/integrations/padrino) * [Rack](/ruby/integrations/rack) * [Rails](/ruby/integrations/rails) * [Sinatra](/ruby/integrations/sinatra) * [Webmachine](/ruby/integrations/webmachine) ## Background jobs Jobs run in the same trace as the code that enqueued them: * [Active Job](/ruby/integrations/active-job) * [Delayed Job](/ruby/integrations/delayed-job) * [Que](/ruby/integrations/que) * [Resque](/ruby/integrations/resque) * [Shoryuken](/ruby/integrations/shoryuken) * [Sidekiq](/ruby/integrations/sidekiq) How the trace reaches a job differs per library. Each integration's page describes its own behavior and limits. # Installing AppSignal for Ruby Source: https://docs.appsignal.com/ruby/installation Install the appsignal gem with Bundler, check the build requirements, enable distributed tracing, and upgrade or uninstall the gem. Please follow the [installation guide](/guides/new-application) first, when adding a new application to AppSignal. ## Requirements Before you can compile the AppSignal gem make sure the build/compilation tools are installed for your system. Please check the [Supported Operating Systems](/support/operating-systems) page for any system dependencies that may be required. ## Installing the gem We recommend you install and manage the AppSignal gem dependency with [Bundler](http://bundler.io/). Add the following line to your `Gemfile`. ```ruby Ruby theme={null} # Gemfile source "https://rubygems.org" gem "appsignal" ``` Then run `bundle install` to install the gem. To install AppSignal in your application we recommend you run the `appsignal install` command. Please provide it with your [Push API key](/appsignal/terminology#push-api-key) to configure it properly. ```sh Shell theme={null} bundle exec appsignal install YOUR_PUSH_API_KEY ``` This will present you with an installation script that can integrate automatically in some frameworks and gems and will allow you to configure AppSignal. For more information on how to integrate AppSignal into your application see the [integrations documentation](/ruby/integrations) to see what steps are necessary. ### Distributed tracing To enable distributed tracing, follow the [Ruby collector configuration guide](/ruby/configuration/collector) to configure collector mode. ## Upgrading New releases include bug and security fixes, so keep AppSignal up to date. To update within your current major version, run `bundle update appsignal` and redeploy. To upgrade to a new major version of AppSignal for Ruby, follow the upgrade guide for that version: * [Upgrading from 4 to 5](/ruby/installation/upgrade-from-4-to-5) * [Upgrading from 3 to 4](/ruby/installation/upgrade-from-3-to-4) * [Upgrading from 2 to 3](/ruby/installation/upgrade-from-2-to-3) *** > [!NOTE] > > 📖 Continue with our [installation guide](/guides/new-application). ## Uninstall Uninstall AppSignal from your app by following the steps below. When these steps are completed your app will no longer send data to the AppSignal servers. 1. In the `Gemfile` of your app, delete the `gem "appsignal"` line. 2. Run `bundle install` to update your `Gemfile.lock` with the removed gem state. 3. Remove any AppSignal [configuration files](/ruby/configuration/) from your app. * Configuration file location: `config/appsignal.rb` or `config/appsignal.yml` 4. Remove any system environment variables from your development, staging, production, etc. hosts. * Environment variables prefixed with `APPSIGNAL_` * Environment variable [`APP_REVISION`](/ruby/configuration/options#option-revision) 5. Commit, deploy and restart your app. * This will make sure the AppSignal servers won't continue to receive data from your app. 6. Optional: Make sure no `appsignal-agent` processes are running in the background. * Check the output of `ps aux | grep appsignal-agent` and kill the processes still running. 7. Finally, [remove the app](/guides/application/deleting-applications) on AppSignal.com. > [!NOTE] > > 📖 Continue with our [uninstall > guide](/guides/application/deleting-applications). # Upgrade from AppSignal for Ruby gem 2.x to 3.x Source: https://docs.appsignal.com/ruby/installation/upgrade-from-2-to-3 Upgrade AppSignal for Ruby from gem 2.x to 3.x. Applications on 2.x continue with the 3.x to 4.x and 4.x to 5.x guides afterwards. AppSignal for Ruby 3.0 is a major release as it changes the way it instruments other gems, removes support for older Ruby versions, removes the integrated JavaScript integration and removes previously deprecated modules. Follow this guide to make the upgrade process smoother. ## Upgrade to the latest 2.x series Before upgrading to AppSignal for Ruby gem 3.0, please first upgrade to the latest gem from the 2.x series. This version will log and print deprecation warnings for things that will be removed in version 3.x of the gem. Run the tests for your app the gem is integrated with, fix any deprecation warnings and errors you may encounter. This upgrade step will make upgrading an easier process. First, in the app's `Gemfile`, update the version lock to `~> 2.0` and run `bundle update appsignal` in a terminal in the same directory as the `Gemfile`. ```ruby Ruby theme={null} # Gemfile gem "appsignal", "~> 2.0" ``` After all deprecation warnings have been resolved that appeared during testing and running the app, remove the version lock from the `Gemfile` and run `bundle update appsignal` again to update to AppSignal for Ruby 3.0. ```ruby Ruby theme={null} # Gemfile gem "appsignal" ``` ## Removed Ruby 1.9 supported The 3.x series of the Ruby gem will no longer support Ruby 1.9 and older versions. Ruby 1.9 has been End of Life since [23th of February 2015](https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended/) and should no longer be used in production. Future versions of the AppSignal for Ruby gem may drop other End of Life versions of Ruby. Please upgrade to a newer version of Ruby to continue using AppSignal for Ruby moving forward. ## Compatibility with other instrumentation gems In the 3.x series the AppSignal for Ruby gem changed the internals of all its integrations of other gems. Instead of aliasing methods to provide instrumentation, the 3.x series uses `Module.prepend` (introduced in Ruby 2.0), a method to include Ruby Modules in classes and ensuring the included module gets called first. **What does this means for your apps?** Other instrumentation gems may either use the method aliasing or `Module.prepend` method to providing instrumentation. These instrumentation methods are **incompatible** with one another if used on the same Ruby methods. If one gem uses method aliasing, and another `Module.prepend` the app will be caught in a loop and raise a [`stack level too deep (SystemStackError)`][module prepend issue]. The Ruby ecosystem seems to be moving towards the `Module.prepend` method of providing instrumentation so the AppSignal gem has updated its instrumentation method to be more compatible with other gems. If an app starts encountering this issue with the AppSignal for Ruby 3.x series, upgrade other APM and error reporting gems in the app. They may have been updated to instrument using `Module.prepend` as well. If the issue persists, please contact the maintainers of the other gems to update their implementation to `Module.prepend`, and downgrade the AppSignal for Ruby gem to the 2.x series for now. Please also [inform us][contact], so we can keep a list of compatible gems. For more information and background of this change, see [issue 603 on the Ruby gem issue tracker][module prepend issue]. ## Moved modules Some modules in the gem have been moved or renamed. The 2.x series of the gem will print a warning if it encounters any with the new location of the called module. This warning is printed by a fallback when the old module name is called. This warning will no longer be printed if the new module name is being called instead. If an app extended or monkeypatched an AppSignal module, the module name needs to be updated for the patch to work again. Do be warned that we do not provide support for these patches. If a private module has been removed without replacement, we do not provide the integration any more or it has been merged into another module. ## Removed JavaScript integration The AppSignal for Ruby gem included a JavaScript exception tracking middleware, which has been removed in the 3.x series. Instead we recommend you use our dedicated [AppSignal for Front-end JavaScript integration](/front-end/). ### Removed options The following options will no longer affect the AppSignal for Ruby gem, it can be removed from your apps. * `enable_frontend_error_catching` - removed config option * `APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING` - removed environment variable config option * `frontend_error_catching_path` - removed config option * `APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH` - removed environment variable config option ### Removed classes The following classes have been removed from the Ruby gem and calling them will result in a `NameError`. * `Appsignal::JSExceptionTransaction` - removed JavaScript transaction class * `Appsignal::Rack::JSExceptionCatcher` - removed middleware ## Removed `appsignal notify_of_deploy` command The `appsignal notify_of_deploy` command has been removed. Instead we recommend using the [`revision`](/ruby/configuration/options#option-revision) config option to report deploys more accurately. For more information on the topic of deploy markers, please see our [deploy markers section](/application/markers/deploy-markers). If the `revision` option is not a good replacement for your deploy method, please use our [deploy markers API page](/api/markers) about how to send the request to notify AppSignal of deploys. And see our [Push & deploy page](https://appsignal.com/redirect-to/app?to=info) for your app for an example using your app's config. ## Removed deprecations In AppSignal for Ruby 2.x series and older, some behavior of the AppSignal gem may have been deprecated. Most of these deprecations have been removed in the 3.x series. On the latest release in the AppSignal for Ruby 2.x series, all these deprecations should print an warning to STDERR and to the [`appsignal.log`](/support/debugging#log-location) when still used. Please check the app output and logs while on the latest 2.x series gem and fix all deprecation warnings before upgrading. Each deprecation should print/log a warning with the changes needed to resolve the warning. ## Welcome to 3.x! This guide should cover upgrading most Ruby applications to 3.x. If you have any questions, ran into errors, or would like assistance upgrading to the new version, please don't hesitate to [contact support][contact]. [contact]: mailto:support@appsignal.com [module prepend issue]: https://github.com/appsignal/appsignal-ruby/issues/603 # Upgrade from AppSignal for Ruby gem 3.x to 4.x Source: https://docs.appsignal.com/ruby/installation/upgrade-from-3-to-4 A guide to help applications upgrade from AppSignal for Ruby gem 3 to version 4. AppSignal for Ruby 4.0 is a major release that introduces multiple error support, amendable sample data, changes to how it instruments other gems, how custom instrumentation works, and the removal of previously deprecated modules. Follow this guide to make the upgrade process smoother. ## Upgrade to the latest 3.x series Before upgrading to AppSignal for Ruby gem 4.0, upgrade to the latest gem from the 3.x series. This version will print and log deprecation warnings for things that were removed in version 4.x of the Ruby gem. Run the tests for your app the gem is integrated with and fix any deprecation warnings and errors you may encounter. First, in the app's `Gemfile`, update the version lock to `~> 3.0` and run `bundle update appsignal` in a terminal in the same directory as the `Gemfile`. ```ruby Ruby theme={null} # Gemfile gem "appsignal", "~> 3.0" ``` Run your applications and fix any deprecation warnings printed to the application's STDERR output and logged in `appsignal.log` during its operation. ## Upgrade to the latest 4.x series After all deprecation warnings are resolved using version 3 of the Ruby gem, remove the version lock from the `Gemfile` and run `bundle update appsignal` again to update AppSignal for Ruby to version 4. ```ruby Ruby theme={null} # Gemfile gem "appsignal" ``` ## Changes Below are all the notable changes between the latest Ruby gem version 3 and the new version 4. Please go through them and update your application as described. ### Main library * The `Appsignal.start_logger` method is removed. The logger is now automatically started on `Appsignal.start`. Applications need to remove the `Appsignal.start_logger` call. * The AppSignal Ruby gem configuration is frozen after `Appsignal.start` is called. The configuration can no longer be modified after the Ruby gem has started. * The `Appsignal.start` method can only be called once. Subsequent calls are ignored by the Ruby gem. ### Configuration * AppSignal will not start if loading the `config/appsignal.yml` file causes an error. Check the application output or the `appsignal.log` file for any warnings. * Configure AppSignal in Ruby with the new [`Appsignal.configure` helper](/ruby/configuration/load-order#configure-helper). Apps using the `Appsignal.config = Appsignal::Config.new(...)` pattern must update their apps to use this method instead. * The `Appsignal.config =` method is removed. Instead, use the [`Appsignal.configure` helper](/ruby/configuration/load-order#configure-helper) to configure AppSignal in Ruby. * The `skip_session_data` option is removed. Use the [`send_session_data` option](/ruby/configuration/options#option-send_session_data) instead. * The `debug` option is removed. Use the [`log_level: debug` option](/ruby/configuration/options#option-log_level) instead. * The `transaction_debug_mode` option is removed. Use the [`log_level: trace` option](/ruby/configuration/options#option-log_level) instead. * The `working_dir_path` option is removed. Use the [`working_directory_path` option](/ruby/configuration/options#option-working_directory_path) instead. ### Integrations * The `Appsignal::Rack::EventHandler` middleware is added. It will add the `response_status` tag to traces and track a `response_status` metric with the request's response status code. See [our Rack integration docs](/ruby/integrations/rack) for more information. * The `Appsignal::Rack::InstrumentationMiddleware` middleware replaces the `Appsignal::Rack::GenericInstrumentation` middleware. This new middleware does not set the action to "unknown" by default. It is required to set the action name in each app endpoint with `Appsignal.set_action` when only using the `InstrumentationMiddleware` middleware. See [our Rack integration docs](/ruby/integrations/rack) for more information. * `Appsignal::Grape::Middleware` is renamed to `Appsignal::Rack::GrapeMiddleware`. * The `Appsignal::Rack::StreamingListener` is replaced by `Appsignal::Rack::InstrumentationMiddleware`. * The `Appsignal::Hooks::SidekiqPlugin` is removed without replacement. * The Grape, Hanami, Padrino and Sinatra integrations now use the `Appsignal.load` mechanism to integrate with these libraries. Please follow the installation guides for these libraries to update to the new loading mechanism. * [Sinatra](/ruby/integrations/sinatra) * [Hanami](/ruby/integrations/hanami) * [Grape](/ruby/integrations/grape) * [Padrino](/ruby/integrations/padrino) * Using more than one of these libraries or mounting them on a Rails app? [Follow this guide](/ruby/integrations/rack-libraries) as well. * The errors and performance issues reported by our Rake integration are now reported under the "rake" namespace. ### Custom instrumentation * The [`Appsignal.report_error` helper](/ruby/instrumentation/exception-handling) makes it easier to always report errors, without knowing the difference between the `Appsignal.set_error` and `Appsignal.send_error` helpers. ```ruby Ruby theme={null} # Before Appsignal.set_error(error) Appsignal.send_error(error, :tag => "value", "custom namespace") # After Appsignal.report_error(error) Appsignal.report_error(error) do Appsignal.set_namespace("custom namespace") Appsignal.add_tags(:tag => "value") end ``` * Multiple errors can be reported on one transaction with the [`Appsignal.report_error` helper](/ruby/instrumentation/exception-handling#reporting-multiple-exceptions). * The `Appsignal.monitor_transaction` and `Appsignal.monitor_single_transaction` helpers are replaced by the [`Appsignal.monitor` and `Appsignal.monitor_and_stop` helpers](/ruby/instrumentation/background-jobs). * Note: newer versions of the Ruby gem have [deprecated the `Appsignal.monitor_and_stop` helper](/ruby/instrumentation/background-jobs#stop-requirement). * New helpers for adding tags and sample data (parameters, request headers, session data and custom data) to transactions. See the [customization helpers](/guides/custom-data) documentation for more information. ```ruby Ruby theme={null} # Before Appsignal.tag_request(:tag => "value") Appsignal::Transaction.current.set_sample_data( "custom_data", :i18n => { :locale => "en_GB", :default_locale => "en_US" } ) # After Appsignal.add_tags(:tag => "value") Appsignal.add_custom_data( :i18n => { :locale => "en_GB", :default_locale => "en_US" } ) ``` * Sample data is amended by default. Adding additional parameters, request headers, session data and custom data will merge it with the previously set values. See the [customization helpers](/guides/custom-data) documentation for more information. * The `Appsignal::Transaction::GenericRequest` helper is removed. Use our [customization helpers](/guides/custom-data) to add metadata to the transaction. * The `appsignal.action` and `appsignal.route` request environment keys are removed. Use the `Appsignal.set_action` helper to set the action name instead. * The `tags` and `namespace` arguments were removed from the `Appsignal.set_error` and `Appsignal.send_error` helpers. Use the block method to customize the transaction before it's sent instead. See [our exception handling guide](/ruby/instrumentation/exception-handling) for more information. * The `Appsignal::Minutely` constant is renamed to `Appsignal::Probes`. * The `Appsignal::Probes.probes.register` method is replaced with `Appsignal::Probes.register`. See [our minutely probes documentation](/ruby/instrumentation/minutely-probes) for more information. * The `Appsignal.set_host_gauge` and `Appsignal.set_process_gauge` helpers are removed without replacement. Instead, tag the metric with the hostname or process ID using the [`Appsignal.set_gauge` helper](/metrics/custom#gauge). * The `Appsignal.listen_for_error` helper is removed without replacement. Instead, manually rescue errors using `rescue => error` and report them using the [`Appsignal.report_error` helper](/ruby/instrumentation/exception-handling#appsignal-report_error). ### Library internals Listed here are changes to library internals that may have previously been used in our documentation or support cases. We recommend you refrain from relying on these anymore. These are private components and may change at any moment. Breaking changes include: * The `Appsignal::Transaction.create` and `Appsignal::Transaction.new` methods no longer accept the `id`, `request`, and `options` arguments. The transaction ID is now automatically generated. * Instead of manually creating a Transaction object, use the [`Appsignal.monitor` helper](/ruby/instrumentation/background-jobs) instead. * To set metadata on the transaction, use our [customization helpers](/guides/custom-data). * The `Appsignal::Transaction#set_http_or_background_action` method is removed. Use the `Appsignal.set_action` helper instead. * The `Appsignal::Transaction#set_http_or_background_queue_start` method is removed. Use the `Appsignal::Transaction#set_queue_start` helper instead. * The `AppSignal::Transaction#params=` helper is removed. Use the [`Appsignal.add_params` helper](/guides/custom-data/request-parameters) instead. ## Welcome to 4.x! This guide should cover upgrading most Ruby applications to AppSignal Ruby gem 4.x. If you have any questions, ran into errors, or would like assistance upgrading to the new version, please don't hesitate to [contact support][contact]. [contact]: mailto:support@appsignal.com # Upgrade from AppSignal for Ruby gem 4.x to 5.x Source: https://docs.appsignal.com/ruby/installation/upgrade-from-4-to-5 A guide to help applications upgrade from AppSignal for Ruby gem 4 to version 5. Upgrading from AppSignal for Ruby 4.x to 5.x requires no changes to your application. Update the gem and your app reports data in the same way as it did with 4.x. ## Upgrade to the latest 5.x series In the app's `Gemfile`, remove or update any version lock on the `appsignal` gem, and run `bundle update appsignal` in a terminal in the same directory as the `Gemfile`. ```ruby Ruby theme={null} # Gemfile gem "appsignal", "~> 5.0" ``` ## Collector mode AppSignal for Ruby 5.x adds [collector mode](/ruby/configuration/collector), which sends data to an AppSignal collector using OpenTelemetry. Collector mode is optional: the gem only uses it when you set the [`collector_endpoint`](/ruby/configuration/options#option-collector_endpoint) option. To move your app to collector mode after upgrading, follow [migrating to collector mode](/ruby/configuration/collector#migrating). # Custom instrumentation for Ruby Source: https://docs.appsignal.com/ruby/instrumentation Overview of custom instrumentation for Ruby, covering instrumentation helpers, exception handling, breadcrumbs, and ignoring instrumentation. AppSignal provides many ways to provide more insights in your application by adding more instrumentation or tagging the data that appears in the UI at AppSignal.com. * [Integrating AppSignal](/ruby/instrumentation/integrating-appsignal) * [Instrumentation](/ruby/instrumentation/instrumentation) * [Exception handling](/ruby/instrumentation/exception-handling) * [Breadcrumbs](/ruby/instrumentation/breadcrumbs) * [Ignore instrumentation](/ruby/instrumentation/ignore-instrumentation) * [Scripts and background jobs](/ruby/instrumentation/background-jobs) * [Method instrumentation](/ruby/instrumentation/method-instrumentation) * [Event formatters](/ruby/instrumentation/event-formatters) * [Minutely probes](/ruby/instrumentation/minutely-probes) * [Request queue time](/ruby/instrumentation/request-queue-time) * [Custom marker reporting](/ruby/instrumentation/custom-markers) * [Command line tool](/ruby/command-line) ## Contact us Don't hesitate to [contact us](mailto:support@appsignal.com) if you run into any issues while implementing custom instrumentation. We're here to help. # Instrumentation for scripts and background jobs Source: https://docs.appsignal.com/ruby/instrumentation/background-jobs AppSignal supports [many gems out-of-the-box][integrations] and doesn't require additional instrumentation to report error and performance data. For custom scripts and libraries we don't support, you can add monitoring by following this guide. ## Monitoring scripts An AppSignal trace is composed of two elements: a transaction and events. Before reporting events with [our instrumentation helpers](#instrumentation-events), you must first create a transaction. Use the `Appsignal.monitor` helper to create a transaction and make it active for the duration of the given block. The monitor helper will report the instrumented code block as performance measurements listed in the Performance section in the AppSignal UI, grouped by action name. It will track the block's duration and report exceptions that occur inside. ```ruby Ruby theme={null} class CronJobScript def call Appsignal.monitor( :namespace => "cron", :action => "CronJobScript#call" ) do # Your code end end end ``` The `monitor` helper accepts two keyword arguments: * `namespace` (Optional): Customize the namespace of the transaction. Defaults to "web". * `action` (Required): We group the script's traces by this action name for issue creation and notifications. Without an action name, no information about the monitored block is reported, because we don't know how to group the data. ### Set the action name later The `Appsignal.monitor` helper's `action` argument can be left nil or explicitly set to `:set_later`, but only if the `Appsignal.set_action` helper is still called inside the block to set the action name. Without an action name, no data is reported about the instrumented block. This method of setting the action name can be helpful if the action name can only be determined in a processing step inside the block. ```ruby Ruby theme={null} class CronJobScript def call Appsignal.monitor( :action => :set_later ) do # Your code # Set action name later Appsignal.set_action("My action name") end end end ``` ### Instrumentation events By default, the Ruby gem will report events from [supported integrations][integrations]. These events will appear in the event timeline. Use [our instrumentation helpers](/ruby/instrumentation/instrumentation) to add your own events to the event timeline. This creates a more detailed breakdown of what's happening inside the monitored block. ```ruby Ruby theme={null} class CronJobScript def call Appsignal.monitor( :namespace => "cron", :action => "CronJobScript#call" ) do Appsignal.instrument "fetch.plans" do # Complex part of fetching payment plans end Appsignal.instrument "send.invoices" do # Complex part of sending invoices end end end end ``` ## Stop requirement For scripts running on short-lived hosts, it is required to stop the AppSignal Ruby gem before the script exits. This will ensure it reports the data from the script to AppSignal before the host shuts down. This behavior is only needed in such scenarios like: * When a scheduled task (a cron job) is run by a hosting service. * When a script is run on a container that starts to run this script and shuts down when the script exits. * When a script is run on a Heroku runner, or similar hosting providers. It is not needed to stop the AppSignal Ruby gem if the host on which the script is started, continues to run after the script has exited. AppSignal is stopped automatically when the script exits and a container or hosting environment like Heroku is detected. This behavior is controlled by the [`enable_at_exit_hook` option](/ruby/configuration/options#option-enable_at_exit_hook). Ensure this option is set to true for scripts that require AppSignal to be stopped, if it's not automatically detected. It may be needed to add an additional `sleep` call of a couple seconds to ensure there's enough time to send all the data. Use the `at_exit` usage example from the code below if needed. ```ruby Ruby theme={null} # This block is called after all tasks are ran # Ensures the AppSignal agent has enough time to send the data to the AppSignal servers at_exit { sleep 10 } # Your script code ``` ### Monitor and stop helper > [!WARNING] > > The `Appsignal.monitor_and_stop` helper is deprecated in favor of the [`enable_at_exit_hook` option](/ruby/configuration/options#option-enable_at_exit_hook), which ensures `Appsignal.stop` is called when the process exits, not whenever the `Appsignal.monitor_and_stop` helper is called. > It's usage is described in the section above this one. > > Only use this helper in versions of the Ruby gem that do not support the [`enable_at_exit_hook` option](/ruby/configuration/options#option-enable_at_exit_hook). If your process always runs one task/job and immediately exits afterward, you can use the `Appsignal.monitor_and_stop` helper. This will ensure that AppSignal stops automatically after the block has been executed. ```ruby Ruby theme={null} # This block is called right before the script exits # Ensures the AppSignal agent has enough time to send the data to the AppSignal servers at_exit do sleep 10 end class CronJobScript def call Appsignal.monitor_and_stop( :namespace => "cron", :action => "CronJobScript#call" ) do # Your code end end end ``` ## See also * [Solid Queue: run background jobs in your database](/tutorials/ruby/solid-queue): use the database you already run as an Active Job backend, and manage Solid Queue with Puma or as a separate service. AppSignal instruments its jobs automatically. * [Sidekiq batches: run jobs in parallel, then act](/tutorials/ruby/batching-background-jobs): split one unit of work across many jobs, then run a callback once every job has succeeded. The callback runs as a Sidekiq job, so AppSignal instruments it automatically. * [Mission Control Jobs: a job dashboard inside Rails](/tutorials/ruby/mission-control-jobs): mount an engine that browses queues, workers, and failed jobs from inside your own application. [integrations]: /ruby/integrations.html # Breadcrumbs Source: https://docs.appsignal.com/ruby/instrumentation/breadcrumbs > [!TIP] > > Breadcrumbs are available since Ruby gem version `2.11.2`. Breadcrumbs where initially implemented in our [Front-end Javascript library](/front-end/breadcrumbs) with the idea that it would help debug an issue when you have a trail of breadcrumbs with (user) actions leading up to the error. We then realized this could also be useful for back-end requests, where you can add a time-ordered list of actions leading up to the error. For example adding breadcrumbs through decision trees that are otherwise not instrumented. ![Breadcrumbs](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/frontend/breadcrumbs.svg?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=1f7cb85f6a8662c46a42a3aa90340eb4) ## Usage By default, no breadcrumbs are tracked, but it's really easy to track your own. Wherever an interesting event, operation or state change occurs in your app, you can leave a breadcrumb like so: ```ruby Ruby theme={null} Appsignal.add_breadcrumb("Navigation", "https://example.com", "", { :response => 200 }, Time.now.utc) Appsignal.add_breadcrumb("Network", "[GET] https://example.com", "", { :response => 500 }) Appsignal.add_breadcrumb("UI", "closed modal(change_password)", "User closed modal without actions") ``` Only the last 20 added breadcrumbs will be added to the current transaction. ## Breadcrumb Options | Option | Type | Description | | - | - | - | | category | String | Category to label the event under | | action | String | Contextual information related to the event | | message | String | (optional) A log message or other string to send to AppSignal | | metadata | `Object` | (optional) An object of metadata related to the event | | time | Time object | (optional) Time object that responds to `.to_i`, defaults to `Time.utc` | # Custom markers Source: https://docs.appsignal.com/ruby/instrumentation/custom-markers [Custom markers](/application/markers/custom-markers) can be added to graphs and charts to mark important changes. They work similarly to Deploy markers, which let you know when a deployment was made. There are several ways to send [custom markers](/application/markers/custom-markers), through our UI, [API](/api/markers) and [public endpoint API](/api/public-endpoint/custom-markers). The Ruby gem also includes a helper class to create custom markers through our public endpoint. See the example below on how it can be used: ```ruby Ruby theme={null} Appsignal::CustomMarker.report( # The icon shown on the timeline :icon => "🎉", # The message shown on hover :message => "Big event happened!", # Any time object or a string with a ISO8601 valid time is accepted :created_at => Time.now ) ``` You can call this helper anywhere in your application where an event occurs that needs to be tracked on the graph timeline, like Rake tasks. # Event formatters Source: https://docs.appsignal.com/ruby/instrumentation/event-formatters Event formatters are helper classes to format event metadata for AppSignal transactions. In the AppSignal gem, event formatters are used to format event metadata from [ActiveSupport::Notifications instrumentation][as_instrumentation] events to AppSignal event metadata. When a block of code is instrumented by ActiveSupport::Notifications, AppSignal will record the event on the transactions, just like it would for the [`Appsignal.instrument` helper][instrument_helper]. Event formatters allow the data to be passed to the `ActiveSupport::Notifications.instrument` method call to be formatted for AppSignal events. The metadata for the events formatted by the event formatters will be visible on trace detail pages in the event timeline. Hover over a specific event and the on mouse hover pop-up will show details like the exact database being queried or the query that was executed. > [!TIP] > > **Note**: If there are no other reasons to use > \[`ActiveSupport::Notifications`]\[as\_instrumentation] instrumentation than > AppSignal instrumentation, we recommend using the \[`Appsignal.instrument` > helper]\[instrument\_helper] for instrumentation. Using > `ActiveSupport::Notifications` adds more overhead than directly calling > `AppSignal.instrument`. No event formatter will be needed either, as > `AppSignal.instrument` accepts the metadata to be set directly. ## Creating an event formatter An AppSignal event formatter is a class with one instance method, `format`. This format method receives the event payload Hash and needs to return an Array with three values. It's possible to add event formatter for libraries that use ActiveSupport::Notifications instrumentation, but look out that there's not already an event formatter registered for it. It's also possible to create an event formatter for your own events. When adding your own event names, please mind the [event naming](/api/event-names) guidelines. Each event formatter receives an event metadata "payload" Hash from which the event formatter can format the metadata for the event in AppSignal. This AppSignal event metadata needs to be returned by the event formatter in this order in an Array: ```ruby Ruby theme={null} def format(payload) [ "event title", "event body", Appsignal::EventFormatter::DEFAULT ] end ``` 1. An event title (`String`) * A more descriptive title of an event, such as `"Fetch current user"` or `"Fetch blog post comments"`. It will appear next to the event name in the event tree on the performance trace page to provide a little more context on what's happening. 2. An event body (`String`) * More details such as the database query that was used by the event. 3. An event body format (`Integer`) * Body format supports formatters to scrub the given data in the `body` argument to remove any sensitive data from the value. There are currently two supported values for the `body_format` argument. * `Appsignal::EventFormatter::DEFAULT` * This default value will indicate to AppSignal to leave the value intact and not scrub any data from it. * `Appsignal::EventFormatter::SQL_BODY_FORMAT` * The `SQL_BODY_FORMAT` value will indicate to AppSignal to run your data through the SQL sanitizer and scrub any values in SQL queries. ```sql SQL theme={null} -- An event body with the value of: SELECT * FROM users WHERE email = 'hector@appsignal.com' AND password = 'iamabot' -- becomes SELECT * FROM users WHERE email = ? AND password = ? ``` > [!WARNING] > > **Warning**: the event formatter has no exception handling wrapped around it. > If the custom event formatter raises an error, it will crash the web request > or background job. ## Example event formatter ```ruby Ruby theme={null} # A custom event formatter class class MyCustomEventFormatter def format(payload) [ payload[:title], payload[:body], Appsignal::EventFormatter::DEFAULT ] end end # Register the custom event formatter class for a specific event Appsignal::EventFormatter.register("event.custom", MyCustomEventFormatter) # Can be registerd multiple times for other event names Appsignal::EventFormatter.register("other_event.custom", MyCustomEventFormatter) ``` Then when instrumenting a block of code, use the event name that's registered for your custom event formatter. ```ruby Ruby theme={null} ActiveSupport::Notifications.instrument( "event.custom", # Use the registered event name { # Pass along event metadata :title => "some event name", :body => "some event body" } ) do sleep 2 end ``` ## Formatting Dry::Monitor events Event formatters also format events instrumented through [Dry::Monitor notifications](/ruby/instrumentation/instrumentation#drymonitornotifications). Register the formatter against the Dry::Monitor event ID followed by `.dry`, so an event instrumented as `sql` is formatted by the formatter registered for `sql.dry`. The first value the formatter returns means something different for these events. For an ActiveSupport::Notifications event it is the event's title. For a Dry::Monitor event it is the event's name, and the event is recorded in the timeline without a title. ```ruby Ruby theme={null} class MyQueryFormatter def format(payload) [ "query.my_library", # The event name, rather than the title payload[:query], Appsignal::EventFormatter::SQL_BODY_FORMAT ] end end Appsignal::EventFormatter.register("sql.dry", MyQueryFormatter) ``` ## Unregistering an event formatter Unregister a formatter to stop AppSignal from using it for an event name. ```ruby Ruby theme={null} Appsignal::EventFormatter.unregister("event.custom", MyCustomEventFormatter) ``` Use `Appsignal::EventFormatter.registered?("event.custom")` to check whether an event name has a formatter registered. ## Changes in gem 2.5 In AppSignal for Ruby gem version `2.5.2` some changes were made in how event formatters are registered. The old method of registering event formatters was deprecated in this release and will be removed in version `3.0` of the Ruby gem. The new method of registering EventFormatters will allow custom formatters to be registered after AppSignal has loaded. This allows EventFormatters to be registered in [Rails initializers](http://guides.rubyonrails.org/configuring.html#using-initializer-files). In gem version `2.5.1` and older, it is possible to register an event formatter like the following example, calling the `register` method in the class itself. ```ruby Ruby theme={null} # Pre 2.5.2 method of registering event formatters # This method is now deprecated class MyCustomEventFormatter < Appsignal::EventFormatter register "event.custom" def format(payload) [payload[:title], payload[:body], Appsignal::EventFormatter::DEFAULT] end end ``` With the new setup the register call was extracted from the class itself, so it can instead be registered directly on the EventFormatter class. ```ruby Ruby theme={null} class MyCustomEventFormatter def format(payload) [payload[:title], payload[:body], Appsignal::EventFormatter::DEFAULT] end end Appsignal::EventFormatter.register("event.custom", MyCustomEventFormatter) ``` This also means your EventFormatters no longer need to be a subclass of the `Appsignal::EventFormatter` class. [as_instrumentation]: /ruby/instrumentation/instrumentation#activesupportnotifications [instrument_helper]: /ruby/instrumentation/instrumentation#instrumentation-helpers # Exception handling Source: https://docs.appsignal.com/ruby/instrumentation/exception-handling By default AppSignal tries to record as many exceptions (errors) as possible. With [our integrations](/ruby/integrations) for many frameworks and background job gems, not a lot of exceptions will slip past. In most cases, errors not caused by bugs in your code occur when your app interacts with the real world. Bots might drop by and try to post forms automatically; outdated links might direct visitors to content that doesn't exist anymore, and so on. To avoid these errors from being raised as problems in AppSignal, it's possible to add exception handling to your code or even let AppSignal entirely ignore specific errors. ## Ignore errors The AppSignal configuration makes it possible to [ignore errors](/guides/filter-data/ignore-errors). By providing a list of specific errors AppSignal will not send alerts when these errors are raised. ## Exception handling Simply ignoring an error will silence notifications, but could potentially hide a bigger problem. For this reason we recommend you add exception handling with `begin .. rescue` blocks to your application. Using `begin .. rescue` you can catch specific exceptions and add an alternative code path for when an exception occurs, such as rendering 404 pages or providing the user with more detailed error messages about what went wrong. ```ruby Ruby theme={null} begin user = Post.find(1) rescue RecordNotFound => e render :text => "Could not find post", :status => 404 end ``` There's a couple of scenarios that should be handled like this to provide proper HTTP responses when resources don't exist or when a form submission fails. Read our primer on [Exception handling](https://blog.appsignal.com/blog/2016/10/18/ruby-magic-exceptions-primer.html) for more information on how it works and how to implement it correctly. ### Rails rescue\_from Rails provides a mechanism to handle exceptions on controller-level. By defining a `rescue_from` statement for a specific error it's possible to create an alternative code path for when that exception is raised. Because this can be defined on any controller level this makes it possible to add application-level exception handling. ```ruby Ruby theme={null} class ApplicationController < ActionController::Base rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found private def record_not_found render :text => "404: Resource not found", :status => 404 end end ``` More information about `rescue_from` can be found in the Rails guide about [ActionController](https://guides.rubyonrails.org/action_controller_overview.html#rescue-from). ### Handle 404s If a visitor hits a URL that cannot be handled by your routing or controller Rack and other frameworks will raise an exception. It's usually a good idea to handle these exceptions with a 404 response for your users. In controllers where a `find` operation is performed based on a parameter from an URL, it's recommended you handle `ActiveRecord::RecordNotFound` (or the equivalent in your ORM of choice) to show a 404 response as well. This can hide real bugs though, so it should be done with care. ### Handle invalid authenticity tokens Rails has a mechanism that protects your forms from being filled out by bots too easily. Any time a form is posted without a correct authenticity token a `ActionController::InvalidAuthenticityToken` will be raised. Sometimes legitimate users can run into these errors as well, so it's a good idea to have a separate error page explaining what went wrong. We advise to return this page with a 422 (Unprocessable Entity) response. ### Handle hacking attempts You might get errors because bots or hackers are trying to exploit security issues such as the notorious YAML exploit. Newer versions of Rails will throw a `Hash::DisallowedType` when this happens. A `RangeError` is also often a result of a hacking attempt. You could rescue these type of errors and return a 403 (Forbidden) response. ## Exception reporting helper methods AppSignal provides a single interface to report exceptions with [`Appsignal.report_error`](#appsignal-report_error). If your application is using Ruby gem version 3 or older, see the [legacy exception handling section](#legacy-exception-handling). ## Appsignal.report\_error Applications may have exception handling where they don't want to crash the Ruby process. By adding exception handling, the exception will no longer bubble up to the AppSignal instrumentation. AppSignal will not report these exceptions. If you want to report the exception without crashing the application, use the `Appsignal.report_error` helper to report it to AppSignal from within the exception handling. If an AppSignal Transaction is active, this helper will add the exception to the current Transaction. Applications can report multiple exceptions on one Transaction. If no Transaction is active, this helper will create a new Transaction and report the exception on the newly created Transaction. AppSignal will always report the exception this way when using `Appsignal.report_error`. ```ruby Ruby theme={null} begin # Some code that raises an exception rescue => error Appsignal.report_error(error) puts "Exiting. An error occurred: #{error}" exit 1 end ``` ### Adding metadata Customizing the metadata on the Transaction for the exception is possible by passing a block to the `Appsignal.report_error` helper. See our [Tagging](/guides/tagging) and [Data Customization](/guides/custom-data) guides for more information on what type of data can be added in this block. The metadata set in the `Appsignal.report_error`'s block only applies to the exception given to the helper. Metadata set outside the `Appsignal.report_error` blocks is added to all exceptions if there's an active transaction. ```ruby Ruby 5.x theme={null} begin # some code rescue => error Appsignal.report_error(error) do Appsignal.set_namespace("admin") Appsignal.set_action("MyCustomAction#perform") Appsignal.add_request_payload(:param1 => "value1", :param2 => "value2") Appsignal.add_tags(:tag1 => "value1", :tag2 => "value2") Appsignal.add_custom_data( :i18n => { :locale => "en_GB", :default_locale => "en_US" } ) end end ``` ```ruby Ruby 4.x theme={null} begin # some code rescue => error Appsignal.report_error(error) do Appsignal.set_namespace("admin") Appsignal.set_action("MyCustomAction#perform") Appsignal.add_params(:param1 => "value1", :param2 => "value2") Appsignal.add_tags(:tag1 => "value1", :tag2 => "value2") Appsignal.add_custom_data( :i18n => { :locale => "en_GB", :default_locale => "en_US" } ) end end ``` In version 5.0.0 of the Ruby gem, `Appsignal.add_params` is replaced by a method per parameter type. See [parameter types](/guides/custom-data/request-parameters#parameter-types) for which method to use. ### Reporting multiple exceptions Multiple errors can be reported in one Transaction, like a Rails controller action handling an HTTP request or a Sidekiq background job. A maximum of 10 errors can be set on one Transaction. If multiple exceptions are reported in one Transaction, the metadata set in the `Appsignal.report_error`'s block only applies to the exception given to the helper. Metadata set outside of the `Appsignal.report_error` blocks is added to all exceptions. ```ruby Ruby theme={null} def index # This tag is added to all exceptions Appsignal.add_tags(:some_tag_for_all_errors => true) begin raise "something went wrong" rescue => error # Report the first exception Appsignal.report_error(error) do # This tag is only added to the first exception Appsignal.add_tags(:some_tag => true) end end begin raise "something else went wrong" rescue => error # Report the second exception Appsignal.report_error(error) do # This tag is only added to the second exception Appsignal.add_tags(:other_tag => true) end end # This tag is added to all exceptions Appsignal.add_tags(:another_tag_for_all_errors => true) end ``` ### Report exceptions that crash a process By default, AppSignal will report exceptions that crash a Ruby process as long as AppSignal is started before the exception occurs. ```ruby Ruby theme={null} # some_script.rb require "appsignal" Appsignal.start raise "I will crash the process!" ``` To disable this functionality, set the [`enable_at_exit_reporter` config option](/ruby/configuration/options#option-enable_at_exit_reporter) to `false`. ### Short-lived Ruby processes When reporting exceptions from [Ruby scripts](/ruby/instrumentation/background-jobs), [Rake tasks](/ruby/integrations/rake), Ruby processes that are short-lived, read the documentation on those pages on when to best call `Appsignal.stop` to ensure all exceptions are reported to AppSignal. ## Legacy exception handling Read this section when using AppSignal for Ruby gem version 3 or older. For newer versions of our Ruby gem, use the [`Appsignal.report_error` helper](#appsignal-report_error). AppSignal provides two exception reporting helper methods, which one you use will depend on the context of the error. The methods are: * **[`set_error`](#appsignal-set_error):** The `set_error` helper sets the error on the currently active Transaction. If no transaction is active, no error is reported. Setting an error on the currently active transaction overrides any error previously set on the transaction. * **[`send_error`](#appsignal-send_error):** Use `send_error` to report errors when no AppSignal transaction is active. ### Appsignal.set\_error There are scenarios where you have your own exception handling and don't want to crash the Ruby process. By adding your own exception handling the error is no longer bubbled up to the AppSignal integration and thus not recorded automatically. If you still want to track the error you can use `Appsignal.set_error` to add the exception to the current AppSignal Transaction. The error will be recorded in AppSignal, but your process will not crash. ```ruby Ruby theme={null} require "yaml" class SomeClass def call YAML.load(File.read("config.yml")) rescue SystemCallError => exception Appsignal.set_error(exception) puts "No config file found. Using defaults." end end ``` The exception will be tracked by AppSignal like any other error, and it allows you to provide custom error handling and fallbacks. Calling `set_error` only works when there is an AppSignal transaction active. Otherwise the error will be ignored. A transaction is active in most of our [automatically supported integrations](/ruby/integrations) and when using `Appsignal.monitor` or `Appsignal.monitor_transaction`. For more information on when to use `Appsignal.monitor_transaction`, see our [instrumentation for scripts and background jobs guide](/ruby/instrumentation/background-jobs). See [`Appsignal.send_error`](#appsignal-send_error) for sending errors without an AppSignal transaction. ```ruby Ruby theme={null} require "yaml" Appsignal.monitor :action => "My action" do begin YAML.load(File.read("config.yml")) rescue SystemCallError => exception Appsignal.set_error(exception) puts "No config file found. Using defaults." end end ``` ### Appsignal.send\_error AppSignal provides a mechanism to send errors to AppSignal without having to start a transaction. This is useful for tracking errors that occur in code that's not in a web or background job context, such as separate [Rake tasks](/ruby/integrations/rake) or [Ruby scripts](/ruby/instrumentation/background-jobs). This is useful for instrumentation that doesn't automatically create AppSignal transactions to profile, such as our [integrations](/ruby/integrations). You can use the `Appsignal.send_error` method to directly send an exception to AppSignal from any place in your code without starting an AppSignal transaction with `Appsignal.monitor` first. ```ruby Ruby theme={null} begin # some code rescue => e Appsignal.send_error(e) end ``` #### Adding metadata In AppSignal for Ruby gem 2.9 and newer an additional block can be passed to the `Appsignal.send_error` method to add more metadata to the error transaction. This includes metadata such as the action name and parameters. Older versions of the Ruby gem will not allow additional metadata to be set. ```ruby Ruby theme={null} begin # some code rescue => e Appsignal.send_error(e) do |transaction| transaction.set_action("my_action") transaction.set_namespace("my_namespace") transaction.params = { :time => Time.now.utc } end end ``` ### Appsignal.listen\_for\_error > [!WARNING] > > This helper is removed in Ruby gem version 4. Instead, use a Ruby `rescue` > block with the [`Appsignal.report_error` helper](#appsignal-report_error). An alternative way to track errors with AppSignal is to wrap code that might raise an exception in a `listen_for_error` block. If an exception gets raised within that block it's automatically tracked by AppSignal and re-raised. This allows the application and frameworks to handle exception as normal. ```ruby Ruby theme={null} require "rake" require "appsignal" task :fail do Appsignal.listen_for_error do raise "I am an exception in a Rake task" end end ``` ## See also * [The Ruby debug gem: breakpoints, stepping, and the stack](/tutorials/ruby/debugging-with-the-debug-gem): use breakpoints and inspect the call stack while reproducing an exception locally. # Ignore instrumentation Source: https://docs.appsignal.com/ruby/instrumentation/ignore-instrumentation ## Ignore instrumentation events A web request or background job trace can contain many instrumentation events shown on the event timeline. However, not all events are essential as they may not provide significant or valuable insights into a trace's performance, and seeing a high number of events can make it difficult to spot problematic areas on the timeline. If the application has a place that creates a lot of events, like queries, external requests, or rendering views, the Ruby gem can ignore these events using the `ignore_instrumentation_events` helper. (In Ruby gem 3.10 and older the `ignore_instrumentation_events` helper is called `without_instrumentation`). ```ruby Ruby theme={null} class BackgroundWorker def perform Appsignal.ignore_instrumentation_events do 10_000.times do Appsignal.instrument "event_name.group_name" do # This instrumentation event will not be reported # Do complicated calculations end end end end end ``` The `ignore_instrumentation_events` helper will ignore events reported by the `instrument` helper. The Ruby gem will continue reporting errors and metrics that occur within this block. The `ignore_instrumentation_events` helper does not affect the trace's total duration. # Custom instrumentation for Ruby Source: https://docs.appsignal.com/ruby/instrumentation/instrumentation Add instrumentation to Ruby code with AppSignal helpers, nest events, and collect data from ActiveSupport::Notifications and Dry::Monitor. In order to find out what specific pieces of code are causing performance problems it's useful to add custom instrumentation to your application. This allows us to create better breakdowns of which code runs slowest and what type of action was the most time spent on. When you view saved traces of slow requests in AppSignal you'll be able to see all the instrumentation your application uses internally. Template rendering, ActiveRecord queries and caching are instrumented and will be shown in the trace. ![Default event tree](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/app_performance_sample_timeline_1.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=5d66c763209a2fa1e9e04252e792d566) That's already very useful, but wouldn't it be great if we could see measurements of specific pieces of code you suspect might influence your performance? Well, you can! By adding custom instrumentation, you can create more detailed breakdowns of a request or background job. You can instrument your code with the AppSignal instrumentation helpers, or with a notification library that AppSignal reads. Rails applications use ActiveSupport Notifications, and dry-rb applications use Dry::Monitor notifications. > [!TIP] > > **Note**: Make sure you've [integrated > AppSignal](/ruby/instrumentation/integrating-appsignal) before adding > custom instrumentation to your application if it's not automatically > integrated by one of our supported [integrations](/ruby/integrations). > Follow our [instrumentation for scripts and background jobs > guide](/ruby/instrumentation/background-jobs) for applications that we > don't automatically instrument. > [!TIP] > > **Note**: This page only describes how to add performance instrumentation to > your code. To track errors please read our [exception > handling](/ruby/instrumentation/exception-handling) guide. ## Instrumentation helpers When you add custom instrumentation to your code you'll be able to receive even more insights into your application. For example, you have to work with an external API that fetches articles for your homepage: ```ruby Ruby theme={null} class ArticleFetcher def self.fetch(category) Appsignal.instrument('fetch.article_fetcher') do # Download and process the articles end end end ArticleFetcher.fetch('Latest news') ``` Once you add custom instruments like this AppSignal will start picking them up and will show you how much time both an event group (`article_fetcher` in this case) and individual events took. ![Event tree with fetcher](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/app_performance_sample_timeline_2.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=d32f6f6efe5cce3991168d0fe9f06a77) In this case you'll notice that this API call is a huge influence on the performance of our homepage, which was hidden before. We might want to consider caching the articles. > [!TIP] > > **Note**: The name of the event you're instrumenting is important for our > processor. Read more about [event naming](/api/event-names). > [!TIP] > > **Note**: When AppSignal reports to [the AppSignal > Collector](/ruby/configuration/collector), these helpers take extra arguments > that describe the event as an OpenTelemetry span. Read more about [AppSignal > for Ruby and OpenTelemetry](/ruby/instrumentation/opentelemetry). ### Nesting instrumentation You can use as many instruments in any combination you like. You can nest instrument calls and AppSignal will handle the nesting and aggregates of the measurements nicely. You just have to keep the final segment (after the last dot) of the key consistent. ```ruby Ruby theme={null} Appsignal.instrument('fetch.article_fetcher') do 10.times do Appsignal.instrument('fetch_single_article.article_fetcher') do # Fetch single article end end end ``` ### Collecting more data per event By default AppSignal will collect the duration of an event and send it to our servers. Since custom instrumentation is not hooked up to any framework internals you might need to pass along more data if you want event details to show up in AppSignal. This can be a descriptive title, or more specific information like the query from a database call. We already do this for ActiveRecord, Sequel, Redis, MongoDB, Sinatra, Grape, [and more](/ruby/integrations). There are two helpers to allow you to instrument your code with AppSignal. ```ruby Ruby theme={null} Appsignal.instrument(name, title = nil, body = nil, body_format = Appsignal::EventFormatter::DEFAULT, &block) # and Appsignal.instrument_sql(name, title = nil, body = nil, &block) ``` #### `name` argument The name of the event that will appear in the event tree in AppSignal. Read more about [event key naming](/api/event-names). #### `title` argument A more descriptive title of an event, such as `"Fetch current user"` or `"Fetch blog post comments"`. It will appear next to the event name in the event tree on the performance trace page to provide a little more context on what's happening. ```ruby Ruby theme={null} Appsignal.instrument('fetch.custom_database', 'Fetch current user') do # ... end ``` In [collector mode](/ruby/configuration/collector), the event's span is named after both, as `category (title)`. The example above is recorded as `fetch.custom_database (Fetch current user)`. An event with no title is named after its category alone, and a title that matches the category is not repeated. #### `body` argument More details such as a database query that was used by the event. ```ruby Ruby theme={null} sql = 'SELECT * FROM posts ORDER BY created_at DESC LIMIT 1' Appsignal.instrument('fetch.custom_database', 'Fetch latest post', sql) do # ... end ``` > [!WARNING] > > **Warning**: Please make sure the body payloads are sanitized > (sensitive/dynamic data is removed). Non-sanitized body events will be > discarded if they reach a certain limit. Good: ```ruby Ruby theme={null} Appsignal.instrument('custom.instrument', 'Instrument stuff', 'command/dynamic/?') do # ... end Appsignal.instrument('custom.instrument', 'Instrument stuff', 'command/dynamic/?') do # ... end ``` Bad: ```ruby Ruby theme={null} Appsignal.instrument('custom.instrument', 'Instrument stuff', 'command/dynamic/123') do # ... end Appsignal.instrument('custom.instrument', 'Instrument stuff', 'command/dynamic/234') do # ... end ``` When passing in an SQL query as the body, you can use `body_format = Appsignal::EventFormatter::SQL_BODY_FORMAT` to do so. #### `body_format` argument Body format supports formatters to scrub the given data in the `body` argument to remove any sensitive data from the value. There are currently two supported values for the `body_format` argument. ##### `Appsignal::EventFormatter::DEFAULT` value The `Appsignal::EventFormatter::DEFAULT` is the default value of this argument. By default AppSignal will leave the value intact and not scrub any data from it. ##### `Appsignal::EventFormatter::SQL_BODY_FORMAT` value The `Appsignal::EventFormatter::SQL_BODY_FORMAT` value will run your data through the SQL sanitizer and scrub any values in SQL queries. We recommend you use the `Appsignal.instrument_sql` helper for this instead. ```sql SQL theme={null} SELECT * FROM users WHERE email = 'hector@appsignal.com' AND password = 'iamabot' -- becomes SELECT * FROM users WHERE email = ? AND password = ? ``` ## ActiveSupport::Notifications > [!TIP] > > In older versions of the AppSignal gem (1.2 and lower) the > `Appsignal.instrument` is not available. If you cannot upgrade, it's still > possible to use `ActiveSupport::Notifications` instead. If you don't want to > use the `Appsignal.instrument` helper, but instead want to use > `ActiveSupport::Notifications`, you can still do so in AppSignal for Ruby gem > 1.3 and higher too. The method for instrumenting your code using `ActiveSupport::Notifications` is very similar to how AppSignal does it. Using the article fetcher example again you can see the differences are quite small. Also see our documentation on AppSignal [event formatters](/ruby/instrumentation/event-formatters) when using `ActiveSupport::Notifications`. For more information about ActiveSupport::Notifications instrumentation, see the official Rails [`ActiveSupport::Notifications` documentation](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html). ```ruby Ruby theme={null} require "active_support" class ArticleFetcher def self.fetch(category) ActiveSupport::Notifications.instrument("fetch.article_fetcher") do # Download and process the articles end end end ArticleFetcher.fetch("Latest news") ``` It works for nested instrumentation calls as well. ```ruby Ruby theme={null} require "active_support" ActiveSupport::Notifications.instrument("fetch.article_fetcher") do 10.times do ActiveSupport::Notifications.instrument("fetch_single_article.article_fetcher") do # Fetch single article end end end ``` `ActiveSupport::Notifications` is highly flexible, you can instrument your code any way you like. More information about `ActiveSupport::Notifications` can be found in the [Rails API docs](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html). > [!WARNING] > > **Warning**: We do not track private `ActiveSupport::Notifications` events > that start with an exclamation mark (`!`). These events mostly include private > events generated by Rails. ## Dry::Monitor::Notifications AppSignal records events instrumented through `Dry::Monitor::Notifications`, the notification system used by the dry-rb libraries and by [ROM](/ruby/integrations/rom). ```ruby Ruby theme={null} require "dry/monitor" notifications = Dry::Monitor::Notifications.new(:app) notifications.instrument(:fetch_articles) do # Download and process the articles end ``` Dry::Monitor reports an event under an ID rather than a name, so AppSignal names the event after its ID followed by `.dry`. The example above is recorded as a `fetch_articles.dry` event. An [event formatter](/ruby/instrumentation/event-formatters) can give an event a name of its own instead. Read more about how AppSignal uses event names in our [event naming](/api/event-names) guide. # Integrating AppSignal in Ruby Source: https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal It's possible that AppSignal does not provide automatic integration for your framework of choice, or maybe you're using your own application setup. See our [list of supported integrations](/ruby/integrations) to see what frameworks and gems we support with the AppSignal gem. When AppSignal does not support your application automatically, it's still possible to add AppSignal instrumentation. Our Ruby gem needs to be configured and started once at the beginning of a process. It can be [configured](/ruby/configuration) through a configuration file or by using environment variables. ## Configuration ### Environment variables When using [environment variables](/ruby/configuration/load-order#environment-variables) to configure AppSignal the gem will read the configuration from the environment once it starts. Calling `Appsignal.start` is enough. ```ruby Ruby theme={null} require "appsignal" # Load your app Appsignal.start ``` ### Configuration file When using a [configuration file](/ruby/configuration#ruby-configuration-file) to configure AppSignal, the Ruby gem needs to be configured before it is started. It will look for the `config/appsignal.rb` file in the current working directory of the application process. Alternatively, it can also be configured using the [`Appsignal.configure` helper](/ruby/configuration#appsignal-configure-helper) as shown in the example below. ```ruby Ruby theme={null} require "appsignal" # Require the AppSignal gem # Optional: load integrations manually # These integrations need to be loaded before `Appsignal.configure` is called. # Appsignal.load(:sinatra) # Optional: Configure AppSignal via the configure helper # Appsignal.configure do |config| # # Some config # end # Lastly, start AppSignal Appsignal.start ``` AppSignal will look in the path of the first argument for a `config/` directory containing an `appsignal.rb` file to load the configuration. The second argument is the environment it will load from the configuration file. ## Next steps Continue with our [instrumentation for scripts and background jobs guide](/ruby/instrumentation/background-jobs) for applications that we don't automatically instrument. Use [instrumentation helpers](/ruby/instrumentation/instrumentation) to break down the instrumented code in more detail. # Add method instrumentation Source: https://docs.appsignal.com/ruby/instrumentation/method-instrumentation > [!TIP] > > Notes: > >
    >
  • > This feature is available since Ruby gem version 1.3 and only works for > classes. >
  • > >
  • > Ruby 3.0 support for keyword arguments was added in Ruby gem `2.11.4`. >
  • >
Sometimes [instrumentation blocks](/ruby/instrumentation/instrumentation) are not accurate enough. Every application is different, and so is the code that runs it. Developers know what code and, more accurately, what methods to instrument. It's possible to instrument methods in your Ruby code directly with AppSignal. Using the `appsignal` Ruby gem you can use our object integrations which provides you with some useful helpers to do so. ## Installation Activate the object integration by requiring the following line after loading the appsignal gem itself ```ruby Ruby theme={null} require 'appsignal/integrations/object' ``` and proceed to specify which methods you want to test on any class you want. ### Example ```ruby Ruby theme={null} require 'appsignal' require 'appsignal/integrations/object' class Foo def bar 1 end appsignal_instrument_method :bar def self.bar 2 end appsignal_instrument_class_method :bar end Foo.new.bar # => 1 Foo.bar # => 2 ``` ## Usage We have different helpers for instance methods and class methods, `appsignal_instrument_method` and `appsignal_instrument_class_method` respectively. Call them on class level in any Ruby class, even those from the Ruby standard library, and start instrumenting. You don't need to include anything else in the class, once you load the integration file it becomes available everywhere. Instrument any method by calling the helper with the name of the method you want to instrument. If the method does not exist, it will throw an error, just like Ruby would do by default. Once a request has been processed by AppSignal with this type of instrumentation you will be able to see the method instrumentation in the event breakdown on the trace page. ![Event tree with method instrumentation](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/method_instrumentation.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=52f4c7f087df04214b1c2d01be8caa89) You're also able to customize the name of the event that's send to us using the `:name` option. ```ruby Ruby theme={null} class Foo def bar end appsignal_instrument_method :bar def self.bar end appsignal_instrument_class_method :bar, name: "bar.class_method.Foo.methods" end ``` # Minutely probes Source: https://docs.appsignal.com/ruby/instrumentation/minutely-probes Minutely probes are a mechanism to periodically send [custom metrics](/metrics/custom) to AppSignal. This is a system that is included in the AppSignal Ruby gem by default. At the start of every minute the minutely probes are triggered one by one to collect metrics and then snoozed until the next minute. By default the AppSignal Ruby gem enables probes for [libraries](/ruby/integrations) that are detected for your app. > [!TIP] > > **Note**: In AppSignal Ruby gem 3.7.0 and lower, use the > `Appsignal::Minutely.probes` module to register probes, rather than the new > `Appsignal::Probes` API. ## Usage The minutely probes allow the AppSignal Ruby gem to collect [custom metrics](/metrics/custom) by default for [integrations](/ruby/integrations) and app-specific metrics by [creating your own probe](#creating-probes). ### Multiple instances Once activated, the minutely probes system runs on every instance of an app. This means that if a probe report metrics without some kind of differentiating tag, global metrics may be overwritten by instance-level metrics. For example, there's a probe that tracks how large the local background job queue is for an app. The queue database runs locally on the instance and queue sizes may vary wildly. Each instance of an app reports different metric values for the same metric and tags, overwriting the metric value every minute with those of the last reporting instance. To remedy this, we suggest [tagging](/metrics/custom#metric-tags) your metrics with the hostname or something else unique for each instance. For example, the [Sidekiq probe](/ruby/integrations/sidekiq#hostname-configuration) tags metrics with the Redis hostname by default. Alternatively you can [disable minutely probes](/ruby/configuration/options#option-enable_minutely_probes) for all but one instance, on which the minutely probes process is run. We suggest using the [`APPSIGNAL_ENABLE_MINUTELY_PROBES`](/ruby/configuration/options#option-enable_minutely_probes) environment variable to only enable it on the instance of your choosing. ## Configuration The minutely probes are configured using the [`enable_minutely_probes`](/ruby/configuration/options#option-enable_minutely_probes) config option. ## Creating probes If you want to track more [custom metrics](/metrics/custom) from your app than our the default probes that ship with our [integrations](/ruby/integrations/), you can add your own probe(s). An AppSignal minutely probe can be either of three things. Which of the three types to use for your class depends on the use case. * [Lambda probe](#lambda-probe) * [Class probe](#class-probe) * [Initialized class probe](#initialized-class-probe) ### Lambda probe The simplest probe type to register. If you have no dependencies for your probe this is the preferred method. ```ruby Ruby theme={null} # config/initializers/appsignal.rb or a file that's loaded on boot Appsignal::Probes.register(:my_probe, lambda do Appsignal.set_gauge("database_size", 10) end) ``` ### Class probe A class probe is a lazy initialized probe. It will only be started if the minutely probes are started. It will be initialized at the start of the minutely probes thread and remain initialized for as long as your app is running. This method is useful when you do not have [`enable_minutely_probes`](/ruby/configuration/options#option-enable_minutely_probes) enabled for every environment and don't want it to be initialized by default. ```ruby Ruby theme={null} # config/initializers/appsignal.rb or a file that's loaded on boot # Creating a probe using a Ruby class class BackgroundJobLibraryProbe def initialize # This is only called when the minutely probe gets initialized require "background_job_library" @connection = BackgroundJobLibrary.connection end def call stats = @connection.fetch_queue_stats Appsignal.set_gauge "background_job_library_queue_length", stats.queue_length Appsignal.set_gauge "background_job_library_processed_jobs", stats.processed_jobs end end # Registering a Class probe Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe ) ``` ### Initialized class probe This method is most useful for [overriding default probes](#overriding-default-probes). The AppSignal Ruby gem ships some probes for [integrations](/ruby/integrations) by default. These default probes register probes as a [class](#class-probe) so they won't be initialized when overridden. When the probe default config does not fit your use case you can [override a default probe](#overriding-default-probes) with your own config. Note that we do not register a [class as a probe](#class-probe), but an instance of the class using `.new` and pass along a config object, e.g. `BackgroundJobLibraryProbe.new()`. ```ruby Ruby theme={null} # config/initializers/appsignal.rb or a file that's loaded on boot require "background_job_library" # Creating a probe using a Ruby class class BackgroundJobLibraryProbe def initialize(config) @connection = BackgroundJobLibrary.connection(config) end def call stats = @connection.fetch_queue_stats Appsignal.set_gauge "background_job_library_queue_length", stats.queue_length Appsignal.set_gauge "background_job_library_processed_jobs", stats.processed_jobs end end # Registering an initialized Class probe Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe.new(:database => "redis://localhost:6379") ) ``` ## Registering probes Probes can be registered with the `register` method on the `Appsignal::Probes` module. This method accepts two arguments. * `key` - This is the key/name of the probe. This will be used to identify the probe in case an error occurs while executing the probe (which will be logged to the [appsignal.log file](/support/debugging#logs)) and to [override an existing probe](#overriding-default-probes). * `probe` - This is one of the [supported probe types](#creating-probes) that should be called every minute to collect metrics. ```ruby Ruby theme={null} # config/initializers/appsignal.rb or a file that's loaded on boot Appsignal::Probes.register(:my_probe, lambda do Appsignal.set_gauge("database_size", 10) end) ``` ### Rails apps We recommend registering your probes in a Rails initializer, like: `config/initializers/my_probe.rb`. ## Dependency requirements Not always should a probe be added to the list of probes by default. Some dependency may be required for the probe to work properly. This dependency check is used in probes shipped in the gem, but can also be used in your own probes. By adding a class method called `dependencies_present?`, a check can be performed ahead of starting the probe whether not it should be started. This works on both [class probes](#class-probe) and [initialized class probes](#initialized-class-probe). For the latter scenario there should be no call to said dependency in the `initialize` method of the probe as it's already initialized. ```ruby Ruby theme={null} # config/initializers/appsignal.rb or a file that's loaded on boot require "background_job_library" # Creating a probe using a Ruby class class BackgroundJobLibraryProbe def self.dependencies_present? # Only start the probe if the BackgroundJobLibrary version is higher or # equal to 1.0.0. Gem::Version.new(BackgroundJobLibrary::Version) >= Gem::Version.new("1.0.0") end def initialize(config = {}) @config = config end def call stats = connection.fetch_queue_stats Appsignal.set_gauge "background_job_library_queue_length", stats.queue_length Appsignal.set_gauge "background_job_library_processed_jobs", stats.processed_jobs end private def connection @connection ||= BackgroundJobLibrary.connection(@config) end end # Registering a Class probe with a `dependencies_present?` check Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe ) # Also works for initialized probes Appsignal::Probes.register( :background_job_library_probe, BackgroundJobLibraryProbe.new(:url => "schema://my_connection_url:9090") ) ``` ## Overriding default probes AppSignal ships with default probes for certain [integrations](/ruby/integrations/). If for any reason this probe does not function properly or requires some additional configuration for your use case, you can override the default probe by [initializing the probe class](#initialized-class-probe) with your own config. Example overriding the [Sidekiq probe](/ruby/integrations/sidekiq#hostname-configuration). ```ruby Ruby theme={null} # config/initializers/appsignal.rb or a file that's loaded on boot Appsignal::Probes.register( :sidekiq, # Use the same key as the default Sidekiq probe to override it Appsignal::Probes::SidekiqProbe.new(:hostname => ENV["REDIS_URL"]) ) ``` (Note that you'll need to set the `REDIS_URL` environment variable yourself.) Overriding probes will log a debug message in the [appsignal.log file](/support/debugging#logs) which can help to detect if a probe is correctly overridden. ## Unregister probes To unregister previously registered probes, including the default probes, use the `Appsignal::Probes.unregister` method. Call the unregister method with the name of the probe to unregister it. ```ruby Ruby theme={null} Appsignal::Probes.unregister( :probe_name # Use the same key as used in `Probes.register` to unregister it ) ``` # AppSignal for Ruby and OpenTelemetry Source: https://docs.appsignal.com/ruby/instrumentation/opentelemetry > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. In [collector mode](/ruby/configuration/collector), AppSignal builds its traces out of OpenTelemetry spans. A transaction becomes the root span of a trace. Every event you instrument becomes a child span inside it. Your own OpenTelemetry instrumentation therefore shares those traces. This page covers what that gives you, and how to describe a span in more detail than AppSignal does on its own. ## Describing a span in OpenTelemetry's terms Attributes are key and value pairs on a span. The [semantic conventions](https://opentelemetry.io/docs/specs/semconv/) name the attributes to use for common work, such as a database query or an outgoing HTTP request. Use those names where they apply, so other tools can read what you record. Add attributes to the span AppSignal is currently recording with `add_opentelemetry_attributes`: ```ruby Ruby theme={null} Appsignal.instrument("query.my_database") do Appsignal::Transaction.current.add_opentelemetry_attributes( "db.system.name" => "mysql", "db.namespace" => "orders" ) run_the_query end ``` The attributes are added to the innermost event that is open at the time, which is the `query.my_database` event in the example above. When no event is open, they are added to the transaction's own span instead. A value must be a string, an integer, a float, or a boolean. Any other value is converted to a string. ## Span kinds and instrumentation scopes ### Span kind A span's kind says what role the work played in the trace. A span that served an incoming request is a `:server` span. A span that called out to another service is a `:client` span. Sending and receiving a message on a queue are `:producer` and `:consumer` spans. Work that stayed inside your application is an `:internal` span. An event's span can be any of those five kinds. It is `:internal` unless you set one. The exception is `Appsignal.instrument_sql`, which records a `:client` span, because a query is an outgoing call to a datastore. A transaction's span can be `:server`, `:consumer`, `:producer`, or `:internal`. It is `:server` unless you set one. A kind outside that list falls back to `:server`. ```ruby Ruby theme={null} Appsignal.instrument("request.my_api", :opentelemetry_kind => :client) do call_the_api end ``` ### Instrumentation scope An instrumentation scope names the library a piece of instrumentation is written for, as a name and version pair. It is not always the library the work ran through. Instrumentation for a database adapter is scoped to the database library it talks to, not to the adapter. AppSignal breaks down the time events took and the allocations they made by instrumentation scope. The scope therefore decides which library a span's cost is reported against. Spans are recorded under AppSignal's default scope when you do not set one. Set a scope of your own when you instrument a library on its behalf, so that its cost is reported against that library. ```ruby Ruby theme={null} Appsignal.instrument( "query.my_database", :opentelemetry_scope => ["my_database", "2.1.0"] ) do run_the_query end ``` ### Which methods accept a kind or a scope Pass `opentelemetry_kind` and `opentelemetry_scope` to any method that starts a transaction or records an event: * `Appsignal.monitor` * `Appsignal.monitor_and_stop` * `Appsignal.send_error` * `Appsignal.report_error` * `Appsignal.instrument` * `Appsignal.instrument_sql` Set `opentelemetry_kind` to `:internal` on `Appsignal.instrument_sql` to override its `:client` default. ## Continuing a trace from somewhere else Work can reach your application from somewhere AppSignal does not instrument, carrying an OpenTelemetry context of its own. That context names the trace the work belongs to. Passing it lets both sides be read as one trace instead of two. Pass the context as `opentelemetry_context`. Say what the transaction's span should do with it as `opentelemetry_relationship`: * `:parent` makes the transaction's span a child of the incoming span. The work continues the same trace. This is what happens when you pass a context and say nothing else. * `:link` starts a new trace and records a link back to the incoming span. Use this when the work is its own unit rather than a continuation, which is usually the case for a background job. * `:both` parents the span and records the link. * `:none` ignores the incoming context. ```ruby Ruby theme={null} context = OpenTelemetry.propagation.extract(message.headers) Appsignal.monitor( :action => "MessageConsumer#perform", :namespace => "background_job", :opentelemetry_kind => :consumer, :opentelemetry_relationship => :link, :opentelemetry_context => context ) do handle(message) end ``` ### Which methods accept a context and a relationship Pass `opentelemetry_context` and `opentelemetry_relationship` to any method that starts a transaction: * `Appsignal.monitor` * `Appsignal.monitor_and_stop` * `Appsignal.send_error` * `Appsignal.report_error` `Appsignal.report_error` is the exception. It starts a transaction only when none is open. Both arguments apply when it starts one, and are ignored when it adds the error to a transaction that is already open. You only need any of this for work AppSignal does not instrument. The libraries listed under [distributed tracing](/ruby/distributed-tracing) are connected for you. ## Using the OpenTelemetry SDK directly You can create spans with the OpenTelemetry SDK inside code AppSignal is tracing. AppSignal makes its own span current while it records, so a span you create becomes a child of the AppSignal event you are inside. ```ruby Ruby theme={null} tracer = OpenTelemetry.tracer_provider.tracer("my-app") Appsignal.instrument("checkout") do # This span is recorded as a child of the "checkout" event. tracer.in_span("charge_card") do |span| span.set_attribute("payment.provider", "stripe") charge_the_card end end ``` Use `in_span` rather than starting and finishing spans yourself. It makes the span current for the duration of the block, finishes it afterwards, and does both correctly when your code raises an error. Data you report through AppSignal is always recorded on a span AppSignal created, never on a span you created. An error reported to AppSignal inside your own span is recorded on the AppSignal event that surrounds it, or on the transaction's span when no event is open. Your spans carry only what you record on them yourself. ## Using third-party OpenTelemetry instrumentation You can install instrumentation packages written by other people, such as the ones the OpenTelemetry project publishes for common libraries. Install and configure them as their own documentation describes. AppSignal needs no setup for them, and their spans appear in your traces alongside AppSignal's own. This works because those packages record their work under whatever span is currently open, and AppSignal keeps its own span open while it records. So their spans land inside the request or job AppSignal is tracing, in the place you would expect. It does not work the other way around. AppSignal always starts a transaction as the beginning of a new trace, and does not look at what OpenTelemetry currently has open. If a package opens a span of its own and an AppSignal request or job begins inside it, that request does not join the package's trace. You get two traces instead of one, with no connection between them. This matters when a package instruments the entry point into your application, because AppSignal instruments those entry points too. When a package instruments work that happens partway through a request AppSignal is already tracing, which is the usual case, the two fit together without you doing anything. When you do need to join a trace that AppSignal did not start, pass its context yourself. See [continuing a trace from somewhere else](#continuing-a-trace-from-somewhere-else). # Track request queue time Source: https://docs.appsignal.com/ruby/instrumentation/request-queue-time ## Queue times A common setup for Ruby application is that the Ruby webserver such as Unicorn or Puma runs behind another (outer) webserver such as Nginx or Apache. Those are usually used to terminate SSL connections and handle static assets for example. When your Ruby webserver is busy processing requests, Nginx or Apache can still accept new connections and wait for a Ruby process to become available to handle the request. The outer webserver queue's the request in the meantime. Ideally there is enough capacity that the outer webserver never has to wait on Ruby, but in practice this can happen when there's a sudden spike of requests. A good indicator of capacity therefore is the queue time metric, e.g. the amount of time between when the outer webserver accepted the request and Ruby handles the request. A long queue time for a longer period of time indicates that you'll need to scale up the amount of Ruby processes/threads to handle requests, or scale more webservers. You can find the queue time metrics on the Performance graphs page: ![Screenshot of Queue time graph](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/queue_time_graph.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=59ec70caa98e86cf5ec34dd5c76eb045) ## Setup AppSignal automatically tracks the queue time on Heroku, but if you run your own server with NGINX or Apache, you'll need to setup the correct headers for queue time tracking to work. ### NGINX You can use the [`${msec}`](http://nginx.org/en/docs/http/ngx_http_core_module.html#variables) variable with [NGINX 1.2.6](http://nginx.org/en/docs/http/ngx_http_core_module.html#variables) or higher. This is the current time in milliseconds. ```ruby Ruby theme={null} proxy_set_header X-Request-Start "t=${msec}"; ``` ### Apache In Apache [mod\_headers](https://httpd.apache.org/docs/current/mod/mod_headers.html) exposes a `"$t"` variable that can be used to track the queue time. Add the header as follows: ```ruby Ruby theme={null} RequestHeader set X-Request-Start "%t" ``` ### HAProxy Add the following to the relevant HAProxy frontend configuration to track the request's queue time. This exposes the datetime value for when the request was sent so that AppSignal can calculate the request's queue time. ```conf Config theme={null} http-request set-header X-Request-Start t=%[date(0, us)] ``` ## Namespaces From Ruby gem 2.11 and newer queue time is reported for all namespaces. Previously it would only report queue times for the "web" and "background" namespaces. Update to the latest version of the Ruby gem if you do not see queue time graphs for your [custom namespaces](/application/namespaces) # Ruby integrations Source: https://docs.appsignal.com/ruby/integrations Ruby frameworks and gems AppSignal instruments, including Rails, Sinatra, Sidekiq, Solid Queue, Puma, and Active Job. AppSignal works with most popular Ruby frameworks and gems out-of-the-box such as: * [Action Cable](/ruby/integrations/action-cable) * [Active Job](/ruby/integrations/active-job) * [Capistrano](/ruby/integrations/capistrano) * [DataMapper](/ruby/integrations/datamapper) * [Delayed::Job](/ruby/integrations/delayed-job) * [Elasticsearch](/ruby/integrations/elasticsearch) * [Excon](/ruby/integrations/excon) * [Faraday](/ruby/integrations/faraday) * [Garbage Collection](/ruby/integrations/garbage-collection) * [Global VM Lock](/ruby/integrations/global-vm-lock) * [Grape](/ruby/integrations/grape) * [GraphQL](/ruby/integrations/graphql) * [Hanami](/ruby/integrations/hanami) * [HTTP.rb](/ruby/integrations/http) * [MongoDB](/ruby/integrations/mongodb) * [Multiple Rack libraries](/ruby/integrations/rack-libraries) * [Net::HTTP](/ruby/integrations/net-http) * [Padrino](/ruby/integrations/padrino) * [Puma](/ruby/integrations/puma) * [Que](/ruby/integrations/que) * [Rack](/ruby/integrations/rack) * [Rake](/ruby/integrations/rake) * [Redis](/ruby/integrations/redis) * [Resque](/ruby/integrations/resque) * [ROM](/ruby/integrations/rom) * [Ruby on Rails](/ruby/integrations/rails) * [Ruby VM](/ruby/integrations/ruby-vm) * [Sequel](/ruby/integrations/sequel) * [Shoryuken](/ruby/integrations/shoryuken) * [Sidekiq](/ruby/integrations/sidekiq) * [Solid Queue](/ruby/integrations/solidqueue) * [Sinatra](/ruby/integrations/sinatra) * [ViewComponent](/ruby/integrations/view-component) * [Webmachine](/ruby/integrations/webmachine) We try to make most integrations work automatically, but some might require some manual configuration steps. ## Supported through another integration Some libraries and frameworks don't have a dedicated integration page, but AppSignal can monitor them through one of the integrations above. AppSignal does not have a dedicated GoodJob integration. GoodJob jobs are monitored through our [GoodJob page](/ruby/integrations/goodjob) when GoodJob is configured as the Active Job queue adapter. If a certain library isn't automatically supported it's possible to [integrate AppSignal manually][integrating]. For a more detailed examples on how to integrate AppSignal, visit our [examples repository][examples-repo]. [integrating]: /ruby/instrumentation/integrating-appsignal.html [examples-repo]: https://github.com/appsignal/appsignal-examples # Action Cable Source: https://docs.appsignal.com/ruby/integrations/action-cable [Action Cable](https://guides.rubyonrails.org/action_cable_overview.html) is Rails' framework for WebSocket connections, allowing real-time communication between the server and client. ## Supported instrumentation When you have Action Cable channels in your Rails application, AppSignal automatically tracks: * Channel subscription events * Channel messages * Error tracking in channels All Action Cable activity is reported under your application's "action\_cable" namespace. ## No additional configuration needed AppSignal supports Action Cable out-of-the-box without the need for manual instrumentation. For additional Rails setup instructions, see our [Rails integration guide](/ruby/integrations/rails). # Active Job Source: https://docs.appsignal.com/ruby/integrations/active-job Active Job is a framework for declaring jobs and making them run on a variety of queuing backends shipped with Rails. The Active Job integration tracks the execution and events from the job being performed. When AppSignal detects Active Job metrics, it will create an [Intelligence dashboard](#intelligence-dashboard), allowing you to monitor core metrics visually. ## Supported adapters The Active Job integration supports all [Active Job adapters](https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html). It may also offer support for adapters not listed on that page, which are accessible through a separate gem. However, these adapters have not been tested. Adapters without a dedicated AppSignal integration are monitored through Active Job instrumentation, such as [GoodJob](/ruby/integrations/goodjob). ## Integration with AppSignal-supported libraries The following background job libraries that AppSignal supports are automatically integrated with Active Job, allowing AppSignal to give you more in-depth performance insights: * [Delayed::Job](/ruby/integrations/delayed-job) * [Que](/ruby/integrations/que) * [Resque](/ruby/integrations/resque) * [Sidekiq](/ruby/integrations/sidekiq) * [Solid Queue](/ruby/integrations/solidqueue) ## Report errors on job discard Set the [`activejob_report_errors` config option](/ruby/configuration/options#option-activejob_report_errors) to `discard` to only report errors when a job is discarded. When a job is discarded, all job retries have been exhausted, and the job is no longer retried. Read the [Active Job documentation](https://guides.rubyonrails.org/active_job_basics.html#exceptions) to learn more about Active Job exception handling and failed job retries. ```ruby Ruby theme={null} class ExampleJob < ActiveJob::Base # Configure the retry attempts using the `retry_on` method retry_on StandardError, :attempts => 2 # ... end ``` > [!WARNING] > > Some Active Job adapters (such as Sidekiq, Delayed::Job, etc.) have their own > retry system. After Active Job has exhausted its retries, these libraries > may trigger their own job retry system. > > This will retry jobs even after it has exhausted the Active Job retries and > discarded the job. To avoid retrying jobs after Active Job has stopped > retrying the job, and it reporting errors for those retries, make sure the > adapter's retry system is disabled. > > When relying on Sidekiq's retry system, also configure it [to report errors > only on discard](/ruby/integrations/sidekiq#report-errors-on-job-discard), > so that it won't report errors multiple times. ## Enqueue instrumentation Enqueuing a job through Active Job records an `enqueue.active_job` event, titled after the job being enqueued. When a job is enqueued through an adapter that AppSignal also instruments, such as Sidekiq or Resque, AppSignal suppresses the adapter's own enqueue event and records the enqueue once as the Active Job event. AppSignal records enqueue events on the active transaction's event timeline, for example when you enqueue a job from within a web request or from within another job. It only records them when a transaction is active, so enqueuing a job outside of a transaction records nothing. To stop recording enqueue events across all background job integrations, set the [`enable_job_enqueue_instrumentation` config option](/ruby/configuration/options#option-enable_job_enqueue_instrumentation) to `false`. This does not affect the instrumentation of the jobs themselves. ## Metadata AppSignal collects the following metadata for Active Job jobs: | Metadata | Description | | - | - | | Active Job ID | The Active Job ID is reported by the Active Job adapter. | | Arguments | Arguments passed to the job when calling `perform_later`. | | Events | All `*.active_job` events. | | Job name | e.g. `MyBackgroundJob#perform` as used to group the job for AppSignal incidents. | | Priority | The trace's priority, if using an adapter that supports job priority. | | Provider job ID | The job ID reported by the Active Job adapter. | | Queue | The trace's queue name, if using an adapter that supports multiple queues. | | Queue time\* | Time elapsed from a job being queued and performed. | *\*From Rails version 6 onwards queue times are reported for the namespace they are reported from and can be viewed in AppSignal's [Performance Graphs](https://appsignal.com/redirect-to/app?to=performance/graphs).* AppSignal uses Active Job metadata to give you deeper contextual insights into job performance. When inspecting Active Job traces in AppSignal: * The job name groups the job's traces on the Performance page: ![Active Job traces grouped by job name on the Performance page](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/active-job/job-performance-samples.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=588a6106f603a5fabf6d90a600858de8) * Metadata (excluding job name and events) is available as filterable tags on the trace page: ![Active Job metadata shown as tags on a trace](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/active-job/job-tags.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=e5ae132bde76673f2d68f2aa30a48d00) * The job's spans appear in the trace timeline on the [trace page](/trace-page): ![Trace timeline of an Active Job job](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/active-job/job-event-timeline.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=2356c80ec1f15588a277647b7b78c6f3) ## Intelligence dashboard When AppSignal receives Active Job metrics, it will create an Active Job Intelligence dashboard, available from the dashboard section of the AppSignal app. When a newer version of the dashboard is available, a banner at the top offers to [update it](/metrics/intelligence-dashboards#dashboard-updates). ![Active Job Intelligence dashboard showing job status, throughput, duration, and queue time charts](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/active-job/dashboard.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=64dcb74f9b649537ef637f2b32cf6ad8) The Active Job Intelligence dashboard in AppSignal The Active Job Intelligence dashboard will have the following graphs: | Graph | Metrics | [Tags](/appsignal/terminology#tags) | | - | - | - | | [Duration per job class](#duration-per-job-class-graph) | `trace_duration` |
  • `namespace`
  • `action`
  • | | [Job status per queue](#job-status-per-queue-graph) | `active_job_queue_job_count` |
  • `status`
  • `queue`
  • | | [Job status per queue with priority](#job-status-per-queue-with-priority-graph) | `active_job_queue_priority_job_count` |
  • `status`
  • `queue`
  • `priority`
  • | | [Queue time per queue](#queue-time-per-queue-graph) | `active_job_queue_time` | `queue` | | [Throughput per job class](#throughput-per-job-class-graph) | `trace_duration` |
  • `namespace`
  • `action`
  • | > [!NOTE] > > The Duration and Throughput charts use `trace_duration` on accounts that have been moved to trace metrics. Accounts that have not been moved yet see these charts powered by `transaction_duration` instead. Tags give you a contextual breakdown of Active Job performance information. AppSignal reports the following tags for Active Job jobs: | Name | Description | | - | - | | `action` | The name of the action the metric was reported from (eg: `YourWorker#perform`). | | `namespace` | The namespace the job ran in. On this dashboard it is always `background`. | | `queue` | Named queue in which jobs are processed, e.g. `default` or `mailer`. | | `status` | Status of each job, either `processed` or `failed`. Jobs that are `failed` are also counted as `processed`. | | `priority` | The priority given to each job, e.g. `0` or `1`. | Each tag is represented with a colored line on the graph. ### Duration per job class graph The Duration per job class graph shows the amount of time that it took for jobs to execute, grouped by the class that defines the job. You can use this graph to monitor the performance of jobs, per class, giving you a helicopter view of job performance and allowing you to quickly identify and investigate spikes in duration time. ### Job status per queue graph The Job status per queue graph shows the number of jobs that were executed, grouped by their resulting status and by the queue in which they were enqueued. You can use this graph to monitor job error counts and performance based on queue, identify bottlenecks, and optimize your background jobs for scalability. ### Job status per queue with priority graph > [!TIP] > > Not all [Active Job adapters](#supported-adapters) support job priority. If > jobs have no priority values, the graph will be empty. The Job status per queue with a priority graph shows the number of jobs that were executed, grouped by their resulting status by the queue in which they were enqueued, and by the priority that was given to them. You can use this graph to monitor job error counts and performance based on queue and priority, identify bottlenecks, and optimize your background jobs for scalability. ### Queue time per queue graph The Queue time per queue graph shows how long jobs waited in each queue before they started, as a mean, 90th percentile, and 95th percentile. You can use this graph to spot queues that are falling behind and decide whether a queue needs more workers. ### Throughput per job class graph The Throughput per job class graph shows the amount of jobs that were executed, grouped by the class that defines the job. You can use this graph to monitor how many jobs are executed, grouped by the class that defines the job. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The enqueue and the job's own span both carry: * `messaging.system` — the queueing library. * `messaging.destination.name` — the queue the job was put on. * `messaging.operation.type` — whether the span is the enqueue or the job running. A span for a job that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A job runs in the same trace as the code that enqueued it, appearing under the request or job that scheduled it. You can trace a slow job back to what caused it to run. The trace is carried in the job's serialized arguments. Active Job runs on a queue adapter. When that adapter is one AppSignal instruments, such as Sidekiq or Resque, its own behavior applies as well. Read more about [distributed tracing](/distributed-tracing). ## See also * [Solid Queue: run background jobs in your database](/tutorials/ruby/solid-queue): use the database you already run as an Active Job backend. Rails 8 configures it in new applications; this covers adding it to an existing one. * [Sidekiq batches: run jobs in parallel, then act](/tutorials/ruby/batching-background-jobs): split one unit of work across many jobs, then run a callback once every job has succeeded. # Capistrano Source: https://docs.appsignal.com/ruby/integrations/capistrano The [Capistrano](http://capistranorb.com/) integration makes sure an AppSignal deploy marker is created on every deploy. Read more about [deploy markers](/appsignal/terminology#markers). Some manual configuration may be required. ## Installation Make sure you load the `appsignal/capistrano` file in Capistrano's `Capfile`. This should be done automatically when you run the `appsignal install` command during installation. ```ruby Ruby theme={null} # Capfile require 'capistrano' # Other Capistrano requires. require 'appsignal/capistrano' ``` ## Configuration ### appsignal\_config ```ruby Ruby theme={null} # deploy.rb set :appsignal_config, name: 'My app' ``` `appsignal_config` allows you to override any config loaded from the [configuration file](/ruby/configuration). ### appsignal\_env (since gem version 1.3) ```ruby Ruby theme={null} # deploy.rb set :stage, :alpha set :appsignal_env, :staging ``` `appsignal_env` allows you to load a different AppSignal environment when a stage name doesn't match the AppSignal environment as named in the AppSignal config file or environment variable. ### appsignal\_revision (since gem version 0.8.8) > [!WARNING] > > This method of reporting deploy markers is **deprecated** and may be removed at any time in the future. > > Since Ruby gem 4.6.0, AppSignal automatically detects deployments by reading the `REVISION` file that Capistrano adds to the release directory. > > Reporting deploy markers using this method is only useful for small applications that use one application instance. It creates a new deploy marker at a specific time, regardless of the version the application is actually running. This also means it's more error prone to group data that shouldn't belong to it under the deploy. In Capistrano 2 AppSignal is able to fetch the revision from the Capistrano config. In Capistrano 3 however, this is no longer available and setting the revision is recommended. ```ruby Ruby theme={null} # deploy.rb set :appsignal_revision, "my_revision" ``` The revision can be set manually or fetched from the git repository locally. ```ruby Ruby theme={null} # Sets the current branch's git commit SHA as the revision set :appsignal_revision, `git rev-parse --short HEAD`.strip ``` If you're using the branch configuration setting Capistrano you can also set git to fetch the commit SHA from the selected branch. ```ruby Ruby theme={null} set :branch, "main" # Sets the selected branch's git commit SHA as the revision set :appsignal_revision, `git rev-parse --short #{fetch(:branch)}`.strip ``` ### appsignal\_user (since gem version 2.4.0) Used in combination with `appsignal_revision` (if necessary), it's possible to customize a deploy user for Capistrano deploys. By default this uses the system's local username, read from the `USER` or `USERNAME` environment variable, so there's no need to configure it if the system has these variables available. If you do want to customize the deploy user, set the `:appsignal_user` config option in your Capistrano config. ```ruby Ruby theme={null} # deploy.rb set :appsignal_user, "Jane" # Custom deploy user name ``` ## Example applications We have two example applications in our examples repository on GitHub. The examples show how to set up AppSignal in small Capistrano applications while loading configuration values from the environment using gems like dotenv and Figaro. * [AppSignal + Capistrano + dotenv][example-dotenv-app] * [AppSignal + Capistrano + Figaro][example-figaro-app] [example-dotenv-app]: https://github.com/appsignal/appsignal-examples/tree/capistrano+dotenv [example-figaro-app]: https://github.com/appsignal/appsignal-examples/tree/capistrano+figaro # CodeOwnership Source: https://docs.appsignal.com/ruby/integrations/code-ownership The AppSignal gem is compatible out of the box with the [CodeOwnership](https://github.com/rubyatscale/code_ownership) gem. ## Usage When an error is reported, the AppSignal gem will tag the current transaction with the owner of the file that caused the error: ![CodeOwnership integration in AppSignal](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/ruby/integrations/ownership/owner-tag.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=12141ed9f7c50631e3e5f56a92426cfd) You can use this tag to filter traces in AppSignal. ## Disable integration CodeOwnership integration is enabled by default. To disable it, set the [`instrument_code_ownership` configuration option](/ruby/configuration/options#option-instrument_code_ownership) to `false`. # DataMapper Source: https://docs.appsignal.com/ruby/integrations/datamapper The AppSignal gem works out of the box with [DataMapper](http://datamapper.org/)! Nothing to do. Lucky! ## Performance monitoring Queries run through DataMapper are recorded as `query.data_mapper` events. The event body holds the query that ran, with its values removed. The event appears in the event timeline of your application's performance actions, and in the "Slow queries" performance panel. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The query's span carries: * `db.system.name` — the database the query ran against, such as `postgresql` or `mysql`. * `db.query.text` — the query, with its values removed. # Delayed::Job Source: https://docs.appsignal.com/ruby/integrations/delayed-job [Delayed::Job](https://github.com/collectiveidea/delayed_job) is one of the most popular background processors for Ruby and Rails, originally created at [Shopify](https://shopifyengineering.myshopify.com/). The AppSignal gem detects Delayed Job when it's present and hooks into the standard Delayed Job callbacks. No further action is required to enable integration. This integration aims to support all the different Delayed::Job enqueuing methods. Some methods may have limitations or customization options. ## Classes with `#perform` methods > [!TIP] > > **Note**: Reporting of jobs using this method is supported since AppSignal > Ruby gem version 2.11.0. Delayed Job supports enqueuing jobs based on instances of classes or structs that listen to a `perform` instance method, when enqueued with `Delayed::Job.enqueue`. AppSignal will use the object's class name as the action naming, appending `#perform` to the action name. A job for `StructJob` is reported as `StructJob#perform`. ```ruby Ruby theme={null} class StructJob < Struct.new(:id) def perform # Do stuff end end Delayed::Job.enqueue(StructJob.new("id")) # Reported as "StructJob#perform" ``` Note that this method of enqueuing does not support arguments as a whole object is enqueued. Job objects are serialized when enqueued and deserialized when processed. AppSignal does not read the state of the deserialized object. The argument `id` for the `StructJob` in the example above is not reported. ## Jobs using `display_name` Delayed Job allows any class to define its own `display_name`. This `display_name` value can interfere with AppSignal's reporting if it is built using dynamic values, such as the arguments given to the job. If the `display_name` method return value does not return a String with the `ClassName#method_name` format, AppSignal treats each job as a separate entity, creating many Incidents and notifications. This breaks the grouping AppSignal does for these jobs, resulting in AppSignal reporting many unique variations of incidents for the job, and unusable metrics in graphs. To prevent this from happening, define an `appsignal_name` method that returns a job name using the `ClassName#method_name` format. This way the jobs will be grouped correctly again. ```ruby Ruby theme={null} class StructJobWithName < Struct.new(:id) def perform # Do stuff end # This returns an unique job name, creating new incidents and graphs for each # unique job name. def display_name "StructJobWithName-#{id}" end # This will group the jobs back to a single entity, allowing incidents # and graphs to work properly. def appsignal_name "StructJobWithName#perform" end end Delayed::Job.enqueue(StructJobWithName.new("id")) # Reported as "StructJobWithName#perform" ``` ## Delay method call support Method calls queued with the delay extension will be reported with an action name similar to how they are called. The arguments given to the delayed method will be reported as the arguments for the job. ```ruby Ruby theme={null} Post.delay.archive_all("some selector") # Reported as "Post.archive_all" Post.create(:title => "Post title").delay.send_mail("mail subject") # Reported as "Post#send_mail" ``` ## Delayed::Job.enqueue support > [!TIP] > > **Note**: Job name detection was added in Ruby gem version 2.11.0. Custom jobs objects enqueued with `Delayed::Job.enqueue` will be reported as normal, but will not report arguments. A whole object is given to Delayed::Job, and serialized into YAML and back. We can't detect arguments in this scenario. ```ruby Ruby theme={null} Delayed::Job.enqueue job_object ``` ## Enqueue instrumentation Enqueuing a job with Delayed::Job records an `enqueue.delayed_job` event, titled after the job being enqueued. If a job defines an `appsignal_name`, the enqueue event uses it, the same way the performed job's action name does. AppSignal records enqueue events on the active transaction's event timeline, for example when you enqueue a job from within a web request or from within another job. It only records them when a transaction is active, so enqueuing a job outside of a transaction records nothing. To stop recording enqueue events across all background job integrations, set the [`enable_job_enqueue_instrumentation` config option](/ruby/configuration/options#option-enable_job_enqueue_instrumentation) to `false`. This does not affect the instrumentation of the jobs themselves. ## Active Job support The Delayed Job integration is compatible with [Active Job](/ruby/integrations/active-job). It will report [queue times in graphs](https://appsignal.com/redirect-to/app?to=performance/graphs), queues and priorities if set on the job. Upgrade to version 2.11.0 of the Ruby gem or newer for improved support. ## Changes to the integration ### Queue time In AppSignal for Ruby gem 2.3.0 a change was made to the queue time registration. In [PR #297](https://github.com/appsignal/appsignal-ruby/pull/297) the start time of the job was used rather than the creation time of the job. This means that the time from when a job was created until the time it should start is no longer registered as queue time. This will prevent very long queue times from skewing the queue time graphs on AppSignal.com. ## Example applications Below is a list of example apps available to test the Delayed::Job integration with: * [AppSignal + Rails 5 + Delayed::Job](https://github.com/appsignal/appsignal-examples/tree/rails-5+delayed_job) * The example shows how to set up AppSignal with Delayed::Job and Rails. In the `README` file it lists all known and tested methods of enqueuing jobs that AppSignal supports. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The enqueue and the job's own span both carry: * `messaging.system` — the queueing library. * `messaging.destination.name` — the queue the job was put on. * `messaging.operation.type` — whether the span is the enqueue or the job running. A span for a job that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A job runs in the same trace as the code that enqueued it, appearing under the request or job that scheduled it. You can trace a slow job back to what caused it to run. The trace is carried on the job payload, alongside its other data. Read more about [distributed tracing](/distributed-tracing). # Elasticsearch Source: https://docs.appsignal.com/ruby/integrations/elasticsearch The AppSignal gem works out of the box with [the official Elasticsearch gem for Rails](https://rubygems.org/gems/elasticsearch-rails). ## Performance monitoring Searches run by your application are recorded as `search.elasticsearch` events, titled after the search that ran. The event appears in the trace event timeline and in the slow queries feature. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The search's span carries: * `db.operation.name` — the operation that ran. * `db.collection.name` — the index the search ran against. # Excon Source: https://docs.appsignal.com/ruby/integrations/excon [Excon](https://github.com/excon/excon) is an HTTP client library for Ruby. AppSignal instruments Excon requests automatically when the Excon gem is detected on start. No manual setup is required. ## Performance monitoring Requests made with Excon appear in the event timeline of your application's performance actions as `request.excon` events, showing the request method and host. They also appear in the "Slow API requests" performance panel, where you can review the requests your application makes to other services and the impact they have on its performance. Requests made through [Faraday](/ruby/integrations/faraday) using its Excon adapter are recorded once, as a Faraday event. ## What one event covers When Excon retries a request or follows a redirect, AppSignal records one event covering every attempt or hop. Earlier versions recorded a request as several events. A pipelined request is the exception. Excon returns from it before reading the response, so its event covers only sending the request. ## Disabling the integration To disable the Excon integration, set the [`instrument_excon` config option](/ruby/configuration/options#option-instrument_excon) to `false`. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `server.address` and `server.port` — the host that was called. * `url.full` — the full request URL. * `http.response.status_code` — the status the other service responded with. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. Requests made with this library carry the current trace to the service being called, in a `traceparent` request header. When that service reports to AppSignal too, its work joins the same trace. You can open a slow outgoing request and see what the other service spent its time on. The [HTTP servers](/ruby/distributed-tracing#http-servers) AppSignal supports continue the trace. Any other service starts its own. # Faraday Source: https://docs.appsignal.com/ruby/integrations/faraday [Faraday](https://github.com/lostisland/faraday) is an HTTP client library that provides a single interface over many HTTP adapters. AppSignal instruments Faraday requests automatically when the Faraday gem is detected on start. No manual setup is required. Faraday sends requests through an underlying adapter, which is Net::HTTP by default. AppSignal also instruments some of these adapters, such as [Net::HTTP](/ruby/integrations/net-http) and [Excon](/ruby/integrations/excon). To avoid recording the same request twice, AppSignal records each Faraday request once as a Faraday event and does not instrument the adapter for that request. ## Performance monitoring Requests made with Faraday appear in the event timeline of your application's performance actions as `request.faraday` events, showing the request method and host. They also appear in the "Slow API requests" performance panel, where you can review the requests your application makes to other services and the impact they have on its performance. ## Disabling the integration To disable the Faraday integration, set the [`instrument_faraday` config option](/ruby/configuration/options#option-instrument_faraday) to `false`. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `server.address` and `server.port` — the host that was called. * `url.full` — the full request URL. * `http.response.status_code` — the status the other service responded with. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. Requests made with this library carry the current trace to the service being called, in a `traceparent` request header. When that service reports to AppSignal too, its work joins the same trace. You can open a slow outgoing request and see what the other service spent its time on. The [HTTP servers](/ruby/distributed-tracing#http-servers) AppSignal supports continue the trace. Any other service starts its own. # Garbage Collection Source: https://docs.appsignal.com/ruby/integrations/garbage-collection The Ruby VM (Virtual Machine) uses Garbage Collection (GC) to prevent it from running out of process memory. Garbage Collection helps prevent your application from suffering memory outages due to running out of memory. This processes of cleaning up unused memory in Ruby apps can happen at any time. To get more insights into this you can use [Ruby's Garbage Collection profiler](https://ruby-doc.org/core/GC/Profiler.html). ## Profiler > [!WARNING] > > We do not recommend enabling the Garbage Collection profiler in production > environments, at least not for extended periods of time. The profiler's > additional overhead may negatively impact your application's performance. When the Ruby Garbage Collection profiler is enabled AppSignal will automatically collect metrics for its Ruby VM Intelligence dashboard. The "GC time" graph will show how long the Ruby VM took to clean up the unused memory between measurements. This graph will spike if it suddenly has to process a lot more memory, such as after a high memory usage task or request for example. The GC profiler is disabled by default, so no metrics are reported in this graph. To enable the GC profiler, add the code shown below to your application. The profiler can be enabled at any time in the application, such as on boot or in preparation of memory intensive operations. Once the GC profiler is enabled, the "GC time" graph will start showing metrics after at least two minutes. This metric is reported by our [minutely probes](/ruby/instrumentation/minutely-probes) system and new measurements are made every minute. ```ruby Ruby theme={null} GC::Profiler.enable ``` To temporarily enable the GC profiler, make sure to disable the profiler afterwards. ```ruby Ruby theme={null} GC::Profiler.enable # Do memory intensive operation GC::Profiler.disable ``` For the Ruby gem to report any duration over zero for the garbage collection time, the profiler must be enabled for more than two minutes. This is the initial time the Ruby gem needs to measure the garbage collection time. We recommend enabling GC profiling for longer than the minimum of two minutes to ensure we have complete measurements required to compare and graph. # Global VM Lock Source: https://docs.appsignal.com/ruby/integrations/global-vm-lock The Ruby VM (Virtual Machine) schedules Ruby threads for execution. At any given point, only one thread at a time can be active and interact with the state of the Ruby VM. The mechanism by which the Ruby interpreter ensures this is the Global VM Lock (GVL). Switching between threads has an overhead of its own. The metrics on the Global VM Lock allow you to see the time a thread spends waiting for its turn to run, and the number of threads awaiting execution at a given time. These metrics can provide helpful insights for understanding performance issues in your application. When AppSignal detects Global VM Lock metrics, it will create an [Intelligence dashboard](#intelligence-dashboards), allowing you to monitor core metrics visually. ## Installation > [!WARNING] > > The `gvltools` library is only compatible with the official Ruby interpreter. > JRuby is not supported. For AppSignal to be able to obtain Global VM Lock metrics, you must add the `gvltools` library to your project: ```shell Shell theme={null} bundle add gvltools ``` Once installed, the AppSignal integration will automatically collect Global VM Lock metrics every minute. ## Intelligence dashboards Intelligence dashboards will appear in the [Dashboard](https://appsignal.com/redirect-to/app?to=dashboard) section of AppSignal. The Global VM Lock Intelligence dashboard, titled **Ruby GVL**, has the following graphs: | Graph | Metric | Tags | | - | - | - | | [Global timer](#global-timer-graph) | `gvl_global_timer` |
  • `hostname`
  • `process_id`
  • `process_name`
  • | | [Waiting threads](#waiting-threads-graph) | `gvl_waiting_threads` |
  • `hostname`
  • `process_id`
  • `process_name`
  • | AppSignal reports the following tags for Global VM Lock metrics: | Name | Description | | - | - | | `hostname` | The name of the host that the metric was reported from | | `process_id` | The ID of the process that the metric was reported from | | `process_name` | The name of the process that the metric was reported from | > [!TIP] > > The `process_id` and `process_name` tags are only reported when using > AppSignal for Ruby version 3.9.3 or newer. ![Ruby GVL Intelligence dashboard](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/ruby/integrations/global-vm-lock/dashboard-graphs.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=7adb9334fbf51a1ab2d6e28aad0c5d3f) ### Global timer graph The global timer graph shows the time that threads spent waiting to be resumed during the last minute, that is, waiting for their code to be executed again. #### Configuring global timer measurement Measuring the global timer has an estimated performance overhead of 5%. To prevent negative impacts on your application's performance, you may want to disable `gvl_global_timer` by default and enable it when needed for specific requests or thread-intensive jobs. To disable this metric at start time, set [the `enable_gvl_global_timer` configuration option](/ruby/configuration/options#option-enable_gvl_global_timer) to `false`. Then, you can use the `gvltools` library to enable and disable the global timer measurement without having to restart your application: ```ruby Ruby theme={null} require "gvltools" GVLTools::GlobalTimer.enable # some code that uses threads ... GVLTools::GlobalTimer.disable ``` ### Waiting threads graph The waiting threads graph shows the number of threads waiting to be resumed at any given time. The graph does not include threads that are not ready to be resumed, such as threads that are sleeping or awaiting an I/O event. To disable this metric, you can set [the `enable_gvl_waiting_threads` configuration option](/ruby/configuration/options#option-enable_gvl_waiting_threads) to `false`. # GoodJob Source: https://docs.appsignal.com/ruby/integrations/goodjob AppSignal monitors GoodJob jobs through Active Job instrumentation. [GoodJob](https://github.com/bensheldon/good_job) does not have a dedicated AppSignal integration. Instead, GoodJob is instrumented as an Active Job queue adapter. When GoodJob runs jobs through Active Job, AppSignal monitors them through the [Active Job integration](/ruby/integrations/active-job). Active Job instrumentation is enabled by default. In AppSignal for Ruby 4.9.0 and newer, you can control it with the [`instrument_active_job` config option](/ruby/configuration/options#option-instrument_active_job). There is no GoodJob-specific AppSignal setup, but you can configure it as your Active Job queue adapter like so: ```ruby Ruby theme={null} # config/application.rb or config/environments/{RAILS_ENV}.rb config.active_job.queue_adapter = :good_job ``` After GoodJob runs jobs through Active Job, AppSignal reports them as Active Job jobs. Jobs are grouped by their Active Job class name, for example `MyBackgroundJob#perform`, and include the standard Active Job metadata. See [Active Job metadata](/ruby/integrations/active-job#metadata) for the full list of what AppSignal collects. # Grape Source: https://docs.appsignal.com/ruby/integrations/grape [Grape](https://www.ruby-grape.org/) applications are officially supported. Instrumenting Grape applications requires some manual setup. Follow the installation steps in AppSignal, starting by clicking 'Add app' on the [accounts screen](https://appsignal.com/accounts). > [!NOTE] > > Is your application using a combination of Rails, Grape, Hanami, Padrino or Sinatra? Follow our guide for [instrumenting multiple Rack applications](/ruby/integrations/rack-libraries). ## Installation > [!TIP] > > This installation guide is for Ruby gem 3.12 and newer. For applications using > an older AppSignal for Ruby gem, follow our [legacy installation > guide](#legacy-installation). After [installing and configuring the AppSignal gem](/ruby/installation), add the AppSignal integration after the Grape app is loaded. The Grape integration is required from the AppSignal Ruby gem, and the event and instrumentation middlewares are added in the following code examples. ```ruby Ruby theme={null} # config.ru require "appsignal" # Add this require # Load the Grape integration Appsignal.load(:grape) # Add the AppSignal Rack event middleware # AppSignal for Ruby gem 4.7+ required use Appsignal::Rack::EventMiddleware # Require the app require_relative "api" # Start AppSignal Appsignal.start # Start the app run Acme::API ``` The next step is to add the AppSignal middleware to the application's base API class. It will report any unhandled exceptions from the application. ```ruby Ruby theme={null} # api.rb module Acme class API < Grape::API # Add this line insert_before Grape::Middleware::Error, Appsignal::Rack::GrapeMiddleware # Include this middleware # ... end end ``` ### Legacy installation Applications using AppSignal for Ruby gem 3.11 or older, follow these steps to install AppSignal in Grape applications. The Grape integration is required from the AppSignal Ruby gem, and the event handler and instrumentation middlewares are added in the following code examples. ```ruby Ruby theme={null} # config.ru require "appsignal/integrations/grape" # Add this require # Configure AppSignal Appsignal.config = Appsignal::Config.new( Dir.pwd, # The root of your app ENV["RACK_ENV"] # The environment of your app (development/production) ) # Start AppSignal Appsignal.start_logger # Not required in Ruby gem 3.9.3+ Appsignal.start # Add the AppSignal Rack EventHandler # AppSignal for Ruby gem 3.8+ required use ::Rack::Events, [Appsignal::Rack::EventHandler.new] # Require the app require_relative "api" # Start the app run Acme::API ``` The next step is to add the AppSignal middleware to the application's base API class. It will report any unhandled exceptions from the application. ```ruby Ruby theme={null} # api.rb module Acme class API < Grape::API # Add this line insert_before Grape::Middleware::Error, Appsignal::Grape::Middleware # Include this middleware # ... end end ``` ## Grape 4 On Grape 4, a request's action name and path describe the endpoint's full route, including the API prefix, the path version and the mount point. An endpoint that declares no path of its own also no longer gets a trailing slash. For example, an API with `prefix "api"` is reported as `GET::Acme::API#/users/:id/` on Grape 3 and as `GET::Acme::API#/api/users/:id` on Grape 4. Requests are grouped by action name, so traces for endpoints whose names change will be grouped separately after upgrading to Grape 4. ## Mounted Grape apps Mounting Grape applications on Ruby on Rails applications is supported. The Ruby gem needs to be a recent version to properly instrument requests for mounted Grape apps. ## Ignoring errors To ignore a specific Grape error, set the `grape.skip_appsignal_error` flag in the request environment. Setting this flag to `true` will instruct AppSignal not to report any errors during the request. Use this flag only if you need to dynamically ignore errors from a Grape application. Specify error classes in the [`ignore_errors` option](/guides/filter-data/ignore-errors) to ignore them for the entire application. For more information on muting notifications for specific errors see our [notification settings documentation](/application/notification-settings). ```ruby Ruby theme={null} get "/" do env["grape.skip_appsignal_error"] = true # Add this line to an endpoint or callback raise "uh oh" # Example error, don't copy this end ``` ## Reporting errors from `rescue_from` If an error is rescued in the app using `rescue_from,` AppSignal will not receive and track it. To still report the error, call `Appsignal.report_error` in the `rescue_from` block. (Use the `Appsignal.set_error` helper when using Ruby gem version 3 or older.) ```ruby Ruby theme={null} class Api < ::Grape::API insert_before Grape::Middleware::Error, Appsignal::Grape::Middleware format :json rescue_from :all do |error| Appsignal.report_error(error) error!({ :error => "error message" }.to_json, 500) end end ``` ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `url.scheme`, `url.path`, and `url.query` — the address that was requested. * `http.response.status_code` — the status your application responded with. A span for a request that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A request that arrives with a `traceparent` request header continues the trace it names. The request appears inside the calling service's trace, under the request that caused it. You can follow a slow request from that service into this application without switching traces. The [HTTP clients](/ruby/distributed-tracing#http-clients) AppSignal supports start the trace. A request without the header starts a new one. # GraphQL Source: https://docs.appsignal.com/ruby/integrations/graphql [GraphQL](https://graphql-ruby.org/) is the Ruby gem for GraphQL servers. AppSignal supports the GraphQL gem through the built-in instrumentation module in the GraphQL gem. ## Instrumentation To instrument your GraphQL app using AppSignal, load the AppSignal middleware in your schema. ```ruby Ruby theme={null} # TODO: Change the schema class to your schema class class MySchema < GraphQL::Schema trace_with(GraphQL::Tracing::AppsignalTrace) end ``` * Reference: [GraphQL AppSignal docs](https://graphql-ruby.org/queries/tracing.html#appsignal). ## Customize namespace and action You can AppSignal instrumentation helper methods to customize your instrumentation further. In the example below we group the requests by [namespace](/guides/namespaces) and action name: ```ruby Ruby theme={null} class GraphqlController < ApplicationController def create result = MySchema.execute(params[:query], :variables => params[:variables], :context => {}) render :json => result ensure # Customize the namespace Appsignal::Transaction.current.set_namespace("graphql") # Customize the action name based on the operationName, if any Appsignal::Transaction.current.set_action(params[:operationName] || "Unknown") end ``` # Hanami Source: https://docs.appsignal.com/ruby/integrations/hanami [Hanami](https://hanamirb.org/) are officially supported. Instrumenting Hanami applications requires some manual setup. Follow the installation steps in AppSignal, starting by clicking 'Add app' on the [accounts screen](https://appsignal.com/accounts). > [!NOTE] > > Is your application using a combination of Rails, Grape, Hanami, Padrino or Sinatra? Follow our guide for [instrumenting multiple Rack applications](/ruby/integrations/rack-libraries). > [!TIP] > > This page describes the integration for the Hanami framework, installed via > the "hanami" gem. The Hanami::API framework (from the "hanami-api" gem) is not > supported. ## Installation After installing the AppSignal gem, add the AppSignal integration after requiring `hanami/boot` in the `config.ru` file. ```ruby Ruby theme={null} # config.ru require "appsignal" # Add this require require "hanami/boot" # Load the Hanami integration Appsignal.load(:hanami) # Start AppSignal Appsignal.start run Hanami.app # For Ruby gem 3.11 and older require "appsignal/integrations/hanami" # Add this line ``` ## Exception handling Hanami doesn't have any exception handling by default. The web server (like Puma or Unicorn) will show a basic "internal server error" page if an error occurs in the app. These unhandled exceptions will be reported to AppSignal automatically. The [Hanami exception handling guide](https://guides.hanamirb.org/v2.1/actions/exception-handling/) explains how to add custom exception handling to Hanami applications to render custom error pages. Handled exceptions will not be reported to AppSignal automatically. We recommend adding the following code to the application's base Action class found in `app/action.rb` to add exception handling for `StandardError`. This way, adding exception handling to every action class is unnecessary. In the `handle_standard_error` method, configured by `handle_exception`, call the `Appsignal.report_error` helper to report the exception to AppSignal and not miss any errors reported by your app. (Use the `Appsignal.set_error` helper when using Ruby gem version 3 or older.) ```ruby Ruby theme={null} # app/action.rb # auto_register: false # frozen_string_literal: true require "hanami/action" module MyHanamiApp class Action < Hanami::Action handle_exception StandardError => :handle_standard_error private def handle_standard_error(request, response, exception) # Report the error to AppSignal Appsignal.report_error(exception) # Render custom error page response.status = 500 response.body = "Sorry, something went wrong handling your request" end end end ``` After you add the `Appsignal.report_error` method to the Hanami exceptions you want to report, AppSignal will report these errors whenever they occur. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `url.scheme`, `url.path`, and `url.query` — the address that was requested. * `http.response.status_code` — the status your application responded with. A span for a request that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A request that arrives with a `traceparent` request header continues the trace it names. The request appears inside the calling service's trace, under the request that caused it. You can follow a slow request from that service into this application without switching traces. The [HTTP clients](/ruby/distributed-tracing#http-clients) AppSignal supports start the trace. A request without the header starts a new one. # HTTP.rb gem Source: https://docs.appsignal.com/ruby/integrations/http [The http.rb gem](https://github.com/httprb/http) is an HTTP client library for Ruby. AppSignal instruments http.rb requests automatically when the gem is detected on start. No manual setup is required. ## Performance monitoring Requests made with http.rb appear in the event timeline of your application's performance actions as `request.http_rb` events, showing the request method and host. They also appear in the "Slow API requests" performance panel, where you can review the requests your application makes to other services and the impact they have on its performance. ## Chained requests AppSignal also instruments requests made through a chained client, such as `HTTP.follow.get(...)` or `HTTP.headers(...).get(...)`, recording them as `request.http_rb` events like any other request. ## Disabling the integration To disable the http.rb integration, set the [`instrument_http_rb` config option](/ruby/configuration/options#option-instrument_http_rb) to `false`. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `server.address` and `server.port` — the host that was called. * `url.full` — the full request URL. * `http.response.status_code` — the status the other service responded with. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. Requests made with this library carry the current trace to the service being called, in a `traceparent` request header. When that service reports to AppSignal too, its work joins the same trace. You can open a slow outgoing request and see what the other service spent its time on. The [HTTP servers](/ruby/distributed-tracing#http-servers) AppSignal supports continue the trace. Any other service starts its own. # MongoDB instrumentation Source: https://docs.appsignal.com/ruby/integrations/mongodb The [Mongoid] gem relies on the [Mongo Ruby Driver]. AppSignal activates Mongo Ruby Driver instrumentation automatically if it is detected in the project. AppSignal's MongoDB instrumentation supports the [Mongo Ruby Driver] gem and the [Mongoid] gem out-of-the-box; no manual setup is required. When AppSignal detects MongoDB metrics, it will create an [Intelligence dashboard](#intelligence-dashboard), allowing you to monitor core metrics visually. To disable this integration, set the [`instrument_mongo` config option](/ruby/configuration/options#option-instrument_mongo) to `false`. ## Performance monitoring Once AppSignal begins reporting MongoDB metrics, AppSignal will give you performance insights via: * [Trace timeline](#event-timeline) * [Trace breakdown](#trace-breakdown) * [Slow queries](#slow-queries) ### Trace timeline Queries run through the driver are recorded as `query.mongodb` spans, titled after the command that ran. The trace timeline on the [trace page](/trace-page) gives you deep insights into MongoDB query performance, allowing you to see exactly what queries are run, when, and what impact they're having on your application's responsiveness. ![Trace timeline showing MongoDB query spans in a web request](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/mongodb/event-timeline.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=bfe40bc69aecda90aa23faa694bfc7e7) ### Trace breakdown The trace breakdown on a trace page shows how a request's time and allocations were split across span groups, such as `action_controller` and `mongodb`, so you can spot slow MongoDB queries at a glance. ![Trace breakdown showing time and allocations per span group, with mongodb taking most of the time](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/mongodb/sample-breakdown.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=b81c8d4b5e0465bb90833ff9ee3df410) ### Slow queries AppSignal has a whole suite of tools aimed at helping you improve your application's performance. Slow queries is a simple and informative overview of your application's slow queries and the impact they're having on your application's performance, allowing you to quickly and confidently decide on the steps needed to optimize them. ![The Slow queries page listing MongoDB queries by impact](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/mongodb/slow-queries.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=2ee47002468031e5d7f8d3c1fd314c61) ## Intelligence dashboard When AppSignal receives MongoDB metrics, it will create a MongoDB Intelligence dashboard, available from the dashboard section of the AppSignal app. The MongoDB Intelligence dashboard will have the following graphs: | Graph | Metrics | Tags | | - | - | - | | [Throughput](#throughput-graph) | `mongodb_query_duration` | `database` | | [Query duration](#query-duration-graph) | `mongodb_query_duration` | `database` | Tags give you a contextual breakdown of MongoDB performance information. AppSignal reports the following tag for MongoDB metrics: | Name | Description | | - | - | | `database` | Name of database metric data is recorded from. | Each tag will be represented with a colored line on the graph: ![Example MongoDB dashboard](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/ruby/integrations/mongodb/dashboard.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=c1765eeec6ec674e68749b07af56a796) ### Throughput graph The Throughput graph shows the amount of queries executed on each MongoDB database. You can use this graph to understand how many queries your app's databases are handling, spot inefficient queries, and potential n+1 and scaling problems. ### Query duration graph The Query duration graph shows the 95th percentile and average duration of the queries executed on each MongoDB database. You can use this graph to understand the performance of database queries, pinpoint performance issues, and fine-tune slow queries. [Mongoid]: https://github.com/mongodb/mongoid [Mongo Ruby Driver]: https://github.com/mongodb/mongo-ruby-driver ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The query's span carries: * `db.operation.name` — the command that ran, such as `find`. * `db.collection.name` — the collection the command ran against. * `db.namespace` — the database the command ran against. * `server.address` and `server.port` — the server the command was sent to. * `db.response.status_code` — the result the server returned. # Net::HTTP Source: https://docs.appsignal.com/ruby/integrations/net-http [Net::HTTP](https://docs.ruby-lang.org/en/master/Net/HTTP.html) is the HTTP client built into Ruby's standard library. AppSignal instruments Net::HTTP requests automatically. No manual setup is required. ## Performance monitoring Requests made with Net::HTTP appear in the event timeline of your application's performance actions as `request.net_http` events, showing the request method and host. They also appear in the "Slow API requests" performance panel, where you can review the requests your application makes to other services and the impact they have on its performance. ## Disabling the integration To disable the Net::HTTP integration, set the [`instrument_net_http` config option](/ruby/configuration/options#option-instrument_net_http) to `false`. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `server.address` and `server.port` — the host that was called. * `url.full` — the full request URL. * `http.response.status_code` — the status the other service responded with. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. Requests made with this library carry the current trace to the service being called, in a `traceparent` request header. When that service reports to AppSignal too, its work joins the same trace. You can open a slow outgoing request and see what the other service spent its time on. The [HTTP servers](/ruby/distributed-tracing#http-servers) AppSignal supports continue the trace. Any other service starts its own. # Ownership Source: https://docs.appsignal.com/ruby/integrations/ownership The AppSignal gem is compatible out of the box with the [Ownership](https://github.com/ankane/ownership/) gem. ## Usage When using the Ownership gem to assign ownership to specific blocks of code, the AppSignal for Ruby gem will automatically add an owner tag to the resulting trace, with the last owner that was assigned to a block of code during that trace as the tag's value: ```ruby Ruby theme={null} # This will set the owner tag for this trace to :growth owner :growth do crunch_user_numbers end ``` ![Ownership integration in AppSignal](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/ruby/integrations/ownership/owner-tag.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=12141ed9f7c50631e3e5f56a92426cfd) You can use this tag to filter traces in AppSignal by the team that owns the corresponding code. When an error is reported, the owner tag for the error trace will be set to the owner of the block of code that caused the error. ## Setting namespaces You can also set the [`ownership_set_namespace` configuration option](/ruby/configuration/options#option-ownership_set_namespace) to `true` in order to, alongside the owner tag, have the namespace be automatically set to the owner. Using namespaces allows you to easily see which performance actions and errors are owned by a specific team. Note that changing the namespace for actions and errors that have already been reported to AppSignal will cause them to be reported as new actions and errors. ## Disable integration To disable the integration with the Ownership gem entirely, set the [`instrument_ownership` configuration option](/ruby/configuration/options#option-instrument_ownership) to `false`. # Padrino Source: https://docs.appsignal.com/ruby/integrations/padrino [Padrino](http://www.padrinorb.com/) applications are officially supported. Instrumenting Padrino applications requires some manual setup. Follow the installation steps in AppSignal, starting by clicking 'Add app' on the [accounts screen](https://appsignal.com/accounts). > [!NOTE] > > Is your application using a combination of Rails, Grape, Hanami, Padrino or Sinatra? Follow our guide for [instrumenting multiple Rack applications](/ruby/integrations/rack-libraries). ## Installation After installing the AppSignal gem, add the AppSignal integration after requiring `padrino`. ```ruby Ruby theme={null} # config/boot.rb require "rubygems" unless defined?(Gem) require "bundler/setup" require "appsignal" # Add this require # Load the Padrino integration Appsignal.load(:padrino) # Start AppSignal Appsignal.start # For Ruby gem 3.11 and older require "appsignal/integrations/padrino" # Add this line ``` Then, create the AppSignal configuration file. For more details on configuring AppSignal, see the [Ruby configuration](/ruby/configuration) page. After these steps, start your Padrino app and wait for data to arrive in AppSignal. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `url.scheme`, `url.path`, and `url.query` — the address that was requested. * `http.response.status_code` — the status your application responded with. A span for a request that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A request that arrives with a `traceparent` request header continues the trace it names. The request appears inside the calling service's trace, under the request that caused it. You can follow a slow request from that service into this application without switching traces. The [HTTP clients](/ruby/distributed-tracing#http-clients) AppSignal supports start the trace. A request without the header starts a new one. # Puma Source: https://docs.appsignal.com/ruby/integrations/puma [Puma](http://puma.io/) was built for speed and parallelism. Puma is a small library providing a fast and concurrent HTTP 1.1 server for Ruby web applications. The AppSignal Ruby gem automatically inserts a listener into the Puma server; no manual setup is required. ## Puma metrics plugin The AppSignal Puma plugin will [collect metrics about how Puma is operating](#puma-metrics-plugin). When AppSignal detects Puma metrics, it will create an [Intelligence dashboard](#intelligence-dashboard), allowing you to monitor core metrics visually. To enable the metrics collection, add the AppSignal plugin to your Puma configuration: ```ruby Ruby theme={null} # puma.rb (or config/puma.rb) plugin :appsignal ``` > [!TIP] > > The StatsD server bundled with the AppSignal Agent must be active for the Puma > metrics plugin to work. Make sure [the `enable_statsd` config > option](/ruby/configuration/options#option-enable_statsd) is not set to > `false`. Puma may require additional configuration to load your application's [secrets](#secrets), which may be necessary for AppSignal to start. ## Usage with `prune_bundler` If your `puma.rb` file includes `prune_bundler`, you must add AppSignal as a runtime dependency. > [!TIP] > > To use Puma with `prune_bundler`, Puma version 4.2.0 or higher is required. ```ruby Ruby theme={null} # puma.rb (or config/puma.rb) prune_bundler plugin :appsignal extra_runtime_dependencies ["appsignal"] ``` ## Usage with `preload_app!` If your `puma.rb` file includes `preload_app!`, some configuration is required to correctly report metrics from [minutely probes](/ruby/instrumentation/minutely-probes). When `preload_app!` is true, the minutely probes are run in the Puma primary process. In the primary process, the probes cannot access the same data that the app running in Puma workers can, reporting inaccurate or no data. In the Puma `puma.rb` config file, stop the AppSignal minutely probes in the `before_fork` callback to stop the minutely probes in the Puma main process. Then, start the minutely probes in the worker process from the `on_worker_boot` callback. ```ruby Ruby theme={null} # puma.rb or config/puma.rb # When preload_app! is set preload_app! # Add this before_fork callback to stop the minutely probes in the Puma main process before_fork do Appsignal::Probes.stop end # Add this on_worker_boot callback to start the minutely probes in the Puma worker processes on_worker_boot do Appsignal::Probes.start end ``` ## Secrets If you use a library such as [Rails](https://guides.rubyonrails.org/security.html#custom-credentials) or [dotenv](https://github.com/bkeepers/dotenv) to manage your app's secrets and configure AppSignal, you will need to load these in your Puma configuration. AppSignal runs a background process in Puma's main process when using the Puma plugin. The rest of your app is not loaded by default in Puma's main process (unless you use `preload_app!`, which may not be suitable for your app). Without additional configuration, the AppSignal config will fail to load, and AppSignal will not start. No "on boot" hook is available in Puma to load your extra config in the main process. To load your configuration, add it to the root of your `puma.rb` configuration file, as in the example below. ```ruby Ruby theme={null} # puma.rb (or config/puma.rb) plugin :appsignal # Add this plugin # Rails secrets # Add this line when using Rails secrets in your `config/appsignal.rb` or `config/appsignal.yml` file. require "rails" # Add this section when using dotenv for secrets management require "dotenv" Dotenv.load # or for Rails apps: require "dotenv/load" Dotenv.load # Rest of your Puma config... ``` ### Hostname This probe listens to the [`APPSIGNAL_HOSTNAME` config option from the environment variable](/ruby/configuration/options#option-hostname) for the hostname tag added to all its metrics. If none is set, it will try to detect it automatically. Use the `APPSIGNAL_HOSTNAME` system environment variable to set the hostname if you want to change the detected hostname. ### StatsD port This probe listens to the [`APPSIGNAL_STATSD_PORT` config option from the environment variable](/ruby/configuration/options#option-statsd_port) for the configuration of non-default StatsD ports. If the environment variable is not set, it defaults to 8125. For the Puma main process, it is required to use the environment variable; it will not read the AppSignal file configuration. ## Phased restart Puma [phased restarts](https://github.com/puma/puma/blob/master/docs/restart.md) don't restart the main Puma process, meaning that the AppSignal background process does not get restarted either on a phased restart. If you have made changes to the AppSignal config, you will need to fully restart your Puma app afterward to have the configuration change take effect. ```sh Shell theme={null} # After changing the AppSignal config, restart using: pumactl restart # instead of: pumactl phased-restart ``` ## Intelligence dashboard When AppSignal receives Puma metrics, it creates the **Puma metrics** Intelligence dashboard in the dashboard section of the AppSignal app. The Puma Intelligence dashboard will have the following graphs: | Graph | Metrics | Tags | | - | - | - | | [Connection backlog](#connection-backlog-graph) | `puma_connection_backlog` | `hostname` | | [Pool capacity](#pool-capacity-graph) | `puma_pool_capacity` | `hostname` | | [Threads](#threads-graph) | `puma_threads` |
  • `hostname`
  • `type`
  • | | [Worker info](#worker-info-graph) | `puma_workers` |
  • `hostname`
  • `type`
  • | In the dashboard, the Threads graph is titled "Threads running/max" and the Worker info graph is titled "Workers". Tags give you a contextual breakdown of Puma performance information. AppSignal reports the following tags for Puma metrics: | Name | Description | | - | - | | `hostname` | Name of the host the metric was reported from. | | `type` | For `puma_threads`: `max` or `running`. For `puma_workers`: `count`, `booted`, or `old`. See the descriptions below. | The `type` values have the following meanings: | Value | Description | | - | - | | `max` | Maximum number of configured threads for this server. | | `running` | Number of currently running threads for this server. | | `count` | Total number of workers for this server. | | `booted` | Number of workers that have finished booting. | | `old` | Number of workers running the previous configuration/code of the server at the moment in time. Puma will phase these out as new workers start. | Graphs allow you to monitor your application's metrics visually. You can add markers to graphs and click on any data point to gain insights into your application's state at that time. ![Example Puma Intelligence dashboard](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/ruby/integrations/puma/dashboard-graphs.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=b9c868a34aedc2a6ee3f1e870c0e97c8) ### Connection backlog graph The Connection backlog graph shows the amount of incoming connections to the server that are waiting to be served in the server's backlog queue. You can use the Connection backlog graph to monitor how many requests are waiting to be handled and spot Puma bottlenecks. ### Pool capacity graph The Pool capacity graph shows the amount of Puma threads available to receive requests, including Puma threads that have yet to be spawned. You can use the Pool capacity graph to monitor the availability of Puma threads and optimize workers. ### Threads graph The Threads graph shows information about the threads spawned by Puma to serve web requests aggregated across all Puma workers. To serve web requests, Puma will spawn more threads when needed. The graph will show you the amount of threads running against the max available number of threads. You can use the Threads graph to monitor the demand and supply of Puma threads and optimize workers. ### Worker info graph The Worker info graph shows how many Puma workers are working and what version of your website they are using. The count line shows how many workers are working in total. The booted line shows how many workers have finished booting, old and new. The old line shows how many workers are still running the previous version of your application. You can use the worker info graph to monitor the status and performance of your Puma workers and see how many workers are running on an outdated configuration of your application. [thread pool]: https://github.com/puma/puma/#thread-pool [clustered mode]: https://github.com/puma/puma/#clustered-mode # Que Source: https://docs.appsignal.com/ruby/integrations/que [Que](https://github.com/que-rb/que) is a high-performance alternative to Delayed::Job or Queue Classic that improves the reliability of your application by protecting your jobs with the same ACID guarantees as the rest of your data. AppSignal instruments Que automatically when Que is detected on start, tracking exceptions and performance issues. No manual setup is required. ## Performance monitoring ### Event timeline Que jobs appear in the event timeline of your application's performance actions as `perform_job.que` events. ### Incident grouping AppSignal detects job names from the Que worker class name, suffixed with the `run` method name, resulting in something like `MyWorker#run`. AppSignal groups jobs by this name for performance monitoring and notifications. ## Enqueue instrumentation Enqueuing a Que job records an `enqueue.que` event, titled after the job being enqueued. Bulk enqueues on version 2 of Que record a single `bulk_enqueue.que` event instead. AppSignal records enqueue events on the active transaction's event timeline, for example when you enqueue a job from within a web request or from within another job. It only records them when a transaction is active, so enqueuing a job outside of a transaction records nothing. To stop recording enqueue events across all background job integrations, set the [`enable_job_enqueue_instrumentation` config option](/ruby/configuration/options#option-enable_job_enqueue_instrumentation) to `false`. This does not affect the instrumentation of the jobs themselves. ## Active Job support The Que integration is compatible with [Active Job](/ruby/integrations/active-job). Upgrade to version 2.11.0 of the Ruby gem or newer for improved support. ## Example application We have an example application in our examples repository on GitHub. * [AppSignal + Rails 5 + Que][example-app] The example shows how to set up a Rails 5 app with Que monitored by AppSignal. [example-app]: https://github.com/appsignal/appsignal-examples/tree/rails-5+que ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The enqueue and the job's own span both carry: * `messaging.system` — the queueing library. * `messaging.destination.name` — the queue the job was put on. * `messaging.operation.type` — whether the span is the enqueue or the job running. A span for a job that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A job runs in the same trace as the code that enqueued it, appearing under the request or job that scheduled it. You can trace a slow job back to what caused it to run. Jobs enqueued with `Que.bulk_enqueue` are the exception. They do not appear under the trace that enqueued them. Each job gets a trace of its own, linked back to the bulk enqueue, because one enqueue cannot be the parent of a whole batch. The trace is carried in the job's tags. Que has tags from version 1.0 onwards, so nothing is carried on Que 0.x. Que allows at most five tags per job. A job with no room left for the trace is enqueued without one. Read more about [distributed tracing](/distributed-tracing). # Rack Source: https://docs.appsignal.com/ruby/integrations/rack To instrument Rack applications, AppSignal provides a Rack instrumentation middleware. If you use any of the supported Rack frameworks like [Rails], [Sinatra], [Hanami], [Grape], or [Padrino], we recommend using those instrumentations instead. ## Add the instrumentation middleware > [!TIP] > > Using an older AppSignal Ruby gem? Follow [our legacy > guide](#using-the-legacy-instrumentation-middleware). To [integrate AppSignal][integrate] in a Rack application, we first need to load, [configure][configuration], and start AppSignal. Then, instrument the Rack app by adding our Rack `EventMiddleware` and `InstrumentationMiddleware` to the middleware stack. This documentation explains how to do this in your application's `config.ru` file. ```ruby Ruby theme={null} # config.ru require "appsignal" # Load AppSignal Appsignal.start # Start the AppSignal integration # Add the Rack EventMiddleware first use Appsignal::Rack::EventMiddleware # Add the Rack InstrumentationMiddleware use Appsignal::Rack::InstrumentationMiddleware # Load your app with a require statement here, like require_relative "app" # Add other middleware here if needed # Finally, run the app use MyApp.run ``` Ensure the `EventMiddleware` and `InstrumentationMiddleware` are registered in the application middleware stack as early as possible. The earlier these middleware are registered, the more request runtime the middleware will instrument. If other middleware are registered beforehand, our middleware will not instrument these other middleware. After adding the `EventMiddleware` and `InstrumentationMiddleware` to your app's middleware stack, [the action](#setting-the-action-name) needs to be set for each route in your app in AppSignal. Without an action name to group requests, the event middleware will not report request information. For more insights into the operation of your Rack application, we recommend [adding additional instrumentation][instrumentation] to the application's endpoints. ### The Rack event middleware We recommend adding our Rack event middleware to all Rack applications. This middleware will ensure we track The AppSignal Rack event middleware has the following features: * Instrumentation of the request and recording a `process_request.rack` event. * Reporting Exceptions that occur in the app and middleware. * Tracking the response status code as the `response_status` tag on the trace. * Tracking the response status code as the `response_status` metric, with the `namespace` and `status` tags. ### The Rack instrumentation middleware We recommend that in addition to the `Appsignal::Rack::EventMiddleware`, the `AppSignal::Rack::InstrumentationMiddleware` is added to the app. This middleware supplements the event middleware's instrumentation by adding tags for the request path and request method, as well as tracking response body handling and response body closing operations. The instrumentation middleware has the following features: * Instrumentation of the request and recording a `process_request.rack` event. * Reporting Exceptions that occur in the app. * Tracking the request path and request method as tags on the trace. * Instrumentation of the response body handling and recording a `process_response_body.rack` event for this operation. * Instrumentation of the response body closing and recording a `close_response_body.rack` event for this operation. ## Using the legacy instrumentation middleware > [!WARNING] > > The GenericInstrumentation middleware was deprecated in Ruby gem 3.10.0. > Please use the [new guide](#add-the-instrumentation-middleware) instead. To [integrate AppSignal][integrate] in a Rack application, we first need to load, [configure][configuration], and start AppSignal. Then, instrument the Rack app by adding our Rack `GenericInstrumentation` middleware to the middleware stack. This documentation explains how to do this in your application's `config.ru` file. ```ruby Ruby theme={null} # config.ru # Load and configure AppSignal require "appsignal" # Load AppSignal Appsignal.config = Appsignal::Config.new( File.expand_path("../", __FILE__), # Application root path ENV["RACK_ENV"], # Application environment ) Appsignal.start # Start the AppSignal integration Appsignal.start_logger # Start logger # Load your app with a require statement here, like require_relative "app" # Add the GenericInstrumentation middleware use Appsignal::Rack::GenericInstrumentation # Add other middleware here if needed # Finally, run the app use MyApp.run ``` Ensure the `EventMiddleware` and `InstrumentationMiddleware` are registered in the application middleware stack as early as possible. The earlier these middleware are registered, the more request runtime the middleware will instrument. If other middleware are registered beforehand, our middleware will not instrument these other middleware. After adding the `EventMiddleware` and `InstrumentationMiddleware` to your app's middleware stack, [the action](#setting-the-action-name) needs to be set for each route in your app in AppSignal. Without an action name to group requests, the event middleware will not report request information. For more insights into the operation of your Rack application, we recommend [adding additional instrumentation][instrumentation] to the application's endpoints. ## Setting the action name Set an action name on the AppSignal transaction for a request so we can group endpoints in our issues and metrics. We recommend using a static action name per endpoint, like `GET /blog`, `POST /users`, `PUT /users/:id`, etc. To set an action name for a request, call the `Appsignal.set_action` helper from the app. > [!WARNING] > > Do not use the request path of the route as the action name if the path has > dynamic segments. Using real request paths for action names breaks our request > grouping by creating unique issues for each possible request path. ```ruby Ruby theme={null} # app.rb require "rack" # Example pure-Rack app class MyApp def call(env) case [env["REQUEST_METHOD"], env["PATH_INFO"]] when ["GET", "/"] Appsignal.set_action("GET /") # Action name set here body = <<~BODY

    Rack example app

    BODY [200, {"Content-Type" => "text/html"}, [body]] when ["GET", "/slow"] Appsignal.set_action("GET /slow") # Action name set here sleep 1 [200, {"Content-Type" => "text/plain"}, ["Slow response"]] when ["GET", "/error"] Appsignal.set_action("GET /error") # Action name set here raise "uh oh" else Appsignal.set_action("NotFound") # Action name set here [404, {"Content-Type" => "text/plain"}, ["Page not found"]] end end end ``` [configuration]: /ruby/configuration [integrate]: /ruby/instrumentation/integrating-appsignal.html [instrumentation]: /ruby/instrumentation/instrumentation.html [Rails]: /ruby/integrations/rails.html [Sinatra]: /ruby/integrations/sinatra.html [Hanami]: /ruby/integrations/hanami.html [Grape]: /ruby/integrations/grape.html [Padrino]: /ruby/integrations/padrino.html ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `url.scheme`, `url.path`, and `url.query` — the address that was requested. * `http.response.status_code` — the status your application responded with. A span for a request that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A request that arrives with a `traceparent` request header continues the trace it names. The request appears inside the calling service's trace, under the request that caused it. You can follow a slow request from that service into this application without switching traces. The [HTTP clients](/ruby/distributed-tracing#http-clients) AppSignal supports start the trace. A request without the header starts a new one. # Multiple Rack libraries Source: https://docs.appsignal.com/ruby/integrations/rack-libraries If an application uses multiple Ruby web frameworks, like the ones listed below, follow this guide to set up instrumentation for all libraries. * [Grape](/ruby/integrations/grape) * [Hanami](/ruby/integrations/hanami) * [Padrino](/ruby/integrations/padrino) * [Sinatra](/ruby/integrations/sinatra) * [Rails](/ruby/integrations/rails), no `Appsignal.load` required for Rails. ## Installation For each library AppSignal should integrate with, call `Appsignal.load(:library_name)` where `:library_name` is replaced with the library name you want to instrument. Follow the guides listed above for each library for additional steps per library and guidance on where to position each `Appsignal.load` call. ```ruby Ruby theme={null} require "appsignal" Appsignal.load(:grape) Appsignal.load(:hanami) Appsignal.load(:padrino) Appsignal.load(:sinatra) Appsignal.start ``` ## Rack example app For example, in an application that uses a lot of these Rack libraries: ```ruby Ruby theme={null} # config.ru require "appsignal" Appsignal.load(:grape) require_relative "./app" Appsignal.load(:hanami) Appsignal.load(:padrino) Appsignal.load(:sinatra) Appsignal.start run MyApp.run ``` ## Rails app example In a Rails app, add the loaders to the `config/application.rb` file. ```ruby Ruby theme={null} # config/application.rb require_relative "boot" require "rails/all" Bundler.require(*Rails.groups) Appsignal.load(:sinatra) # ... ``` # Ruby on Rails Source: https://docs.appsignal.com/ruby/integrations/rails What AppSignal instruments in Ruby on Rails, configuring it in an initializer, and the Rails error reporter and backtrace cleaner. [Ruby on Rails](http://rubyonrails.org/) is supported out-of-the-box by AppSignal. To install follow the installation steps in AppSignal, start by clicking 'Add app' on the [accounts screen](https://appsignal.com/accounts). The AppSignal integration for Rails works by tracking exceptions and performance in requests. When an error occurs in a controller during a request AppSignal will report it. Performance issues will be based on the duration of a request and create a timeline of events detailing which parts of the application took the longest. ## What AppSignal instruments for Rails In Rails apps, AppSignal instruments these Rails components and events automatically: * **Controller requests (Action Controller)**: AppSignal reports performance samples and exceptions, grouped by controller action, for example `UsersController#show`. Samples can include filtered request parameters, session data, headers, request path, request method, request ID, response status, and queue time when available. * **View rendering (Action View)**: AppSignal reports events for template rendering (`render_template.action_view`) and partial rendering (`render_partial.action_view`) in the request timeline. * **Database queries and model loading (Active Record)**: AppSignal reports events for SQL queries (`sql.active_record`) and model instantiation (`instantiation.active_record`) in the request timeline. * **Background jobs ([Active Job](/ruby/integrations/active-job))**: AppSignal reports job execution, enqueue events, queue time, job arguments, queue, priority, Active Job ID, provider job ID, and job status metrics. * **WebSocket channels ([Action Cable](/ruby/integrations/action-cable))**: AppSignal reports channel actions, subscribe callbacks, and unsubscribe callbacks. * **Mailer processing (Action Mailer)**: AppSignal reports an `action_mailer_process` counter for each `process.action_mailer` event, tagged with the mailer and action. * **[Rails error reporter](#error-reporter)**: AppSignal reports errors sent through `ActiveSupport::ErrorReporter`, with severity and source tags. * **[Rails runners](#runners)**: AppSignal reports errors from Rails runners. Performance requires manual instrumentation. Requests to Rails' health check endpoint, `Rails::HealthController#show`, are ignored by default through the [`ignore_actions`](/ruby/configuration/options#option-ignore_actions) option. Errors raised while the application boots, before the initializers have run, are not reported by default. See [Error reporting from initializers](#error-reporting-from-initializers). ## Active Job See our [Active Job page](/ruby/integrations/active-job) for more information on how our Active Job instrumentation works. ## Action Cable See our [Action Cable page](/ruby/integrations/action-cable) for more information on how our Action Cable instrumentation works. ## Configure AppSignal in an initializer We recommend using our [`config/appsignal.rb` config file](/ruby/configuration/load-order#appsignal-rb-config-file) or [environment variables](/ruby/configuration/load-order#5-environment-variables) to [configure AppSignal](/ruby/configuration). By default, it's not possible to configure AppSignal from a Rails initializer, because AppSignal loads before your application's initializers, in order to be able to report errors that take place during initialization. To configure AppSignal in a Rails initializer, first configure Rails to start AppSignal after the app's initializers have run. ```ruby Ruby theme={null} # config/application.rb # ... module MyApp class Application < Rails::Application # Add this line config.appsignal.start_at = :after_initialize # Other config end end ``` Then, in the initializer: ```ruby Ruby theme={null} # config/initializers/appsignal.rb Appsignal.configure do |config| config.ignore_actions = ["My action"] end ``` Do not call `Appsignal.start` in the initializers. The Ruby gem will start AppSignal automatically when Rails has run all initializers. When a Rails app is configured to start AppSignal after the initializers have loaded, it is no longer possible to [report errors from initializers when booting Rails app](#error-reporting-from-initializers). ## Error reporting from initializers By default, AppSignal reports errors that occur in controller, Rake tasks and Active Job jobs. It does not report errors that occur when the application is booting, before the Rails initializers. To do get notified when these errors occur, adding the following to your `config.ru` file, around the line that requires the `environment.rb` file. ```ruby Ruby theme={null} # config.ru begin require ::File.expand_path("../config/environment", __FILE__) rescue Exception => error Appsignal.send_error(error) raise end ``` The errors that occur here will not be grouped under an incident with an action name. ## Backtrace cleaner With the Rails integration, AppSignal will run the backtrace of each exception through the [Rails backtrace cleaner][backtrace cleaner docs]. This cleaner gives you the option to modify or filter out unwanted backtrace lines, removing clutter and noise from the backtrace. You can add or remove filters and silencers to the default configuration. **Filters** will mutate the given line. An example would be to remove the `Rails.root` prefix. **Silencers** will remove the line from the backtrace, if the given expression returns `true`. You can add these additional backtrace cleaner rules in an initialize. For example: ```ruby Ruby theme={null} # config/initializers/backtrace_cleaner.rb bc = Rails.backtrace_cleaner bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } bc.add_silencer { |line| line.index('').nil? and line.index('/') == 0 } bc.add_silencer { |line| line.index('/vendor/') == 0 } ``` For more information about the backtrace cleaner, see the [Rails BacktraceCleaner documentation][backtrace cleaner docs]. ## Error reporter AppSignal reports errors raised via `ActiveSupport::ErrorReporter` by default. `ActiveSupport::ErrorReporter` was introduced in Rails 7.0 to standardize custom error reporting. You can disable this functionality with the [`enable_rails_error_reporter`](/ruby/configuration/options#option-enable_rails_error_reporter) configuration option. If a transaction is active in the context an error is reported through the Rails error reporter, it will include the same metadata and sample data as the active transaction: namespace, action name, tags, custom data, parameters, etc. ```ruby Ruby theme={null} # In both scenarios, the error is reported by AppSignal Rails.error.handle do raise "some error" end Rails.error.record do raise "some error" end ``` > [!WARNING] > > In AppSignal for Ruby gem version 3, some behavior was different. Please > consult the [Ruby gem 3 legacy behavior](#ruby-gem-3-legacy-behavior) section > for more information about the differences. ### Namespace and action from the current transaction When reporting errors, we determine the namespace and action name in which it takes place, such as a controller or background job, on a best-effort basis. The incident namespace and action name will not always be set or be accurate. If an AppSignal transaction is active (like in a web request or background job) the error reported with `Rails.error.handle/record` will have the same namespace, action name, tags, parameters, custom data, etc. as the active transaction. If no AppSignal transaction is active, no namespace, action name, tags, etc. will be set by default. ### Namespace and action from the context If you want to change the reported error's namespace and action name without changing them on the already active AppSignal transaction, you can customize this on the error reporter call. ```ruby Ruby theme={null} # The error reported here will have the "custom_namespace" namespace # and "CustomizedActionName#index" action name Rails.error.handle(:context => { :appsignal => { :namespace => "custom_namespace", :action => "CustomizedActionName#index" } }) do raise "some error" end ``` ### Tags from the active transaction By default, the request/job's transaction tags are copied to the error reporter's error AppSignal transaction from the request/job's transaction. ```ruby Ruby theme={null} # Rails controller example using a before_action callback class ExamplesController < ApplicationController before_action do Appsignal.add_tags(:tag1 => "value1", :tag2 => "value2") end def index # The error reported here will have the same tags set # as in the `before_action` callback Rails.error.handle do raise "some error" end end end ``` ### Tags from context You can add tags to a reported error by using `context` in the `Rails.error.handle/record` call. These tags will only be set on the error reported with the `Rails.error.handle/record` methods. ```ruby Ruby theme={null} Rails.error.handle(:context => { :tag1 => "value1", :tag2 => "value2" }) do raise "some error" end ``` The same tagging limitations apply as for using [`Appsignal.add_tags`](/guides/tagging#ruby). ### Ruby gem 3 legacy behavior In AppSignal for Ruby gem version 3 the error reporting behavior is different. * Errors reported with the `Rails.error.handle` method are reported to AppSignal. * Errors reported with `Rails.error.record` are not reported to AppSignal to avoid reporting the error twice when it's being reported by our Rails error reporting middleware. All errors reported with the Rails error reporter are reported as separate errors. They do not always include the same metadata and sample data from any active AppSignal transaction. See the section for [context inheritance limitations](#context-inheritance-limitations) for more information. ```ruby Ruby theme={null} # Reported by AppSignal Rails.error.handle do raise "some error" end # NOT reported by AppSignal Rails.error.record do raise "some error" end ``` #### Context inheritance limitations In Ruby gem 3 the context inheritance from the active transaction is limited. The metadata and some of the sample data is only copied if it set at the time `Rails.error.handle/record` is called. In practice this mean Rails controllers and Active Job jobs will be accurately reported. Other libraries like Sidekiq jobs, no action name is set when reporting errors with `Rails.error.handle`. Tags set after `Rails.error.handle/record` is called are not reported for the error reported using this helper. ## Runners AppSignal will automatically report errors inside [Rails runners](https://guides.rubyonrails.org/command_line.html#bin-rails-runner). Some manual setup is also required to instrument a runner's performance. We recommend putting the runner's code in a separate file and wrap it in the [`Appsignal.monitor` helper](/ruby/instrumentation/background-jobs), as shown in the example below. ```bash Bash theme={null} bin/rails runner path_to_file.rb ``` ```ruby Ruby theme={null} Appsignal.monitor(:namespace => :runner, :action => "Runner name") do # Some code end ``` If your Rails runner runs on a container that is only started to run this task, make sure that [`enable_at_exit_hook` option](/ruby/configuration/options#option-enable_at_exit_hook) is set to `true` (which should be the default on containers). This will ensure the data gets flushed to the AppSignal agent before the runner shuts down. [backtrace cleaner docs]: https://api.rubyonrails.org/classes/ActiveSupport/BacktraceCleaner.html [error reporter]: https://guides.rubyonrails.org/error_reporting.html ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `url.scheme`, `url.path`, and `url.query` — the address that was requested. * `http.response.status_code` — the status your application responded with. A span for a request that raised also carries `error.type`, the class of the error. Each Active Record query records a span of its own, which carries: * `db.system.name` — the database the query ran against, such as `postgresql` or `mysql`. * `db.query.text` — the query, with its values removed. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A request that arrives with a `traceparent` request header continues the trace it names. The request appears inside the calling service's trace, under the request that caused it. You can follow a slow request from that service into this application without switching traces. The [HTTP clients](/ruby/distributed-tracing#http-clients) AppSignal supports start the trace. A request without the header starts a new one. ## See also * [params.expect: strong parameters in Rails 8](/tutorials/ruby/params-expect): Rails 8 adds `params.expect` to permit and require parameters in one step. It rejects unexpected parameter shapes as bad requests. * [params.with\_defaults: default values for Rails parameters](/tutorials/ruby/parameters-with-defaults): set fallback values for parameters the browser may omit. Submitted values override these defaults. * [User impersonation in Rails 8 authentication](/tutorials/ruby/impersonation): let an administrator view the application as another user, by extending the Rails 8 authentication generator. * [Solid Queue: run background jobs in your database](/tutorials/ruby/solid-queue): use the database you already run as an Active Job backend. Rails 8 configures it in new applications; this covers adding it to an existing one. * [All Ruby and Rails tutorials](/tutorials): screencasts and written walkthroughs on Rails, produced with GoRails. # Rake task monitoring Source: https://docs.appsignal.com/ruby/integrations/rake Every exception recorded in a [Rake][rake] task will be sent to AppSignal and filed under the "Background" [namespace](/application/namespaces). Note that we only track exceptions in Rake tasks. There is no performance monitoring for Rake tasks. (To manually integrate performance monitoring in select Rake tasks please see our [integration guide][integration] and [custom instrumentation guide][custom-instrumentation].) Depending on what version of the AppSignal gem you use and in what context some manual steps are required. ## Integrations ### Rails applications For Rails applications make sure you depend on the `:environment` task. This loads the Rails application into memory and starts AppSignal as part of the application. ```ruby Ruby theme={null} # lib/tasks/my_task.rb task :my_task => :environment do # do stuff end ``` #### Rakefile Your Rails application's `Rakefile` should look something like the example below. This should already be the case, no need to change it. ```ruby Ruby theme={null} # Rakefile require File.expand_path("../config/application", __FILE__) # Only require this file for gem version < 1.0 # require "appsignal/integrations/rake" Rails.application.load_tasks ``` (For older versions of the AppSignal gem, versions `< 1`, you will need to require the Rake integration manually. It is automatically loaded for version `1.x` and higher.) ### Ruby applications For pure Ruby applications some extra steps are required to load AppSignal. AppSignal needs to be required, configured and loaded. See also our [integration guide][integration]. ```ruby Ruby theme={null} # Rakefile require "appsignal" Appsignal.start task :foo do raise "bar" end ``` ## Monitoring Rake task performance To monitor Rake task performance and all events that occur in the task, configure AppSignal with the [`enable_rake_performance_instrumentation` config option](/ruby/configuration/options#option-enable_rake_performance_instrumentation) set to `true`. With this feature enabled, all Rake tasks will instrumented and counted towards your plan. ## Stop requirement For Rake tasks running on short-lived hosts, it is required to stop the AppSignal Ruby gem before the Rake process exits. This will ensure it reports the data from the Rake tasks to AppSignal before the host shuts down. This behavior is only needed in such scenarios like: * When a scheduled Rake task (a cron job) is run by a hosting service. * When a Rake task is run on a container that starts to run this Rake task and shuts down when the Rake task exits. * When a Rake task is run on a Heroku runner, or similar hosting providers. It is not needed to stop the AppSignal Ruby gem if the host on which the script is started, continues to run after the script has exited. AppSignal is stopped automatically when the Rake task exits and a container or hosting environment like Heroku is detected. This behavior is controlled by the [`enable_at_exit_hook` option](/ruby/configuration/options#option-enable_at_exit_hook). Ensure this option is set to true for scripts that require AppSignal to be stopped, if it's not automatically detected. It may be needed to add an additional `sleep` call of a couple seconds to ensure there's enough time to send all the data. Use the `at_exit` usage example from the code below if needed. ```ruby Rakefile theme={null} # Short-lived host example task # This block is called after all tasks are ran # Ensures the AppSignal agent has enough time to send the data to the AppSignal servers at_exit { sleep 10 } task :foo do # Your Rake task code end ``` ### Stop requirement legacy > [!WARNING] > > The section below is for applications using Ruby gem 4.5.7 and lower. > These versions do not include the [`enable_at_exit_hook` option](/ruby/configuration/options#option-enable_at_exit_hook) which automates this behavior. > > For newer versions of the Ruby gem, see the [stop requirement section](#stop-requirement). When running a single Rake task on a short-lived host (e.g. with Docker containers, Kubernetes or Heroku schedulers) there are three requirements. This guarantees that the app's AppSignal extension has time to flush the data to the agent and the agent has time to send the data to our API before shutting (the container) down. **The requirements are:** * `Appsignal.stop` must be called in the Rake task. * When [Rake task performance monitoring](#monitoring-rake-task-performance) is enabled, this is done automatically for all tasks. * [`running_in_container`](/ruby/configuration/options#option-running_in_container) must be set to true in the config. * For most containers types `running_in_container` is automatically set to true when detected, for others manual configuration is required. * A sleep of e.g. 10 seconds to give AppSignal agent time to sent the data An example of how `Appsignal.stop` is called in the Rakefile: ```ruby Rakefile theme={null} # Short-lived host example task # This block is called after all tasks are ran # The argument "rake" is the name of the parent process name which is being # stopped and logs it as the reason why AppSignal is stopping. at_exit do Appsignal.stop "rake" sleep 10 # For short-lived hosts, give the AppSignal agent time to send the data end task :foo do # Tracking data with AppSignal in your task Appsignal.increment_counter "my_custom_counter" end ``` **Note**: A sleep of 10 seconds was added to the end of the Rake task example in the example above. This is required for tasks that are run on short-lived hosts. When the task completes, the process stops. The `Appsignal.stop` call flushes all the transaction data currently in the AppSignal extension to our agent. It then sleeps for 10 seconds to allow the agent to send the data before shutting down. [rake]: https://github.com/ruby/rake [integration]: /ruby/instrumentation/integrating-appsignal.html [custom-instrumentation]: /ruby/instrumentation/instrumentation.html # Redis gem Source: https://docs.appsignal.com/ruby/integrations/redis The AppSignal gem works out of the box with the [`redis`](https://rubygems.org/gems/redis/) and [`redis-client`](https://rubygems.org/gems/redis-client) Ruby gems. ## Performance monitoring Redis commands run by your application are recorded as `query.redis` events. The event body holds the command that ran, with its arguments removed. The event appears in the event timeline of your application's performance actions, and in the "Slow queries" performance panel. If you wish to disable our integration with the Redis gem, set the [`instrument_redis` config option](/ruby/configuration/options#option-instrument_redis) to `false` to disable it. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The query's span carries: * `db.operation.name` — the command that ran, such as `GET`. * `db.namespace` — the database number the command ran against. The command itself is not recorded as an attribute. It is already sanitized into the event body. # Resque Source: https://docs.appsignal.com/ruby/integrations/resque [Resque](https://github.com/resque/resque) is a Redis-backed Ruby library for creating background jobs, placing them on multiple queues, and processing them later. AppSignal instruments Resque automatically when the Resque gem is detected on start. No manual setup is required. ## Performance monitoring ### Event timeline Resque jobs appear in the event timeline of your application's performance actions as `perform.resque` events. ### Incident grouping AppSignal detects job names from the Resque worker class name, suffixed with the `perform` method name, resulting in something like `MyWorker#perform`. AppSignal groups jobs by this name for performance monitoring and notifications. ## Enqueue instrumentation Enqueuing a Resque job records an `enqueue.resque` event, titled after the job being enqueued. AppSignal records enqueue events on the active transaction's event timeline, for example when you enqueue a job from within a web request or from within another job. It only records them when a transaction is active, so enqueuing a job outside of a transaction records nothing. To stop recording enqueue events across all background job integrations, set the [`enable_job_enqueue_instrumentation` config option](/ruby/configuration/options#option-enable_job_enqueue_instrumentation) to `false`. This does not affect the instrumentation of the jobs themselves. ## Active Job support The Resque integration is compatible with [Active Job](/ruby/integrations/active-job). Upgrade to version 2.11.0 of the Ruby gem or newer for improved support. ## Example apps We've added a Rails 5 + Resque [example app](https://github.com/appsignal/appsignal-examples/tree/rails-5+resque) to our [examples repository](https://github.com/appsignal/appsignal-examples). Take a look if you're having trouble getting AppSignal for Resque configured. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The enqueue and the job's own span both carry: * `messaging.system` — the queueing library. * `messaging.destination.name` — the queue the job was put on. * `messaging.operation.type` — whether the span is the enqueue or the job running. A span for a job that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A job runs in the same trace as the code that enqueued it, appearing under the request or job that scheduled it. You can trace a slow job back to what caused it to run. The trace is carried on the job payload, alongside its class and arguments. Read more about [distributed tracing](/distributed-tracing). # Ruby Object Mapper (ROM) Source: https://docs.appsignal.com/ruby/integrations/rom [ROM](https://rom-rb.org/) is a persistence and mapping toolkit for Ruby. AppSignal instruments ROM queries automatically when the `dry-monitor` gem is detected on start. No manual setup is required. ROM reports its queries through [Dry::Monitor notifications](/ruby/instrumentation/instrumentation#drymonitornotifications), which AppSignal reads. ## Performance monitoring Queries made through ROM appear in the event timeline of your application's performance actions, showing the query that was executed. ## Event names ROM queries are reported as `query.rom` events. Earlier versions reported them under a different event name. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The query's span carries: * `db.system.name` — the database the query ran against, such as `postgresql` or `mysql`. * `db.query.text` — the query, with its values removed. # Ruby VM Source: https://docs.appsignal.com/ruby/integrations/ruby-vm The Ruby VM (Virtual Machine) schedules Ruby threads for execution. At any given point, only one thread at a time can interact with the state of the Ruby VM. AppSignal supports Ruby VM out of the box. When AppSignal detects Ruby VM metrics, it will create an [Intelligence dashboard](#intelligence-dashboards), allowing you to monitor core metrics visually. ## Intelligence dashboards Intelligence dashboards will appear in the dashboard section of the AppSignal app. ![The Ruby VM Intelligence dashboard in AppSignal](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/ruby-vm/dashboard-created.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=08a13f3e98472c730220fa1e17a76beb) The Ruby VM Intelligence dashboard, titled **Ruby (VM) metrics**, will have the following graphs: | Graph | Metrics | Tags | | - | - | - | | [Allocated objects](#allocated-objects-graph) | `allocated_objects` | `hostname` | | [Garbage Collection Count](#garbage-collection-count-graph) | `gc_count` |
  • `metric`
  • `hostname`
  • | | [GC time](#gc-time-graph) | `gc_time` | `hostname` | | [Heap slots](#heap-slots-graph) | `heap_slots` |
  • `metric`
  • `hostname`
  • | | [Ruby VM](#ruby-vm-graph) | `ruby_vm` |
  • `metric`
  • `hostname`
  • | | [Thread count](#thread-count-graph) | `thread_count` | `hostname` | In the dashboard, the Garbage Collection Count graph is titled "GC counts". Tags give you a contextual breakdown of Ruby VM performance information. AppSignal reports the following tags for Ruby VM performance: | Name | Description | | - | - | | `hostname` | The name of the host the metric was reported from. | | `metric` | Which value of a metric the line shows. For `gc_count`: `gc_count`, `minor_gc_count`, or `major_gc_count`. For `heap_slots`: `heap_live` or `heap_free`. For `ruby_vm`: `class_serial`, `global_constant_state`, `constant_cache_invalidations`, or `constant_cache_misses`. | AppSignal will represent each tag with a colored line on the graph: ![Ruby VM Intelligence dashboard example graph](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/ruby/integrations/ruby-vm/gc-count-graph.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=2aea582a012bc62c561298e9c97a992d) ### Allocated objects graph The Allocated objects graph shows how many objects the Ruby virtual machine allocated since the previous measurement, one minute earlier. You can use the Allocated objects graph to monitor and optimize your application's memory usage and performance. ### Garbage collection count graph The GC counts graph shows the amount of garbage collection events/runs during the last minute, split between major and minor events. You can use the GC counts graph to monitor the frequency of garbage collection and its impact on your application’s performance and memory usage. ### GC time graph The GC time graph shows how long the Ruby VM spent in garbage collection between measurements. It only shows data when the [Ruby GC profiler](/ruby/integrations/garbage-collection) is enabled. You can use the GC time graph to see how much time each host spends in garbage collection. ### Heap slots graph The Heap slots graph shows the heap slots currently allocated by the Ruby virtual machine, split between live and free slots. You can use the Heap slots graph to monitor memory allocation and identify the potential causes of memory leaks or fragmentation. ### Ruby VM graph > [!WARNING] > > The metrics `constant_cache_misses` and `constant_cache_invalidations` are > only available in Ruby versions 3.2.0 and higher. The Ruby VM graph shows statistics from the RubyVM.stat method about the constant cache and the classes created in your application. You can use the Ruby VM graph to monitor the cache status of constant values and how your application affects the Ruby VM state. ### Thread count graph The Thread count graph shows the number of live threads in your application's process, including sleeping threads. You can use the Thread count graph to monitor your application's threading. Ruby VM Lock runs serially, meaning it can only execute one thread at a time. A high thread count may lead to performance problems. # Sequel Source: https://docs.appsignal.com/ruby/integrations/sequel The [Sequel][sequel] gem is a fast ORM for Ruby. AppSignal supports Sequel automatically and no manual instrumentation is needed. ## Performance monitoring Queries run through Sequel are recorded as `sql.sequel` events. The event body holds the query that ran, with its values removed. The event appears in the event timeline of your application's performance actions, and in the "Slow queries" performance panel. ## Disable instrumentation We have a configuration option to disable instrumentation for Sequel. Read more about [`:instrument_sequel`][instrument-sequel]. ## Known issues ### sequel-rails integration When using the [sequel-rails][sequel-rails] gem the instrumentation from the sequel-rails gem and AppSignal gem can [conflict when running migrations][instrumentation-issue]. Because both gems are instrumenting sequel you'll get two instrumentation events and possible an error. [Disable the AppSignal sequel instrumentation](#disable-instrumentation) is this occurs. ### Lack of instrumentation Some Sequel extensions override the AppSignal Ruby gem instrumentation. One such extension is the [error\_sql][error_sql-extension]. This causes AppSignal to be unable to instrument Sequel. The effect being no Sequel instrumentation events to appear on AppSignal.com. To use the AppSignal instrumentations in this scenario, the AppSignal Sequel instrumentation needs to be loaded manually after all other extensions have loaded. ```ruby Ruby theme={null} # Load extension that overrides the AppSignal instrumentation. This is an # example. Other extensions might override it too. Sequel::Database.extension :error_sql # Manually load the instrumentation of sequel with AppSignal in combination # with an extension that overrides the AppSignal gem instrumentation on load. # # Make sure you set `instrument_sequel` to `false` in the AppSignal config. # http://docs.appsignal.com/ruby/configuration/ # # Note: Use `Appsignal::Hooks::SequelLogExtension` for Sequel version 4.34 # and below. Sequel::Database.register_extension( :appsignal_integration, Appsignal::Hooks::SequelLogConnectionExtension ) Sequel::Database.extension(:appsignal_integration) ``` Note: only since version `2.0.2` do the other extension's functionality remain intact after loading the AppSignal instrumentation. ## Example applications We have two example applications in our examples repository on GitHub. * [AppSignal + Sequel][example-app]\ The example shows how to set up AppSignal with Sequel and Rails, without ActiveRecord and using only the sequel gem, not the sequel-rails gem. * [AppSignal + Sequel - manual instrumentation app][example-manual-instrumentation-app]\ This example shows how to manually load the AppSignal Sequel instrumentation in a Rails application, using only the sequel gem, not the sequel-rails gem. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The query's span carries: * `db.system.name` — the database the query ran against, such as `postgresql` or `mysql`. * `db.namespace` — the name of the database it connected to. * `db.query.text` — the query, with its values removed. [sequel]: http://sequel.jeremyevans.net/ [sequel-rails]: https://github.com/TalentBox/sequel-rails [instrument-sequel]: /ruby/configuration/options.html#option-instrument_sequel [instrumentation-issue]: https://github.com/appsignal/appsignal-ruby/issues/91 [example-app]: https://github.com/appsignal/appsignal-examples/tree/rails-5+sequel [example-manual-instrumentation-app]: https://github.com/appsignal/appsignal-examples/tree/rails-5+sequel-manual-instrumentation [error_sql-extension]: http://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/error_sql_rb.html # Shoryuken Source: https://docs.appsignal.com/ruby/integrations/shoryuken [Shoryuken](https://github.com/phstc/shoryuken) is a thread-based message processor for [AWS SQS][aws-sqs]. AppSignal instruments Shoryuken automatically when the Shoryuken gem is detected on start. No manual installation is required if Shoryuken is part of a Rails app. If you're using a standalone Shoryuken app, see our [integration guide][integration-guide]. ## Performance monitoring ### Event timeline Shoryuken jobs appear in the event timeline of your application's performance actions as `perform_job.shoryuken` events. ### Incident grouping AppSignal detects job names from the Shoryuken worker class name, suffixed with the `perform` method name, resulting in something like `MyWorker#perform`. AppSignal groups jobs by this name for performance monitoring and notifications. ## Enqueue instrumentation Enqueuing a Shoryuken job records an `enqueue.shoryuken` event, titled after the job being enqueued. AppSignal records enqueue events on the active transaction's event timeline, for example when you enqueue a job from within a web request or from within another job. It only records them when a transaction is active, so enqueuing a job outside of a transaction records nothing. To stop recording enqueue events across all background job integrations, set the [`enable_job_enqueue_instrumentation` config option](/ruby/configuration/options#option-enable_job_enqueue_instrumentation) to `false`. This does not affect the instrumentation of the jobs themselves. ## Batch support If an app uses a worker with the `:batch => true` option, that worker processes multiple messages in the same tick. This requires Ruby gem `2.11.3` or higher, which adds support for the batch option. ```ruby Ruby theme={null} # my_worker.rb class MyWorker include Shoryuken::Worker shoryuken_options :queue => "batched", :batch => true def perform(sqs_msg, body) # Do stuff puts "Performing BatchedWorker job: #{body}" sleep 1 end end ``` ## Example application We have an example application for a standalone Shoryuken application available in our [examples repository][example-app] on GitHub. [aws-sqs]: https://aws.amazon.com/sqs/ [integration-guide]: /ruby/instrumentation/integrating-appsignal.html [example-app]: https://github.com/appsignal/appsignal-examples/tree/shoryuken ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The enqueue and the job's own span both carry: * `messaging.system` — the queueing library. * `messaging.destination.name` — the queue the job was put on. * `messaging.operation.type` — whether the span is the enqueue or the job running. A span for a job that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A job runs in the same trace as the code that enqueued it, appearing under the request or job that scheduled it. You can trace a slow job back to what caused it to run. The trace is carried in the message's SQS message attributes. SQS allows at most ten per message, so a message using all ten is sent without a trace. Messages received in batches do not continue a trace. A batch is handled as one unit, so there is no single trace for it to belong to. Read more about [distributed tracing](/distributed-tracing). # Sidekiq Source: https://docs.appsignal.com/ruby/integrations/sidekiq How AppSignal monitors Sidekiq jobs for performance and errors, instruments enqueuing, and builds the Sidekiq Intelligence dashboard. [Sidekiq](http://sidekiq.org) is a simple and efficient background processor for Ruby. It's also the processor we use to process jobs in AppSignal. When AppSignal detects Sidekiq metrics, it will create an [Intelligence dashboard](#intelligence-dashboard), allowing you to monitor core metrics visually. ## Sidekiq monitoring for Ruby on Rails apps The AppSignal Ruby gem automatically inserts a listener into the Sidekiq server middleware stack if the `Sidekiq` module is present if you use Rails. No further action is required. The Sidekiq integration is compatible with [Active Job](/ruby/integrations/active-job). ## Sidekiq monitoring for Ruby apps Adding this config should only be necessary when Sidekiq doesn't automatically load AppSignal through the app's framework, like Rails. Add this snippet to your Sidekiq config with the right environment and name: ```ruby Ruby theme={null} require 'appsignal' Sidekiq.configure_server do |config| config.on(:startup) do # Start AppSignal Appsignal.start end config.on(:shutdown) do # Stop the agent Appsignal.stop('Sidekiq shutdown') end end ``` ## Performance monitoring Once AppSignal begins reporting Sidekiq metrics, AppSignal will give you performance insights via: * [Trace timeline](#event-timeline) * [Error tracking](#error-tracking) * [Incident grouping](#incident-grouping) * [Trace breakdown](#trace-breakdown) ### Trace timeline `perform_job.sidekiq` spans appear in the trace timeline on the [trace page](/trace-page): ![Trace timeline of a Sidekiq job](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/sidekiq/event-timeline.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=91c0d769f2dfad870d89c88aa681bd4f) ### Error tracking Track exceptions that occur when running Sidekiq jobs. When Sidekiq encounters a problem before or after a job has been processed, such as parsing JSON from Redis, it will raise an error. This error is reported under the SidekiqInternal action on the background namespace, as the job context is unknown when the error occurs. ![Example sidekiq error](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/sidekiq/error.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=54a0b5823201ce638b0b97690c0686bd) #### Report errors on job discard Set the [`sidekiq_report_errors` config option](/ruby/configuration/options#option-sidekiq_report_errors) to `discard` to only report errors when a job is discarded. When a job is discarded, all job retries have been exhausted, and the job is no longer retried. Read the [Sidekiq documentation](https://github.com/sidekiq/sidekiq/wiki/Error-Handling) to learn more about Sidekiq exception handling and failed job retries. > [!WARNING] > > When using Sidekiq with Active Job's retry system, configure it [to report > errors only on > discard](/ruby/integrations/active-job#report-errors-on-job-discard), so > that it won't report errors multiple times. > > After the Active Job retries are exhausted, the Sidekiq retry system will > take over. Disable the Sidekiq retry system if this is unwanted behavior. ### Incident grouping AppSignal detects job names from the Sidekiq worker class name, suffixed with the `perform` method name, resulting in something like `MyWorker#perform`. ![Sidekiq jobs grouped by worker class name on the Performance page](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/sidekiq/job-performance-samples.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=180e2f120fd17232663ce4402a45087c) ### Trace breakdown The trace breakdown on a trace page shows how a job's time was split across event groups, such as `sidekiq` and `active_record`, so you can spot performance problems without reading the whole timeline. ![Trace breakdown of a Sidekiq job](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/ruby/integrations/sidekiq/sample-breakdown.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=d78c0a4180ffae659d722cc1cf942481) ## Enqueue instrumentation Enqueuing a Sidekiq job records an `enqueue.sidekiq` event, titled after the job being enqueued. AppSignal records enqueue events on the active transaction's event timeline, for example when you enqueue a job from within a web request or from within another job. It only records them when a transaction is active, so enqueuing a job outside of a transaction records nothing. To stop recording enqueue events across all background job integrations, set the [`enable_job_enqueue_instrumentation` config option](/ruby/configuration/options#option-enable_job_enqueue_instrumentation) to `false`. This does not affect the instrumentation of the jobs themselves. ## Intelligence dashboard When AppSignal receives Sidekiq metrics, it will create a Sidekiq Intelligence dashboard, available from the dashboard section of the AppSignal app. The Sidekiq Intelligence dashboard will have the following graphs: | Graph | Metrics | Tags | | - | - | - | | [Connection count](#connection-count-graph) | `sidekiq_connection_count` | `hostname` | | [Duration per worker](#duration-per-worker-graph) | `trace_duration` |
  • `action`
  • `namespace`
  • | | [Job status per queue](#job-status-per-queue-graph) | `sidekiq_queue_job_count` |
  • `status`
  • `queue`
  • | | [Overall job status](#overall-job-status-graph) | `sidekiq_job_count` |
  • `status`
  • `hostname`
  • | | [Queue latency](#queue-latency-graph) | `sidekiq_queue_latency` |
  • `hostname`
  • `queue`
  • | | [Queue length](#queue-length-graph) | `sidekiq_queue_length` |
  • `hostname`
  • `queue`
  • | | [Redis memory usage](#redis-memory-usage-graph) |
  • `sidekiq_memory_usage`
  • `sidekiq_memory_usage_rss`
  • | `hostname` | | [Throughput per worker](#throughput-per-worker-graph) | `trace_duration` |
  • `action`
  • `namespace`
  • | | [Worker/processes count](#workerprocesses-count-graph) |
  • `sidekiq_worker_count`
  • `sidekiq_process_count`
  • | `hostname` | > [!NOTE] > > The Duration per worker and Throughput per worker charts use `trace_duration` on accounts that have been moved to trace metrics. Accounts that have not been moved yet see these charts powered by `transaction_duration` instead. Tags give you a contextual breakdown of Sidekiq performance information. AppSignal reports the following tags for Sidekiq jobs: | Name | Description | | - | - | | `action` | The name of the action the metric was reported from (e.g., `YourWorker#perform`). | | `hostname` | The hostname of the Redis server Sidekiq uses, or the `hostname` value set in the [probe config](#hostname-configuration). | | `namespace` | The name of the namespace the metric was reported from. | | `queue` | Named queue in which jobs are processed, e.g. `default` or `mailer`. | | `status` | Status of each job. For Job status per queue: `processed` or `failed`. For Overall job status: `processed`, `failed`, `retry_queue`, `died`, `scheduled`, or `enqueued`. Jobs that are `failed` are also counted as `processed`. | Each tag will be represented with a colored line on the graph: ![Example Sidekiq dashboard](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/ruby/integrations/sidekiq/dashboard.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=142e1a00e315e511d35fb80892957e22) ### Connection count graph The Connection count graph shows the number of clients connected to the Redis server Sidekiq uses, per Redis host. You can use the Connection count graph to spot connection trends and bottlenecks, and optimize resources. ### Duration per worker graph The Duration per worker graph shows the amount of time that it took for jobs to execute, grouped by namespace and action. You can use the Duration per worker graph to monitor the performance of workers per action and namespace, giving you a helicopter view of Sidekiq performance and allowing you to quickly identify and investigate spikes in duration time. ### Job status per queue graph The Job status per queue graph shows the number of jobs that were executed, grouped by their resulting status and by the queue in which they were enqueued. You can use the Job status per queue graph to monitor job error counts and performance based on queue, identify bottlenecks, and optimize your background jobs for scalability. ### Overall job status graph The Overall job status graph shows the number of Sidekiq jobs per status and Redis host. You can use the Overall job status graph to monitor failed, dead, retrying, scheduled, and enqueued jobs. ### Queue latency graph The Queue latency graph shows the latency the queue experienced at the time of measurement. [Sidekiq calculates this](https://github.com/mperham/sidekiq/wiki/API) as the time since the oldest job in the queue was enqueued. This value is reported as milliseconds. You can use the Queue latency graph to spot delays in processing jobs, detect queue congestion, and understand how quickly background jobs start. ### Queue length graph The Queue length graph shows the length of Sidekiq queues per queue and Redis host. You can use the Queue length graph to monitor queue performance and spot and solve Sidekiq bottlenecks. ### Redis memory usage graph The Redis memory usage graph shows: * The total memory allocated by Redis (`sidekiq_memory_usage`) * The resident set size, the physical memory used by Redis as seen by the operating system (`sidekiq_memory_usage_rss`) You can use the Redis memory usage graph to monitor Sidekiq's memory usage, improve resource management, and optimize memory-intensive jobs. ### Throughput per worker graph The Throughput per worker graph shows the number of jobs that were executed, grouped by namespace and action. You can use this graph to see how many jobs each worker class processes and spot workers whose volume changes unexpectedly. ### Worker/processes count graph The Worker/processes count graph shows the number of Sidekiq workers and executed processes. You can use the Worker/processes count graph to manage workload distribution, optimize resource allocation, and identify performance problems. ## Hostname configuration AppSignal attempts to detect the hostname of the Redis instance your Sidekiq instance uses to store its queues. If the detection is not accurate, it's possible to customize the hostname configuration by overriding the default Sidekiq probe. First, you'll need to [override the default Sidekiq probe](/ruby/instrumentation/minutely-probes#overriding-default-probes) by registering a new probe with the same name (`:sidekiq`). This probe will need a configuration hash, including the `:hostname` key, with the new hostname value. By specifying the `:hostname` config option in the Sidekiq minutely probe, the metrics will be tagged with the given hostname value. The `:hostname` config option value is not used to establish a Redis or Sidekiq connection. For example: ```ruby Ruby theme={null} # config/initializers/appsignal.rb or a file that's loaded on boot # Ruby gem 2.11.0 and newer Appsignal::Minutely.probes.register( :sidekiq, # Use the same key as the default Sidekiq probe to override it Appsignal::Probes::SidekiqProbe.new(:hostname => "my_sidekiq_hostname") ) # Ruby gem 2.10.x and older Appsignal::Minutely.probes.register( :sidekiq, # Use the same key as the default Sidekiq probe to override it Appsignal::Hooks::SidekiqProbe.new(:hostname => "my_sidekiq_hostname") ) ``` In version 2.11.0 of the Ruby gem, the `SidekiqProbe` constant was moved to its own module. Upon calling the constant, a warning will be printed and logged. Update to the new constant name `Appsignal::Probes::SidekiqProbe` to remove the warning. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The enqueue and the job's own span both carry: * `messaging.system` — the queueing library. * `messaging.destination.name` — the queue the job was put on. * `messaging.operation.type` — whether the span is the enqueue or the job running. A span for a job that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A job runs in the same trace as the code that enqueued it, appearing under the request or job that scheduled it. You can trace a slow job back to what caused it to run. The trace is carried on the job itself, alongside its other data. Read more about [distributed tracing](/distributed-tracing). ## See also * [Sidekiq batches: run jobs in parallel, then act](/tutorials/ruby/batching-background-jobs): split one unit of work across many jobs, then run a callback once every job has succeeded. Covers why the callback needs its own class, and how to chain one batch into the next. # Sinatra Source: https://docs.appsignal.com/ruby/integrations/sinatra [Sinatra](http://www.sinatrarb.com/) applications are officially supported. Instrumenting Sinatra applications requires some manual setup. Follow the installation steps in AppSignal, starting by clicking 'Add app' on the [accounts screen](https://appsignal.com/accounts). > [!NOTE] > > Is your application using a combination of Rails, Grape, Hanami, Padrino or Sinatra? Follow our guide for [instrumenting multiple Rack applications](/ruby/integrations/rack-libraries). ## Installation After installing the AppSignal gem, add the AppSignal integration after requiring `sinatra` (or `sinatra/base`). ```ruby Ruby theme={null} require "appsignal" # Add this require require "sinatra" # or require "sinatra/base" # Load the Sinatra integration Appsignal.load(:sinatra) # Start AppSignal Appsignal.start # For Ruby gem 3.11 and older require "appsignal/integrations/sinatra" ``` Then, create the AppSignal configuration file. For more details on configuring AppSignal, see the [Ruby configuration](/ruby/configuration) page. After these steps, start your Sinatra app and wait for data to arrive in AppSignal. ## Ignoring errors To ignore a specific Sinatra error, set the `Sinatra.skip_appsignal_error` flag in the request environment. This flag will tell AppSignal to ignore the error that occurs during the request and not report it to AppSignal. Only ignore errors like this if you need to ignore errors from a Sinatra app using code. See the [`ignore_errors` option](/guides/filter-data/ignore-errors) to ignore it for the entire app. To avoid being notified about an error, see [our notification settings](/application/notification-settings). ```ruby Ruby theme={null} get "/" do env["sinatra.skip_appsignal_error"] = true # Add this line to an endpoint or callback raise "uh oh" # Example error, don't copy this end ``` ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `url.scheme`, `url.path`, and `url.query` — the address that was requested. * `http.response.status_code` — the status your application responded with. A span for a request that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A request that arrives with a `traceparent` request header continues the trace it names. The request appears inside the calling service's trace, under the request that caused it. You can follow a slow request from that service into this application without switching traces. The [HTTP clients](/ruby/distributed-tracing#http-clients) AppSignal supports start the trace. A request without the header starts a new one. # Solid Queue Source: https://docs.appsignal.com/ruby/integrations/solidqueue [Solid Queue](https://github.com/rails/solid_queue) is a DB-based queueing backend for Active Job. AppSignal's Solid Queue integration allows you to track enqueued job executions and any events the jobs perform. ## Active Job support The Solid Queue integration works out-of-the-box with our [Active Job integration](/ruby/integrations/active-job). ## Example apps We've added a Rails 7 + Solid Queue [example app](https://github.com/appsignal/test-setups/tree/main/ruby/rails7-solid-queue) to our [test-setups repository](https://github.com/appsignal/test-setups). Please take a look if you're having trouble getting AppSignal for Solid Queue configured. ## See also * [Solid Queue: run background jobs in your database](/tutorials/ruby/solid-queue): install Solid Queue, manage it with Puma or as a separate service, and read the tables it creates. * [Mission Control Jobs: a job dashboard inside Rails](/tutorials/ruby/mission-control-jobs): mount an engine that browses those tables from inside your own application: queues, workers, and failed jobs. # ViewComponent gem Source: https://docs.appsignal.com/ruby/integrations/view-component The AppSignal gem can instrument events emitted by the [ViewComponent](https://viewcomponent.org/) Ruby gem. In order for AppSignal to be able to instrument these events, ViewComponent must be configured to emit these events. For example, in your `config/application.rb` file: ```ruby Ruby theme={null} # config/application.rb module MyRailsApp class Application < Rails::Application # add the following lines config.view_component.instrumentation_enabled = true config.view_component.use_deprecated_instrumentation_name = false end end ``` ## Performance monitoring Components rendered by your application are recorded as `render.view_component` events, titled after the component that rendered. The event appears in the event timeline of your application's performance actions. # Webmachine Source: https://docs.appsignal.com/ruby/integrations/webmachine ## Installation A [Webmachine](https://github.com/webmachine/webmachine-ruby/) application requires a few manual steps to get working. 1. Create the AppSignal configuration file or configure it with environment variables. For more details on configuring AppSignal, see the [Ruby configuration](/ruby/configuration) page. 2. Make sure AppSignal is required, `require "appsignal"`. 3. Configure AppSignal using `Appsignal.config`. 4. Start AppSignal using `Appsignal.start`. An example of a Webmachine `app.rb` file: ```ruby Ruby theme={null} # app.rb require "webmachine" require "appsignal" Appsignal.start class MyResource < Webmachine::Resource def to_html "Hello, world!" end end # Start a web server to serve requests via localhost MyResource.run ``` After these steps, start your Webmachine app and wait for data to arrive in AppSignal. ## Request headers Webmachine reports the request headers named in the [`request_headers`](/ruby/configuration/options#option-request_headers) configuration option, or in [`keep_request_headers`](/ruby/configuration/options#option-keep_request_headers) when using a collector. Earlier versions reported no request headers at all. ## Span attributes > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. The request's span carries: * `http.request.method` — the request method. * `url.scheme`, `url.path`, and `url.query` — the address that was requested. * `http.response.status_code` — the status your application responded with. A span for a request that raised also carries `error.type`, the class of the error. ## Distributed tracing > [!NOTE] > > **Collector mode only:** this applies when AppSignal for Ruby runs in [collector mode](/ruby/configuration/collector). It has no effect otherwise. A request that arrives with a `traceparent` request header continues the trace it names. The request appears inside the calling service's trace, under the request that caused it. You can follow a slow request from that service into this application without switching traces. The [HTTP clients](/ruby/distributed-tracing#http-clients) AppSignal supports start the trace. A request without the header starts a new one. # SDKs & telemetry Source: https://docs.appsignal.com/sdks Send error, performance, metric, and log data to AppSignal with a language SDK, OpenTelemetry, or a standalone telemetry tool. AppSignal collects data from your application through language SDKs and standalone telemetry tools. Choose your language or tool to find its installation, configuration, and instrumentation documentation. ## Language SDKs AppSignal's own SDKs, with the deepest feature coverage. > **[Ruby](/ruby)** > > Monitor Rails, Sinatra, Sidekiq, and other Ruby applications with the AppSignal gem. > **[Elixir](/elixir)** > > Monitor Phoenix, Ecto, Oban, and other Elixir applications. > **[Node.js](/nodejs/3.x)** > > Monitor JavaScript and TypeScript applications, with plugins for popular frameworks and packages. > **[Python](/python)** > > Monitor Django, Flask, Celery, and other Python applications. > **[PHP](/php)** > > Monitor PHP applications, with auto-instrumentation for Laravel and Symfony. > **[JavaScript (browser)](/browser)** > > Track front-end errors, and measure Core Web Vitals from real users. Breadcrumbs and vitals need no configuration. > **[JavaScript](/front-end)** > > Track errors in front-end JavaScript applications, with plugins for breadcrumbs and framework integrations. ## Languages via OpenTelemetry AppSignal supports additional languages through OpenTelemetry. Any tool or service that exports OpenTelemetry traces, metrics, or logs can send data to AppSignal. > **[Go](/go)** > > Monitor Go applications through OpenTelemetry. > **[Java](/java)** > > Monitor Java applications through OpenTelemetry. > **[OpenTelemetry](/opentelemetry)** > > Send data from any other language or service that supports the OpenTelemetry protocol. ## Telemetry tools Standalone tools that monitor processes and hosts, and collect telemetry outside your application code. > **[Wrap](/wrap)** > > Monitor any process running on your servers, such as cron jobs or database servers. > **[Collector](/collector)** > > Collect and process OpenTelemetry data before sending it to AppSignal. > **[Standalone agent](/standalone-agent/installation)** > > Collect host metrics, StatsD, and NGINX data from servers that don't run your application. # Public Status Page Source: https://docs.appsignal.com/uptime-monitoring/public-status-page You can use our public status pages to expose your uptime monitoring metrics to your users and to keep your users informed during your application's downtime. ## Set up > [!TIP] > > To set up a public status page **on a custom domain**, follow the instructions > on the [Custom > Domain](/uptime-monitoring/public-status-page/custom-domain) page > **before** continuing with the instructions in this page. To set up a new public status page, [navigate to "Uptime Pages"](https://appsignal.com/redirect-to/organization?to=status_pages) and click on the "Add status page" button. You can select any of your existing uptime monitors to be displayed on the public status page. > [!TIP] > > To set up a public status page, you must have already created an [Uptime > Monitor](/uptime-monitoring/setup) in any of your applications. When creating a public status page, you can choose a subdomain name for the public status page to be publicly available at, or you can choose a custom domain name. For example, if you choose the subdomain "my-app", your public status page will be available at `https://my-app.appsignal-status.com`. Once the subdomain is available, you can share it with your users so that they can see your application's current status. > [!TIP] > > It can take up to ten minutes for the public status page to be available at > the subdomain. ![Screenshot of uptime monitoring page](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/uptime/public-status-page.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=a71c55c0d4d52f90cf6e95638e26b670) ### Status page updates You can post a status update for your public status page by clicking on the "Add update" button. When posting a status update, you can set the status to **Investigating**, **Identified** or **Recovering** to signal that an incident has started or is still taking place. This will report that your application is currently down. Once your application's incident is over, use the **Resolved** state to let your users know that your application is back up. ![Screenshot of uptime monitoring page](https://mintcdn.com/appsignal-715f5a51/g-Xvhfxoo9Zu0ive/assets/images/screenshots/uptime/no-known-issue.png?fit=max\&auto=format\&n=g-Xvhfxoo9Zu0ive\&q=85\&s=c93012102f688548d9d51eecaec764cc) # Custom Domain Source: https://docs.appsignal.com/uptime-monitoring/public-status-page/custom-domain You can configure a custom domain for your application's Public Status Page. > [!TIP] > > You must follow the instructions on this page **before** the public status > page is created. If you have already created a public status page, after > following the instructions on this page, you will need to delete the status > page and create it again. To use custom status page URLs, you must set up a CNAME (Canonical Name) record in your domain's DNS (Domain Name System) records. How you add a new CNAME record will vary [depending on your DNS provider](#popular-dns-provider-documentation). The "Host" or "Name" setting of the CNAME must be set to the subdomain's name where you want the public status page to be accessible. For example, if you want the public status page to be accessible at `status.example.app`, you would set the "Host" or "Name" value to `status`. The "Value" setting must always be set to the following value: `cname.appsignal-status.com` Once you've added your new CNAME record, it may take several hours for the changes to take effect. Once the changes have replicated across the DNS network, you can create a public status page, setting the "Custom domain" value to the full domain name you want the public status page to be accessible at, including the subdomain (for example, `status.example.app`). > [!TIP] > > Currently, we do not support IPv6. You need to make sure the endpoint is > reachable through IPv4. ### Popular DNS Provider Documentation Below are links that take you to the CNAME-specific documentation of popular DNS providers. If your DNS provider is not listed, instructions should be available in the support section of their website. * [GoDaddy](https://www.godaddy.com/help/add-a-cname-record-19236) * [namecheap](https://www.namecheap.com/support/knowledgebase/article.aspx/9646/2237/how-to-create-a-cname-record-for-your-domain/) * [Domain.com](https://www.domain.com/help/article/dns-management-how-to-add-edit-and-delete-dns-records-video) * [Google Domains](https://support.google.com/a/answer/47283?hl=en) * [DreamHost](https://help.dreamhost.com/hc/en-us/articles/360035516812-Adding-custom-DNS-records) > [!NOTE] > > 🛟 Need a hand? [Contact us](mailto:support@appsignal.com), and we'll help you > get your Public Status Page custom domain set up. # Uptime monitoring Source: https://docs.appsignal.com/uptime-monitoring/setup With AppSignal uptime monitoring you can receive alerts when your application is down. We check your application from multiple regions across the world, and we will alert you when your application can't be reached from any of these regions. We also graph the performance of the endpoint you provide from different regions around the world. ![Screenshot of uptime monitoring dashboard](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/uptime_monitoring.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=dc95e8fd778222052f7938becb3c5274) ## Setup To setup a new uptime monitor check, click the "Add uptime monitor" button on the [Uptime Monitoring](https://appsignal.com/redirect-to/app?to=uptime_monitors) page. Provide the full URL (including `http://` or `https://`) of the page you'd like to check. Our servers will make a request to this URL every minute from multiple regions and report if the request fails or if the response status code is not in the `2xx` range. Each monitor in an app needs a unique name. Alert triggers find a monitor's metrics by its `name` tag, so two monitors with the same name would mix their data. In order to receive notifications when your application is down, select a notification method. To prevent receiving alerts on small network hiccups, we recommend setting an alert warm-up period of at least one minute. You can set headers to be sent in the requests we perform against the URL you provide. This allows you to set authorization headers to enable the requests to go through. ## How it works We ping your applications from AWS Lambda workers that are executed from the following regions: We will request the given URL from the following regions: * Asia-Pacific (Seoul) * Europe (Frankfurt) * North America (N. Virginia) * South America (São Paulo) There's a 30 second timeout to the connection. If your server does not respond within that time frame, we consider the application to be down. Note that if our requests to your application are failing from a single region, that doesn't necessarily mean your application is down. It could instead point to a networking issue between AWS Lambda and your endpoint. ### User Agent Our uptime monitoring requests to your application will set the `User-Agent` header as follows, where `` is a version number like `1.0`: ```sh Shell theme={null} AppSignalBot/ (+https://appsignal.com) ``` This allows you to detect requests coming from AppSignal. ### IP Allowlisting We run our uptime checks on a serverless framework and have no control over what IP address will be used to make the request to your application. Therefore, we're unable to provide a list of IP addresses to allowlist. The URL to monitor must be publicly reachable from the open internet. ## Metrics For every uptime monitor check we create several metrics that you can use to create your own [custom graphs](/metrics/custom#graphing-custom-metrics) and set your own [anomaly detection triggers](/anomaly-detection#creating-and-configuring-triggers). To query `uptime_monitor_error_count` or `uptime_monitor_duration` for a specific monitor, use `region` together with either the monitor `name` or `id`. Prefer `id` because a monitor name can change, but its `id` stays the same. The region tag values are `asia-pacific`, `europe`, `north-america`, and `south-america`. To query `days_until_ssl_expiration` for a specific monitor, use its `name` or `id`. This metric does not use a `region` tag. ### Error count The `uptime_monitor_error_count` metric is a counter that, for a given minute, will be set to zero if the request succeeded or to one if the request fails. ![Screenshot of uptime monitoring error count custom metrics form](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/uptime_monitoring_error_count.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=30bd7f6f3af1158f698dddf9cf398263) ### Endpoint performance The `uptime_monitor_duration` metric is a gauge that tracks the duration of the request for each region. This allows you to see if the latency to your servers is increasing. ![Screenshot of uptime monitoring performance custom metrics form](https://mintcdn.com/appsignal-715f5a51/MS9b5WO71lSfD5jG/assets/images/screenshots/uptime_monitoring_performance.png?fit=max\&auto=format\&n=MS9b5WO71lSfD5jG\&q=85\&s=b94101d33b24c4123e3a915618eac0a6) ### Request timing The `uptime_monitor_timing` metric is a gauge that records how long each phase of the request took, in milliseconds. It shows where the time goes when a monitor is slow: resolving the hostname, connecting, or waiting for the server. For example, if `ttfb` is high but `dns` and `connect` are low, your server is slow to respond. If `connect` is high in one region only, the network path to that region is the problem, not your application. Select a phase with the `phase` tag: | `phase` | What it measures | | - | - | | `dns` | Resolving the hostname. | | `connect` | Opening the TCP connection to the server. | | `tls` | The TLS handshake. Not recorded for plain HTTP URLs. | | `ttfb` | From sending the request until the response headers arrive. This includes the time your server spends handling the request. | | `download` | Reading the response body. Only recorded when the monitor has a body check. | | `total` | The whole check, from start to finish. | If the URL redirects, every phase includes the redirected requests too. To query this metric for a specific monitor, use `region`, `phase`, and either the monitor `name` or `id`. The app does not show these timings yet. Query them through the [Public API (V2)](/api/v2/metrics#uptime-monitor-timings) or ask your agent through [AppSignal MCP](/mcp/workflows#finding-where-an-uptime-check-spends-its-time). ## Plans and Requests If the application serving the URL uses an AppSignal integration, our uptime monitor can use up a lot of your plan's monthly requests. We recommend setting up a dedicated health-check endpoint and configuring AppSignal to ignore requests to that endpoint so that they don't count toward your plan's limit. ### Example Here's an example of a health-check endpoint in Ruby on Rails. We make sure to hit all our external services, such as the database and Redis, something that might not happen on the homepage, ensuring all services are operational. ```ruby Ruby theme={null} # routes.rb resource :health_check, :only => :show ``` ```ruby Ruby theme={null} # health_checks_controller.rb class HealthChecksController < ApplicationController def show # Check MongoDB Account.mongo_client.command(:getLastError => 1) # Check Redis Redis.new.ping head 200 rescue Mongo::Error, Redis::CannotConnectError head 503 end end ``` Then, we configure AppSignal to ignore requests to that endpoint using [the `ignore_actions` configuration option](/ruby/configuration/options#option-ignore_actions): ```ruby Ruby theme={null} Appsignal.configure do |config| config.ignore_actions << "HealthChecksController#show" end ``` ```yaml YAML theme={null} default: &defaults ignore_actions: - HealthChecksController#show ``` # AppSignal for Elixir Source: https://docs.appsignal.com/elixir AppSignal for Elixir monitors Elixir and Phoenix applications. Start here for installation, configuration, integrations, custom instrumentation, and version support. AppSignal supports the [Elixir language][elixir-lang] with an [Elixir package][appsignal-package]. The package supports pure Elixir applications and the Phoenix framework out-of-the-box. Other frameworks and packages might require some [custom instrumentation](/elixir/instrumentation). ## Installation To get started with AppSignal for Elixir, follow our guide to [installing AppSignal](/elixir/installation) in your Elixir application for both pure Elixir and Phoenix installations. ## Configuration It's possible to configure the AppSignal Elixir package using an initializer or using environment variables. Read more about [configuring AppSignal](/elixir/configuration). ## Integrations The AppSignal Elixir package also integrates with popular integrations such as the Phoenix framework. We currently support the following integrations: * [Absinthe](/elixir/integrations/absinthe) * [Broadway](/elixir/integrations/broadway) * [Ecto](/elixir/integrations/ecto) * [Erlang](/elixir/integrations/erlang) * [Finch](/elixir/integrations/finch) * [HTTPoison](/elixir/integrations/httpoison) * [Oban](/elixir/integrations/oban) * [Phoenix](/elixir/integrations/phoenix) * [Plug](/elixir/integrations/plug) * [Tesla](/elixir/integrations/tesla) ## Instrumentation To make your own integrations with AppSignal or to add custom instrumentation to your application, see the [instrumentation](/elixir/instrumentation) documentation. ## Version support AppSignal for Elixir supports maintained Elixir releases. The current package line (`2.x`) requires Elixir `1.9` or higher. See our [maintenance policy](/support/maintenance-policy). For older Elixir or AppSignal package versions, see [planning an upgrade from an older version](/support/maintenance-policy#planning-an-upgrade-from-an-older-version). [elixir-lang]: http://elixir-lang.org/ [appsignal-package]: https://hex.pm/packages/appsignal # AppSignal for Elixir: Command line tools Source: https://docs.appsignal.com/elixir/command-line The [AppSignal for Elixir package][package] ships with several command line tools. These tools make it easier to install AppSignal in an application, send deploy notifications and diagnose any problems with the installation. ## Install A command line tool to install AppSignal in an application. Read more about the [appsignal install][cli-install] command line tool. ## Diagnose A self diagnostic tool for the AppSignal for Elixir package. This tool can be used to debug your AppSignal installation and is one of the first thing our support team asks for when there's an issue. Read more about the [appsignal diagnose][cli-diagnose] command line tool. ## Demo A command to demonstrate and test the AppSignal for Elixir package. Useful for testing the AppSignal installation and configuration. Read more about the [appsignal demo][cli-demo] command line tool. ## Check install A command to test if the AppSignal for Elixir package's extension (NIF) was successfully installed. Read more about the [appsignal check install][cli-check-install] command line tool. [package]: https://github.com/appsignal/appsignal-elixir [cli-install]: /elixir/command-line/install.html [cli-diagnose]: /elixir/command-line/diagnose.html [cli-demo]: /elixir/command-line/demo.html [cli-check-install]: /elixir/command-line/check-install.html # AppSignal for Elixir: Check installation tool Source: https://docs.appsignal.com/elixir/command-line/check-install The AppSignal for Elixir package ships with a command line tool to check if the package's extension ([a NIF](/elixir/why-nif)) was installed correctly. Our package does not error or fail builds when the extension is not installed correctly. This behavior is *by design*. We would rather have no data reported to AppSignal than have entire applications brought down because our extension could not be installed. We know it's not always easy to check if our package and extension were installed correctly. In some cases, failing a build or deployment when this happens is the best approach. The check install tool can help with this. If you want the build to fail when our extension isn't installed correctly, you can run the check installation task in your CI (Continuous Integration) or deployment process as described below. The command will fail with status code `1` when the extension is not installed correctly. ## Usage In your project's command line, run: ```bash Bash theme={null} mix appsignal.check_install ``` ### With a release binary In your project's command line, run: ```bash Bash theme={null} bin/your_app command appsignal_tasks check_install ``` ## Exit codes * Exits with status code `0` if the extension installation was successful. * Exits with status code `1` if the extension installation was unsuccessful. # AppSignal for Elixir: Demonstration tool Source: https://docs.appsignal.com/elixir/command-line/demo The AppSignal for Elixir package ships with a command line tool used to send demonstration traces to AppSignal. Upon running it, it sends an error and performance trace to AppSignal from the user's machine. This command line tool is useful when testing AppSignal on a system and validating the local configuration. It tests if the installation of AppSignal has succeeded and if the AppSignal agent is able to run on the machine's architecture and communicate with the AppSignal servers. The same test is also run during installation using [mix appsignal.install](/elixir/command-line/install). Read more about how to use the demonstration command on the [Debugging][debugging] page. This tool is available since version 0.11.0 of the AppSignal for Elixir package. ## Usage On the command line in your project run: ```bash Bash theme={null} mix appsignal.demo ``` ### With a specific environment ```bash Bash theme={null} MIX_ENV=prod mix appsignal.demo ``` ### With a release binary ```bash Bash theme={null} bin/your_app command appsignal_tasks demo ``` ## Exit codes * Exits with status code `0` if the command has completed successfully. * Exits with status code `1` if the command has completed with an error. [debugging]: /support/debugging.html # AppSignal for Elixir: Diagnose tool Source: https://docs.appsignal.com/elixir/command-line/diagnose The AppSignal for Elixir package ships with a self diagnostic tool. This tool can be used to debug your AppSignal installation and is one of the first thing our support team asks for when there's an issue. This tool has been available since version `0.12.0` of the AppSignal for Elixir package. ## The diagnostic report This command line tool is useful when testing AppSignal on a system and validating the local configuration. It outputs useful information to debug issues and it checks if AppSignal agent is able to run on the machine's architecture and communicate with the AppSignal servers. This diagnostic tool collects and outputs the following: * information about the AppSignal package. * information about the host system, Elixir and Erlang. * if the AppSignal [extension](/appsignal/how-appsignal-operates#extension) and [agent](/appsignal/how-appsignal-operates#agent) can run on the host system. * all configured config options (including default values). * if the configuration is valid and active. * if the Push API key is present and valid (internet connection required). * where configuration option values originate from. * if the required system paths exist, are writable, and which user and group are owners. * small parts of the tail from the available log files. Read more about how to use the diagnose command on the [Debugging][debugging] page. ## Submitting the report Since package version `1.3.0` you will be prompted to send the report to AppSignal. If accepted the report will be send to our servers and you will receive a support token. When you [send this support token to us](mailto:support@appsignal.com) we will review the report and help you debug the issue. We've seen that copy-pasting the report output usually loses formatting and makes it harder to read, which is why it's send to our servers in the JSON format. In package version `1.9.0` the option was added to view the report yourself on AppSignal.com. A link to the report is printed in the diagnose output. This web view will also show any validation problems and warnings our system detected. ## Usage On the command line in your project: ```bash Bash theme={null} mix appsignal.diagnose ``` ### With an Elixir release binary If your Elixir app is packaged in an Elixir release binary, built with `mix release` you will not be able to call the task using `mix`. Instead use the `eval` command on your release binary to call the AppSignal task `diagnose` like so: ```bash Bash theme={null} bin/your_app eval ":appsignal_tasks.diagnose()" ``` ### With a release binary If your Elixir app is packaged in a release binary with a tool such as [distillery](https://github.com/bitwalker/distillery) you will not be able to call the task using `mix`. Instead use the `command` command on your release binary to call the AppSignal task `diagnose` like so: ```bash Bash theme={null} bin/your_app command appsignal_tasks diagnose ``` ## Options | Option | Description | | - | - | | [Environment option](#environment-option) | Set the environment to use in the command, e.g. `production` or `staging`. | | [`--[no-]send-report`](#report-submission-option) | Automatically send, or do not send the report. | ### Environment option Select a specific environment with the CLI. ```bash Bash theme={null} MIX_ENV=prod mix appsignal.diagnose ``` The environment option is useful when the default environment is not the one you want to diagnose. The diagnose tool will warn you when no environment is selected. ### Report submission option The options to [submit the report](#submitting-the-report) immediately, or not, were added to the AppSignal package version `1.9.0`. Selecting whether or not to send the report with these options will no longer prompt this question, making it easier to use in non-interactive environments. Submit the report to AppSignal: ```bash Bash theme={null} mix appsignal.diagnose --send-report ``` Do not submit the report to AppSignal: ```bash Bash theme={null} mix appsignal.diagnose --no-send-report ``` ## Configuration output format ### Configuration option values format The configuration options are printed to the CLI as their inspected values. This means we print them as Elixir would in a console. * Strings values are printed with double quotes around them, e.g. `"My app name"`. * Booleans values are printed as their raw values: `true` and `false`. * List values are printed as a collection of values surrounded by square brackets, e.g. `["HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET"]`. * Empty Lists are printed as two square brackets: `[]`. * Nil values are printed as `nil`. ### Configuration sources The configuration section also prints where values from config options come from. This may help by identifying sources that override values from other config sources. For more on which configuration sources are available and in which order they're loaded and thus their priority, see the [configuration load order](/elixir/configuration/load-order) page. The configuration options are printed as demonstrated below depending on where the configuration option value comes from and how many sources set this option. ```text Shell theme={null} Configuration # Option with a value loaded only from the default source send_params: true # Option with one source # A different source than the default source name: "My app name" (Loaded from file) # Option with multiple sources # Listed in order of priority (highest priority last) active: true Sources: default: false file: false env: true ``` ## Exit codes * Exits with status code `0` if the command has completed successfully. * Exits with status code `1` if the command has completed with an error. [debugging]: /support/debugging.html # AppSignal for Elixir: Install Source: https://docs.appsignal.com/elixir/command-line/install Command line tool to install AppSignal in an Elixir application. Documentation on usage, options and configuration methods. Command line tool to install AppSignal in an Elixir application. The command line tool is primarily used to help set up the configuration for AppSignal. Please follow the [installation guide](/guides/new-application) when adding a new application to AppSignal. After the configuration/installation is completed the installer perform the [demonstration](/elixir/command-line/demo) command line tool and sends demo data to AppSignal servers to help with the installation wizard. This tool is available since version 0.13.0 of the AppSignal for Elixir package. ## Configuration methods There are two configuration methods the installer provides: using a configuration file or using environment variables. ### Configuration file It's possible to configure AppSignal with the Mix configuration. The AppSignal for Elixir package looks for the configuration loaded by Mix in the. Our installer will write the configuration to `config/appsignal.exs` and add an import to your other configuration file(s). When this option is chosen the given Push API key is written to the configuration file. We do not recommend checking this key into version control (git/svn/mercurial/etc). Instead, use a `APPSIGNAL_PUSH_API_KEY` environment variable or a secrets management tool for your application. See the [configuration documentation](/elixir/configuration) for more information. ### Environment variables It's possible to configure AppSignal using only system environment variables. When this option is selected no configuration is written to the file system. See the [configuration documentation](/elixir/configuration) for more information. ## Usage On the command line in your project run: ```bash Bash theme={null} mix appsignal.install # For example mix appsignal.install 1234-1234-1234-1234 ``` Where your "Push API key" can be found in the [installation wizard](https://appsignal.com/redirect-to/organization?to=sites/new) for your organization. ## Exit codes * Exits with status code `0` if the command has completed successfully. * Exits with status code `1` if the command has completed with an error. # AppSignal Elixir configuration Source: https://docs.appsignal.com/elixir/configuration Set the minimal required configuration for AppSignal for Elixir, configure each application environment, and disable AppSignal in tests. Configuration. Important, because without it the AppSignal Elixir package won't know which application it's instrumenting or in which environment. On this topic we'll explain how to configure AppSignal, what can be configured in the Elixir package and what the minimal configuration needed is. ## Minimal required configuration The minimal required configuration needed by AppSignal for Elixir are the following items. If they are not present, AppSignal will not send any data to AppSignal.com. * A valid [Push API Key](/appsignal/terminology#push-api-key) * The application's OTP app name * An application name * An application environment (`dev` / `prod` / `test`) * The application environment to be set to `active: true` ```elixir Elixir theme={null} # Example minimal config file # config/config.exs config :appsignal, :config, otp_app: :appsignal_phoenix_example, name: "AppsignalPhoenixExample", push_api_key: "your-push-api-key", env: Mix.env, active: true ``` Alternatively, you can configure the agent using system environment variables. AppSignal will automatically become active if the `APPSIGNAL_PUSH_API_KEY` environment variable is set. ```elixir Elixir theme={null} export APPSIGNAL_OTP_APP="appsignal_phoenix_example" export APPSIGNAL_PUSH_API_KEY="your-push-api-key" export APPSIGNAL_APP_NAME="AppsignalPhoenixExample" export APPSIGNAL_APP_ENV="prod" ``` ## Configuration options Read about all the configuration options on the [options page](/elixir/configuration/options). ## Application environments An application can have multiple environments such as "development"/"dev", "test", "staging" and "production". To separate the errors and performance issues that occur in the "development" environment and those in "production", it's possible to set the environment in which the application is running with the `env` configuration option. A typical environment configuration file would contain the following. ```elixir Elixir theme={null} # config/prod.exs config :appsignal, :config, active: true, env: :prod ``` The above configuration file example is also what is generated by the AppSignal installer per environment. If you activate AppSignal per environment, using `active: true` in the `config/{env}.exs` file, the `active` option is not required in the main `config/config.exs` file. ### Disable AppSignal for tests If you put your entire AppSignal configuration in the `config/config.exs` instead of `config/prod.exs` (e.g. for having AppSignal enabled during development), make sure to put `active: false` in your test configuration unless you want to submit all your test results. ```elixir Elixir theme={null} # config/test.exs config :appsignal, :config, active: false ``` ## Example configuration ```elixir Elixir theme={null} # config/config.exs config :appsignal, :config, otp_app: :appsignal_phoenix_example, name: "AppsignalPhoenixExample", push_api_key: "your-push-api-key", env: Mix.env, ``` ```elixir Elixir theme={null} # config/test.exs config :appsignal, :config, active: false ``` # AppSignal for Elixir load order Source: https://docs.appsignal.com/elixir/configuration/load-order The AppSignal Elixir can be configured in a couple different ways. Through mix configuration or through environment variables. The configuration is loaded in a four step process. Starting with the package defaults and ending with reading environment variables. The configuration options can be mixed without losing configuration from a different option. Using an initializer, a configuration file and environment variables together will work. ## Load order * 1. [Package defaults - `default`](#1-package-defaults) * 2. [System detected settings - `system`](#2-system-detected-settings) * 3. [Mix app config file - `file`](#3-mix-configuration) * 4. [Environment variables - `env`](#4-environment-variables) * 5. [Overrides - `override`](#5-overrides) ## Package defaults The AppSignal package starts with loading its default configuration, setting paths and enabling certain features. The agent defaults can be found in the [configuration options documentation](/elixir/configuration/options). This source is listed as `default` in the [diagnose](/elixir/command-line/diagnose) output. ## System detected settings The package detects what kind of system it's running on and configures itself accordingly. For example, when it's running on Heroku it sets the configuration option `:running_in_container` to `true` and `:log` to `"stdout"`. This source is listed as `system` in the [diagnose](/elixir/command-line/diagnose) output. ## Mix configuration The AppSignal package is most commonly configured with configuration in the Mix configuration file. ```elixir Elixir theme={null} # config/config.exs # or config/prod.exs config :appsignal, :config, otp_app: :appsignal_phoenix_example, name: "AppsignalPhoenixExample", push_api_key: "your-push-api-key", env: Mix.env, active: true ``` This step will override all given options from the defaults or system detected configuration. This source is listed as `file` in the [diagnose](/elixir/command-line/diagnose) output. ## Environment variables Our integration will look for its configuration in environment variables. When found these will override all given configuration options from previous steps. ```bash Bash theme={null} export APPSIGNAL_APP_NAME="AppsignalPhoenixExample" # start your app here ``` This source is listed as `env` in the [diagnose](/elixir/command-line/diagnose) output. ## Overrides When all the configuration is known, our integration will do a final check to find out if the configuration doesn't contradict itself or if some defaults config options are not set. The "override" configuration source will include those last configuration changes made by the integration. When it overrides a config option value, this value is leading. For example, at some point we deprecated the `skip_session_data` option in favor of the `send_session_data` option. When the `skip_session_data` config option was configured by the app, but `send_session_data` was not, the integration would use the value of `skip_session_data` to set the `send_session_data` config option value. # Elixir package configuration options Source: https://docs.appsignal.com/elixir/configuration/options The following list includes all configuration options with the name of the environment variable and the name of the key in the configuration file. For more information on how to configure AppSignal with a configuration file or system environment variables, see our [Configuration](/elixir/configuration) topic. ## Available options * Required options * [`active`](#option-active) * [`env`](#option-env) * [`name`](#option-name) * [`otp_app`](#option-otp_app) * [`push_api_key`](#option-push_api_key) * Options * [`bind_address`](#option-bind_address) * [`ca_file_path`](#option-ca_file_path) * [`cpu_count`](#option-cpu_count) * [`debug`](#option-debug) * [`dns_servers`](#option-dns_servers) * [`ecto_repos`](#option-ecto_repos) * [`enable_error_backend`](#option-enable_error_backend) * [`enable_host_metrics`](#option-enable_host_metrics) * [`enable_minutely_probes`](#option-enable_minutely_probes) * [`enable_nginx_metrics`](#option-enable_nginx_metrics) * [`enable_statsd`](#option-enable_statsd) * [`endpoint`](#option-endpoint) * [`files_world_accessible`](#option-files_world_accessible) * [`filter_parameters`](#option-filter_parameters) * [`filter_session_data`](#option-filter_session_data) * [`host_role`](#option-host_role) * [`hostname`](#option-hostname) * [`http_proxy`](#option-http_proxy) * [`ignore_actions`](#option-ignore_actions) * [`ignore_errors`](#option-ignore_errors) * [`ignore_logs`](#option-ignore_logs) * [`ignore_namespaces`](#option-ignore_namespaces) * [`instrument_absinthe`](#option-instrument_absinthe) * [`instrument_broadway`](#option-instrument_broadway) * [`instrument_ecto`](#option-instrument_ecto) * [`instrument_finch`](#option-instrument_finch) * [`instrument_oban`](#option-instrument_oban) * [`instrument_tesla`](#option-instrument_tesla) * [`log`](#option-log) * [`log_level`](#option-log_level) * [`log_path`](#option-log_path) * [`logging_endpoint`](#option-logging_endpoint) * [`nginx_port`](#option-nginx_port) * [`report_oban_errors`](#option-report_oban_errors) * [`request_headers`](#option-request_headers) * [`revision`](#option-revision) * [`running_in_container`](#option-running_in_container) * [`send_environment_metadata`](#option-send_environment_metadata) * [`send_params`](#option-send_params) * [`send_session_data`](#option-send_session_data) * [`skip_session_data`](#option-skip_session_data) * [`statsd_port`](#option-statsd_port) * [`transaction_debug_mode`](#option-transaction_debug_mode) * [`working_dir_path`](#option-working_dir_path) * [`working_directory_path`](#option-working_directory_path) ## active | Field | Value | | - | - | | Config file key | `active` | | System environment key | `APPSIGNAL_ACTIVE` | | Required | yes | | Type | Boolean (`true` / `false`) | | Default value | `false` / detected by system | | Available since version | `0.1.0` | ### Description > [!NOTE] > > **Note**: When the [`APPSIGNAL_PUSH_API_KEY`](#option-push_api_key) > environment variable is set, this defaults to `true`. This can be overridden > by setting the `APPSIGNAL_ACTIVE` system environment variable to `false`: > `APPSIGNAL_ACTIVE=false`. Configure AppSignal to be active or not for a given environment. Most commonly used in the [file configuration](/elixir/configuration) per environment. ## env | Field | Value | | - | - | | Config file key | `env` | | System environment key | `APPSIGNAL_APP_ENV` | | Required | yes | | Type | `Atom` | | Default value | `dev` | | Available since version | `0.1.0` | | |
    • `0.9.2`: The environment variable name for this configuration option was renamed from `APPSIGNAL_ENVIRONMENT` to `APPSIGNAL_APP_ENV`.
    | ### Description The environment of the app to be reported to AppSignal. This option is set by default by our installer, to `Mix.env`. To override it, change the value in `config/appsignal.exs` (or your config file of choice). ```elixir Elixir theme={null} # config/appsignal.exs # or config/config.exs config :appsignal, :config, env: Mix.env # Installer default # Set your own value config :appsignal, :config, env: :staging ``` To override the config option in the system environment, use the `APPSIGNAL_APP_ENV` environment variable. ```sh Shell theme={null} # The method of setting environment variables may differ on your system export APPSIGNAL_APP_ENV=staging mix run ``` The environment variable option is commonly used on platforms, such as Heroku, where apps run in the `production` environment by default. This setting allows an override to set the environment to `staging`, for example. ```sh Shell theme={null} heroku config:set APPSIGNAL_APP_ENV=staging ``` > [!NOTE] > > **Note**: Changing the [name](#option-name) or environment of an existing app > will create a new app on AppSignal.com. > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## name | Field | Value | | - | - | | Config file key | `name` | | System environment key | `APPSIGNAL_APP_NAME` | | Required | yes | | Type | `String` | | Default value | nil (This is unset by default) | ### Description Name of your application as it should be displayed on AppSignal.com. > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## otp\_app | Field | Value | | - | - | | Config file key | `otp_app` | | System environment key | `APPSIGNAL_OTP_APP` | | Required | yes | | Type | `Atom` | | Default value | nil (This is unset by default) | | Available since version | `2.0.0` | ### Description The OTP app name of your application, to be used for automatic configuration of instrumentation for libraries like Ecto. ## push\_api\_key | Field | Value | | - | - | | Config file key | `push_api_key` | | System environment key | `APPSIGNAL_PUSH_API_KEY` | | Required | yes | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.1.0` | ### Description The organization-level authentication key to authenticate with our Push API. Read more about the [AppSignal Push API key](/appsignal/terminology#push-api-key). > [!NOTE] > > **Note**: When the [`APPSIGNAL_PUSH_API_KEY`](#option-push_api_key) system > environment variable is set, the [`active`](#option-active) option will > default to `true` instead of `false`. This means AppSignal will be consider > active for the loaded environment even if `active` is set to `false` in the > config file. For more information see the [`active`](#option-active) option. ## bind\_address | Field | Value | | - | - | | Config file key | `bind_address` | | System environment key | `APPSIGNAL_BIND_ADDRESS` | | Required | no | | Type | `String` | | Default value | `127.0.0.1` | | Available since version | `2.7.7` | ### Description A valid IPv4 address the AppSignal agent uses as a binding for its TCP and UDP servers. Use a specific address if you only want the agent to listen to requests made to that address. Set this option to `0.0.0.0` to allow to receive requests from hosts using any IP address. By default it only listens to requests made on the same host. This option is applied to all the agent servers (StatsD, OpenTelemetry and NGINX). ## ca\_file\_path | Field | Value | | - | - | | Config file key | `ca_file_path` | | System environment key | `APPSIGNAL_CA_FILE_PATH` | | Required | no | | Type | `String` | | Default value | Packaged `cacert.pem` file path. | | Available since version | `0.12.0` | ### Description Configure the path of the SSL certificate file. By default this points to the AppSignal [vendored `cacert.pem` file](https://github.com/appsignal/appsignal-elixir/blob/f90759c04a4ff0274e2566704a462d652c988a70/priv/cacert.pem) in the package itself. Use this option to point to another certificate file if there's a problem connecting to our API. > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. ## cpu\_count | Field | Value | | - | - | | Config file key | `cpu_count` | | System environment key | `APPSIGNAL_CPU_COUNT` | | Required | no | | Type | `Float` | | Default value | `undefined` | | Available since version | `2.9.1` | ### Description The available CPU capacity of the host, in number of CPUs. This is used to calculate the CPU usage percentage in the host metrics. If not set, the agent will attempt to automatically detect this from cgroups. The number of CPUs can be a fraction, e.g. `0.5`. ## debug | Field | Value | | - | - | | Config file key | `debug` | | System environment key | `APPSIGNAL_DEBUG` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `1.0.0` | | |
    • `2.2.8`: Deprecated in favor of the [`log_level` config option](#option-log_level).
    | ### Description > [!WARNING] > > **Warning**: This config option is deprecated in Elixir package 2.2.8. Please > use the [`log_level`](#option-log_level) option instead for Elixir package > 2.2.8 and newer. Enable debug logging, this is usually only needed on request from support. With this option enabled AppSignal will log a lot more information about decisions that are made during metrics collection and when data is sent to AppSignal.com servers. Enabling debug logging could have a slight impact on the disk usage and IO, especially on high-traffic sites. CPU overhead is minimal with the debug option enabled. > [!NOTE] > > This option sets the severity level of AppSignal's internal logger. This > configuration option does not affect the [logging feature](/logging). ## dns\_servers | Field | Value | | - | - | | Config file key | `dns_servers` | | System environment key | `APPSIGNAL_DNS_SERVERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.3.0.beta.2` | ### Description Configure DNS servers for the AppSignal agent to use. ```elixir Elixir theme={null} # config/config.exs config :appsignal, :config, dns_servers: ["8.8.8.8", "8.8.4.4"] ``` ```sh Shell theme={null} # In the host environment export APPSIGNAL_DNS_SERVERS="8.8.8.8,8.8.4.4" ``` If you're affected by our [DNS timeouts](/support/known-issues/dns-timeouts), try setting a DNS server manually using this option that doesn't use more than **4** dots in the server name. * Acceptable values: `8.8.8.8`, `my.custom.local.server`. * Not acceptable values: `foo`, `my.awesome.custom.local.dns.server`. If the DNS server cannot be reached the agent will fall back on the host's DNS configuration and output a message in the `appsignal.log` file: `A problem occurred while setting DNS servers`. ## ecto\_repos | Field | Value | | - | - | | Config file key | `ecto_repos` | | System environment key | `APPSIGNAL_ECTO_REPOS` | | Required | no | | Type | `list(String)` | | Default value | `nil` | | Available since version | `2.0.0` | ### Description Configure which Ecto repos to instrument queries for. If unset, AppSignal will automatically find your repos through your application configuration. ```elixir Elixir theme={null} # config/config.exs config :appsignal, :config, ecto_repos: [AppsignalPhoenixExample.Repo, AppsignalPhoenixExample.AnotherRepo] ``` ```sh Shell theme={null} # In the host environment export APPSIGNAL_ECTO_REPOS="AppsignalPhoenixExample.Repo,AppsignalPhoenixExample.AnotherRepo" ``` ## enable\_error\_backend | Field | Value | | - | - | | Config file key | `enable_error_backend` | | System environment key | `APPSIGNAL_ENABLE_ERROR_BACKEND` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `2.4.1` | | |
    • `2.16.0`: The error backend is opt-in. It was enabled by default in earlier versions.
    | ### Description Enables the error backend in the Elixir integration. ## enable\_host\_metrics | Field | Value | | - | - | | Config file key | `enable_host_metrics` | | System environment key | `APPSIGNAL_ENABLE_HOST_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | \`\`true` / detected by system` | ### Description Set this option to `false` to disable [host metrics](/metrics/host-metrics) collection. On Heroku and Dokku host metrics are disabled by default. This is done because these systems will report inaccurate metrics from within the containers. Host metrics collection on these systems cannot be enabled. For Heroku, use the [Heroku log drain](/heroku/host-metrics) instead. ## enable\_minutely\_probes | Field | Value | | - | - | | Config file key | `enable_minutely_probes` | | System environment key | `APPSIGNAL_ENABLE_MINUTELY_PROBES` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.10.1` | ### Description Enables the [minutely probes](/elixir/instrumentation/minutely-probes) system. ## enable\_nginx\_metrics | Field | Value | | - | - | | Config file key | `enable_nginx_metrics` | | System environment key | `APPSIGNAL_ENABLE_NGINX_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `2.5.2` | ### Description Set to `true` to enable the NGINX metrics server. [See the NGINX metrics documentation for details.](/metrics/nginx) When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 27649. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## enable\_statsd | Field | Value | | - | - | | Config file key | `enable_statsd` | | System environment key | `APPSIGNAL_ENABLE_STATSD` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `2.2.6` | ### Description Enables the [StatsD server](/standalone-agent/statsd) in the AppSignal agent. When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 8125. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## endpoint | Field | Value | | - | - | | Config file key | `endpoint` | | System environment key | `APPSIGNAL_PUSH_API_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://push.appsignal.com` | ### Description Configure the endpoint to send data to AppSignal. This setting will not have to be changed. ## files\_world\_accessible | Field | Value | | - | - | | Config file key | `files_world_accessible` | | System environment key | `APPSIGNAL_FILES_WORLD_ACCESSIBLE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.3.4` | ### Description If this is set to `true` the [AppSignal working directory](/appsignal/how-appsignal-operates#working-directory) that is created is accessible for all users (Unix permissions `0666`). This is often necessary because processes for the same app run under a different user. Set to `false` to disable this behaviour (Unix permissions `0644`). ## filter\_parameters | Field | Value | | - | - | | Config file key | `filter_parameters` | | System environment key | `APPSIGNAL_FILTER_PARAMETERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | ### Description List of parameter keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. You can configure this with a list of keys in the configuration file. ```elixir Elixir theme={null} # config/appsignal.exs config :appsignal, :config, filter_parameters: ["password", "secret"] ``` Read more about [parameter filtering](/application/parameter-filtering). ## filter\_session\_data | Field | Value | | - | - | | Config file key | `filter_session_data` | | System environment key | `APPSIGNAL_FILTER_SESSION_DATA` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.6.0` | | |
    • `1.6.3`: An upgrade to this version or higher is recommended.
    | ### Description List of session data keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. You can configure this with a list of keys in the configuration file. ```elixir Elixir theme={null} # config/appsignal.exs config :appsignal, :config, filter_session_data: ["name", "email", "api_token", "token"] ``` Read more about [session data filtering](/application/session-data-filtering). ## host\_role | Field | Value | | - | - | | Config file key | `host_role` | | System environment key | `APPSIGNAL_HOST_ROLE` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `2.7.7` | ### Description Group hosts by role and generate metrics based on this role. One such metric is the `reporting_hosts` counter metric. A good role indicates what the main role of the server is, like "webserver", "processor", "api", "database", "loadbalancer", etc. ## hostname | Field | Value | | - | - | | Config file key | `hostname` | | System environment key | `APPSIGNAL_HOSTNAME` | | Required | no | | Type | `String` | | Default value | detected from system | | Available since version | `0.12.0` | ### Description This overrides the server's hostname. Useful for when you're unable to set a custom hostname or when a nondescript id is generated for you on hosting services. ## http\_proxy | Field | Value | | - | - | | Config file key | `http_proxy` | | System environment key | `APPSIGNAL_HTTP_PROXY` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | ### Description If you require the agent to connect to the Internet via a proxy set the complete proxy URL in this configuration key. ## ignore\_actions | Field | Value | | - | - | | Config file key | `ignore_actions` | | System environment key | `APPSIGNAL_IGNORE_ACTIONS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | ### Description With this config option you can specify a list of actions that will be ignored by AppSignal. Everything that happens including exceptions will not be transmitted to AppSignal. This can be useful to ignore health check endpoints or other actions that you don't want to monitor. Read more about [ignoring actions](/guides/filter-data/ignore-actions). ## ignore\_errors | Field | Value | | - | - | | Config file key | `ignore_errors` | | System environment key | `APPSIGNAL_IGNORE_ERRORS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | ### Description List of error classes that will be ignored. Any exception raised with this error class will not be transmitted to AppSignal. Read more about [ignoring errors](/guides/filter-data/ignore-errors). ## ignore\_logs | Field | Value | | - | - | | Config file key | `ignore_logs` | | System environment key | `APPSIGNAL_IGNORE_LOGS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `2.10.0` | ### Description List of log messages that will be ignored. Any log message containing any of the elements of the list will not be transmitted to AppSignal. A small subset of regex syntax is supported, read more about it in our [Ignore Logs](/guides/filter-data/ignore-logs) guide. ## ignore\_namespaces | Field | Value | | - | - | | Config file key | `ignore_namespaces` | | System environment key | `APPSIGNAL_IGNORE_NAMESPACES` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.3.0` | ### Description List of namespaces that will be ignored. Any error raised or slow request that occurs in this namespace will not be send to AppSignal. Read more about [namespaces](/application/namespaces). ## instrument\_absinthe | Field | Value | | - | - | | Config file key | `instrument_absinthe` | | System environment key | `APPSIGNAL_INSTRUMENT_ABSINTHE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.7.0` | ### Description Whether to automatically instrument Telemetry events for the [Absinthe package integration](/elixir/integrations/absinthe), can be `true` or `false`. ## instrument\_broadway | Field | Value | | - | - | | Config file key | `instrument_broadway` | | System environment key | `APPSIGNAL_INSTRUMENT_BROADWAY` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.18.0` | ### Description Whether to automatically instrument Telemetry events for the [Broadway package integration](/elixir/integrations/broadway), can be `true` or `false`. ## instrument\_ecto | Field | Value | | - | - | | Config file key | `instrument_ecto` | | System environment key | `APPSIGNAL_INSTRUMENT_ECTO` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.5.1` | ### Description Whether to automatically instrument Telemetry events for the [Ecto package integration](/elixir/integrations/ecto), can be `true` or `false`. ## instrument\_finch | Field | Value | | - | - | | Config file key | `instrument_finch` | | System environment key | `APPSIGNAL_INSTRUMENT_FINCH` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.5.1` | ### Description Whether to automatically instrument Telemetry events for the [Finch package integration](/elixir/integrations/finch), can be `true` or `false`. ## instrument\_oban | Field | Value | | - | - | | Config file key | `instrument_oban` | | System environment key | `APPSIGNAL_INSTRUMENT_OBAN` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.5.1` | ### Description Whether to automatically instrument Telemetry events for the [Oban package integration](/elixir/integrations/oban), can be `true` or `false`. ## instrument\_tesla | Field | Value | | - | - | | Config file key | `instrument_tesla` | | System environment key | `APPSIGNAL_INSTRUMENT_TESLA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.7.3` | ### Description Whether to automatically instrument Telemetry events for the [Tesla package integration](/elixir/integrations/tesla), can be `true` or `false`. ## log | Field | Value | | - | - | | Config file key | `log` | | System environment key | `APPSIGNAL_LOG` | | Required | no | | Type | `Atom` | | Default value | `:file` | ### Description > [!NOTE] > > This option configures what logger that AppSignal's internal logging > functionality will use and does not affect the [logging feature](/logging). > > **Note**: The [AppSignal agent](/appsignal/how-appsignal-operates), > which is used by the integration, will always write to the "appsignal.log" file. Select which logger the AppSignal integration will use. Accepted values are `file` and `stdout`. See also the `log_path` configuration. * `file` (default) * Write all AppSignal logs to the file system. * `stdout` (default on [Heroku](https://heroku.com)) * Print AppSignal logs in the parent process' STDOUT instead of to a file. Useful with hosting solutions such as container systems and Heroku. ## log\_level | Field | Value | | - | - | | Config file key | `log_level` | | System environment key | `APPSIGNAL_LOG_LEVEL` | | Required | no | | Type | `String` | | Default value | `info` | | Available since version | `2.2.8` | ### Description > [!NOTE] > > This option sets the severity level of AppSignal's internal logger and does > not affect the [logging feature](/logging). Set the severity level of AppSignal's internal logger. If it is configured to "info" it will log all error, warning and info messages, but not log the debug messages. Setting it to the levels "debug" or "trace" is usually only needed on request from support. Setting the level to "debug"/"trace" could have a slight impact on the disk usage and IO, especially on high-traffic sites. CPU overhead is minimal with the debug option enabled. Accepted values: * error * warning * info * debug * trace ## log\_path | Field | Value | | - | - | | Config file key | `log_path` | | System environment key | `APPSIGNAL_LOG_PATH` | | Required | no | | Type | `String` | | Default value | `/tmp` | | Available since version | `1.0.0` | | |
    • `1.9.0`: The default log path was changed from `/tmp/appsignal/` to `/tmp/`.
    | ### Description > [!NOTE] > > This option configures the location of AppSignal's internal logging file and > does not affect the [logging feature](/logging). > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. Override the location of the path (directory) where the `appsignal.log` file can be written to. ## logging\_endpoint | Field | Value | | - | - | | Config file key | `logging_endpoint` | | System environment key | `APPSIGNAL_LOGGING_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://appsignal-endpoint.net` | | Available since version | `2.4.0` | ### Description Configure the endpoint AppSignal sends logs and check-ins to. This setting will not have to be changed. ## nginx\_port | Field | Value | | - | - | | Config file key | `nginx_port` | | System environment key | `APPSIGNAL_NGINX_PORT` | | Required | no | | Type | `Integer` | | Default value | `27649` | | Available since version | `2.15.8` | ### Description Configure the port on which the NGINX metrics server is exposed. When AppSignal receives NGINX metrics, it listens on a `localhost`-bound server, by default on port 27649. If you're running several AppSignal-instrumented applications in the same server with NGINX metrics enabled, use this option to configure each application to listen on a different port. ## report\_oban\_errors | Field | Value | | - | - | | Config file key | `report_oban_errors` | | System environment key | `APPSIGNAL_REPORT_OBAN_ERRORS` | | Required | no | | Type | `String` | | Default value | `all` | | Available since version | `2.5.1` | ### Description When to report errors received by the [Oban package integration](/elixir/integrations/oban)'s exception event handler while processing a job. Possible values are: * `all`: Report all errors for every execution of jobs, including retries. * `discard`: Report errors when the job is discarded due to the error. Use this option to only report errors when all job retries have been exhausted. * `none`: Report no errors for jobs, including retries. ## request\_headers | Field | Value | | - | - | | Config file key | `request_headers` | | System environment key | `APPSIGNAL_REQUEST_HEADERS` | | Required | no | | Type | `list(String)` | | Default value | `["accept", "accept-charset", "accept-encoding", "accept-language", "cache-control", "connection", "content-length", "range"]` | | Available since version | `1.6.0` | | |
    • `1.6.3`: An upgrade to this version or higher is recommended.
    | ### Description The `request_headers` config option contains a list of HTTP request headers which are read and stored by the AppSignal Elixir package. This `request_headers` config option is an *allowlist*, which means that it will only report headers as specified by this config option. If this config option is unset it will use the AppSignal default. Following list is the AppSignal package default. ```elixir Elixir theme={null} # config/appsignal.exs config :appsignal, :config, request_headers: ~w( accept accept-charset accept-encoding accept-language cache-control connection content-length range ) ``` To configure AppSignal to not store any HTTP request headers on AppSignal transactions, configure the option with an empty list. ```elixir Elixir theme={null} # config/appsignal.exs config :appsignal, :config, request_headers: [] ``` ## revision | Field | Value | | - | - | | Config file key | `revision` | | System environment key | `APP_REVISION` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `1.5.0` | | |
    • `1.10.12`: Auto detection for Heroku deploys with the Dyno Metadata labs feature enabled.
    • `2.7.6`: Auto detection for Render deploys.
    • `2.10.2`: Auto detection for Kamal deploys.
    • `2.13.1`: Auto detection for Scalingo deploys.
    • `2.18.2`: Reads the `HEROKU_BUILD_COMMIT` environment variable.
    | ### Description Set the app revision to report the currently running version of your app. AppSignal will create a deploy marker when this value changes, and tag all incoming data with the current revision. The AppSignal integration automatically detects the deployed Git commit and uses it as the revision when you deploy using the following tools or providers: * Kamal * Render * Scalingo * Heroku, when the [Heroku Labs: Dyno Metadata](https://devcenter.heroku.com/articles/dyno-metadata) feature is enabled Set the `revision` config option to override the detected revision. Use a single value without spaces, such as a Git commit SHA (`abc0123`) or a version number (`1.2.3`). AppSignal builds links to your source code from this value. Read more about [choosing a revision value](/application/markers/deploy-markers#choosing-a-revision-value). Read more about deploy markers in the [deploy markers topic](/application/markers/deploy-markers). When more than one source sets the revision, the Ruby gem uses the first one in this list that is set: 1. The `revision` config option or the `APP_REVISION` environment variable. 2. The environment variable set by Heroku (`HEROKU_BUILD_COMMIT` or `HEROKU_SLUG_COMMIT`), Render (`RENDER_GIT_COMMIT`), Kamal (`KAMAL_VERSION`), or Scalingo (`CONTAINER_VERSION`), in that order. 3. The `REVISION` file in the application's root directory. ## running\_in\_container | Field | Value | | - | - | | Config file key | `running_in_container` | | System environment key | `APPSIGNAL_RUNNING_IN_CONTAINER` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | detected by agent | ### Description AppSignal expects to be running on the same machine between different deploys. Set this key to `true` if the application is running in a container, such as with Docker. Newer versions of the AppSignal integration automatically detect its container environment, so no manual configuration is necessary. If you're having trouble with the automatic detection, please [contact support](mailto:support@appsignal.com). This option is set to `true` automatically on [Heroku](http://heroku.com/). ## send\_environment\_metadata | Field | Value | | - | - | | Config file key | `send_environment_metadata` | | System environment key | `APPSIGNAL_SEND_ENVIRONMENT_METADATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.2.8` | ### Description Send environment metadata about the app. For more information please read about [environment metadata](/application/environment-metadata). ## send\_params | Field | Value | | - | - | | Config file key | `send_params` | | System environment key | `APPSIGNAL_SEND_PARAMS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.10.0` | ### Description Whether to skip sending request parameters to AppSignal. For more information please read about [send\_params](/application/parameter-filtering) in filtering request parameters. ## send\_session\_data | Field | Value | | - | - | | Config file key | `send_session_data` | | System environment key | `APPSIGNAL_SEND_SESSION_DATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.2.10` | ### Description Set this option to `false` to not send any session data with exception and performance traces. For more information please read about [request session data filtering](/application/session-data-filtering). ## skip\_session\_data | Field | Value | | - | - | | Config file key | `skip_session_data` | | System environment key | `APPSIGNAL_SKIP_SESSION_DATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | ### Description > [!WARNING] > > **Warning**: This config option is deprecated in the Elixir package 2.2.10. > Please use the [`send_session_data`](#option-send_session_data) option instead > for newer versions of the Elixir package. ## statsd\_port | Field | Value | | - | - | | Config file key | `statsd_port` | | System environment key | `APPSIGNAL_STATSD_PORT` | | Required | no | | Type | `Integer` | | Default value | `8125` | | Available since version | `2.7.2` | ### Description Set this option to configure the StatsD HTTP server port of the AppSignal agent process. Configure this port if another process is already running on the machine that is also using this port to avoid conflicts. ## transaction\_debug\_mode | Field | Value | | - | - | | Config file key | `transaction_debug_mode` | | System environment key | `APPSIGNAL_TRANSACTION_DEBUG_MODE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `1.11.4` | | |
    • `2.2.9`: Deprecated in favor of the [`log_level` config option](#option-log_level).
    | ### Description > [!WARNING] > > **Warning**: This config option is deprecated in Elixir package 2.2.9. Please > use the [`log_level`](#option-log_level) option instead for Elixir package > 2.2.9 and newer. Enable transaction debug mode. This enables very detailed logging of transactions and events which is useful when developing integrations or when events aren not tracked as expected. The log is only written if the general `debug` option is on as well. > [!NOTE] > > This option sets the severity level of AppSignal's internal logger and does > not affect the [logging feature](/logging). ## working\_dir\_path | Field | Value | | - | - | | Config file key | `working_dir_path` | | System environment key | `APPSIGNAL_WORKING_DIR_PATH` | | Required | no | | Type | `String` | | Default value | detected by agent | | Available since version | `1.8.0` | ### Description > [!WARNING] > > **Warning**: This config option is deprecated in Elixir package 1.8.0. Please > use the [`working_directory_path`](#option-working_directory_path) option > instead for Elixir package 1.8.0 and newer. Override the location where AppSignal for Elixir can store temporary files. Use this option if the default location is not suitable. See our [how AppSignal operates](/appsignal/how-appsignal-operates) page for more information about the purpose of this working directory. If you are running multiple applications using AppSignal on the same server, use this configuration option to select different working directories for every AppSignal instance, otherwise the two instances could conflict with one another. For more information on this scenario see our [running multiple applications on one host](/guides/application/multiple-applications-on-one-host) documentation. ```elixir Elixir theme={null} # config/config.exs config :appsignal, :config, working_dir_path: "/tmp/project_1/" ``` > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. ## working\_directory\_path | Field | Value | | - | - | | Config file key | `working_directory_path` | | System environment key | `APPSIGNAL_WORKING_DIRECTORY_PATH` | | Required | no | | Type | `String` | | Default value | detected by agent | | Available since version | `1.8.0` | | |
    • `1.8.0`: Renamed from [`working_dir_path`](#option-working_dir_path).
    | ### Description Override the location where AppSignal for Elixir can store temporary files. Use this option if the default location is not suitable. See our [how AppSignal operates](/appsignal/how-appsignal-operates) page for more information about the purpose of this working directory. If you are running multiple applications using AppSignal on the same server, use this configuration option to select different working directories for every AppSignal instance, otherwise the two instances could conflict with one another. For more information on this scenario see our [running multiple applications on one host](/guides/application/multiple-applications-on-one-host) documentation. ```elixir Elixir theme={null} # config/appsignal.exs config :appsignal, :config, working_directory_path: "/tmp/project_1/" ``` > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. # Session data filtering Source: https://docs.appsignal.com/elixir/configuration/session-data-filtering In most apps, at least some of the data that is sent to the application is sensitive or personally identifiable information that should not leave the network. To prevent AppSignal from storing this data the Elixir package should be configured to not send this data at all or filter out specific values. In web applications sessions can be used to store user preferences and other sensitive data without it having to be persisted in the database or sent using [parameters](/application/parameter-filtering). In Phoenix applications AppSignal automatically stores the contents of the user's session on the AppSignal transaction. This can be disabled or specific values can be filtered out. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). > [!TIP] > > This feature is available since AppSignal Elixir package [version > 1.6.0](https://blog.appsignal.com/2018/05/08/elixir-integration-1-6.html). ## AppSignal session data filtering Session data filtering will filter out any values from specified keys in the [`filter_session_data`](/elixir/configuration/options#option-filter_session_data) configuration option. Any filtered out value will be replaced with `[FILTERED]` before it leaves your application and is sent to the AppSignal servers. This means that AppSignal never receives any of the filtered data. In the session data filtering, there's support for nested hashes and nested hashes in arrays. Any hash we encounter in your session data will be filtered. To use this filtering, add the following to your `config/appsignal.exs` file in the environment group you want it to apply. The [`filter_session_data`](/elixir/configuration/options#option-filter_session_data) value is an Array of Strings. ```elixir Elixir theme={null} # config/appsignal.exs config :appsignal, :config, filter_session_data: ["name", "email", "api_token", "token"] ``` ## Send session data > [!WARNING] > > **Warning**: The `skip_session_data` option is deprecated since AppSignal > Elixir package 2.2.10. Set [`send_session_data`](/elixir/configuration/options#option-send_session_data) option to `false` instead to not send any session data with exception and performance traces. For more information please read about [request session data filtering](/application/session-data-filtering). ```elixir Elixir theme={null} # config/appsignal.exs # Session data is sent by default. Set this to false to stop sending it config :appsignal, :config, send_session_data: true ``` # Installing AppSignal for Elixir Source: https://docs.appsignal.com/elixir/installation Install the AppSignal package in an Elixir application, configure it, and add optional Phoenix, Plug, and custom instrumentation. Please follow the [installation guide](/guides/new-application) first, when adding a new application to AppSignal. ## Requirements Before you can compile the AppSignal package, make sure the build/compilation tools are installed for your system. Please check the [Supported Operating Systems](/support/operating-systems) page for any system dependencies that may be required. ## Installation Installing the AppSignal package in your Elixir application requires a couple of manual steps. Currently, AppSignal support Phoenix, Plug and pure Elixir apps. If AppSignal does not support your use-case or if you find a problem with the documentation, don't hesitate to [contact us][support]. You can also create a pull-request on our public [Elixir repository][elixir-repo]. ### Installing the package > [!NOTE] > > 📖 **Note**: If you're running an umbrella application, see also our [umbrella > installation guide](/elixir/installation/umbrella). > [!TIP] > > **Note**: If you use the \[Phoenix framework]\[phoenix] or \[Plug]\[plug], > continue with the [integrating AppSignal into > Phoenix](/elixir/integrations/phoenix) or [integrating AppSignal into > Plug](/elixir/integrations/plug) guides. 1. Start by adding `appsignal` to your list of dependencies in `mix.exs`. ```elixir Elixir theme={null} # mix.exs def deps do [ {:appsignal, "~> 2.8"} ] end ``` 2. Then run `mix deps.get`. 3. Then run `mix appsignal.install YOUR_PUSH_API_KEY` or follow the [manual configuration guide](#configuration). After the installation is complete, start your application. When the AppSignal OTP application starts, it looks for a valid configuration (e.g. an AppSignal Push API key), and start the AppSignal agent. If it can't find a valid configuration, a warning will be logged. See the [Configuration](#configuration) section on how to fully configure the AppSignal agent. ### Configuration Before the AppSignal package works you need to configure it. To be able to send data to AppSignal you first need to [create an account on AppSignal.com](https://appsignal.com/users/sign_up). Or, if you already have an account, click on the "add app" button on [AppSignal.com/accounts](https://appsignal.com/accounts). During the installation process you can run the `mix appsignal.install` command with the hexadecimal [Push API key](/appsignal/terminology#push-api-key) or manually configure AppSignal using the guide below. For more information about configuring the AppSignal package for Elixir, please read our [configuration documentation](/elixir/configuration). #### Manual configuration If you want to manually configure AppSignal you will need to place the AppSignal Push API key you receive in the installation process in your application's `config/config.exs` configuration file. Using the AppSignal configuration you are also able to configure an application name and environment and more. ```elixir Elixir theme={null} # config/config.exs config :appsignal, :config, otp_app: :appsignal_phoenix_example, name: "AppsignalPhoenixExample", push_api_key: "your-push-api-key", env: Mix.env, active: true ``` Alternatively, you can configure AppSignal using OS environment variables. ```sh Shell theme={null} export APPSIGNAL_OTP_APP="appsignal_phoenix_example" export APPSIGNAL_PUSH_API_KEY="your-push-api-key" export APPSIGNAL_APP_NAME="AppsignalPhoenixExample" export APPSIGNAL_APP_ENV="prod" ``` For more information about configuring the AppSignal package for Elixir, please read our [configuration options page](/elixir/configuration). ### Run your application! Once you've completed this guide your application is ready to be monitored by AppSignal! Start your application up and perform some requests on it. By triggering an error or two you'll also test the error reporting. [Contact us][support] if you have questions regarding installation or encountered any problems during the installation. ### Optional: Add Phoenix instrumentation Read more about how you can integrate more instrumentation in your Phoenix application in our [integrating Phoenix guide](/elixir/integrations/phoenix). ### Optional: Add Plug instrumentation Read more about how you can integrate more instrumentation in your Plug application in our [integrating Plug guide](/elixir/integrations/plug). ### Optional: Add custom instrumentation Add custom instrumentation to your application to get a more in-depth view of what's happening in your application. Read more about custom instrumentation in our [instrumentation documentation](/elixir/instrumentation). ## Upgrading New releases include bug and security fixes, so keep AppSignal up to date. To update to the latest version your `mix.exs` allows, run `mix deps.update appsignal` and redeploy. *** > [!NOTE] > > 📖 Continue with our [installation guide](/guides/new-application). ## Uninstall Uninstall AppSignal from your app by following the steps below. When these steps are completed your app will no longer send data to the AppSignal servers. 1. In the `mix.exs` of your app, delete the `{:appsignal, "~> 2.0"}` line. 2. Run `mix deps.get` to update your `mix.lock` with the removed packages state. 3. Remove any AppSignal [configuration files](/elixir/configuration/) from your app. * Configuration file location: `config/appsignal.exs` * And its references in any other files in `config/*.exs` 4. Remove any system environment variables from your development, staging, production, etc. hosts. * Environment variables prefixed with `APPSIGNAL_` * Environment variable [`APP_REVISION`](/elixir/configuration/options#option-revision) 5. Commit, deploy and restart your app. * This will make sure the AppSignal servers won't continue to receive data from your app. 6. Optional: Make sure no `appsignal-agent` processes are running in the background. * Check the output of `ps aux | grep appsignal-agent` and kill the processes still running. 7. Finally, [remove the app](/guides/application/deleting-applications) on AppSignal.com. > [!NOTE] > > 📖 Continue with our [uninstall > guide](/guides/application/deleting-applications). [support]: mailto:support@appsignal.com [elixir-repo]: https://github.com/appsignal/appsignal-elixir [phoenix]: http://www.phoenixframework.org/ [plug]: https://github.com/elixir-plug/plug # Installing AppSignal in an umbrella application Source: https://docs.appsignal.com/elixir/installation/umbrella AppSignal works with umbrella applications, but there are some things to keep in mind. The dependency should be added to each nested application inside the umbrella, and the configuration should be added to the umbrella's main configuration file. This guide goes over the first steps to install AppSignal in your umbrella Elixir and Phoenix projects. For more information and further steps, check out the [main installation guide](/elixir/installation). ## Installation Add the AppSignal dependency to each application that will use it. This includes all Phoenix applications and all backend applications that communicate with the database. ```elixir Elixir theme={null} defp deps do [ {:appsignal, "~> 2.0"} ] end ``` Then, run AppSignal’s installer in the umbrella’s root directory to add the configuration to the umbrella application’s configuration files. ```sh Shell theme={null} $ mix appsignal.install YOUR_PUSH_API_KEY ``` By default, each nested application in an umbrella uses the main umbrella configuration, so the nested apps should all have access to the main configuration. ## Phoenix The installation for Phoenix in an umbrella application are mostly the same as [setting up AppSignal “regular” Phoenix application](/elixir/integrations/phoenix). One thing to keep in mind is to `use Appsignal.Phoenix` in your application’s endpoint file. If you have multiple nested Phoenix applications, use the module in each. > [!TIP] > > If you include `use Plug.Builder` or any other module that redefines the > `call/2` function, make sure to place the `use Appsignal.Phoenix` line after > that. ```elixir Elixir theme={null} defmodule AppsignalPhoenixExampleWeb.Endpoint do use Phoenix.Endpoint, otp_app: :appsignal_phoenix_example use Appsignal.Phoenix # ... end ``` # Custom instrumentation for Elixir Source: https://docs.appsignal.com/elixir/instrumentation Overview of custom instrumentation for Elixir, including manual integration, spans, exception handling, and minutely probes. AppSignal provides many ways to bring more insights in your application by adding more instrumentation or tagging the data that appears in the UI at AppSignal.com. * [Integrating AppSignal](/elixir/instrumentation/integrating-appsignal) * [Instrumentation](/elixir/instrumentation/instrumentation) * [Exception handling](/elixir/instrumentation/exception-handling) * [Minutely probes](/elixir/instrumentation/minutely-probes) * [Mix tasks](/elixir/instrumentation/mix_tasks) * [Command line tool](/elixir/command-line) ## Contact us Don't hesitate to [contact us](mailto:support@appsignal.com) if you run into any issues while implementing custom instrumentation. We're here to help. # Exception handling Source: https://docs.appsignal.com/elixir/instrumentation/exception-handling In most applications some errors will get raised that aren't related to possible bugs in your code, they just happen when your app gets into contact with the real world. Bots might drop by and try to automatically post forms, outdated links might direct visitors to content that doesn't exist anymore and so on. To avoid these errors from being raised as problems in AppSignal it's possible to add exception handling to your code or even let AppSignal completely ignore certain errors. ## Ignore errors The AppSignal configuration makes it possible to [ignore errors](/guides/filter-data/ignore-errors). By providing a list of specific errors AppSignal will not send alerts when these errors are raised. ## Appsignal.set\_error/3 If you want to rescue exceptions in your application to prevent crashes, but still want to track the occurrence you can use [`Appsignal.set_error/2`][hexdocs-set_error-2] to add the exception to the current AppSignal transaction: ```elixir Elixir theme={null} try do raise "Exception!" rescue exception -> Appsignal.set_error(exception, __STACKTRACE__) end ``` ### Erlang The AppSignal integration tries its best to convert errors raised from Erlang to Elixir exceptions. For example, a `:badarg` raised from Erlang is automatically converted to an `ArgumentError`. However, sometimes the best it can do is wrapping the error originating from Erlang in an `ErlangError`. Since these don’t give much insight into the underlying issue, we recommend adding information from within your application by catching the error, creating an Elixir exception yourself and adding that to the current span using the `set_error/2` function. > [!WARNING] > > **NOTE:** `Appsignal.set_error/2` was added in AppSignal for Elixir 2.1.0. If > you're on a lower version, use `Appsignal.set_error/3` instead. On versions before 2.1.0, use `catch` and `Appsignal.send_error/3`: ```elixir Elixir theme={null} try do raise "Exception!" catch kind, reason -> Appsignal.set_error(kind, reason, __STACKTRACE__) end ``` The exception will be tracked by AppSignal like any other error, and it allows you to provide custom error handling and fallbacks. If you do not have an error object when calling `send_error`, but still want to report the scenario as an error, it's also possible to initialize a custom error struct. ```elixir Elixir theme={null} defmodule MyCustomError do defexception message: "default message" # Customize if you call it without a custom message end case Worker.do_something() do :ok -> IO.puts "yay!" {:error, message} -> Appsignal.set_error(:error, %MyCustomError{ message: message }, []) end ``` **Note:** This function only works when there is an AppSignal transaction active. Otherwise the error will be ignored. Please see [`Appsignal.send_error/3`](#appsignal-send_error/3) for sending errors without an AppSignal transaction. ## Appsignal.send\_error/3 AppSignal provides a mechanism to track errors that occur in code that's not in a web or background job context, such as Mix tasks. This is useful for instrumentation that doesn't automatically create AppSignal transactions to profile. You can use the [`Appsignal.send_error/3`][hexdocs-send_error] function to directly send an exception to AppSignal from any place in your code without starting an AppSignal transaction first. ```elixir Elixir theme={null} try do raise "Exception!" catch kind, reason -> Appsignal.send_error(kind, reason, __STACKTRACE__) end ``` If you do not have an error object when calling `send_error`, but still want to report the scenario as an error, it's also possible to initialize a custom error struct. ```elixir Elixir theme={null} defmodule MyCustomError do defexception message: "default message" # Customize if you call it without a custom message end case Worker.do_something() do :ok -> IO.puts "yay!" {:error, message} -> Appsignal.send_error(:error, %MyCustomError{ message: message }, []) end ``` ### Additional metadata To add metadata to the sent error, pass a function as the fourth argument to `Appsignal.send_errror/4`: ```elixir Elixir theme={null} try do raise "Exception!" catch kind, reason -> Appsignal.send_error(kind, reason, __STACKTRACE__, fn span -> Appsignal.Span.set_attribute(span, "key", "value") end) end ``` > [!WARNING] > > **NOTE:** `Appsignal.send_error/4` was added in AppSignal for Elixir 2.1.0. [hexdocs-set_error-2]: https://hexdocs.pm/appsignal/Appsignal.Instrumentation.html#set_error/2 [hexdocs-send_error]: https://hexdocs.pm/appsignal/Appsignal.Instrumentation.html#send_error/3 # Custom instrumentation for Elixir Source: https://docs.appsignal.com/elixir/instrumentation/instrumentation Add spans to Elixir traces with Appsignal.instrument and function decorators, start new traces, set namespaces, and instrument Phoenix channels. In order to find out what specific pieces of code are causing performance problems it's useful to add custom instrumentation to your application. This allows us to create better breakdowns of which code runs slowest and what type of action the most amount of time was spent on. Custom instrumentation is possible in two ways: using function decorators and instrumentation helper functions. The function decorators are easiest to use, but are less flexible than the instrumentation helper functions. This short guide will help you set up custom instrumentation. More details on the usage of certain helpers can be found in the Hex docs for the [AppSignal package](https://hexdocs.pm/appsignal/). > [!TIP] > > **Note**: Make sure you've [integrated > AppSignal](/elixir/instrumentation/integrating-appsignal) before adding > custom instrumentation to your application if it's not automatically > integrated by one of our supported [integrations](/elixir/integrations). > [!TIP] > > **Note**: This page only describes how to add performance instrumentation to > your code. To track errors please read our [exception > handling](/elixir/instrumentation/exception-handling) guide. ## `Appsignal.instrument/2-3` The `instrument/2` function is used to add instrumentation by wrapping a piece of code in a span. A span eventually becomes a trace, or an event in another span's trace in AppSignal. ### Add spans to traces In the following example we have a Phoenix controller with an `index/2` function which calls a slow function. The `slow` function is instrumented using the `Appsignal.instrument/2` function which records it as a separate event in this Phoenix request. It will show up on AppSignal.com in the event timeline of this trace to provide more insight in where the most time was spent during the request. ```elixir Elixir theme={null} defmodule AppsignalPhoenixExampleWeb.PageController do use AppsignalPhoenixExampleWeb, :controller def index(conn, _params) do slow() render(conn, "index.html") end defp slow do Appsignal.instrument("slow", fn -> :timer.sleep(1000) end) end end ``` Here, we wrap our function's contents with a call to `Appsignal.instrument3`, and we pass `"slow"` as the name for the event. ### Starting new traces In the Phoenix example an AppSignal trace has already been started, thanks to the first-party support for Phoenix in the AppSignal package. Not all frameworks and packages are currently supported directly and automatically start traces. The same is true for your own pure Elixir applications. Like when adding spans to already-instrumented traces, a new root span is created using the `Appsignal.instrument/2` function: ```elixir Elixir theme={null} defmodule AppsignalElixirExample do def example_fn do Appsignal.instrument("instrument", fn -> :timer.sleep(500) end) end end ``` This example creates a trace named "instrument" in the "background" namespace in AppSignal. The name will also be used as the category name for the main span. To use a different category name, use `instrument/3` instead: ```elixir Elixir theme={null} defmodule AppsignalElixirExample do def example_fn do Appsignal.instrument("instrument", "call.instrument", fn -> :timer.sleep(500) end) end end ``` When passing a function that takes an argument, the `instrument/2-3` function calls it with the opened span to allow further customization. See the docs on hex.pm for [all available Span functions](https://hexdocs.pm/appsignal/Appsignal.Span.html). ```elixir Elixir theme={null} defmodule AppsignalElixirExample do def example_fn do Appsignal.instrument("Build complicated SQL query", "prepare_query.sql", fn span -> # Example of building a complex SQL query in the instrument block and performing it query = "SOME complicate SQL query" # The body is only set here because it's the value being calculated and instrumented in this function Appsignal.Span.set_sql(span, query) Database.perform_query(query) end) end end ``` ### Exception handling To report errors using custom instrumentation please read more in our [exception handling guide](/elixir/instrumentation/exception-handling). ## Function decorators Using the `Appsignal.Instrumentation.Decorators` decorator module, it's possible add custom instrumentation to your Elixir applications without changing the functions' contents. ### Transaction events In the following example we have a Phoenix controller with an `index/2` function which calls a slow function. The `slow` function is instrumented using the AppSignal `transaction_event` decorator which records it as a separate event in this Phoenix request. It will show up on AppSignal.com in the event timeline of this transaction trace to provide more insight in where the most time was spent during the request. ```elixir Elixir theme={null} # Phoenix controller example defmodule PhoenixExample.PageController do use PhoenixExample.Web, :controller # Include this use Appsignal.Instrumentation.Decorators def index(conn, _params) do slow() render conn, "index.html" end # Decorate this function to add custom instrumentation @decorate transaction_event() defp slow do :timer.sleep(1000) end end ``` If you want to group certain events together under the same event group (other group are `phoenix_controller`, `phoenix_render`, `ecto`, etc.) you can also supply a group name to the `transaction_event` decorator. ```elixir Elixir theme={null} @decorate transaction_event("github_api") defp get_data_from_github do # Third-party API call end ``` This will create an event `get_data_from_github.github_api` in the event timeline. For more information on how event names are used, please read our [event naming guidelines](/api/event-names). ### Transactions In the Phoenix example an AppSignal transaction has already been started, thanks to the first-party support for Phoenix in the AppSignal package. Not all frameworks and packages are currently supported directly and automatically start transactions. The same is true for your own pure Elixir applications. In order to track `transaction_event` decorators we will need to start an AppSignal transaction beforehand. We can start a transaction with the `transaction` function decorator. ```elixir Elixir theme={null} # Pure Elixir example defmodule FunctionDecoratorsExample do # Include this use Appsignal.Instrumentation.Decorators # No transaction is started beforehand like in Phoenix, so we need to start # it ourselves. @decorate transaction() def call do slow() # ... end # Decorate this function to add custom instrumentation @decorate transaction_event() defp slow do :timer.sleep(1000) end end ``` **Note**: When using pure Elixir applications, make sure that the AppSignal application is started before you start a transaction. For more information, see how to [integrate AppSignal](/elixir/instrumentation/integrating-appsignal). ### Namespaces In order to differentiate between HTTP requests and background jobs we can pass a namespace to the transaction once we start it. The following two namespaces are official namespaces supported by AppSignal. * `http_request` - the default - is called the "web" namespace * `background_job` - creates the "background" namespace ```elixir Elixir theme={null} defmodule FunctionDecoratorsExample do # Include this use Appsignal.Instrumentation.Decorators # No namespace argument defaults to `:http_request` @decorate transaction() def web_function do # do stuff end # The "background" namespace @decorate transaction(:background_job) def background_function do # do stuff end end ``` For more information about what namespaces are, please see our [namespaces](/application/namespaces) documentation. ### Custom namespaces You can also create your own namespaces to track transactions in a separate part of your application such as an administration panel. This will group all the transactions with this namespace in a separate section on AppSignal.com so that slow admin controllers don't interfere with the averages of your application's speed. ```elixir Elixir theme={null} @decorate transaction(:admin) def some_function do # do stuff end ``` ### Phoenix channels There is a custom function decorator for Phoenix channels. This decorator is meant to be put before the `handle_in/3` function of a `Phoenix.Channel` module. ```elixir Elixir theme={null} defmodule FunctionDecoratorsExample.MyChannel do # Include this use Appsignal.Instrumentation.Decorators # Add this channel function decorator @decorate channel_action() def handle_in("ping", _payload, socket) do # your code here.. end end ``` Channel events will be displayed under the "background" namespace, showing the channel module and the action argument that it's used on. ## Manually creating and closing spans In some cases it can be useful to manually handle spans. You can use the span API to instrument tasks for example: ```elixir Elixir theme={null} def index(conn, _params) do current = Appsignal.Tracer.current_span() fn -> span = "http_request" |> Appsignal.Tracer.create_span(current) |> Appsignal.Span.set_name("name") |> Appsignal.Span.set_attribute("appsignal:category", "category") :timer.sleep(1000) Appsignal.Tracer.close_span(span) end |> Task.async() |> Task.await() render(conn, "index.html") end ``` # Integrating AppSignal in Elixir Source: https://docs.appsignal.com/elixir/instrumentation/integrating-appsignal It's possible that AppSignal does not provide automatic integration for your framework of choice, or maybe you're using your own application setup. When AppSignal does not support something out-of-the-box it's still possible to instrument applications. AppSignal needs to be configured and started once at the beginning of a process. It can be [configured](/elixir/configuration) through Mix configuration or by using environment variables. ## Configuration The AppSignal for Elixir package needs to be configured before it can send data to AppSignal.com. There are two methods of configuration. Using the mix configuration and using environment variables. See the [configuration pages](/elixir/configuration) for the full configuration guide. ## Starting AppSignal In order for AppSignal to instrument your application the AppSignal process must be started in the Erlang BEAM VM. Make sure to put this line in a location that is always run in your application. ```elixir Elixir theme={null} {:ok, _} = Application.ensure_all_started(:appsignal) ``` **Note**: This is not required for frameworks that AppSignal integrates with, such as Phoenix, but it is for pure Elixir applications and code outside these integrations, such as independent tasks or background jobs. ## Add custom instrumentation Continue with our guide to [add custom instrumentation](/elixir/instrumentation/instrumentation) to your application. # Minutely probes Source: https://docs.appsignal.com/elixir/instrumentation/minutely-probes Minutely probes are a mechanism to periodically send [custom metrics](/metrics/custom) to AppSignal. This is a system that is included in the AppSignal Elixir package by default. At the start of every minute the minutely probes are triggered to collect metrics and then snoozed until the next minute. By default the AppSignal Elixir package enables a probe for the ErlangVM. > [!TIP] > > **Note**: We recommend using AppSignal Elixir package `1.10.1` and up when > using this feature. ## Usage The minutely probes allow the AppSignal Elixir package to collect [custom metrics](/metrics/custom) by default for the ErlangVM and app-specific metrics by [creating your own probe](#creating-probes). ### Multiple instances Once activated, the minutely probes system runs on every instance of an app. This means that if a probe report metrics without some kind of differentiating tag, global metrics may be overwritten by instance-level metrics. To remedy this, we suggest [tagging](/metrics/custom#metric-tags) your metrics with the hostname or something else unique for each instance. For example, the ErlangVM Probe tags metrics with the hostname by default. Alternatively you can [disable minutely probes](/elixir/configuration/options#option-enable_minutely_probes) for all but one instance, on which the minutely probes process is run. We suggest using the [`APPSIGNAL_ENABLE_MINUTELY_PROBES`](/elixir/configuration/options#option-enable_minutely_probes) environment variable to only enable it on the instance of your choosing. ## Configuration The minutely probes are configured using the [`enable_minutely_probes`](/elixir/configuration/options#option-enable_minutely_probes) config option. The default value is `true`. ## Creating probes If you want to track more [custom metrics](/metrics/custom) from your app than our default probes do, you can add your own probe(s). An AppSignal minutely probe can be an [Anonymous function](#anonymous-function), or a [Module based function](#module-based-function). ### Anonymous function The simplest probe type to register. If you have no dependencies for your probe this is the preferred method. ```elixir Elixir theme={null} Appsignal.Probes.register(:my_probe, fn -> Appsignal.set_gauge("database_size", 10) end) ``` ### Module based function A module based function can be useful if you have a more complex probe, or a probe that has dependencies. ```elixir Elixir theme={null} # lib/my_app/probes/my_probe.ex defmodule MyApp.MyProbe do def call do Appsignal.set_gauge("database_size", 10) end end ``` Now you can register this probe in the start function of your OTP app. ```elixir Elixir theme={null} Appsignal.Probes.register(:my_probe, &MyApp.MyProbe.call/0) ``` ### Stateful probes As of version `2.2.8` of the AppSignal Elixir package, probes can pass state between runs. If your probe takes an argument, the return value of the last run will be passed as the value for that argument in the following run. An initial state to be used for the probe's first run can be provided as the third argument to `Appsignal.Probes.register`. If it is not provided, the initial state will be `nil`. ```elixir Elixir theme={null} Appsignal.Probes.register(:stateful_probe, fn minutes -> Appsignal.set_gauge("uptime_minutes", minutes) minutes + 1 end, 0) ``` Or, as a module based function: ```elixir Elixir theme={null} # lib/my_app/probes/my_probe.ex defmodule MyApp.MyProbe do def call(minutes) do Appsignal.set_gauge("uptime_minutes", minutes) minutes + 1 end end ``` Which you can then register as: ```elixir Elixir theme={null} Appsignal.Probes.register(:stateful_probe, &MyApp.MyProbe.call/1, 0) ``` ## Registering probes Probes can be registered with the `register` method on the `Appsignal.Probes` module. This method accepts three arguments. * `key` - This is the key/name of the probe. This will be used to identify the probe in case an error occurs while executing the probe (which will be logged to the [appsignal.log file](/support/debugging#logs)) and to [override an existing probe](#overriding-default-probes). * `probe` - This is one of the [supported probe types](#creating-probes) that should be called every minute to collect metrics. * `state` - This is the initial state that will be passed to your probe. If your probe does not take state as an argument, then this argument has no effect. It is an optional argument, and its default value is `nil`. To add a probe, register it in your application's `start/2` function, just before the supervisor is started. In a Phoenix app this will look like this: ```elixir Elixir theme={null} # lib/my_app/application.ex def start(_type, _args) do children = [ MyApp.Repo, MyAppWeb.Endpoint, ] Appsignal.Probes.register(:my_probe, &MyProbe.call/0) opts = [strategy: :one_for_one, name: Weekmenu.Supervisor] Supervisor.start_link(children, opts) end ``` ## Overriding default probes AppSignal ships with default probes for certain [integrations](/elixir/integrations/). If for any reason this probe does not function properly or requires some additional configuration for your use case, you can override the default probe by registering a new probe with the same key. ```elixir Elixir theme={null} # lib/my_app/application.ex Appsignal.Probes.register(:erlang, fn() -> # Do things end) ``` Overriding probes will log a debug message in the [appsignal.log file](/support/debugging#logs) which can help to detect if a probe is correctly overridden. ## Unregister probes To remove a previously registered probe, including a default probe, use the `unregister` method on the `Appsignal.Probes` module. Call it with the key of the probe you want to remove. ```elixir Elixir theme={null} Appsignal.Probes.unregister(:my_probe) ``` The AppSignal Elixir package registers the default ErlangVM probe under the `:erlang` key. To disable it, unregister the `:erlang` probe in your application's `start/2` function, just before the supervisor is started: ```elixir Elixir theme={null} # lib/my_app/application.ex def start(_type, _args) do children = [ MyApp.Repo, MyAppWeb.Endpoint, ] Appsignal.Probes.unregister(:erlang) opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end ``` # Mix tasks Source: https://docs.appsignal.com/elixir/instrumentation/mix_tasks AppSignal for Elixir doesn't automatically instrument mix tasks, but you can set up manual instrumentation and error handling using [custom instrumentation](/elixir/instrumentation/). ## Starting and stopping AppSignal Since Mix tasks don't automatically start applications, you'll need to explicitly start the `:appsignal` application in your task: ```elixir Elixir theme={null} Application.ensure_all_started(:appsignal) ``` To make sure AppSignal has enough time to flush data to its agent, call `Appsignal.Nif.stop/0` at the end of your task, which blocks until the extension has had enough time to flush the sent payloads to the agent before stopping. ## Catching errors To wrap errors in your task to be sent to AppSignal, add a `rescue` block to catch errors from your code. Pass the captured exception to `Appsignal.send_error/3` to report it to AppSignal. Add an `after` clause to your `rescue` block to call `Appsignal.Nif.stop/0`. ```elixir Elixir theme={null} defmodule Mix.Tasks.Rescue do use Mix.Task def run(_) do {:ok, _} = Application.ensure_all_started(:appsignal) raise "rescue!" catch kind, reason -> stack = __STACKTRACE__ Appsignal.send_error(kind, reason, stack) reraise(reason, stack) after Appsignal.Nif.stop :timer.sleep(35_000) # For one-off containers end end ``` **Note:** A sleep of 35 seconds was added to the end of the Mix task. This is recommended for tasks that are run on one-off containers. When the task completes the process stops. The `Appsignal.Nif.stop/0` function call flushes all the transaction data currently in the AppSignal extension to our agent. There it is [transmitted on a 30 second interval](/appsignal/how-appsignal-operates#agent). The one-off container may have exited before that time. To ensure the data is still transmitted, it needs to wait for 35 seconds. ## Measuring performance To measure performance in your task, start and stop a transaction manually and add events using the instrumentation helpers, like described in the [custom helper instrumentation](/elixir/instrumentation/instrumentation#starting-new-traces). ```elixir Elixir theme={null} defmodule Mix.Tasks.Instrument do use Mix.Task def run(_) do {:ok, _} = Application.ensure_all_started(:appsignal) Appsignal.instrument(fn span -> span |> Appsignal.Span.set_namespace("background_job") |> Appsignal.Span.set_name("Mix.Tasks.Instrument") Appsignal.instrument(fn span -> Appsignal.Span.set_name("task.instrumented") :timer.sleep(1_000) end) end) Appsignal.Nif.stop() :timer.sleep(35_000) # For one-off containers end end ``` # Elixir integrations Source: https://docs.appsignal.com/elixir/integrations Libraries AppSignal for Elixir instruments, including Phoenix, Ecto, Oban, Absinthe, Broadway, Finch, and Tesla, plus third-party integrations such as Ash. AppSignal for Elixir currently supports the following Elixir integrations: * [Absinthe](/elixir/integrations/absinthe) * [Broadway](/elixir/integrations/broadway) * [Ecto](/elixir/integrations/ecto) * [Erlang](/elixir/integrations/erlang) * [Finch](/elixir/integrations/finch) * [HTTPoison](/elixir/integrations/httpoison) * [Oban](/elixir/integrations/oban) * [Phoenix](/elixir/integrations/phoenix) * [Plug](/elixir/integrations/plug) * [Tesla](/elixir/integrations/tesla) If you want to integrate with AppSignal manually, please read our [integration guide](/elixir/instrumentation/integrating-appsignal). ## Third-party integrations The following integrations have been developed for AppSignal for Elixir by third-parties: * [Ash](https://hexdocs.pm/ash_appsignal/getting-started-with-ash-appsignal.html) # Absinthe Source: https://docs.appsignal.com/elixir/integrations/absinthe The AppSignal for Elixir package instruments operations performed by [Absinthe](https://github.com/absinthe-graphql/absinthe), a GraphQL toolkit for Elixir, using the Telemetry library. AppSignal will automatically recognize operations executed by Absinthe and wrap them into a `call.graphql` event on your Event Timeline, like in the below example: ![Screenshot of Absinthe executed events being shown in the Events Timeline](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/elixir/integrations/absinthe/event-timeline.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=fe1baf2032214c5bd1e44125f275ad17) Combined with our [Ecto integration](/elixir/integrations/ecto), AppSignal's Absinthe integration helps provide a comprehensive overview of what's happening when a GraphQL query is executed. ## Automatic Instrumentation Absinthe is automatically instrumented, requiring no configuration. To disable the Absinthe instrumentation, set the `instrument_absinthe` [config option](/elixir/configuration/options#option-instrument_absinthe) to `false`. # Broadway Source: https://docs.appsignal.com/elixir/integrations/broadway The AppSignal for Elixir package instruments operations performed by [Broadway](https://github.com/elixir-broadway/broadway), a multi-stage data ingestion and data processing pipeline library for Elixir, using the Telemetry library. AppSignal recognizes telemetry events dispatched by Broadway and creates performance traces: ![Trace timeline for a Payo.Pipeline#handle\_message trace, with a child span for enrich.payment](https://mintcdn.com/appsignal-715f5a51/6ozcHwo36jxLcttH/assets/images/screenshots/elixir/integrations/broadway/performance-trace-timeline.png?fit=max\&auto=format\&n=6ozcHwo36jxLcttH\&q=85\&s=4321af0085eb53a42cf1647cc82136f7) Performance trace sample from a Broadway event Included tags: ![Tags on a Broadway trace, including hostname, message, processor, producer, and topology\_name](https://mintcdn.com/appsignal-715f5a51/6ozcHwo36jxLcttH/assets/images/screenshots/elixir/integrations/broadway/performance-tags.png?fit=max\&auto=format\&n=6ozcHwo36jxLcttH\&q=85\&s=6fa8caf36ce01e10c11c1650cf6864e9) Trace sample tags Broadway's message payload: ![Payload on a Broadway trace](https://mintcdn.com/appsignal-715f5a51/6ozcHwo36jxLcttH/assets/images/screenshots/elixir/integrations/broadway/performance-payload.png?fit=max\&auto=format\&n=6ozcHwo36jxLcttH\&q=85\&s=5da72ab49ed3657c646c03f69f2cb6c5) Trace sample payload ## Automatic Instrumentation Broadway is automatically instrumented, requiring no configuration. To disable the Broadway instrumentation, set the `instrument_broadway` [config option](/elixir/configuration/options#option-instrument_broadway) to `false`. # Instrumenting Ecto queries Source: https://docs.appsignal.com/elixir/integrations/ecto How AppSignal records Ecto queries through Telemetry, instruments preloads, and reports query metrics, with manual handler setup. AppSignal uses Ecto’s Telemetry instrumentation to gain information about queries ran in your app by attaching a handler that gets called whenever a query is executed. > [!NOTE] > > Ecto query events are attached to the current AppSignal transaction. Phoenix > and Plug applications start this transaction automatically for each request. > In pure Elixir projects, no transaction is started for you, so query events > are only reported once you start one yourself. See [Starting new > transactions](/elixir/instrumentation/instrumentation#decorator-transactions). ## Automatic instrumentation The Ecto instrumentation automatically hooks into your Ecto repos if the `:otp_app` configuration is configured to your app's OTP app name. The installer automatically configures this for you. ```elixir Elixir theme={null} config :appsignal, :config, otp_app: :my_app, # Set this to the name of your OTP app name: "My app", push_api_key: "your-api-key", env: Mix.env ``` The integration then uses your app's configuration to find out which repos are configured, as your app will have a configuration line like this in `config/config.exs`: ```elixir Elixir theme={null} config :my_app, ecto_repos: [AppsignalPhoenixExample.Repo] ``` ### Disable automatic instrumentation To disable automatic Ecto instrumentation, set [the `instrument_ecto` config option](/elixir/configuration/options#option-instrument_ecto) to `false`. ## Instrumenting Ecto preloads Since Ecto preload queries internally use several Elixir processes to carry out the different database queries involved, some manual changes to your codebase are necessary for AppSignal to properly instrument them. At the top of your Ecto repo module, replace `use Ecto.Repo` with `use Appsignal.Ecto.Repo`, as in the following example: ```elixir Elixir theme={null} defmodule MyApp.Repo do # replace `use Ecto.Repo` with `use Appsignal.Ecto.Repo` use Appsignal.Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Postgres end ``` If your Ecto repo module has its own implementation of the `default_options/1` function, make sure to call `super` within it to merge its default options with those of AppSignal's Ecto repo instrumentation: ```elixir Elixir theme={null} defmodule MyApp.Repo do use Appsignal.Ecto.Repo, ... def default_options(operation) do super(operation) ++ [ # ... your default options here ... ] end end ``` ## Manual handler attachment For repos that aren't listed in the `:ecto_repos` configuration, you can attach a handler manually when starting your app’s supervisor. In most applications, this is done in your application’s `start/2` function. ```elixir Elixir theme={null} def start(_type, _args) do children = [ AppsignalPhoenixExample.Repo, AppsignalPhoenixExampleWeb.Endpoint ] Appsignal.Ecto.attach(:my_otp_app, MyApp.Repo) opts = [strategy: :one_for_one, name: AppsignalPhoenixExample.Supervisor] Supervisor.start_link(children, opts) end ``` In this example, we’ve attached the Telemetry handler to our Phoenix application by calling `Appsignal.Ecto.attach/2`. The first argument is the name of the OTP app that the repo belongs to, and the second argument is the repo's module. ## Metrics In addition to instrumenting your Ecto queries, AppSignal for Elixir collects metrics about your Ecto repos' performance: * `ecto_query_time`: The time the database spends executing each query, tagged by `repo` and `hostname`, and for each table by `repo` and `source`. * `ecto_queue_time`: The time spent waiting for a database connection from the pool, tagged by `repo` and `hostname`. * `ecto_decode_time`: The time spent decoding query results into Elixir terms, tagged by `repo` and `hostname`, and for each table by `repo` and `source`. * `ecto_idle_time`: The time the connection sat idle in the pool before being checked out, tagged by `repo` and `hostname`. * `ecto_total_time`: The sum of queue, query, and decode time, tagged by `repo` and `hostname`, and for each table by `repo` and `source`. AppSignal uses these metrics to create the Ecto Intelligence dashboard with the following graphs: * **Query time**: 95th percentile of time the database spent executing each query, per table. * **Throughput**: number of queries per table. * **Total time**: 95th percentile of total Ecto time (queue, query, and decode), per table. * **Decode time**: mean time spent decoding query results into Elixir terms, per table. * **Queue time**: 95th percentile of time spent waiting for a database connection from the pool, per host. * **Idle time**: mean time connections sat idle in the pool before being checked out, per host. * **Total time per host**: mean total Ecto time (queue, query, and decode), per host. ![Intelligence dashboard showing key Ecto metrics](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/elixir/integrations/ecto/automated-dashboard.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=bd9fda6f70da2a5aa22b8ff56b7a3c4e) The Ecto Intelligence dashboard in AppSignal # Erlang Source: https://docs.appsignal.com/elixir/integrations/erlang The AppSignal for Elixir package integrates with the Erlang VM to provide metrics not just about your app but the virtual machine it's running in. ## Minutely probe Since AppSignal Elixir package `1.10.1` and up a [minutely probe](/elixir/instrumentation/minutely-probes) is activated by default. Once we detect these metrics we'll add an [Intelligence dashboard](/metrics/intelligence-dashboards) to your apps. This probe will report the following [metrics](/metrics/custom) grouped by `hostname` tag: * `erlang_io` - gauge * Tag `type`: * `input` * `output` * `erlang_schedulers` - gauge * Tag `type`: * `total` * `online` * `erlang_processes` - gauge * Tag `type`: * `limit` * `count` * `erlang_memory` - gauge * Tag `type`: * `total` * `processes` * `processes_used` * `system` * `atom` * `atom_used` * `binary` * `code` * `ets` * `erlang_atoms` - gauge * Tag `type`: * `limit` * `count` * `erlang_scheduler_utilization` - gauge (since version `2.2.8`) * Tag `type`: * `normal` * Tag `id`: the ID of the scheduler * `total_run_queue_lengths` - gauge (since version `1.11.0`) * Tag `type`: * `total` * `cpu` * `io` ## Intelligence dashboard When AppSignal receives these metrics, it creates the Erlang [Intelligence dashboard](/metrics/intelligence-dashboards) with the following graphs. Each is grouped by `hostname` and `type`, except Scheduler utilization, which shows one line per scheduler `id` for `normal` schedulers: | Graph | Metric | Description | | - | - | - | | IO | `erlang_io` | Total input and output since the VM started, in kilobytes. | | Schedulers | `erlang_schedulers` | Total and online schedulers. | | Processes | `erlang_processes` | Process count against the process limit. | | Memory | `erlang_memory` | Memory usage per memory type. | | Atom usage | `erlang_atoms` | Usage of atoms in Erlang and the configured limit. | | Scheduler utilization | `erlang_scheduler_utilization` | Load distribution for Erlang schedulers, per scheduler. | | Run queue length | `total_run_queue_lengths` | Total for all schedulers, by type. | ![Intelligence dashboard showing key Erlang VM metrics](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/elixir/integrations/erlang/intelligence-dashboard.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=f35669f89edaa215c89794835603bdf0) The Erlang Intelligence dashboard in AppSignal ### Configuration This probe listens to the [`hostname` config option](/elixir/configuration/options#option-hostname) for the hostname tag added to all its metrics. If none is set it will try to detect it automatically. Use the `hostname` config option to set the hostname if you want to change the detected hostname. # Finch Source: https://docs.appsignal.com/elixir/integrations/finch The AppSignal for Elixir package instruments HTTP requests performed by [Finch](https://github.com/sneako/finch). Finch is a performance-focused HTTP client built on top of [Mint](https://blog.appsignal.com/2022/10/20/appsignal-for-elixir-now-supports-finch.html#:~:text=on%20top%20of-,Mint,-%2C%20Elixir%27s%20low%2Dlevel), Elixir's low-level HTTP client library, and has built-in support for request telemetry. Finch handles the opening and closing of connections, making it easier for you to add HTTP requests to your application. AppSignal will automatically recognize external requests executed by Finch and wrap them into a `request.finch` event on your Event Timeline, like in the below example: ![Event Timeline](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/elixir/integrations/finch/event-timeline.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=75978cce3de54feb4dd9b805f6fcd5ef) In the Event Timeline, you'll see how much time Finch spends making external API requests. This data may help inform you to move the API requests to a background job or introduce caching to help speed up performance and limit unnecessary API requests. ## Automatic Instrumentation > [!TIP] > > The `instrument_finch` config option was added in version `2.5.1` of the > AppSignal for Elixir integration. Finch is automatically instrumented, requiring no configuration. To disable the Finch instrumentation, set [the `instrument_finch` config option](/elixir/configuration/options#option-instrument_finch) to `false`. # HTTPoison Source: https://docs.appsignal.com/elixir/integrations/httpoison The AppSignal for Elixir package instruments HTTP requests performed by [HTTPoison](https://github.com/edgurgel/httpoison). HTTPoison is a popular HTTP client for Elixir. Unlike Finch and Tesla, HTTPoison does not emit telemetry events, so AppSignal cannot automatically instrument it. Instead, AppSignal provides wrapper modules that you opt into: `Appsignal.HTTPoison` as a drop-in client, and `Appsignal.HTTPoison.Base` for custom client modules. The response and error structs (`%HTTPoison.Response{}`, `%HTTPoison.Error{}`, ...) are HTTPoison's own types and are returned unchanged. AppSignal will wrap requests executed via `Appsignal.HTTPoison` as `request.httpoison` events on your performance traces' event timeline, allowing you to see how much time HTTPoison spends making external API requests. This data may help inform you to move the API requests to a background job, or to introduce caching to help speed up performance and limit unnecessary API requests. ## Configuration HTTPoison instrumentation is opt-in. Choose the approach that best fits your application. ### Using Appsignal.HTTPoison directly Call `Appsignal.HTTPoison` instead of `HTTPoison` to make instrumented requests. Pattern-match on `%HTTPoison.Response{...}` and `%HTTPoison.Error{...}` as normal — these are HTTPoison's own struct types, returned unchanged: > [!WARNING] > > Do not use `alias Appsignal.HTTPoison`. This would shadow the `HTTPoison` > module name, causing `%HTTPoison.Response{}` and `%HTTPoison.Error{}` pattern > matches to fail. ```elixir Elixir theme={null} defmodule MyAppWeb.PageController do use MyAppWeb, :controller def index(conn, _params) do case Appsignal.HTTPoison.get("https://api.example.com/users") do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> render(conn, :index, users: body) {:ok, %HTTPoison.Response{status_code: status}} -> conn |> put_status(status) |> text("Error") {:error, %HTTPoison.Error{reason: reason}} -> conn |> put_status(500) |> text("Error: #{reason}") end end end ``` ### Custom client modules If you use a custom HTTP client module based on `HTTPoison.Base`, replace `use HTTPoison.Base` with `use Appsignal.HTTPoison.Base`. No further changes are needed — inside the module, you can call methods like `get/1` and `post/3`, and match on HTTPoison's response and error structs as normal: ```elixir Elixir theme={null} defmodule MyApp.ApiClient do # replace `use HTTPoison.Base` with `use Appsignal.HTTPoison.Base` use Appsignal.HTTPoison.Base def process_url(url) do "https://api.example.com" <> url end def users do case get("/users") do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> {:ok, body} {:ok, %HTTPoison.Response{status_code: status}} -> {:error, status} {:error, %HTTPoison.Error{reason: reason}} -> {:error, reason} end end end ``` All requests made through your custom client will then be instrumented automatically. If your module overrides `request/5`, make sure to call `super` to preserve the instrumentation: ```elixir Elixir theme={null} defmodule MyApp.ApiClient do use Appsignal.HTTPoison.Base def request(method, url, body, headers, options) do # ... custom logic here ... super(method, url, body, headers, options) end end ``` # Oban Source: https://docs.appsignal.com/elixir/integrations/oban AppSignal for Elixir instruments Oban jobs automatically, reports their errors and traces, and collects job performance metrics. The AppSignal for Elixir package instruments jobs performed by [Oban](https://oban.pro) workers, and collects metrics about your jobs' performance. Oban is a job queueing and processing system for Elixir, based on PostgreSQL and Ecto. You can use Oban to schedule jobs to be ran in the background. ## Automatic Instrumentation Oban support is automatically instrumented, requiring no configuration. To disable the Oban instrumentation, set [the `instrument_oban` config option](/elixir/configuration/options#option-instrument_oban) to `false`. > [!NOTE] > > 🔎 The `instrument_oban` config option was added in version `2.5.1` of the > AppSignal for Elixir integration. ## Error Reporting By default, the Oban instrumentation will create an error trace whenever one of your workers fails to process a job, either by returning an `{:error, _}` tuple or by throwing an exception. If you only wish to send errors to AppSignal when the failure causes the job to be discarded, that is, once it's reached its maximum retry attempts, set [the `report_oban_errors` config option](/elixir/configuration/options#option-report_oban_errors) to `"discard"`. Set it to `"none"` to never send Oban job errors to AppSignal. > [!TIP] > > The `report_oban_errors` config option was added in version `2.5.1` of the > AppSignal for Elixir integration. > > If using an Oban version before `2.4.0`, the information about the state of > the job is not available, and the `"discard"` option will behave like > `"all"`. ## Performance and Error Traces AppSignal will create performance traces out of jobs executed by your Oban workers: ![Performance trace from an Oban job execution](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/elixir/integrations/oban/performance-sample.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=78add35d419c4d523ac8781f42049bf3) It will also notify errors that cause your workers to fail while processing a job: ![Error trace from an Oban job execution](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/elixir/integrations/oban/error-sample.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=5d3d313619df2b86d54521404963541e) Within the performance and error traces, the tags will contain information about the job: * Job ID, queue, worker and priority * Number of previous attempts * Job state and result after execution Any tags or metadata values added to the job will also be present as tags in the trace, allowing you to filter the traces for a specific tag. You will also be able to see when an Oban job is inserted in the event timeline of your application's performance traces: ![Event timeline showing an Oban job insertion](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/screenshots/elixir/integrations/oban/event-timeline.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=4ba7ea26be30b29287edeef6b0e53545) > [!NOTE] > > 🔎 Some features are only available in certain Oban versions: > > * **2.2.0+:** Tags > * **2.3.0+:** Metadata values and job priority > * **2.4.0+:** Job state after execution > * **2.5.0+:** Job result after execution > * **2.11.0+:** Job insertion event > > To make use of all the features described above, upgrade to the latest Oban version. ## Metrics In addition to the performance and error traces, AppSignal for Elixir will collect metrics about the performance of your Oban jobs: * `oban_job_duration`: the duration of the jobs processed, tagged by the job's worker, and by worker combined with state or hostname. * `oban_job_queue_time`: the time spent by jobs waiting in the queue, tagged by queue. * `oban_job_count`: the amount of jobs processed, tagged by the job's worker, queue and state. Using these metrics, AppSignal creates the Oban Intelligence dashboard, which has the following graphs: * **Job duration**: the mean duration of jobs, per worker. * **Job queue time**: the 95th percentile of the time between scheduling and starting jobs, per queue. * **Jobs completed**: the number of successful jobs, per worker and queue. * **Job exceptions**: the number of failed jobs, per worker. ![Intelligence dashboard showing key Oban metrics](https://mintcdn.com/appsignal-715f5a51/6TK_LN-sxDFuf16X/assets/images/screenshots/elixir/integrations/oban/magic-dashboard.png?fit=max\&auto=format\&n=6TK_LN-sxDFuf16X\&q=85\&s=ca6902216bef7687393cc8c7abe9b100) # Integrating AppSignal into Phoenix Source: https://docs.appsignal.com/elixir/integrations/phoenix Configure AppSignal for Phoenix beyond installation, including channel and LiveView instrumentation, telemetry handlers, and the included Plugs. The AppSignal for Elixir package integrates with Phoenix. To set up the integration, please follow our [installation guide](/elixir/installation). This page will describe further ways of configuring AppSignal for the [Phoenix framework][phoenix]. To add more custom instrumentation to your Phoenix application, read the [Elixir instrumentation](/elixir/instrumentation) documentation. More information can be found in the [AppSignal Hex package documentation][hex-appsignal]. ## Installation 1. The AppSignal instrumentation for Phoenix is part of a separate package, which depends on the primary `appsignal` package. Add the `appsignal_phoenix` package to your `mix.exs` file. ```elixir Elixir theme={null} # mix.exs defmodule AppsignalPhoenixExample.MixProject do # ... defp deps do [ {:phoenix, "~> 1.5.3"}, {:appsignal_phoenix, "~> 2.0"} # ... ] end end ``` 2. Then run `mix deps.get`. 3. Then run `mix appsignal.install YOUR_PUSH_API_KEY`. After installing and configuring, the AppSignal for Phoenix package automatically starts instrumenting HTTP requests, meaning no further setup is necessary. To gain deeper insights, AppSignal can be set up to instrument channels and live views. ## Channels ### Channel instrumentation with a channel's handle Incoming channel requests can be instrumented by wrapping the code in your `handle_in/3` functions with `Appsignal.Phoenix.Channel.instrument/5`: ```elixir Elixir theme={null} defmodule AppsignalPhoenixExampleWeb.RoomChannel do use Phoenix.Channel # ... def handle_in("new_msg", %{"body" => body} = params, socket) do Appsignal.Phoenix.Channel.instrument(__MODULE__, "new_msg", params, socket, fn -> broadcast!(socket, "new_msg", %{body: body}) {:noreply, socket} end) end end ``` Alternatively, you can use function decorators to instrument channels. While less flexible than the instrumentation function, decorators minimize the amount of code you have to add to your application's channels. ```elixir Elixir theme={null} defmodule SomeApp.MyChannel do use Appsignal.Instrumentation.Decorators @decorate channel_action() def handle_in("ping", _payload, socket) do # your code here.. end end ``` Channel events will be displayed under the "Background jobs" tab, showing the channel module and the action argument that you entered. ## LiveView There are two different ways to instrument live views. You can either use our automatic telemetry handlers, or you can manually instrument your live view handlers with our helper functions. ### Automatic telemetry handlers > [!TIP] > > **Note**: The LiveView Telemetry integration is available from AppSignal for > Phoenix version `2.1.0` onward. AppSignal's LiveView Telemetry integration automatically instruments live view events. To set it up, call `Appsignal.Phoenix.LiveView.attach/0` to attach the LiveView Telemetry handlers. We recommend calling this function from your app's `application.ex`: ```elixir Elixir theme={null} defmodule AppsignalPhoenixExample.Application do # ... def start(_type, _args) do Appsignal.Phoenix.LiveView.attach() # <--- attach the LiveView Telemetry handlers children = [ # Start the Ecto repository AppsignalPhoenixExample.Repo, # Start the Telemetry supervisor AppsignalPhoenixExampleWeb.Telemetry, # Start the PubSub system {Phoenix.PubSub, name: AppsignalPhoenixExample.PubSub}, # Start the Endpoint (http/https) AppsignalPhoenixExampleWeb.Endpoint # Start a worker by calling: AppsignalPhoenixExample.Worker.start_link(arg) # {AppsignalPhoenixExample.Worker, arg} ] # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options opts = [strategy: :one_for_one, name: AppsignalPhoenixExample.Supervisor] Supervisor.start_link(children, opts) end end ``` AppSignal will now automatically instrument all `mount`, `handle_event` and `handle_param` events under the `live_view` namespace, meaning you'll receive both performance and error insights into your live views. ### Manual helper functions > [!TIP] > > If you've already configured the automatic telemetry instrumentation above, > you do not need to manually instrument your live view handlers. > [!TIP] > > **Note**: The LiveView helper functions are available from AppSignal for > Elixir version `1.13.0` onward. A LiveView action can also be manually instrumented by wrapping its contents in a `Appsignal.Phoenix.LiveView.instrument/4` block. Given a live view that updates its own state every second, we can add AppSignal instrumentation by wrapping both the mount/2 and handle\_info/2 functions with a `Appsignal.Phoenix.LiveView.instrument`/4 call: ```elixir Elixir theme={null} defmodule AppsignalPhoenixExampleWeb.ClockLive do use Phoenix.LiveView import Appsignal.Phoenix.LiveView, only: [instrument: 4] def render(assigns) do AppsignalPhoenixExampleWeb.ClockView.render("index.html", assigns) end def mount(_session, socket) do # Wrap the contents of the mount/2 function with a call to # Appsignal.Phoenix.LiveView.instrument/4 instrument(__MODULE__, "mount", socket, fn -> :timer.send_interval(1000, self(), :tick) {:ok, assign(socket, state: Time.utc_now())} end) end def handle_info(:tick, socket) do # Wrap the contents of the handle_info/2 function with a call to # Appsignal.Phoenix.LiveView.instrument/4: instrument(__MODULE__, "tick", socket, fn -> {:ok, assign(socket, state: Time.utc_now())} end) end end ``` Calling one of these functions in your app will now automatically create a trace that's sent to AppSignal. These are displayed under the `:live_view` namespace. ## Instrumentation for included Plugs Exceptions in included Plugs are automatically caught by AppSignal, but performance traces need to be set up manually using the custom instrumentation helpers or decorators. See the [Plug](/elixir/integrations/plug#instrumentation-for-included-plugs) documentation for more information. ## Custom instrumentation [Add custom instrumentation](/elixir/instrumentation/instrumentation) to keep track of more complex code and get more complete breakdowns of slow requests. [phoenix]: http://www.phoenixframework.org/ [hex-appsignal]: https://hexdocs.pm/appsignal/ # Integrating AppSignal into Plug Source: https://docs.appsignal.com/elixir/integrations/plug > [!TIP] > > **Note**: Support for custom namespaces was added in version 1.3.0 of the > AppSignal for Elixir package. The AppSignal for Elixir package integrates with Plug. To set up the integration, please follow our [installation guide](/elixir/installation). This page describes how to set up AppSignal in a Plug application, and how to add instrumentation for events within requests. For more information about custom instrumentation, read the [Elixir instrumentation](/elixir/instrumentation) documentation. More information can be found in the [AppSignal Hex package documentation][hex-appsignal]. ## Installation The AppSignal instrumentation for Plug is part of a separate package, which depends on the primary `appsignal` package. Add the `appsignal_plug` package to your `mix.exs` file. ```elixir Elixir theme={null} # mix.exs defmodule AppsignalPlugExample.MixProject do # ... defp deps do [ {:plug, "~> 1.0"}, # Or plug_cowboy ~> 2.0 {:appsignal_plug, "~> 2.0"} # ... ] end end ``` If you're already using our `appsignal_phoenix` package, it's not necessary to add the `appsignal_plug` package as it's already a dependency of the `appsignal_phoenix` package. See also our [Phoenix integration guide](/elixir/installation/umbrella#phoenix). ## Incoming HTTP requests We'll start out with a small Plug app that accepts `GET` requests to `/` and returns a welcome message. To start logging HTTP requests in this app, we'll use the `Appsignal.Plug` module. ```elixir Elixir theme={null} defmodule AppsignalPlugExample do use Plug.Router use Appsignal.Plug # <- Add this plug :match plug :dispatch get "/" do send_resp(conn, 200, "Welcome") end end ``` This will create a transaction for every HTTP request which is performed on the endpoint. ## Custom instrumentation Although `Appsignal.Plug` will start transactions for you, it won't instrument events in your app just yet. To do that, we need to add some custom instrumentation. This example app looks like the one we used before, but it has a slow function (aptly named `slow/0`) we'd like to add instrumentation for. To do that, we need to use the `Appsignal.instrument/2-3` helper in our called function: ```elixir Elixir theme={null} defmodule AppsignalPlugExample do use Plug.Router plug :match plug :dispatch get "/" do slow() send_resp(conn, 200, "Welcome") end defp slow do Appsignal.instrument("slow", fn -> :timer.sleep(1000) end) end use Appsignal.Plug end ``` This will add an event for the `slow/0` function to the current transaction whenever it's called. For more information about custom instrumentation, read the [Elixir instrumentation](/elixir/instrumentation) documentation. ## Instrumentation for included Plugs Exceptions in included Plugs are automatically caught by AppSignal, but performance traces need to be set up manually using the custom instrumentation helpers or decorators. ### Plug instrumentation with decorators To add instrumentation to Plugs, use the `Appsignal.instrument/2` function: ```elixir Elixir theme={null} defmodule SlowPlugWithDecorators do import Plug.Conn def init(opts), do: opts def call(conn, _) do Appsignal.instrument("SlowPlugWithDecorators", fn -> :timer.sleep(1000) conn end) end end ``` [hex-appsignal]: https://hexdocs.pm/appsignal/ # Tesla Source: https://docs.appsignal.com/elixir/integrations/tesla The AppSignal for Elixir package instruments HTTP requests performed by [Tesla](https://github.com/elixir-tesla/tesla). Tesla is a flexible HTTP client library for Elixir. It can use multiple middlewares and adapters to modify and perform HTTP request, and it has built-in support for request telemetry. After configuring Tesla's Telemetry middleware, AppSignal will recognize requests executed via Tesla and show them as `request.tesla` events on your performance traces' Event Timeline. In the Event Timeline, you'll see how much time Tesla spends making external API requests. This data may help inform you to move the API requests to a background job or introduce caching to help speed up performance and limit unnecessary API requests. In the Slow API Requests performance view, you'll be able to see aggregated throughput and average times for different kinds of HTTP requests. Follow the instructions in the [Path Params Grouping](#path-params-grouping) section in order to improve the information shown in this view. ## Configuration Add the `Tesla.Middleware.Telemetry` middleware to your module or client's middleware chain, **before any other middlewares**: ```elixir Elixir theme={null} defmodule MyAPIClient do use Tesla plug Tesla.Middleware.Telemetry # ... plug other middlewares here, **after** the Telemetry middleware end ``` ```elixir Elixir theme={null} client = Tesla.client([ Tesla.Middleware.Telemetry, # ... add other middlewares here, **after** the Telemetry middleware ]) ``` > [!TIP] > > If using the Finch adapter for Tesla, you should [disable AppSignal's Finch > instrumentation](/elixir/integrations/finch#automatic-instrumentation) by > setting the `instrument_finch` configuration option to `false`. ## Enhanced Grouping By default, the AppSignal instrumentation for Tesla will group requests by the domain name they're performed against. The path of the request will not be shown in AppSignal. However, by using certain Tesla middlewares, it's possible to add more information about the request. The following sections describe each middleware's behaviour separately, but it is also possible to use them together. ### Base URL Grouping When using the `BaseUrl` middleware, the base URL provided, including its path, will be used for grouping, providing you with some additional insight into the target of the HTTP requests performed by Tesla: ```elixir Elixir theme={null} defmodule MyAPIClient do use Tesla plug Tesla.Middleware.Telemetry # make sure Telemetry appears **before** any other middleware! plug Tesla.Middleware.BaseUrl, "https://api.example.com/v2/users" def user_comments(id) do get("/#{id}/comments") end end ``` In the above example, requests performed by this client will be shown in the trace's Event Timeline and in the Slow API Requests performance view as `GET https://api.example.com/v2/users`, instead of just `GET https://api.example.com`, providing additional information about the requests that are being performed. ### Path Params Grouping When using the `PathParams` middleware, the URL given to Tesla for the request will be a template, with path parameters being passed separately: ```elixir Elixir theme={null} defmodule MyAPIClient do use Tesla plug Tesla.Middleware.Telemetry # make sure Telemetry appears **before** any other middleware! plug Tesla.Middleware.PathParams def user_comments(id) do params = [user: id] get("https://api.example.com/v2/users/:user/comments", opts: [path_params: params]) end end ``` When `PathParams` is used, the URL template will be shown in AppSignal. Requests will appear as `GET https://api.example.com/v2/users/:user/comments` in the trace's Event Timeline and in the Slow API Requests performance view, providing you with a detailed view of each request type that your client performs. ## Disable Tesla Instrumentation To disable the Tesla instrumentation, set [the `instrument_tesla` config option](/elixir/configuration/options#option-instrument_tesla) to `false`. # Elixir Releases Source: https://docs.appsignal.com/elixir/releases AppSignal’s Elixir integration does not require any extra configuration for apps deployed through [Distillery](https://github.com/bitwalker/distillery) or Elixir 1.9’s releases feature, but the agent needs to be built on a machine with the same architecture as the machine you'll be hosting your application on. AppSignal for Elixir doesn't support cross-compilation at this time. ## Debugging releases Since released applications can be more difficult to debug, here are the steps we take when a support request for a deployed Elixir application comes in. ### Development mode First and foremost, we check if the problem is caused by the release by making sure everything works in development, on your local machine. Start your app locally, on your development machine, in the development environment: ```bash Bash theme={null} $ mix phx.server ``` Request some pages in your app, and sign into AppSignal to see if any performance traces come in. If possible, trigger an exception in one of your app’s controllers to see if it ends up on your errors page too. > [!TIP] > > **Note**: Running AppSignal in your development environment will create a > “dev” environment on your account overview in AppSignal, where the data will > appear. If you don’t receive any data, double-check the steps in the [installation guide](/elixir/installation) and the [Phoenix](/elixir/integrations/phoenix) guide to make sure everything in your app is set up properly. If the install guide doesn’t show any missed steps, run the [diagnose command](/elixir/command-line/diagnose#usage) (still on your local machine): ```bash Bash theme={null} $ mix appsignal.diagnose --send-report ``` The diagnose command runs diagnostics, and the `--send-report` option sends the report to our servers. Then, contact [support](mailto:support@appsignal.com) with the support token you receive at the end of the report. ### Diagnose If everything works locally in development, but your production install isn’t yet, run the diagnose command on your release binary. ```bash Bash theme={null} # Elixir releases $ bin/your_app eval ":appsignal_tasks.diagnose()" # Distillery $ bin/your_app command appsignal_tasks diagnose ``` When asked to send the report to AppSignal, choose `Y`. Then, contact [support](mailto:support@appsignal.com) with the support token you receive at the end of the report. # Why a NIF? Source: https://docs.appsignal.com/elixir/why-nif The AppSignal for Elixir integration relies on [a NIF](http://erlang.org/doc/man/erl_nif.html) that calls out to a library to do the heavy lifting, written in [Rust](https://www.rust-lang.org). Its job is to receive data from the Elixir app, normalize it and write it to a separate agent process over a Unix socket. The agent then sends the data to AppSignal.com periodically for further processing. See our [how AppSignal operates](/appsignal/how-appsignal-operates) page more information about how our agent works. While using a NIF has inherent risks, using one in this case has several advantages: 1. Overhead is very low. The functions in the NIF do nothing more than receive data and send it to a worker thread, so that the C function can return immediately. It's designed to be as fast as possible while having very little impact on the calling thread, and generate minimal garbage collection load. 2. It allows the use of the same library and agent used by AppSignal for [Ruby](/ruby), which runs on thousands of production servers all over the world. It's battle tested technology, processing a combined 1 billion requests *per day* (November 2016). 3. The library and agent are written in Rust, and its primary design considerations were (and remain) robustness and performance. Internally, the AppSignal NIF works as follows: it fork/execs a separate agent process, to which a worker thread in the NIF sends its data over a Unix socket. All I/O and processing in the NIF is asynchronous, so calls to its functions will never hold up the scheduler. In the very unlikely event that something in the extension panics, the extension disables itself without bringing down the host process. While doing native Elixir protobufs to communicate directly with the agent makes more sense from a BEAM standpoint, using a NIF enables the use of a single library. This decreases potential issues because of the volume of testing and fine-tuning that has already happened. By focusing on a single code base, AppSignal can guarantee the highest quality for all of its customers across all supported languages. # Logging from Elixir Source: https://docs.appsignal.com/logging/integrations/elixir This documentation outlines how to configure logging with the AppSignal for Elixir integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Elixir integration. An "application" log source will be created automatically. ### Logger Handler You can configure the Erlang `:logger` to use the `Appsignal.Logger.Handler` module as a handler, by calling the `Appsignal.Logger.Handler.add/2` function on your `Application.start/2` callback: ```elixir Elixir theme={null} @impl true def start(_type, _args) do Appsignal.Logger.Handler.add("phoenix") end ``` The given argument is the group name that describes where you are logging from. This group name can be used in AppSignal to filter your logs. ### Logger Backend > [!TIP] > > Starting with Elixir version 1.15, Elixir logger backends are no longer > recommended. See the [Logger Handler section](#logger-handler) above for the > recommended alternative. Instead of using an Elixir logger handler, you can configure the Elixir logger backend to use the `Appsignal.Logger.Backend` module as a backend by placing the code below in the `config/runtime.exs` file: ```elixir Elixir theme={null} config :logger, backends: [:console, {Appsignal.Logger.Backend, [group: "phoenix"]}] ``` The `group` option describes where you are logging from. This group name can be used in AppSignal to filter your logs. You can also add the backend using the `add_backend/2` function on your `Application.start/2` callback: ```elixir Elixir theme={null} @impl true def start(_type, _args) do Logger.add_backend(Appsignal.Logger.Backend, group: "phoenix") end ``` ### Elixir Logger To send logs to AppSignal without using the Elixir Logger backend, you can use one of `Appsignal.Logger`'s logging functions and provide it with a `groupname` that defines where you are logging from. For example, if we were logging from a helper for invoicing clients: ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", "Generating invoice for customer 129" ) ``` ## Usage ### Sending Logs Like the Elixir/Phoenix logger class, you can define the severity level of your logs by using `fatal`, `error`, `warning`, `info`, and `debug`: ```elixir Elixir theme={null} Appsignal.Logger.warning( "app", "Something's gone terribly wrong here" ) ``` You can pass custom attributes as the last argument, to send log information that can be used when filtering and querying logs: ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", "Generated invoice for customer #{customer.id}", %{ customer_id: customer.id, invoice_id: invoice.id } ) ``` You can query and filter on message contents and attribute values using our [query syntax](/logging/query-syntax). Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface. ## Formats ### Auto detected format The AppSignal for Elixir package will automatically detect the log line's format as JSON, Logfmt or plaintext by default, and parse attributes from it. You don't need to manually set the log format, unless it's not being detected properly. Please also [notify us](mailto:support@appsignal.com?subject=Log%20format%20auto%20detection%20not%20working) if this isn't working automatically. ```elixir Elixir theme={null} # Plaintext format Appsignal.Logger.info( "invoice_helper", "Generated invoice" ) # Logfmt format Appsignal.Logger.info( "invoice_helper", "Generated invoice invoice_id=A145 for customer customer_id=123" ) # JSON format Appsignal.Logger.info( "invoice_helper", ~s({"message": "Generated invoice for customer", "invoice_id": "A145", "customer_id": "123"}) ) ``` ### Logfmt The AppSignal Logger can be explicitly configured to expect the line to be formatted as Logfmt and parse attributes from it. Use this option when using an older AppSignal for Elixir package version, which does not support [automatic format detection](#auto-detected-format). The Logfmt format can be specified when the AppSignal logger is called by adding the `:logfmt` value as the last argument. ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", "Generated invoice invoice_id=A145 for customer customer_id=123", :logfmt ) ``` ### JSON The AppSignal Logger can be explicitly configured to expect the line to be formatted as JSON and parse attributes from it. Use this option when using an older AppSignal for Elixir package version, which does not support [automatic format detection](#auto-detected-format). The JSON format can be specified when the AppSignal logger is called by adding the `:json` value as the last argument. ```elixir Elixir theme={null} Appsignal.Logger.info( "invoice_helper", ~s({"message": "Generated invoice for customer", "invoice_id": "A145", "customer_id": "123"}), :json ) ``` Only primitive non-nested values (numbers, strings, booleans and `null`) will be shown as log attributes. All other attributes will be discarded. ## Filtering Logs You can use [the `ignore_logs` configuration option](/elixir/configuration/options#option-ignore_logs) to ignore log lines based on their message. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Elixir application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging from Node.js Source: https://docs.appsignal.com/logging/integrations/nodejs This documentation outlines how to configure logging with the AppSignal for Node.js integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Node.js integration. An "application" log source will be created automatically. ### Stand-alone usage To use the logger, you need to import AppSignal and set up the logger using the `.logger()` function. The `.logger()` function accepts two arguments: `group` and optionally `severityThreshold`. If `severityThreshold` is not provided, it will default to `info`. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); const logger = Appsignal.logger("app"); // with a severity threshold: const logger = Appsignal.logger("app", "info"); ``` There are six severity levels available `trace`, `debug`, `info`, `log`, `warn`, and `error`, each of them with its own function with the same name. These functions accept two arguments `message` and `attributes`. Attributes is used for metadata and is optional. Messages will only be logged if their severity level is above the severity threshold. ```javascript Node.js theme={null} logger.info("Log message line"); logger.debug("User logged in", { user_id: 123 }); ``` Note that if the message's severity is below the severity threshold set up when initializing the logger, it will not be sent to AppSignal. You can query and filter on message contents and attribute values using our [query syntax](/logging/query-syntax). #### Using multiple logging backends It's currently not possible to send logs to multiple backends using Node.js' standard logger. For more complex setups, we recommend using a logging library like Winston or Pino. ### Usage with Winston If you use Winston to log messages throughout your application, you can use our Winston transport to send those logs to AppSignal. After importing the transport from the AppSignal integration, add it to the list of transports in your Winston logger: ```javascript Node.js theme={null} const winston = require("winston"); const { WinstonTransport } = require("@appsignal/nodejs"); const logger = winston.createLogger({ transports: [new WinstonTransport({ group: "app" })], }); ``` #### Child Logger You can use a child logger to add additional tags to log messages. You define tags when creating the child logger constant or pass tags as metadata when writing a log message. Say we want greater context in our logs of the actions of a particular user within a specific session. In the below example, a child logger for the `background` group is used to add `sessionID` with the additional `drinkID`, and `paymentID` tags are provided as metadata when creating a log message, and if a group is given to the child, it'll override the one set up in the transport. ```javascript Node.js theme={null} const logger = winston.createLogger({...}); const sessionLogger = logger.child({ group: "background", sessionID: user.id, }); sessionLogger.debug("User logged in"); sessionLogger.info("User ordered coffee", { drinkID: 30, paymentID: 20082 }); sessionLogger.debug("User logged out"); ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, add another transport: ```javascript JavaScript theme={null} const winston = require("winston"); const { WinstonTransport } = require("@appsignal/nodejs"); const logger = winston.createLogger({ transports: [ new WinstonTransport({ group: "app" }), new winston.transports.Console(), ], }); ``` ### Usage with Pino If Pino is your preferred logging library, you can use the AppSignal Pino transport to send logs to AppSignal. The group argument will default to "app" if not provided. ```javascript Node.js theme={null} import pino from "pino"; const logger = pino({ transport: { targets: [ { target: "@appsignal/nodejs/pino", options: { group: "my-group" } } ], }, }); ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, add another target: ```javascript Node.js theme={null} import pino from "pino"; const logger = pino({ transport: { targets: [ { target: "@appsignal/nodejs/pino", options: { group: "my-group" } }, { target: 'pino/file', options: {destination: 1} } ], }, }); ``` ## Formats ### Auto detected format The AppSignal for Node.js package will automatically detect the log line's format as JSON, Logfmt or plaintext by default, and parse attributes from it. You don't need to manually set the log format, unless it's not being detected properly. Please also [notify us](mailto:support@appsignal.com?subject=Log%20format%20auto%20detection%20not%20working) if this isn't working automatically. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); // Plaintext format const logger = Appsignal.logger("app", "info"); logger.info("This is about the blog"); // Logfmt format const logger = Appsignal.logger("app", "info"); logger.info("category=blog This is about the blog"); // JSON format const logger = Appsignal.logger("app", "info"); logger.info('{"category": "blog", "message": "This is about the blog"}'); ``` ### Logfmt The AppSignal Logger can be explicitly configured to expect the line to be formatted as Logfmt and parse attributes from it. Use this option when using an older AppSignal for Node.js package version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the `"logfmt"` value as the third argument. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); const logger = Appsignal.logger("app", "info", "logfmt"); logger.info("category=blog this is about the blog"); ``` In the example above, a filterable category attribute with the value "blog" will be logged. ### JSON The AppSignal Logger can be explicitly configured to expect the line to be formatted as JSON and parse attributes from it. Use this option when using an older AppSignal for Node.js package version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the `"json"` value as the third argument. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); const logger = Appsignal.logger("app", "info", "json"); logger.info('{"category": "blog", "message": "this is about the blog"}'); ``` In the example above, a filterable category attribute with the value "blog" will be logged. ## Filtering Logs You can use [the `ignoreLogs` configuration option](/nodejs/3.x/configuration/options#option-ignorelogs) to ignore log lines based on their message. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Node.js application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # Logging from Ruby Source: https://docs.appsignal.com/logging/integrations/ruby This documentation outlines how to configure logging with your AppSignal for Ruby integration. ## Configure Logging > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons). You do not need to create a log source to send logs from the AppSignal for Ruby integration. An "application" log source will be created automatically. ### Rails Logger You can configure the Rails framework to send logs to AppSignal in an initializer file like `config/initializers/logging.rb`: ```ruby Ruby theme={null} # config/initializers/logging.rb appsignal_logger = Appsignal::Logger.new("rails") Rails.logger = ActiveSupport::TaggedLogging.new(appsignal_logger) ``` #### Using multiple logging backends To send logs to both AppSignal's logger and Rails' default logger, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} # config/initializers/logging.rb appsignal_logger = Appsignal::Logger.new("rails") appsignal_logger.broadcast_to(Rails.logger) Rails.logger = ActiveSupport::TaggedLogging.new(appsignal_logger) ``` We do not recommend using Rails' built-in broadcast logger feature, due to compatibility issues when used alongside tagged logging. #### Tagged logging support The use of `ActiveSupport::TaggedLogging` in the above examples enables support for Rails' log tags. For example, if you wish to add the request ID tag to the log messages, add it to the `config.log_tags` array in the `config/application.rb` file: ```ruby Ruby theme={null} module TestApp class Application < Rails::Application config.log_tags = [:request_id] end end ``` #### Using Lograge > [!WARNING] > > This Lograge config is not a replacement for the Rails logger config. If you > want to report logs from `Rails.logger`, the [Rails logger config > steps](#rails-logger) also need to be followed. The [Lograge](https://github.com/roidrage/lograge) library is a popular solution for ingesting structured Rails *request* logs. After adding the `lograge` gem, you can configure it in `config/initializers/lograge.rb` to send logs to AppSignal: ```ruby Ruby theme={null} Rails.application.configure do config.lograge.enabled = true config.lograge.keep_original_rails_log = true config.lograge.logger = Appsignal::Logger.new( "rails", format: Appsignal::Logger::LOGFMT ) end ``` > [!TIP] > > Lograge does not support log levels. All logs emitted via Lograge will appear > with severity level `INFO` in the AppSignal Logging UI. ### Sinatra Logger You can configure Sinatra to send request logs to AppSignal using Rack's CommonLogger middleware. Configure it like shown below. Consider if request logs contain useful information for you, read our [what logs should I store](https://www.appsignal.com/learning-center/what-logs-should-i-store) learning center article. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("sinatra") use Rack::CommonLogger, logger ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("sinatra") logger.broadcast_to(Logger.new($stdout)) use Rack::CommonLogger, logger ``` ### Sidekiq Logger You can configure Sidekiq to send its logs to AppSignal, including the logs emitted by your background jobs: ```ruby Ruby theme={null} Sidekiq.configure_server do |config| config.logger = Appsignal::Logger.new("sidekiq") config.logger.formatter = Sidekiq::Logger::Formatters::WithoutTimestamp.new end ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} Sidekiq.configure_server do |config| config.logger = Appsignal::Logger.new("sidekiq") config.logger.broadcast_to(Logger.new($stdout)) config.logger.formatter = Sidekiq::Logger::Formatters::WithoutTimestamp.new end ``` ### Ruby Logger To send logs to AppSignal as you would with Ruby's `Logger` class, you will need to create an instance of `Appsignal::Logger` and provide it with a `groupname` that defines where you are logging from, for example, if we were logging from a helper for invoicing clients: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper") ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, use our logger's `.broadcast_to` helper: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper") logger.broadcast_to(Logger.new($stdout)) ``` ### Semantic Logger The [Semantic Logger](https://logger.rocketjob.io/) library provides a comprehensive logging solution for Ruby and Rails applications. After adding the `semantic_logger` gem, you can configure it to send logs to AppSignal as follows: ```ruby Ruby theme={null} appsignal_logger = Appsignal::Logger.new("rails", format: Appsignal::Logger::LOGFMT) SemanticLogger.add_appender(logger: appsignal_logger, formatter: :logfmt) ``` #### Using multiple logging backends To send logs to both AppSignal's logger and `STDOUT`, add another appender using the `add_appender` method: ```ruby Ruby theme={null} appsignal_logger = Appsignal::Logger.new("rails", format: Appsignal::Logger::LOGFMT) SemanticLogger.add_appender(logger: appsignal_logger, formatter: :logfmt) SemanticLogger.add_appender(io: $stdout) ``` ## Usage ### Sending Logs Like the Ruby/Rails `Logger` class, you can define the severity level of your logs by using `fatal`, `error`, `warn`, `info`, and `debug`: ```ruby Ruby theme={null} logger.warn("Something went wrong") ``` You can define custom attributes to send log information that can be used when filtering and querying logs: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper") logger.info("Generating invoice for customer", { customer_id: @customer.id }) invoice = generate_invoice(@customer) logger.info("Generated invoice for customer", { customer_id: @customer.id, invoice_id: invoice.id }) ``` You can query and filter on message contents and attribute values using our [query syntax](/logging/query-syntax). Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface. ### Default Logger Attributes When initializing the AppSignal logger, you can provide default attributes that will be included in all log messages: ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper", attributes: { customer_id: @customer.id }) ``` The attributes provided when initializing the logger will be included in all log messages sent from that logger instance. Attributes provided with the log message will be merged with the default logger attributes. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("invoice_helper", attributes: { customer_id: @customer.id }) # This log message will contain the `customer_id` attribute: logger.info("Generating invoice for customer") invoice = generate_invoice(@customer) # This log message will contain the `customer_id` and `invoice_id` attributes: logger.info("Generated invoice for customer", { invoice_id: invoice.id }) ``` When both the logger and the log message provide the same attribute, the log message's attribute will override the default logger attribute. ## Formats ### Auto detected format The AppSignal for Ruby gem will automatically detect the log line's format as JSON, Logfmt or plaintext by default, and parse attributes from it. You don't need to manually set the log format, unless it's not being detected properly. Please also [notify us](mailto:support@appsignal.com?subject=Log%20format%20auto%20detection%20not%20working) if this isn't working automatically. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("group") # Plaintext format logger.info("This is about the blog") # Logfmt format logger.info("category=blog This is about the blog") # JSON format logger.info('{"category": "blog", "message": "This is about the blog"}') ``` ### Logfmt The AppSignal Logger can be explicitly configured to expect the line to be formatted as Logfmt and parse attributes from it. Use this option when using an older AppSignal for Ruby gem version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the Logfmt constant in the format option. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("group", format: Appsignal::Logger::LOGFMT) logger.info("category=blog This is about the blog") ``` In the example above, a filterable category attribute with the value "blog" will be logged. ### JSON The AppSignal Logger can be explicitly configured to expect the line to be formatted as JSON and parse attributes from it. Use this option when using an older AppSignal for Ruby gem version, which does not support [automatic format detection](#auto-detected-format). The log format can be specified when creating a logger. When initializing the AppSignal logger pass the JSON constant in the format option. ```ruby Ruby theme={null} logger = Appsignal::Logger.new("group", format: Appsignal::Logger::JSON) logger.info('{"category": "blog", "message": "This is about the blog"}') ``` In the example above, a filterable category attribute with the value "blog" will be logged. ## Filtering Logs You can use [the `ignore_logs` configuration option](/ruby/configuration/options#option-ignore_logs) to ignore log lines. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more. ## Need Help? After configuring your Ruby application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track! # AppSignal for Node.js Source: https://docs.appsignal.com/nodejs/3.x AppSignal for [Node.js](https://nodejs.org/en/) helps you get the most out of your Node.js application, providing you with the tools you need to track errors and monitor the performance of your application's code. The package supports pure JavaScript and TypeScript applications and can auto-instrument various frameworks and packages with optional plugins. Other frameworks and packages might require some [custom instrumentation](/nodejs/3.x/instrumentation). ## OpenTelemetry OpenTelemetry is an open-source project that facilitates the instrumentation of standardized telemetry data collection. This means that you can easily integrate your data with AppSignal or another vendor of your choice. You're not locked into a single provider's services. As OpenTelemetry is an open-source project, everyone can collaborate on the same base integrations to provide instrumentation for the benefit of everyone. OpenTelemetry currently supports several popular programming languages, including Node.js. OpenTelemetry consists of multiple components: tracing, metrics, and logs. These components are still a work in progress in most programming languages, with tracing for many languages being the most stable component. We support OpenTelemetry's tracing component in our Node.js integration to provide better error reporting and performance measurements. **[Learn more about OpenTelemetry via the project's official website.](https://opentelemetry.io/)** ## Supported Libraries Our integration supports the following libraries and frameworks: * [Node.js Core](/nodejs/3.x/integrations/core) * [Apollo Gateway](/nodejs/3.x/integrations/apollo-gateway) * [BullMQ](/nodejs/3.x/integrations/bullmq) * [Elasticsearch](/nodejs/3.x/integrations/elasticsearch) * [Express](/nodejs/3.x/integrations/express) * [Fastify](/nodejs/3.x/integrations/fastify) * [GraphQL (such as Apollo Server or Yoga)](/nodejs/3.x/integrations/graphql) * [Knex.js](/nodejs/3.x/integrations/knexjs) * [Koa.js](/nodejs/3.x/integrations/koajs) * [MongoDB](/nodejs/3.x/integrations/mongo) * [Mongoose](/nodejs/3.x/integrations/mongoose) * [MySQL (mysql and mysql2 packages)](/nodejs/3.x/integrations/mysql) * [NestJS](/nodejs/3.x/integrations/nestjs) * [Next.js](/nodejs/3.x/integrations/nextjs) * [PostgreSQL](/nodejs/3.x/integrations/pg) * [Prisma](/nodejs/3.x/integrations/prisma) * [Redis (redis and ioredis packages)](/nodejs/3.x/integrations/redis) * [Remix](/nodejs/3.x/integrations/remix) * [Restify](/nodejs/3.x/integrations/restify) ## Supported Environments > [!NOTE] > > 🔧 Support for Node.js is defined on our [maintenance policy > page](/support/maintenance-policy). Node.js is an incredibly flexible runtime, which allows it to be used for a multiple of different use-cases. AppSignal was primarily designed for use on a server, so there are a few places that the Node.js integration is currently not suitable: * **Electron apps:** We don't recommend using @appsignal/nodejs inside [Electron](https://www.electronjs.org/) applications. As we designed the [agent](/appsignal/terminology#agent) to run on a server, it is not currently useful in this environment. It will also lead to possibly unwanted complexity around cross-compilation of the native extension. * **Short-lived processes:** Short-lived processes, such as CLI tools, are a poor fit for the agent, which must be able to stay running for a period of time (at least 60 seconds). * **Serverless functions:** Serverless functions are meant to be short-lived processes, so they are also a poor fit for the agent. * **Statically generated apps:** Some environments (e.g [Gatsby.js](https://www.gatsbyjs.com/), [Svelte](https://svelte.dev/)) offer some access to Node.js APIs but ultimately compile their code down to a client side application, and therefore aren't suitable for the Node.js library. ***Don't panic!*** The [@appsignal/javascript library](/front-end/) does not require the agent and will work where @appsignal/nodejs doesn't currently work, however only error tracking is supported at the moment. # Bundling with esbuild Source: https://docs.appsignal.com/nodejs/3.x/bundling-with-esbuild If you're bundling your Node.js app with [esbuild](https://esbuild.github.io/), it's necessary to mark the packages to instrument as external. For example, if you are running an application with Mongoose and you want to send instrumentation data to AppSignal, you must flag the Mongoose dependency as `external` in your build script command as in the example below: ```json JSON theme={null} { //... "build:appsignal": "esbuild src/appsignal.ts --bundle --platform=node --external:mongoose --external:@appsignal/nodejs" //... } ``` # AppSignal for Node.js: Command line tools Source: https://docs.appsignal.com/nodejs/3.x/command-line The optional [`@appsignal/cli` package][package] includes several command-line tools. These tools make it easier to install AppSignal in an application, send deploy notifications and diagnose any problems with the installation. ## Diagnose A self-diagnostic tool for the AppSignal for nodejs gem. This tool can be used to debug your AppSignal installation and is one of the first things our support team asks for when there's an issue. Read more about the [`npx @appsignal/cli diagnose`][cli-diagnose] command line tool. [package]: https://github.com/appsignal/appsignal-nodejs [cli-diagnose]: /nodejs/3.x/command-line/diagnose.html [cli-demo]: /nodejs/3.x/command-line/demo.html # AppSignal for Node.js: Demonstration tool Source: https://docs.appsignal.com/nodejs/3.x/command-line/demo The AppSignal for Node.js package ships with a command line tool used to send demonstration traces to AppSignal. Upon running it, it sends an error and performance trace to AppSignal from the user's machine. This command line tool is useful when testing AppSignal on a system and validating the local configuration. It tests if the installation of AppSignal has succeeded and if the AppSignal agent is able to run on the machine's architecture and communicate with the AppSignal servers. Read more about how to use the demonstration command on the [Debugging][debugging] page. ## Usage On the command line in your project run: ```bash Bash theme={null} npx @appsignal/cli demo ``` To run it with a specific environment, Push API key or application name, see the [CLI options](#options). ```bash Bash theme={null} npx @appsignal/cli demo --environment=production --api-key="" --application="My app" ``` ## Options | Option | Description | | - | - | | `--api-key=` | Specify the Push API Key to use for the app. [Config option `pushApiKey`](/nodejs/3.x/configuration/options#option-pushapikey). | | `--application=` | The name of the app to send the demo traces for. [Config option `name`](/nodejs/3.x/configuration/options#option-name). | | `--environment=` | Set the environment to use in the command, e.g. `production` or `staging`. [Config option `environment`](/nodejs/3.x/configuration/options#option-environment). | If no options are specified the demo tool will use the [environment variables of config options](/nodejs/3.x/configuration/options) if present. [debugging]: /support/debugging.html # AppSignal for Node.js: Diagnose tool Source: https://docs.appsignal.com/nodejs/3.x/command-line/diagnose The AppSignal Node.js package ships with a self-diagnostic tool. This tool can be used to debug your AppSignal installation and is one of the first things our support team asks for when there's an issue. ## The diagnostic report This command-line tool is useful when testing AppSignal on a system and validating the local configuration. It outputs useful information to debug issues and it checks if AppSignal agent can run on the machine's architecture and communicate with the AppSignal servers. This diagnostic tool collects and outputs the following: * information about the AppSignal package. * information about the host system and Node.js. * if the AppSignal [extension](/appsignal/how-appsignal-operates#extension) and [agent](/appsignal/how-appsignal-operates#agent) can run on the host system. * all configured config options (including default values). * if the configuration is valid and active. * if the Push API key is present and valid (internet connection required). * where configuration option values originate from. Read more about how to use the diagnose command on the [Debugging][debugging] page. ## Submitting the report You need to pass the `--send-report` option to send the diagnose report to AppSignal. If used, the report will be send to our servers and you will receive a support token. When you [send this support token to us](mailto:support@appsignal.com) we will review the report and help you debug the issue. We've seen that copy-pasting the report output usually loses formatting and makes it harder to read, which is why it's sent to our servers in the JSON format. ## Usage On the command line in your project (a directory with a `package.json` and `@appsignal/nodejs` installed) run: ```bash Bash theme={null} npx @appsignal/cli diagnose ``` At the very least, the `APPSIGNAL_PUSH_API_KEY` must be set before the diagnose command can be run. If this isn't set in your environment already, you can also set it at runtime with the `--api-key` option: ```bash Bash theme={null} npx @appsignal/cli diagnose --api-key="" ``` You can also set the environment variable at runtime: ```bash Bash theme={null} APPSIGNAL_PUSH_API_KEY="" npx @appsignal/cli diagnose ``` To run the diagnose on your production server, and send the report to AppSignal for support purposes, you can run the following command: ```bash Bash theme={null} npx @appsignal/cli diagnose --environment=production --send-report --api-key="" ``` The environment option is useful when the default environment is not the one you want to diagnose. The diagnose tool will warn you when no environment is selected. ## Options | Option | Description | | - | - | | [`--environment=`](#environment-option) | Set the environment to use in the command, e.g. `production` or `staging`. | | `--api-key` | Define which API key to use. | | [`--[no-]send-report`](#report-submission-option) | Automatically send, or do not send the report. | ### Environment option Define which app environment AppSignal should load in the diagnose CLI. ```bash Bash theme={null} npx @appsignal/cli diagnose --environment=production ``` ### Report submission option The options to [submit the report](#submitting-the-report) immediately, or not, were added to the AppSignal Node.js package version `1.2.5`. Submit the report to AppSignal: ```bash Bash theme={null} npx @appsignal/cli diagnose --send-report ``` Do not submit the report to AppSignal: ```bash Bash theme={null} npx @appsignal/cli diagnose --no-send-report ``` ## Configuration output format ### Configuration option values format The configuration options are printed to the CLI as their inspected values. This means we print them as Node.js would in a console. * Strings values are printed with double quotes around them, e.g. `"My app name"`. * Booleans values are printed as their raw values: `true` and `false`. * Arrays values are printed as a collection of values surrounded by square brackets, e.g. `["HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET"]`. * Empty Arrays are printed as two square brackets: `[]`. * Null or undefined values are printed as `null` or `undefined`. [debugging]: /support/debugging.html # AppSignal for Node.js configuration Source: https://docs.appsignal.com/nodejs/3.x/configuration Set the minimal required configuration for AppSignal for Node.js, see the configuration options, and configure application environments. In this section, we'll explain how to configure AppSignal, what can be configured in the Node.js package, and what the minimal configuration needed is. ## Minimal required configuration The minimal required configuration needed by AppSignal for Node.js is the following items. If they are not present, AppSignal will not send any data to AppSignal.com. * A valid Push API Key * An application name * An application environment (`development`/`production`/`test` by setting `NODE_ENV`) * The setting `active: true` The integration supports loading its configuration via options passed to the `Appsignal` constructor. We recommend creating an `appsignal.cjs` file to require and initialize AppSignal. ```javascript Node.js theme={null} // appsignal.cjs const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ active: true, name: "", pushApiKey: "", }); ``` Alternatively, you can configure the agent using system environment variables. AppSignal will automatically become active if the `APPSIGNAL_PUSH_API_KEY` environment variable is set. ```bash Bash theme={null} export APPSIGNAL_PUSH_API_KEY="" export APPSIGNAL_APP_NAME="" export APPSIGNAL_APP_ENV="production" ``` ## Configuration options Read about all the configuration options on the [options page](/nodejs/3.x/configuration/options). ## Application environments An application can have multiple environments such as "development", "test", "staging" and "production". To separate the errors and performance issues that occur in the "development" environment and those in "production", it's possible to set the environment in which the application is running with the `NODE_ENV` environment variable. If you activate AppSignal per environment, you can set the `active` property of the options you pass into the constructor conditionally: ```javascript Node.js theme={null} // appsignal.cjs const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ active: process.env.NODE_ENV !== "development", name: "", pushApiKey: "", }); ``` This will also disable AppSignal when running your tests. # AppSignal for Node.js load order Source: https://docs.appsignal.com/nodejs/3.x/configuration/load-order AppSignal for Node.js can be configured in a couple of different ways - through the `Appsignal` constructor or environment variables. The configuration is loaded in a four-step process, starting with the package defaults and ending with reading environment variables. The configuration options can be mixed without losing configuration from a different option. ## Load orders * 1. [Package defaults - `default`](#1-module-defaults) * 2. [System detected settings - `system`](#2-system-detected-settings) * 3. [Environment variables - `env`](#3-environment-variables) * 4. [`Appsignal` constructor - `initial`](#4-initial-configuration-given-to-appsignal-constructor) ## Module defaults The AppSignal module starts with loading its default configuration, setting paths and enabling certain features. The agent defaults can be found in the [configuration options documentation](/nodejs/3.x/configuration/options). ## System detected settings The package detects what kind of system it's running on and configures itself accordingly. For example, when it's running inside a container-based system (such as Docker and Heroku) it sets the configuration option `runningInContainer` to `true`. ## Environment variables AppSignal will look for its configuration in environment variables. When found these will override all given configuration options from previous steps. ```bash Bash theme={null} export APPSIGNAL_APP_NAME="my custom app name" # start your app here ``` ## Initial configuration given to `Appsignal` constructor When initializing the `Appsignal` object, you can pass in the initial configuration you want to apply. This is an `object` of any of the options described below. ```javascript Node.js theme={null} new Appsignal({ active: true, name: "", pushApiKey: "", }); ``` This step will override all given options from the defaults or system detected configuration. # Node.js package configuration options Source: https://docs.appsignal.com/nodejs/3.x/configuration/options The following list includes all configuration options with the name of the environment variable and the name of the key in the configuration file. For more information on how to configure AppSignal with a configuration file or system environment variables, see our [Configuration](/nodejs/3.x/configuration) topic. ## Available options * Required options * [`active`](#option-active) * [`environment`](#option-environment) * [`name`](#option-name) * [`pushApiKey`](#option-pushapikey) * Options * [`additionalInstrumentations`](#option-additionalinstrumentations) * [`bindAddress`](#option-bindaddress) * [`caFilePath`](#option-cafilepath) * [`cpuCount`](#option-cpucount) * [`disableDefaultInstrumentations`](#option-disabledefaultinstrumentations) * [`dnsServers`](#option-dnsservers) * [`enableHostMetrics`](#option-enablehostmetrics) * [`enableMinutelyProbes`](#option-enableminutelyprobes) * [`enableNginxMetrics`](#option-enablenginxmetrics) * [`enableOpentelemetryHttp`](#option-enableopentelemetryhttp) * [`enableStatsd`](#option-enablestatsd) * [`endpoint`](#option-endpoint) * [`filesWorldAccessible`](#option-filesworldaccessible) * [`filterParameters`](#option-filterparameters) * [`filterSessionData`](#option-filtersessiondata) * [`hostname`](#option-hostname) * [`hostRole`](#option-hostrole) * [`httpProxy`](#option-httpproxy) * [`ignoreActions`](#option-ignoreactions) * [`ignoreErrors`](#option-ignoreerrors) * [`ignoreLogs`](#option-ignorelogs) * [`ignoreNamespaces`](#option-ignorenamespaces) * [`log`](#option-log) * [`loggingEndpoint`](#option-loggingendpoint) * [`logLevel`](#option-loglevel) * [`logPath`](#option-logpath) * [`nginxPort`](#option-nginxport) * [`opentelemetryPort`](#option-opentelemetryport) * [`requestHeaders`](#option-requestheaders) * [`revision`](#option-revision) * [`runningInContainer`](#option-runningincontainer) * [`sendEnvironmentMetadata`](#option-sendenvironmentmetadata) * [`sendParams`](#option-sendparams) * [`sendSessionData`](#option-sendsessiondata) * [`statsdPort`](#option-statsdport) * [`workingDirectoryPath`](#option-workingdirectorypath) ## active | Field | Value | | - | - | | Config file key | `active` | | System environment key | `APPSIGNAL_ACTIVE` | | Required | yes | | Type | Boolean (`true` / `false`) | | Default value | `false` | ### Description Configure AppSignal to be active or not for a given environment. Most commonly used in the [file configuration](/nodejs/3.x/configuration) per environment. ## environment | Field | Value | | - | - | | Config file key | `environment` | | System environment key | `APPSIGNAL_APP_ENV` | | Required | yes | | Type | `String` | | Default value | `Read from environment variable `NODE\_ENV`, defaults to "development".` | ### Description The environment of the app to be reported to AppSignal. > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## name | Field | Value | | - | - | | Config file key | `name` | | System environment key | `APPSIGNAL_APP_NAME` | | Required | yes | | Type | `String` | | Default value | `nil` | ### Description Name of your application as it should be displayed on AppSignal.com. > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## pushApiKey | Field | Value | | - | - | | Config file key | `pushApiKey` | | System environment key | `APPSIGNAL_PUSH_API_KEY` | | Required | yes | | Type | `String` | | Default value | `null` (unset by default) | | Available since version | `2.2.5` | | |
    • `2.2.5`: Renamed from `apiKey`.
    | ### Description The organization-level authentication key to authenticate with our Push API. Read more about the [AppSignal Push API key](/appsignal/terminology#push-api-key). ## additionalInstrumentations | Field | Value | | - | - | | Config file key | `additionalInstrumentations` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `3.0.0` | ### Description List of additional OpenTelemetry instrumentations to use with AppSignal, via third-party libraries or your own integrations. ## bindAddress | Field | Value | | - | - | | Config file key | `bindAddress` | | System environment key | `APPSIGNAL_BIND_ADDRESS` | | Required | no | | Type | `String` | | Default value | `127.0.0.1` | | Available since version | `3.0.15` | ### Description A valid IPv4 address the AppSignal agent uses as a binding for its TCP and UDP servers. Use a specific address if you only want the agent to listen to requests made to that address. Set this option to `0.0.0.0` to allow to receive requests from hosts using any IP address. By default it only listens to requests made on the same host. This option is applied to all the agent servers (StatsD, OpenTelemetry and NGINX). ## caFilePath | Field | Value | | - | - | | Config file key | `caFilePath` | | System environment key | `APPSIGNAL_CA_FILE_PATH` | | Required | no | | Type | `String` | | Default value | Packaged `cacert.pem` file path. | ### Description Use this option to point to another certificate file if there's a problem connecting to our API. > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. ## cpuCount | Field | Value | | - | - | | Config file key | `cpuCount` | | System environment key | `APPSIGNAL_CPU_COUNT` | | Required | no | | Type | `Float` | | Default value | `undefined` | | Available since version | `3.3.2` | ### Description The available CPU capacity of the host, in number of CPUs. This is used to calculate the CPU usage percentage in the host metrics. If not set, the agent will attempt to automatically detect this from cgroups. The number of CPUs can be a fraction, e.g. `0.5`. ## disableDefaultInstrumentations | Field | Value | | - | - | | Config file key | `disableDefaultInstrumentations` | | System environment key | `APPSIGNAL_DISABLE_DEFAULT_INSTRUMENTATIONS` | | Required | no | | Type | `list(String)` or Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `3.0.0` | ### Description Allows you to disable the automatic instrumentation of default integrations: * @appsignal/opentelemetry-instrumentation-bullmq * @opentelemetry/instrumentation-amqplib * @opentelemetry/instrumentation-express * @opentelemetry/instrumentation-fastify * @opentelemetry/instrumentation-graphql * @opentelemetry/instrumentation-http * @opentelemetry/instrumentation-ioredis * @opentelemetry/instrumentation-knex * @opentelemetry/instrumentation-koa * @opentelemetry/instrumentation-mongodb * @opentelemetry/instrumentation-mongoose * @opentelemetry/instrumentation-mysql2 * @opentelemetry/instrumentation-mysql * @opentelemetry/instrumentation-nestjs-core * @opentelemetry/instrumentation-pg * @opentelemetry/instrumentation-redis * @opentelemetry/instrumentation-redis-4 * @opentelemetry/instrumentation-restify * @opentelemetry/instrumentation-undici * @prisma/instrumentation To disable all instrumentations, set the value to `true`. ## dnsServers | Field | Value | | - | - | | Config file key | `dnsServers` | | System environment key | `APPSIGNAL_DNS_SERVERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | ### Description Configure DNS servers for the AppSignal agent to use. ```sh Shell theme={null} # In the host environment export APPSIGNAL_DNS_SERVERS="8.8.8.8,8.8.4.4" ``` If you're affected by our [DNS timeouts](/support/known-issues/dns-timeouts), try setting a DNS server manually using this option that doesn't use more than **4** dots in the server name. * Acceptable values: `8.8.8.8`, `my.custom.local.server`. * Not acceptable values: `foo`, `my.awesome.custom.local.dns.server`. If the DNS server cannot be reached the agent will fall back on the host's DNS configuration and output a message in the `appsignal.log` file: `A problem occurred while setting DNS servers`. ## enableHostMetrics | Field | Value | | - | - | | Config file key | `enableHostMetrics` | | System environment key | `APPSIGNAL_ENABLE_HOST_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | \`\`true` / detected by system` | ### Description Set this option to `false` to disable [host metrics](/metrics/host-metrics) collection. On Heroku and Dokku host metrics are disabled by default. This is done because these systems will report inaccurate metrics from within the containers. Host metrics collection on these systems cannot be enabled. For Heroku, use the [Heroku log drain](/heroku/host-metrics) instead. ## enableMinutelyProbes | Field | Value | | - | - | | Config file key | `enableMinutelyProbes` | | System environment key | `APPSIGNAL_ENABLE_MINUTELY_PROBES` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `0.4.0` | | |
    • `2.3.0`: Support added for the environment variable option.
    • `2.3.0`: Disables the minutely probes system from reporting metrics. Before version `2.3.0` it only unregistered the default probes.
    | ### Description Enables the [minutely probes](/nodejs/3.x/instrumentation/minutely-probes) system. ## enableNginxMetrics | Field | Value | | - | - | | Config file key | `enableNginxMetrics` | | System environment key | `APPSIGNAL_ENABLE_NGINX_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `3.0.8` | ### Description Set to `true` to enable the NGINX metrics server. [See the NGINX metrics documentation for details.](/metrics/nginx) When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 27649. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## enableOpentelemetryHttp | Field | Value | | - | - | | Config file key | `enableOpentelemetryHttp` | | System environment key | `APPSIGNAL_ENABLE_OPENTELEMETRY_HTTP` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `3.1.0` | ### Description Set this option to `true` to enable the [OpenTelemetry HTTP server](/standalone-agent/installation). When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 8099. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. This is required for apps using the OpenTelemetry HTTP exporter to report data to AppSignal. ## enableStatsd | Field | Value | | - | - | | Config file key | `enableStatsd` | | System environment key | `APPSIGNAL_ENABLE_STATSD` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `2.2.2` | ### Description Enables the [StatsD server](/standalone-agent/statsd) in the AppSignal agent. When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 8125. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## endpoint | Field | Value | | - | - | | Config file key | `endpoint` | | System environment key | `APPSIGNAL_PUSH_API_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://push.appsignal.com` | ### Description Configure the endpoint to send data to AppSignal. This setting will not have to be changed. ## filesWorldAccessible | Field | Value | | - | - | | Config file key | `filesWorldAccessible` | | System environment key | `APPSIGNAL_FILES_WORLD_ACCESSIBLE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.2.4` | ### Description If this is set to `true` the [AppSignal working directory](/appsignal/how-appsignal-operates#working-directory) that is created is accessible for all users (Unix permissions `0666`). This is often necessary because processes for the same app run under a different user. Set to `false` to disable this behaviour (Unix permissions `0644`). ## filterParameters | Field | Value | | - | - | | Config file key | `filterParameters` | | System environment key | `APPSIGNAL_FILTER_PARAMETERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `2.2.5` | ### Description List of parameter keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. Read more about [parameter filtering](/application/parameter-filtering). ## filterSessionData | Field | Value | | - | - | | Config file key | `filterSessionData` | | System environment key | `APPSIGNAL_FILTER_SESSION_DATA` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `2.2.5` | ### Description List of session data keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. Read more about [session data filtering](/application/session-data-filtering). ## hostname | Field | Value | | - | - | | Config file key | `hostname` | | System environment key | `APPSIGNAL_HOSTNAME` | | Required | no | | Type | `String` | | Default value | detected from system | ### Description This overrides the server's hostname. Useful for when you're unable to set a custom hostname or when a nondescript id is generated for you on hosting services. ## hostRole | Field | Value | | - | - | | Config file key | `hostRole` | | System environment key | `APPSIGNAL_HOST_ROLE` | | Required | no | | Type | `String` | | Default value | `null` (unset by default) | | Available since version | `3.0.19` | ### Description Group hosts by role and generate metrics based on this role. One such metric is the `reporting_hosts` counter metric. A good role indicates what the main role of the server is, like "webserver", "processor", "api", "database", "loadbalancer", etc. ## httpProxy | Field | Value | | - | - | | Config file key | `httpProxy` | | System environment key | `APPSIGNAL_HTTP_PROXY` | | Required | no | | Type | `String` | | Default value | `null` (unset by default) | ### Description If you require the agent to connect to the Internet via a proxy set the complete proxy URL in this configuration key. ## ignoreActions | Field | Value | | - | - | | Config file key | `ignoreActions` | | System environment key | `APPSIGNAL_IGNORE_ACTIONS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | ### Description With this config option you can specify a list of actions that will be ignored by AppSignal. Everything that happens including exceptions will not be transmitted to AppSignal. This can be useful to ignore health check endpoints or other actions that you don't want to monitor. Read more about [ignoring actions](/guides/filter-data/ignore-actions). ## ignoreErrors | Field | Value | | - | - | | Config file key | `ignoreErrors` | | System environment key | `APPSIGNAL_IGNORE_ERRORS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | ### Description List of error classes that will be ignored. Any exception raised with this error class will not be transmitted to AppSignal. Read more about [ignoring errors](/guides/filter-data/ignore-errors). ## ignoreLogs | Field | Value | | - | - | | Config file key | `ignoreLogs` | | System environment key | `APPSIGNAL_IGNORE_LOGS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `3.4.0` | ### Description List of log messages that will be ignored. Any log message containing any of the elements of the list will not be transmitted to AppSignal. A small subset of regex syntax is supported, read more about it in our [Ignore Logs](/guides/filter-data/ignore-logs) guide. ## ignoreNamespaces | Field | Value | | - | - | | Config file key | `ignoreNamespaces` | | System environment key | `APPSIGNAL_IGNORE_NAMESPACES` | | Required | no | | Type | `list(String)` | | Default value | `[]` | ### Description List of namespaces that will be ignored. Any error raised or slow request that occurs in this namespace will not be send to AppSignal. Read more about [namespaces](/application/namespaces). ## log | Field | Value | | - | - | | Config file key | `log` | | System environment key | `APPSIGNAL_LOG` | | Required | no | | Type | `String` | | Default value | `file` | ### Description > [!NOTE] > > This option configures what logger that AppSignal's internal logging > functionality will use and does not affect the [logging feature](/logging). > > **Note**: The [AppSignal agent](/appsignal/how-appsignal-operates), > which is used by the integration, will always write to the "appsignal.log" file. Select which logger the AppSignal integration will use. Accepted values are `file` and `stdout`. See also the `log_path` configuration. * `file` (default) * Write all AppSignal logs to the file system. * `stdout` (default on [Heroku](https://heroku.com)) * Print AppSignal logs in the parent process' STDOUT instead of to a file. Useful with hosting solutions such as container systems and Heroku. ## loggingEndpoint | Field | Value | | - | - | | Config file key | `loggingEndpoint` | | System environment key | `APPSIGNAL_LOGGING_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://appsignal-endpoint.net` | | Available since version | `3.0.1` | ### Description Configure the endpoint AppSignal sends logs and check-ins to. This setting will not have to be changed. ## logLevel | Field | Value | | - | - | | Config file key | `logLevel` | | System environment key | `APPSIGNAL_LOG_LEVEL` | | Required | no | | Type | `String` | | Default value | `info` | | Available since version | `2.2.6` | ### Description > [!NOTE] > > This option sets the severity level of AppSignal's internal logger and does > not affect the [logging feature](/logging). Set the severity level of AppSignal's internal logger. If it is configured to "info" it will log all error, warning and info messages, but not log the debug messages. Setting it to the levels "debug" or "trace" is usually only needed on request from support. Setting the level to "debug"/"trace" could have a slight impact on the disk usage and IO, especially on high-traffic sites. CPU overhead is minimal with the debug option enabled. Accepted values: * error * warning * info * debug * trace ## logPath | Field | Value | | - | - | | Config file key | `logPath` | | System environment key | `APPSIGNAL_LOG_PATH` | | Required | no | | Type | `String` | | Default value | `/tmp` | ### Description > [!NOTE] > > This option configures the location of AppSignal's internal logging file and > does not affect the [logging feature](/logging). > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. Override the location of the path (directory) where the `appsignal.log` file can be written to. ## nginxPort | Field | Value | | - | - | | Config file key | `nginxPort` | | System environment key | `APPSIGNAL_NGINX_PORT` | | Required | no | | Type | `Integer` | | Default value | `27649` | | Available since version | `3.6.7` | ### Description Configure the port on which the NGINX metrics server is exposed. When AppSignal receives NGINX metrics, it listens on a `localhost`-bound server, by default on port 27649. If you're running several AppSignal-instrumented applications in the same server with NGINX metrics enabled, use this option to configure each application to listen on a different port. ## opentelemetryPort | Field | Value | | - | - | | Config file key | `opentelemetryPort` | | System environment key | `APPSIGNAL_OPENTELEMETRY_PORT` | | Required | no | | Type | `String` | | Default value | `8099` | | Available since version | `3.1.0` | ### Description Set this option to configure the OpenTelemetry HTTP server port of the AppSignal agent process. Configure this port if another process is already running on the machine that is also using this port to avoid conflicts. ## requestHeaders | Field | Value | | - | - | | Config file key | `requestHeaders` | | System environment key | `APPSIGNAL_REQUEST_HEADERS` | | Required | no | | Type | `list(String)` | | Default value | `["accept", "accept-charset", "accept-encoding", "accept-language", "cache-control", "connection", "content-length", "range"]` | | Available since version | `2.2.5` | ### Description The `requestHeaders` config option contains a list of HTTP request headers which are read and stored by the AppSignal Node.js package. This `requestHeaders` config option is an *allowlist*, which means that it will only report headers as specified by this config option. If this config option is unset it will use the AppSignal default. Following list is the AppSignal package default. ```javascript Node.js theme={null} client = Appsignal.new( // ...Other config opts requestHeaders: [ "accept", "accept-charset", "accept-encoding", "accept-language", "cache-control", "connection", "content-length", "range" ] ) ``` To configure AppSignal to not store any HTTP request headers on AppSignal transactions, configure the option with an empty list. ```javascript Node.js theme={null} client = Appsignal.new( // ...Other config opts requestHeaders: [] ) ``` ## revision | Field | Value | | - | - | | Config file key | `revision` | | System environment key | `APP_REVISION` | | Required | no | | Type | `String` | | Default value | `null` (unset by default) | | Available since version | `1.0.0` | | |
    • `3.0.16`: Auto detection for Render deploys.
    • `3.4.3`: Auto detection for Kamal deploys.
    • `3.5.3`: Auto detection for Scalingo deploys.
    • `3.9.2`: Reads the `HEROKU_BUILD_COMMIT` environment variable.
    | ### Description Set the app revision to report the currently running version of your app. AppSignal will create a deploy marker when this value changes, and tag all incoming data with the current revision. The AppSignal integration automatically detects the deployed Git commit and uses it as the revision when you deploy using the following tools or providers: * Kamal * Render * Scalingo * Heroku, when the [Heroku Labs: Dyno Metadata](https://devcenter.heroku.com/articles/dyno-metadata) feature is enabled Set the `revision` config option to override the detected revision. Use a single value without spaces, such as a Git commit SHA (`abc0123`) or a version number (`1.2.3`). AppSignal builds links to your source code from this value. Read more about [choosing a revision value](/application/markers/deploy-markers#choosing-a-revision-value). Read more about deploy markers in the [deploy markers topic](/application/markers/deploy-markers). When more than one source sets the revision, the Ruby gem uses the first one in this list that is set: 1. The `revision` config option or the `APP_REVISION` environment variable. 2. The environment variable set by Heroku (`HEROKU_BUILD_COMMIT` or `HEROKU_SLUG_COMMIT`), Render (`RENDER_GIT_COMMIT`), Kamal (`KAMAL_VERSION`), or Scalingo (`CONTAINER_VERSION`), in that order. 3. The `REVISION` file in the application's root directory. ## runningInContainer | Field | Value | | - | - | | Config file key | `runningInContainer` | | System environment key | `APPSIGNAL_RUNNING_IN_CONTAINER` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | detected by agent | ### Description AppSignal expects to be running on the same machine between different deploys. Set this key to `true` if the application is running in a container, such as with Docker. Newer versions of the AppSignal integration automatically detect its container environment, so no manual configuration is necessary. If you're having trouble with the automatic detection, please [contact support](mailto:support@appsignal.com). This option is set to `true` automatically on [Heroku](http://heroku.com/). ## sendEnvironmentMetadata | Field | Value | | - | - | | Config file key | `sendEnvironmentMetadata` | | System environment key | `APPSIGNAL_SEND_ENVIRONMENT_METADATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.2.6` | ### Description Send environment metadata about the app. For more information please read about [environment metadata](/application/environment-metadata). ## sendParams | Field | Value | | - | - | | Config file key | `sendParams` | | System environment key | `APPSIGNAL_SEND_PARAMS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.2.8` | ### Description Whether to skip sending request parameters to AppSignal. For more information please read about [send\_params](/application/parameter-filtering) in filtering request parameters. ## sendSessionData | Field | Value | | - | - | | Config file key | `sendSessionData` | | System environment key | `APPSIGNAL_SEND_SESSION_DATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `2.2.9` | ### Description Set this option to `false` to not send any session data with exception and performance traces. For more information please read about [request session data filtering](/application/session-data-filtering). ## statsdPort | Field | Value | | - | - | | Config file key | `statsdPort` | | System environment key | `APPSIGNAL_STATSD_PORT` | | Required | no | | Type | `Integer` | | Default value | `8125` | | Available since version | `3.0.16` | ### Description Set this option to configure the StatsD HTTP server port of the AppSignal agent process. Configure this port if another process is already running on the machine that is also using this port to avoid conflicts. ## workingDirectoryPath | Field | Value | | - | - | | Config file key | `workingDirectoryPath` | | System environment key | `APPSIGNAL_WORKING_DIRECTORY_PATH` | | Required | no | | Type | `String` | | Default value | detected by agent | | Available since version | `1.0.0` | ### Description Override the location where AppSignal for Node.js can store temporary files. Use this option if the default location is not suitable. See our [how AppSignal operates](/appsignal/how-appsignal-operates) page for more information about the purpose of this working directory. If you are running multiple applications using AppSignal on the same server, use this configuration option to select different working directories for every AppSignal instance, otherwise the two instances could conflict with one another. For more information on this scenario see our [running multiple applications on one host](/guides/application/multiple-applications-on-one-host) documentation. ```javascript Node.js theme={null} // Example: appsignal.js const { Appsignal } = require("@appsignal/nodejs"); const appsignal = new Appsignal({ // Other config workingDirectoryPath: "/tmp/project_1" }); ``` > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. # Installation Source: https://docs.appsignal.com/nodejs/3.x/installation Install @appsignal/nodejs with npm or pnpm, require the client before your application starts, and add integrations and TypeScript support. Please follow the [installation guide](/guides/new-application) first, when adding a new application to AppSignal. ## Requirements Before you can compile the AppSignal package, make sure the build/compilation tools are installed for your system. Please check the [Supported Operating Systems](/support/operating-systems) page for any system dependencies that may be required. ## Installation First, [sign up](https://appsignal.com/users/sign_up) for an AppSignal account. Then, install AppSignal by following the instructions for your package manager. ### Using npm ```bash Bash theme={null} npm install @appsignal/nodejs ``` It's also possible to manually add the `@appsignal/nodejs` package to your `package.json`. Then, run `npm install`. ```json JSON theme={null} { "name": "my-app", "dependencies": { "@appsignal/nodejs": "^3.0.0" } } ``` Create an `appsignal.cjs` file to require and configure AppSignal. This file may also be placed in another location, like in the `src/` directory. For more information about the configuration, see our [configuration section](/nodejs/3.x/configuration). ```javascript Node.js theme={null} // appsignal.cjs const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ active: true, name: "", pushApiKey: "", }); ``` ### Using pnpm pnpm suppresses lifecycle scripts for dependencies by default. The `@appsignal/nodejs` package relies on an `install` lifecycle script to download and compile its native extension. Without it, the extension won't load and AppSignal won't report any data. To install the package and allow its lifecycle script to run: ```bash Bash theme={null} pnpm --allow-build=@appsignal/nodejs add @appsignal/nodejs ``` ### Requiring the AppSignal client Now, you can run your application like you normally would, but use the `--require` flag to load AppSignal's instrumentation before any other library: ```shell Shell theme={null} node --require './appsignal.cjs' index.js ``` We recommend adding the `--require` flag to any script that starts your app: ```json JSON theme={null} { "scripts": { "server": "node --require ./appsignal.cjs index.js" } } ``` You can also use the `--require` flag with tools such as `ts-node` and `nodemon`. When using a wrapper CLI, such as `nest start` or `fastify start`, to start your application, use the `NODE_OPTIONS` environment variable to pass the flag to the Node.js runtime: ```sh Shell theme={null} NODE_OPTIONS='--require ./appsignal.cjs' nest start ``` > [!WARNING] > > For the AppSignal integration to work correctly, the `appsignal.cjs` file > **must** be required before any other dependencies. ### TypeScript support AppSignal is fully compatible with TypeScript. When running a compiled TypeScript application with `node`, we recommend using [the `--enable-source-maps` Node.js flag](https://nodejs.org/api/cli.html#--enable-source-maps) so that error backtraces in AppSignal refer to locations in the original TypeScript code: ```sh Shell theme={null} node --enable-source-maps --require './appsignal.cjs' dist/src/main.js ``` When using a wrapper CLI, such as `nest start` or `fastify start`, to start your application, use the `NODE_OPTIONS` environment variable to pass the flag to the Node.js runtime: ```sh Shell theme={null} NODE_OPTIONS='--enable-source-maps --require ./appsignal.cjs' nest start ``` ### Import AppSignal Client The AppSignal client is accessed from the globally exported `Appsignal.client` object. To use features like [custom metrics](/metrics/custom), you must first import the AppSignal client: ```javascript Node.js theme={null} import { Appsignal } from "@appsignal/nodejs"; // or: const { Appsignal } = require("@appsignal/nodejs"); const client = Appsignal.client; ``` ### Adding integrations AppSignal supports several libraries and frameworks with additional packages, such as Express, Koa, Next.js and more. Additional installation instructions for these packages can be found in the [Node.js integrations section](/nodejs/3.x/integrations). ## Upgrading New releases include bug and security fixes, so keep AppSignal up to date. To update to the latest version your `package.json` allows, run `npm update @appsignal/nodejs` and redeploy. To upgrade to a new major version, follow the [migration guide](/nodejs/3.x/migration-guide). *** > [!NOTE] > > 📖 Continue with our [installation guide](/guides/new-application). ## Uninstalling AppSignal for Node.js Uninstall AppSignal from your app by following the steps below. When these steps are completed your app will no longer send data to the AppSignal servers. 1. Run `npm uninstall @appsignal/nodejs` to uninstall the AppSignal for Node.js integration, or delete the line within the `dependencies` block of your application's `package.json` file referencing the `@appsignal/nodejs` package. 2. Run `npm install` to update your `package.lock` with the removed packages state. 3. Remove any AppSignal [configuration](/nodejs/3.x/configuration/) from your app. 4. Commit, deploy and restart your app. * This will make sure the AppSignal servers won't continue to receive data from your app. 5. Finally, [remove the app](/guides/application/deleting-applications) on AppSignal.com. > [!NOTE] > > 📖 Continue with our [uninstall > guide](/guides/application/deleting-applications). ## Stopping The AppSignal Client AppSignal will stop automatically when your application or machine stops running. However, if you want to stop AppSignal manually you can run the following command: ```javascript Node.js theme={null} import { Appsignal } from "@appsignal/nodejs"; // or: const { Appsignal } = require("@appsignal/nodejs"); Appsignal.client.stop(); ``` # Instrumentation Source: https://docs.appsignal.com/nodejs/3.x/instrumentation How traces and spans work in Node.js, and where to add custom instrumentation. AppSignal provides many ways to provide more insights into your application — by adding more instrumentation or tagging the data that appears in the UI at AppSignal.com. All of the information that we collect from your application forms part of a broader **trace**, a visual representation of the flow of data through your application. **Traces** are made of one or many spans. A Trace can be thought of as a *directed acyclic graph (DAG)* of spans: ![Trace diagram](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/abstract-trace.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=8e955df41909f6fadf6d607478d6badb) * [The Tracer object](/nodejs/3.x/instrumentation/instrumentation#import-opentelemetry-and-define-tracer) * [Creating and using a span](/nodejs/3.x/instrumentation/instrumentation#creating-an-active-span) * [Exception handling](/nodejs/3.x/instrumentation/exception-handling) ## Contact us Don't hesitate to [contact us](mailto:support@appsignal.com) if you run into any issues while implementing tracing. We're here to help. # Additional OpenTelemetry instrumentations Source: https://docs.appsignal.com/nodejs/3.x/instrumentation/additional-instrumentations > [!NOTE] > > 🛟 Don't hesitate to [contact us](mailto:support@appsignal.com) if you run into > any issues while implementing custom instrumentations. We're here to help! In addition to the already included instrumentations, you can also add custom ones as long as they comply with the structure of an OpenTelemetry automatic instrumentation. ## Setup Using the [`additionalInstrumentations`](/nodejs/3.x/configuration/options#option-additionalinstrumentations) config option you can add additional instrumentations that will create spans and send them to AppSignal. Below is an example of how to use `additionalInstrumentations` in your application: ```javascript Node.js theme={null} const { CustomInstrumentation, } = require("opentelemetry-custom-instrumentation"); new Appsignal({ active: true, name: "", pushApiKey: "", additionalInstrumentations: [ new CustomInstrumentation({ // instrumentation config here }), ], }); ``` # Exception handling Source: https://docs.appsignal.com/nodejs/3.x/instrumentation/exception-handling In most applications, some errors will get raised that aren't related to possible bugs in your code; they just happen when your app gets into contact with the real world, like when a bot tries to fill in a form. To avoid these errors from being raised as problems in AppSignal it's possible to add exception handling to your code or even let AppSignal completely ignore certain errors. ## Ignore errors The AppSignal configuration makes it possible to [ignore errors](/guides/filter-data/ignore-errors), by providing a list of specific error names in a denylist, AppSignal will not send alerts when these errors are raised. ## Record Exceptions To use the setError and sendError helpers you need to import them from `@appsignal/nodejs`: ```javascript Node.js theme={null} import { setError, sendError } from "@appsignal/nodejs"; ``` > [!TIP] > > The errors given as an argument to `sendError` and `setError` must be > [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)-like > values. ### Set Error If you want to catch exceptions in your application to prevent crashes, but still want to track the occurrence you can use `setError()` to add the error to your applications current active span. ```javascript Node.js theme={null} import { setError, sendError } from "@appsignal/nodejs" app.get("/kittens", (req, res) => { try { fetchAllKittens() } catch (err) { setError(err) } } ``` ### Send Error The `sendError()` function can be used to record an incident in a new root span. When using `sendError()`, the error is sent independently from the current context, so the trace for the request will not be marked as an error. Therefore it can be helpful to provide further context by using [non-child span helper functions](/nodejs/3.x/instrumentation/instrumentation#helpers). Unlike `setError()`, the `sendError()` function can be used in a context where there's no instrumentation such as a one-off script, or job queue. In the below example `setCustomData()` is used to add additional data to the error span. ```javascript Node.js theme={null} import { setError, sendError } from "@appsignal/nodejs" app.get("/kittens", (req, res) => { try { fetchAllKittens() } catch (err) { // oh no, we ran out of kittens! // let's keep a note that this happened... sendError(err, () => { setCustomData({ message: "We ran out of kittens!" }) }) // ...and go adopt some more! adoptMoreKittens() } } ``` The exception will be tracked by AppSignal like any other error, and it allows you to provide custom error handling and fallbacks. # Custom instrumentation for Node.js Source: https://docs.appsignal.com/nodejs/3.x/instrumentation/instrumentation Create spans with an OpenTelemetry tracer in Node.js, and set namespaces, tags, parameters, and session data with AppSignal helpers. > [!NOTE] > > 🛟 Don't hesitate to [contact us](mailto:support@appsignal.com) if you run into > any issues while implementing custom instrumentations. We're here to help! Including custom instrumentation in your application can be useful for identifying the specific lines of code causing performance problems. AppSignal provides [helpers](#helpers), which let you display relevant data about the state of your application alongside performance metrics to assist you in identifying the root causes of any performance problems your application may be experiencing. ## Setup To use AppSignal's helper functions in your instrumentation, you must first [import `opentelemetry` and define a tracer object](#import-opentelemetry-and-define-tracer). Depending on your instrumentation, you may also need to [create additional spans](#spans). Our [Example Use Cases](#example-use-cases) demonstrate how you can use tracers, spans, and helpers to create your custom instrumentation. ### Import OpenTelemetry and Define Tracer The AppSignal integration for Node.js uses OpenTelemetry tracer objects. These tracers contain various functions for creating custom instrumentations. The Tracer exposes functions for creating and creating new spans. This documentation will outline how you can use tracers and spans to implement your custom integration. You must first import the trace object from `@opentelemetry/api` before working with tracers and spans. By invoking the `getTracer` function on the trace object a new tracer object can be created. You must give your tracer object a name in this function, as seen in the example below, where the `getTracer` function is used to define a tracer with the name `"my interesting app"`. ```javascript Node.js theme={null} import { trace } from "@opentelemetry/api"; const tracer = trace.getTracer("my-interesting-app"); ``` ### Spans A span is the name of the object that we use to capture data about the performance of your application, any errors and any surrounding context. A span forms part of a broader trace, a hierarchical representation of the flow of data through your application. Spans keep track of the start and end time of an event, along with other information, such as the name or other data related to it. You can read more about spans in the [OpenTelemetry Tracing Documentation](https://opentelemetry.io/docs/instrumentation/js/api/tracing/). ### Creating an Active Span New spans can be invoked via the [trace object](#import-opentelemetry-and-define-tracer). Code instrumented inside an Express of Koa handler will already be inside a span. You can create new spans by invoking the`startActiveSpan()` function on the tracer object. Newly created spans will be the child of the span they were created in, if one exists. You can use child spans to measure the performance of tasks executed from within a parent span. You should give your span a name that makes its purpose clear. Execute all of the tasks you wish to monitor within the `startActiveSpan()` function, like in the below example. ```javascript Node.js theme={null} tracer.startActiveSpan("printing coffee beans", async (span) => { const coffeeBeans = await fetchAllCoffeeBeans(); console.log(coffeeBeans); span.end(); }); ``` After the task is complete, you must close the span: `span.end()` ### Example Use Cases When implementing custom instrumentation, you may be curious to understand the behavior of particular functions, for example, how long it takes for them to execute. #### Using Helpers In the below example, we are curious about the performance of our "order-coffee" GET endpoint for different roasts of coffee. To investigate this, we use the `setAttribute` function to create a [tag](#tag) called flavor, the value we retrieve from request parameters. **Note:** Because this is inside an Express request handler, a root span has already been created. ```javascript Node.js theme={null} app.get('/order-coffee', (req, res) => { const roast = req.params.roast setTag("roast", roast) const coffeeBeans = pickCoffeeBeans(roast) prepareCoffeeBag(coffeeBeans) }) } ``` To get deeper insights into how our code is performing, we can use child spans to inspect functions called within our Express handler. The code below creates a child span of the `"picking coffee beans"` span defined in the `pickCoffeeBeans` function. Once the attribute has been assigned and all functions executed, we `.end()` the span to ensure AppSignal receives the start and finish time and attributes we've assigned: ```javascript Node.js theme={null} function pickCoffeeBeans(roast) { tracer.startActiveSpan("picking coffee beans", async (span) => { const roastBrands = { light: "Caffinated Cloud", medium: "Feeling The Buzz", dark: "The Jitters", }; const roastBrand = roastBrands[roast]; setTag("brand", roastBrand); await retrieveDrinkTypes(roastBrand); span.end(); }); } ``` In AppSignal, we can see performance data for this function. We can use the roast and batch tags to filter the data and gain greater insights into what parameters potentially influence how our application's code behaves. ![Screen shot of tags](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/node-instrumentation-sample.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=4afd1219ca91a383ca1519c779eca87b) #### Active Spans While tags are helpful to analyse performance differences on the same function, it does not give us insight into the performance of any functions called from within our function. To give us greater insights into what's happening inside of the `pickCoffeeBeans()`, we create a new `activeSpan` and name it "picking coffee beans". All logic we wish to track is executed from within an async function. We `await` the promise returned by `retrieveDrinkTypes()`, so that we can track it's performance as a child span of the `"picking coffee beans"` span we created in `pickCoffeeBeans()`. ```javascript Node.js theme={null} function pickCoffeeBeans(roast) { tracer.startActiveSpan("picking coffee beans", async (span) => { const roastBrands = { light: "Caffinated Cloud", medium: "Feeling The Buzz", dark: "The Jitters", }; const roastBrand = roastBrands[roast]; await retrieveDrinkTypes(roastBrand); span.end(); }); } function retrieveDrinkTypes(roastBrand) { return new Promise((resolve) => { const span = tracer.startActiveSpan("Fetching coffee types"); const brandDrinks = { "Caffinated Cloud": ["americano", "capuccino"], "Feeling The Buzz": ["capuccino", "latte"], "The Jitters": ["espresso"], }; const drinkTypes = brandDrinks[roastBrand]; // we want to give our Barista's some time prepare the machine setTimeout(() => { resolve(drinkTypes); span.end(); }, 60000); }); } ``` With this instrumentation, AppSignal will provide insights into the performance of the `pickCoffeeBeans()`, which will include the performance data of the `retrieveDrinkTypes()` function, providing greater insight into what factors are impacting the overall performance of a function. ## Helpers > [!WARNING] > > Data sent to AppSignal must not contain any personal data, such as names, > email addresses, etc. It is your responsibility to ensure that your > application's data is sanatized before being forwarded to AppSignal. When > identifying a person is necessary your application must use alternative forms > of identification such as a user ID, hash, or pseudonym. To use helper functions, you must first import them from `@appsignal/nodejs`. In the example below the namespace the code is being executed in is being reported to AppSignal. All available helper functions are outlined in the [below documentation](#helper-functions). ```javascript Node.js theme={null} import { setNamespace } from "@appsignal/nodejs"; setNamespace("web"); ``` All available helper functions for custom instrumentation attributes are outlined in the [list below](#helper-functions). ### Helper Functions > [!TIP] > > The code snippets for the helpers below assume your code is already being > instrumented (for example, inside an Express or Koa request handler). If your > code is not already instrumented, you must [create a span](#spans) and use the > helpers inside of it. * [Namespace](#namespace) * [Tag](#tag) * [Request Parameters](#request-parameters) * [Set Session Data](#set-session-data) * [Request Headers](#request-headers) * [Root Name](#root-name) * [Custom Data](#custom-data) * **[Child Span Helpers:](#child-span-helpers)** * [Category](#category) * [Name](#name) * [Body](#body) ### Namespace Sets the string value of the root span namespace. ```javascript JavaScript theme={null} import { setNamespace } from "@appsignal/nodejs"; setNamespace("app"); ``` ### Tag Sets a tag, for example from a request parameter, which can be used as a filter from within the AppSignal application. In the below example we create a tag called color with the value blue. You can configure tags with names relevant to the context of your application. ```javascript Node.js theme={null} import { setTag } from "@appsignal/nodejs"; setTag("color", "blue"); ``` ### Request Parameters An object that is serializable to JSON. Incoming request parameters request body and query parameters. ```javascript Node.js theme={null} import { setParams } from "@appsignal/nodejs"; const exampleParams = { action: "delete" }; setParams(exampleParams); ``` ### Set Session Data An object that is serializable to JSON. ```javascript Node.js theme={null} import { setSessionData } from "@appsignal/nodejs"; const exampleSessionData = { locale: "en-GB" }; setSessionData(exampleSessionData); ``` ### Request Headers A string containing the header value. ```javascript Node.js theme={null} import { setHeader } from "@appsignal/nodejs"; setHeader("Content-type", "application/json"); ``` ### Root Name Allows you to set the name of the trace. Traces are grouped into actions by their trace name. ```javascript Node.js theme={null} import { setRootName } from "@appsignal/nodejs"; // somewhere in your code where there's an active span... setRootName("The action name"); ``` #### Example Use Case Your application has an endpoint called `GET /coffee`. ```javascript Node.js theme={null} app.get("/coffee", (req, res) => { // ... }); ``` All requests to this endpoint will generate traces called `GET /coffee`, but your endpoint handles multiple actions: `coffee?action=buy`, and `coffee?action=sell`. ![Span Without Root Name](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/span-without-root-name.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=c17dd17713da423bac8d380df6274a1e) While they all use the `GET /coffee` endpoint, they are conceptually very different and so it would make sense for them to be grouped separately in AppSignal rather than in the same `GET /coffee` trace. To do this, you can use the `setRootName()` helper: ```javascript Node.js theme={null} import { setRootName } from "@appsignal/nodejs"; app.get("/coffee", (req, res) => { if (req.query.action === "buy") { setRootName("Buy coffee"); // ... buy coffee } else if (req.query.action === "sell") { setRootName("Sell coffee"); // ... sell coffee } }); ``` Using `setRootName` will change the name of the root span, grouping the traces for the requests `coffee?action=buy` and `coffee?action=sell` into separate actions: ![Root Name Span](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/root-name-span.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=2d6521845df3d5bcd8938900b4b643ac) ### Custom Data An object that is serializable to JSON. ```javascript Node.js theme={null} import { setCustomData } from "@appsignal/nodejs"; const exampleCustomData = { stroopwaffle: "true", coffee: "false" }; setCustomData(exampleCustomData); ``` ### Child Span Helpers The following helpers only apply to child spans. To create a child span, you must create a new [Active Span](#creating-an-active-span). New spans are automatically children of their parent span. #### Category A string containing the child span category. The name should use `.` to express the category's hierarchical inheritance. For example: `cafe.coffee.cupsize` ```javascript Node.js theme={null} import { setCategory } from "@appsignal/nodejs"; setCategory("category.name"); ``` #### Name A string containing the child span event timeline title. ```javascript Node.js theme={null} import { setName } from "@appsignal/nodejs"; setName("Users query"); ``` #### Body > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). The span's body can include additional information about the event, like the HTTP request, the connected host, etc. Be sure to sanitize the information before adding it to the span so no Personal Identifiable Information is sent to AppSignal. This information will be visible for the span when hovering over the event timeline. To store SQL queries in the span's body, please use the [`setSqlBody` helper](#sql-body) instead. ```javascript Node.js theme={null} import { setBody } from "@appsignal/nodejs"; setBody("Span body"); ``` #### SQL body > [!TIP] > > Available since Node.js package 3.0.25. Set a SQL query as the body of the span as it appears in the performance event timeline in the incident trace detail view. This is similar to the [`setBody` helper](#body), but is specialized for SQL queries. Any SQL query set as the body with this attribute will be sanitized to avoid sending PII (Personal Identifiable Information) data to our servers. See the [`setBody` helper](#body) for more details on how the body attribute works. When both the `setBody` and `setSqlBody` helpers are called on the same span, the `setSqlBody` helper's value is leading and the `setBody` helper's value will be ignored. ```javascript Node.js theme={null} import { setSqlBody } from "@appsignal/nodejs"; setSqlBody("SELECT * FROM users"); ``` # Minutely probes Source: https://docs.appsignal.com/nodejs/3.x/instrumentation/minutely-probes Minutely probes are a mechanism to periodically send custom metrics to AppSignal. In minutely intervals from when the probe was first created, a user-defined function can be called in which you can capture metrics to send them to AppSignal. Minutely probe functions are ran asynchronously. Starting with version `2.3.0`, you can enable or disable minutely probes entirely with the [`enableMinutelyProbes`](/nodejs/3.x/configuration/options#option-enableminutelyprobes) config option. ## Creating probes If you need to track custom metrics from your app, you can add your own probe(s). To register a probe, you must call the `probes.register()` method with two arguments: a probe name, and an anonymous function to be called once every minute. ```javascript Node.js theme={null} const meter = appsignal.metrics(); const probes = meter.probes(); // the callback is fired once every minute from when // `register` is called probes.register("database", () => { meter.setGauge("database_size", 10); }); ``` To ensure all minutely probes are ran in a timely manner, it is important to avoid blocking the event loop for long periods inside a minutely probe callback. ## Overriding default probes By default, `@appsignal/nodejs` configures a minutely probe which keeps track of Node.js V8 heap statistics. To disable this probe, use `probes.unregister()`: ```javascript Node.js theme={null} const probes = appsignal.metrics().probes(); probes.unregister("v8_stats"); ``` Before version `2.3.0`, `probes.unregister()` is not available. In versions before `2.3.0`, you can use the [`enableMinutelyProbes`](/nodejs/3.x/configuration/options#option-enableminutelyprobes) config option to disable the default probe. # Node.js Integrations Source: https://docs.appsignal.com/nodejs/3.x/integrations Node.js frameworks and libraries AppSignal instruments automatically, including Express, Fastify, NestJS, Next.js, Prisma, PostgreSQL, Redis, and BullMQ. > [!NOTE] > > 🛟 Don't hesitate to [contact us](mailto:support@appsignal.com) if you run into > any issues with AppSignal's Node.js integrations. We're here to help! AppSignal works with many popular Node.js frameworks and libraries out-of-the-box, such as: * [Node.js Core](/nodejs/3.x/integrations/core) * [Apollo Gateway](/nodejs/3.x/integrations/apollo-gateway) * [BullMQ](/nodejs/3.x/integrations/bullmq) * [Elasticsearch](/nodejs/3.x/integrations/elasticsearch) * [Express](/nodejs/3.x/integrations/express) * [Fastify](/nodejs/3.x/integrations/fastify) * [GraphQL (such as Apollo Server or Yoga)](/nodejs/3.x/integrations/graphql) * [Knex.js](/nodejs/3.x/integrations/knexjs) * [Koa.js](/nodejs/3.x/integrations/koajs) * [MongoDB](/nodejs/3.x/integrations/mongo) * [Mongoose](/nodejs/3.x/integrations/mongoose) * [MySQL (mysql and mysql2 packages)](/nodejs/3.x/integrations/mysql) * [NestJS](/nodejs/3.x/integrations/nestjs) * [Next.js](/nodejs/3.x/integrations/nextjs) * [PostgreSQL](/nodejs/3.x/integrations/pg) * [Prisma](/nodejs/3.x/integrations/prisma) * [Redis (redis and ioredis packages)](/nodejs/3.x/integrations/redis) * [Remix](/nodejs/3.x/integrations/remix) * [Restify](/nodejs/3.x/integrations/restify) More integrations and plugins are being added all the time! Check our [issues page on GitHub](https://github.com/appsignal/appsignal-nodejs/issues) to see if we're working on something for your chosen framework or library. > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). # amqplib Source: https://docs.appsignal.com/nodejs/3.x/integrations/amqplib Advanced Message Queuing Protocol (AMQP) is an open standard protocol that facilitates messaging interoperability across systems, regardless of the message broker vendor or platform they utilize, for example between STOMP and MQTT brokers. The AppSignal for Node.js integration for [amqplib](https://www.npmjs.com/package/amqplib) and compatible packages such as [Rascal](https://www.npmjs.com/package/rascal) allows you to instrument the sending and receiving of messages in your application. ## Installation The amqplib package is instrumented automatically by the AppSignal for Node.js package. ## Features When using the amqplib integration, AppSignal will create a child span for each message that is sent or received. Note that if the messages are received/sent outside of an instrumented context, such as a web request or background job, it's required to manually create a span to wrap the message processing. Below is an example for Rascal using the simplest example found on their repository, with manual instrumentation added to wrap the message processing in a span. ```javascript Node.js theme={null} let Rascal = require("../.."); let config = require("./config"); const trace = require("@opentelemetry/api"); const tracer = trace.getTracer("example-tracer"); Rascal.Broker.create(Rascal.withDefaultConfig(config), function (err, broker) { if (err) throw err; broker.subscribe("demo_sub", function (err, subscription) { if (err) throw err; subscription.on("message", function (message, content, ackOrNack) { tracer.startActiveSpan("received message demo_sub", (span) => { // Process the message ackOrNack(); span.end(); }); }); }); broker.on("error", console.error); setInterval(function () { broker.publish( "demo_pub", new Date().toISOString() + ": hello world", function (err, publication) { tracer.startActiveSpan("sent message demo_pub", (span) => { if (err) throw err; span.end(); }); } ); }, 1000); }); ``` For more information about manual instrumentation, see the [custom instrumentation guide](/nodejs/3.x/instrumentation/instrumentation). # Apollo Gateway Source: https://docs.appsignal.com/nodejs/3.x/integrations/apollo-gateway ## Installation and usage To use the Apollo Gateway instrumentation, you need to disable the GraphQL instrumentation in the service that acts as the gateway. This is because the gateway will send its own spans using the `@apollo/gateway` OpenTelemetry instrumentation for the queries it proxies to the services that implements in the supergraph. To do so, you can use the `disableInstrumentations` option in the `appsignal` configuration. ```javascript Node.js theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ active: true, name: "your-app-name", pushApiKey: "your-push-api-key", disableDefaultInstrumentations: ["@opentelemetry/instrumentation-graphql"], }); ``` You also need to enable the OpenTelemetry instrumentation in your Apollo Gateway config: ```javascript Node.js theme={null} const config = { telemetry: { includeDocument: true, reportExceptions: 1, }, }; ``` ## Features The Apollo Gateway instrumentation will send root spans to AppSignal based on the queries it receives and routes to the subgraphs. You will be able to inspect this data in the Event timeline of performance issues: ![Screenshot of Event timeline showing gateway.request events](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/instrumentations/apollo-gateway/even-timeline.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=290983db8ccb4930894eeec2fe6de9ee) If your federated services are also instrumented with AppSignal, you'll get the usual GraphQL spans for them as well. # BullMQ Source: https://docs.appsignal.com/nodejs/3.x/integrations/bullmq BullMQ is a Node.js job queue library backed by Redis. The AppSignal for Node.js integration for [BullMQ](https://bullmq.io/) instruments the enqueueing and processing in your application. ## Installation For BullMQ versions 5 and below, the BullMQ package is instrumented automatically by the AppSignal for Node.js package. For BullMQ version 6, see the installation and configuration instructions in the following section. If you run your workers as separate processes, make sure to also use `node --require appsignal.cjs ...` when starting the worker processes, so that AppSignal can instrument the workers' job processing. ### BullMQ 6 installation and configuration BullMQ version 6 is not instrumented automatically. It reports through BullMQ's own telemetry instead, which requires installing the `bullmq-otel` package: ```bash Bash theme={null} npm install bullmq-otel ``` Pass a `BullMQOtel` instance as the `telemetry` option to each queue and worker: ```javascript Node.js theme={null} const { Queue, Worker } = require("bullmq"); const { BullMQOtel } = require("bullmq-otel"); const telemetry = new BullMQOtel(); const queue = new Queue("my-queue", { connection, telemetry }); const worker = new Worker("my-queue", processor, { connection, telemetry }); ``` Do not set the `tracerName` option when initializing `BullMQOtel`. AppSignal identifies these spans by their instrumentation scope, which must be `bullmq`. See [BullMQ's telemetry documentation](https://docs.bullmq.io/guide/telemetry) for more information. ## Features When using the BullMQ integration, AppSignal will create a performance trace for each job that is processed by a worker. When a job is enqueued in an instrumented context, such as a web request or background job, AppSignal will display an event in the performance trace's event timeline representing the job enqueueing. # Node.js Core Source: https://docs.appsignal.com/nodejs/3.x/integrations/core > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). Node.js contains several internal modules designed to enable asynchronous I/O capable APIs for your application. AppSignal provides automatic instrumentation for many of these modules. ## `http` and `https` instrumentation AppSignal for Node.js will auto-instrument any incoming and outgoing HTTP(S) requests. Incoming requests will appear as the root span of a trace, while outgoing requests will appear as child spans of an incoming request root span. For incoming requests to be instrumented in detail, you must use a supported web framework such as [Express](/nodejs/3.x/integrations/express), [Koa.js](/nodejs/3.x/integrations/koajs) or [NestJS](/nodejs/3.x/integrations/nestjs). ## Heap statistics minutely probe By default, Appsignal for Node.js will register a minutely probe that keeps track of the V8 engine's heap statistics. Once we detect these metrics we'll add an [Intelligence dashboard](/metrics/intelligence-dashboards) to your app. The metrics reported by this method correspond to those reported by the `v8.getHeapStatistics` method in the Node.js standard library. For more details on how to interpret these metrics, [see the official Node.js documentation on the `v8` module](https://nodejs.org/api/v8.html#v8getheapstatistics). The probe will report the following metrics grouped by `hostname` tag: * `nodejs_total_heap_size` - gauge * `nodejs_total_heap_size_executable` - gauge * `nodejs_total_physical_size` - gauge * `nodejs_used_heap_size` - gauge * `nodejs_malloced_memory` - gauge * `nodejs_number_of_native_contexts` - gauge * `nodejs_number_of_detached_contexts` - gauge The Node.js Heap Statistics Intelligence dashboard has the following graphs: * **Heap**: total heap size, executable heap size, used heap size, total physical size, and malloced memory. * **Native Contexts**: the number of top-level contexts currently active. An increase over time indicates a memory leak. * **Detached Contexts**: the number of contexts that were detached and not yet garbage collected. A non-zero value indicates a potential memory leak. # Elasticsearch Source: https://docs.appsignal.com/nodejs/3.x/integrations/elasticsearch [Elasticsearch](https://www.elastic.co/elasticsearch) is a popular search and analytics engine. The AppSignal for Node.js integration for Elasticsearch provides automatic instrumentation for the [Elasticsearch Node.js client](https://github.com/elastic/elasticsearch-js). ## Installation The Elasticsearch Node.js client includes instrumentation via OpenTelemetry. It will automatically report data to the AppSignal for Node.js package. No additional setup is required to instrument Elasticsearch in your application. ## Features The built-in instrumentation captures spans for search queries, index operations, and other interactions with your Elasticsearch cluster. The integration will send AppSignal spans representing the execution time of each Elasticsearch API call with information about the operation. ## Configuration > [!WARNING] > > The automatic instrumentation can be disabled starting from version `9.x` of `@elastic/elasticsearch`. > If you are using version `8.x` of `@elastic/elasticsearch` make sure you are using `@elastic/transport` version `8.10.0` or higher. You can disable the instrumentation of Elasticsearch by: * setting an environment variable; ```bash Shell theme={null} OTEL_ELASTICSEARCH_ENABLED=false ``` * using a custom `Transport`. ```typescript title="app.ts" theme={null} import { Transport, TransportRequestOptions, TransportRequestParams, } from "@elastic/transport"; class CustomTransport extends Transport { async request( params: TransportRequestParams, options: TransportRequestOptions = {}, ): Promise { options.openTelemetry = { enabled: false }; return super.request(params, options); } } const client = new Client({ /* your client config... */ Transport: CustomTransport, }); ``` You can also leave the instrumentation enabled and **disable it for a single API call** by passing a custom `TransportRequestOptions` object as the second argument to any API call: ```typescript TypeScript theme={null} const response = await client.search({ ... }, { openTelemetry: { enabled: false }, }); ``` # Express Source: https://docs.appsignal.com/nodejs/3.x/integrations/express > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for [Express](https://expressjs.com/). ## Installation Express is instrumented automatically by the AppSignal for Node.js package. In order for errors occurring in your Express application to be forwarded to AppSignal, follow the instructions below to setup the error handler middleware. ## Error Handler The module contains middleware to send any errors that take place in your Express application to AppSignal. ```javascript Node.js theme={null} import { expressErrorHandler } from "@appsignal/nodejs"; // or: const { expressErrorHandler } = require("@appsignal/nodejs"); const app = express(); // add this after all routes, but before any other error handlers app.use(expressErrorHandler()); ``` > [!TIP] > > Only exceptions with status code 500 and above will be reported to AppSignal > automatically. To send exceptions to AppSignal with other status codes, you > can use [custom exception > handling](/nodejs/3.x/instrumentation/exception-handling). ## Features The Express integration will send AppSignal a child span representing the execution time of each middleware, as well as a child span for the request handler. The integration will use the request route as the name of the action. Request query parameters will be sent. The request body will be sent if `req.body` is present (for example, when using a body parsing middleware such as `body-parser`) The request cookies will be sent if `req.cookies` is present (for example, when using a cookie parsing middleware such as `cookie-parser`) When using the error handler middleware, any errors raised by the request handler or any of the middlewares will be reported to AppSignal. # Fastify Source: https://docs.appsignal.com/nodejs/3.x/integrations/fastify > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for Fastify. ## Installation Fastify is automatically instrumented by the AppSignal for Node.js package. To initialize the AppSignal client, you should require the `appsignal.cjs` file before your application starts loading. When calling `fastify start` directly, you can use the `NODE_OPTIONS` environment variable to require it: ```bash Bash theme={null} NODE_OPTIONS='--require ./appsignal.cjs' fastify start [...] ``` The start script references the `appsignal.cjs` file that was created [when configuring AppSignal](/nodejs/3.x/configuration#minimal-required-configuration). ## Features The Fastify integration will send AppSignal a child span representing the execution time of each component used during a web request. The integration will use the request route as the name of the action. Query params and request body are set as span attributes. Errors are automatically tracked. # GraphQL Source: https://docs.appsignal.com/nodejs/3.x/integrations/graphql > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for GraphQL, using the [`graphql`](https://www.npmjs.com/package/graphql) package. This instrumentation will also work with any library that depends on the `graphql` package, such as [Apollo Server](https://www.apollographql.com/) or [Yoga](https://www.the-guild.dev/graphql/yoga-server). ## Installation and usage GraphQL is instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument GraphQL in your application. ## Features The GraphQL integration will send AppSignal child spans representing the parsing, validation, execution and resolution of the query. The span for the execution step will contain the GraphQL query. Any errors that occur when validating the query will be reported to AppSignal. # Knex.js Source: https://docs.appsignal.com/nodejs/3.x/integrations/knexjs > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for [Knex.js](https://knexjs.org/). This instrumentation will also work with any library that depends on the `knex` package, such as [Bookshelf.js](https://bookshelfjs.org/). ## Installation Knex.js is instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument your Knex.js application. ## Features The Knex.js integration will record a child span representing the execution time of each query and containing the SQL query sanitized. # Koa.js Source: https://docs.appsignal.com/nodejs/3.x/integrations/koajs > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for [Koa.js](https://koajs.com/) (`koa`) v2.0.0+. ## Installation Koa.js is instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument your Koa.js application. ## Features The Koa.js integration will send AppSignal a child span representing the execution time of each middleware, as well as a child span for the request handler. If using [`@koa/router`](https://www.npmjs.com/package/@koa/router), the integration will use the request route as the name of the action. Request query parameters will be sent. Any errors raised by the request handler or any of the middlewares will be reported to AppSignal. # MongoDB Source: https://docs.appsignal.com/nodejs/3.x/integrations/mongo > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for MongoDB v3.3+. ## Installation The MongoDB client library is instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument MongoDB in your application. ## Features The MongoDB integration will send AppSignal a child span for each operation performed. The child span represents the duration of the query, and the name of the span contains the name of the collection queried and the operation that was performed. The body of the span contains a sanitised representation of the MongoDB query. # Mongoose Source: https://docs.appsignal.com/nodejs/3.x/integrations/mongoose > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for Mongoose. ## Installation The Mongoose client library is instrumented automatically by the AppSignal for Node.js package. You do not need to perform any additional setup to instrument Mongoose in your application. ## Features The Mongoose integration will send AppSignal a child span for each operation performed against a model. The child span represents the duration of the query, and the name of the span contains the name of the model used and the operation that was performed on that model. # MySQL Source: https://docs.appsignal.com/nodejs/3.x/integrations/mysql > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for MySQL, using the [`mysql`](https://www.npmjs.com/package/mysql) and [`mysql2`](https://www.npmjs.com/package/mysql2) packages. ## Installation The MySQL client library is instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument MySQL in your application. ## Features The MySQL integration will send AppSignal a child span for each query. The child span represents the duration of the query and contains the SQL query sanitized. This instrumentation will also work with any library that depends on the `mysql` or `mysql2` packages as its database adapter, such as [Knex](https://github.com/knex/knex) or [TypeORM](https://github.com/typeorm/typeorm). # NestJS Source: https://docs.appsignal.com/nodejs/3.x/integrations/nestjs > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for [NestJS](https://nestjs.com/). ## Installation NestJS is instrumented automatically by the AppSignal for Node.js package. When calling `nest start` directly, you can use the `NODE_OPTIONS` environment variable to require it: ```bash Bash theme={null} NODE_OPTIONS='--require ./appsignal.cjs' nest start ``` The start script references the `appsignal.cjs` file that was created [when configuring AppSignal](/nodejs/3.x/configuration#minimal-required-configuration). To use AppSignal from the `npm` commands generated when creating an application with the `nest new` command, modify the following scripts from the `scripts` section of your `package.json` file as follows: ```json JSON theme={null} { "scripts": { "start": "NODE_OPTIONS='--require ./appsignal.cjs' nest start", "start:dev": "NODE_OPTIONS='--require ./appsignal.cjs' nest start --watch", "start:debug": "NODE_OPTIONS='--require ./appsignal.cjs' nest start --debug --watch", "start:prod": "node --require ./appsignal.cjs dist/main" } } ``` ## Features The NestJS integration will send AppSignal a child span representing the execution time of each middleware, as well as a child span for the request handler. The name of the controller class and method that handled the request will be used as the name of the action. Any errors raised by your NestJS application will be reported to AppSignal. # Next.js Source: https://docs.appsignal.com/nodejs/3.x/integrations/nextjs The AppSignal integration for [Next.js](https://nextjs.org/). To report both back-end traces and front-end errors, it is recommended to use `@appsignal/nodejs` in combination with [`@appsignal/javascript`](/front-end) and [`@appsignal/react`](/front-end/integrations/react) on the client-side for full-stack performance monitoring and error tracking. > [!TIP] > > Due to technical limitations of the AppSignal agent, it is not possible to use > `@appsignal/nodejs` on Vercel's serverless environment. We recommend using our > [Vercel log drain](/vercel/logs) and our [front-end > JavaScript](/front-end) and [React](/front-end/integrations/react) > packages instead. ## Installation First, follow the [`@appsignal/nodejs` installation instructions](/nodejs/3.x/installation). Then, modify your Next project's `next.config.js` configuration file in order to enable instrumentation hooks: If you are using Next 15: ```javascript JavaScript theme={null} const nextConfig = { serverExternalPackages: ["@appsignal/nodejs"], }; ``` If you are using Next 13 or 14: ```javascript JavaScript theme={null} const nextConfig = { // Add the `experimental` object if not present experimental: { // Add the following lines inside the object instrumentationHook: true, serverComponentsExternalPackages: ["@appsignal/nodejs"], }, }; ``` Then, add the following file to the root of your Next.js project as `instrumentation.js`: > [!TIP] > > If your project has an `src` directory, then the `instrumentation.js` file should be placed in that directory. > > If your project is using the [Next.js App Router](https://nextjs.org/docs/app/building-your-application/routing/defining-routes), the file should not be placed inside the `app` folder, but in the folder that contains the `app` folder. ```javascript JavaScript theme={null} export function register() { if (process.env.NEXT_RUNTIME === "nodejs") { require("./appsignal.cjs"); } } ``` The instrumentation hook file references the `appsignal.cjs` file that was created [when configuring AppSignal](/nodejs/3.x/configuration#minimal-required-configuration). Make sure that the `appsignal.cjs` file is in the same folder as the `instrumentation.js` file, or adjust the path of the `require` in the `instrumentation.js` file accordingly. Finally, modify your `appsignal.cjs` configuration file in order to disable the HTTP instrumentation, which would otherwise generate redundant traces: ```javascript JavaScript theme={null} const { Appsignal } = require("@appsignal/nodejs"); new Appsignal({ // Add the `disableDefaultInstrumentations` list if not present disableDefaultInstrumentations: [ // Add the following line inside the list "@opentelemetry/instrumentation-http", ], }); ``` ### TypeScript support When using TypeScript, the backtraces emitted by server-side Next.js errors will refer to the compiled JavaScript files. Follow these steps to configure Next.js so that the backtraces refer to the original TypeScript code. First, configure Next.js to emit source maps by adding the following lines to your application's `next.config.js` file: ```javascript JavaScript theme={null} const nextConfig = { // Add the `webpack` function if not present webpack: (config, { isServer }) => { // Add the following lines inside the function if (isServer) { config.devtool = "eval-source-map"; } return config; }, }; ``` Then, in your `package.json`, modify how your Next.js application is started when running `npm run start`, using the `NODE_OPTIONS` environment variable to pass the `--enable-source-maps` flag to the Node.js runtime: ```json JSON theme={null} { "scripts": { // Modify the `start` script as follows "start": "NODE_OPTIONS=--enable-source-maps next start" } } ``` Finally, if using the `@appsignal/javascript` front-end integration package to track client-side errors, add the `productionBrowserSourceMaps` option to the `next.config.js` file for Next.js to emit public source maps: ```javascript JavaScript theme={null} const nextConfig = { // Add the `productionBrowserSourceMaps` flag productionBrowserSourceMaps: true, }; ``` ## Features The Next.js integration will send AppSignal a performance trace for each request. Within each trace, the event timeline will show events, along with their duration, corresponding to: * Rendering the document * Running the `getServerSideProps` function *(pages router only)* * Running the route handler * Performing HTTP requests using Next.js' server-side `fetch` *(app router only)* ## Standalone output No data may be reported when Next.js is configured with `output: "standalone"` in `next.config.js`. When Next.js optimizes its app size to only include what is used by the app, it omits the AppSignal extension and agent, which report the data to our servers. When using the [Next.js "with-docker" starter](https://github.com/vercel/next.js/tree/canary/examples/with-docker), specifically the [Dockerfile](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile), a modification is required to make sure the AppSignal extension and agent are included in the production Docker image. Add the following line to your `Dockerfile`, after similar `COPY` lines near the end of the file: ```docker Dockerfile theme={null} # Dockerfile COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@appsignal/nodejs ./node_modules/@appsignal/nodejs ``` The change in Git will look something like this, but your Dockerfile may be slightly different: ```diff Diff theme={null} --- Dockerfile +++ Dockerfile @@ -48,6 +48,7 @@ COPY --from=builder /app/public ./public # https://nextjs.org/docs/advanced-features/output-file-tracing COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@appsignal/nodejs ./node_modules/@appsignal/nodejs USER nextjs ``` # PostgreSQL client Source: https://docs.appsignal.com/nodejs/3.x/integrations/pg > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for PostgreSQL, using the [`pg` package](https://www.npmjs.com/package/pg). ## Installation The PostgreSQL client is instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument PostgreSQL in your application. ## Features The PostgreSQL integration will send AppSignal a child span for each query. The child span represents the duration of the query and contains the SQL query sanitized. This instrumentation will also work with any library that depends on the `pg` package as its database adapter, such as [Knex](https://github.com/knex/knex) or [TypeORM](https://github.com/typeorm/typeorm). # Prisma Source: https://docs.appsignal.com/nodejs/3.x/integrations/prisma > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for Prisma. Prisma is an ORM (Object Relation Mapping) tool for Node.js that allows you to manage and interact with your application's database. You can learn more about Prisma on their [official website](https://www.prisma.io/). ## Installation Starting from Prisma version `v6.1.0`, Prisma is automatically instrumented by the AppSignal for Node.js package. No additional installation or configuration steps are required. ## Features The Prisma integration will send AppSignal a child span for each query, along with other child spans representing the connection to the database and the serialisation process. The child span for the query represents the duration of the query and contains the sanitized SQL query. If using Mongo, it contains the model and method name that was queried. # Redis Source: https://docs.appsignal.com/nodejs/3.x/integrations/redis > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for Redis, using the [`redis`](https://www.npmjs.com/package/redis) and [`ioredis`](https://www.npmjs.com/package/ioredis) packages. ## Installation The Redis client is instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument Redis in your application. ## Features The Redis integration will send AppSignal a child span for each query. The child span represents the duration of the query and contains the query type. This instrumentation will also work with any library that depends on the `redis` or `ioredis` packages as its database adapter. BullMQ, which stores its queues in Redis, is instrumented separately. See the [BullMQ integration](/nodejs/3.x/integrations/bullmq) for traces of the jobs themselves. # Remix Source: https://docs.appsignal.com/nodejs/3.x/integrations/remix The AppSignal for Node.js integration for [Remix](https://remix.run/) ## Installation To enable the instrumentation support for Remix, you first need to install the [OpenTelemetry Remix Instrumentation](https://www.npmjs.com/package/opentelemetry-instrumentation-remix) `^0.5.0` package. After installing the OpenTelemetry Remix Instrumentation package, you must enable the instrumentation in the AppSignal client initialization using the [`additionalInstrumentations`](/nodejs/3.x/configuration/options#option-additionalinstrumentations) config option as shown in the code below. ```javascript Node.js theme={null} // appsignal.cjs const { Appsignal } = require("@appsignal/nodejs"); const { RemixInstrumentation } = require("opentelemetry-instrumentation-remix"); new Appsignal({ active: true, name: "", pushApiKey: "", additionalInstrumentations: [new RemixInstrumentation()], }); ``` This snippet references the `appsignal.cjs` file that was created [when configuring AppSignal](/nodejs/3.x/configuration#minimal-required-configuration). You must set the `NODE_OPTIONS` environment variable to load the `appsignal.cjs` file when starting your Remix app. ```bash Bash theme={null} NODE_OPTIONS='--require ./appsignal.cjs' remix dev ``` > [!TIP] > > Remix is built on top of Express for web requests handling, and that could > make your actions in AppSignal harder to read. If that's your case, you can > disable the Express instrumentation by passing the `disableInstrumentations` > option to the AppSignal client initialization with the value: > `["@opentelemetry/instrumentation-express"]`. ## Features The Remix instrumentation will create performance actions in AppSignal from the Remix request handlers. The action name will be the route of the request handler. Remix loaders are instrumented as child spans of the request handler span. Once configured, errors raised by your Remix application will be reported to AppSignal. # Restify Source: https://docs.appsignal.com/nodejs/3.x/integrations/restify > [!NOTE] > > Default instrumentations can be disabled via the `disableDefaultInstrumentations` config option. You can read more about how to configure this in our [Configuration Options documentation](/nodejs/3.x/configuration/options#option-disabledefaultinstrumentations). The AppSignal for Node.js integration for [restify](http://restify.com/). ## Installation Applications using restify are instrumented automatically by the AppSignal for Node.js package. No additional setup is required to instrument your restify application. ## Features The restify integration will send AppSignal a child span representing the execution time of each middleware, as well as a child span for the request handler. Any errors raised by your restify application will be reported to AppSignal. # Migration Guide Source: https://docs.appsignal.com/nodejs/3.x/migration-guide > [!NOTE] > > 🛟 Don't hesitate to [contact us](mailto:support@appsignal.com) if you run into > any issues while upgrading your application's AppSignal for Node.js package. > We're here to help! This documentation lists the changes between the 2.x and 3.x releases of AppSignal's Node.js package. If you are upgrading from 2.x to 3.x you will need to modify your integration to work successfully. If you run into any issues while upgrading your application, be sure to [contact us](mailto:support@appsignal.com) for support. ## Installing 3.x To install AppSignal for Node.js 3.x run the following command in your application's root directory. #### npm ```bash Bash theme={null} npm install @appsignal/nodejs ``` ## AppSignal Client When upgrading from 2.x to 3.x, you need to change how your application initializes and accesses the AppSignal client. ### Initialize AppSignal Client To initialize the AppSignal client and export it, you will need to create a new `appsignal.cjs` file, like in the example below: ```javascript Node.js theme={null} // appsignal.cjs const { Appsignal } = require("@appsignal/nodejs"); const appsignal = new Appsignal({ active: true, name: "Your app name", }); ``` You will need to require (`--require ./appsignal.cjs`) your `appsignal.cjs` file when starting your application. For example, in your application's `package.json` file, like in the example below: #### Javascript ```json JSON theme={null} "scripts": { "server": "node --require ./appsignal.cjs index.js" } ``` ### Access AppSignal Client In 3.x the AppSignal client is accessed from the globally exported `Appsignal.client` object. The below examples show how to do this within the context of a [custom metrics counter](/metrics/custom#counter). #### 2.x ```javascript Node.js theme={null} import { appsignal } from "./appsignal"; // or: const appsignal = new Appsignal({...}); const meter = appsignal.metrics(); meter.incrementCounter("slow_queries", 1); ``` #### 3.x ```javascript Node.js theme={null} import { Appsignal } from "@appsignal/nodejs"; // or: const { Appsignal } = require("@appsignal/nodejs"); const meter = Appsignal.client.metrics(); meter.incrementCounter("slow_queries", 1); ``` ## Integrations > [!TIP] > > Express and Next.js require an [Error > Handler](/nodejs/3.x/integrations/express#error-handler). AppSignal for Node.js 3.x supports all 2.x integrations out of the box. This means the packages for each integration no longer need to be installed. When moving to 3.x from 2.x you will need to remove any AppSignal integration packages installed for your application. ### Uninstall Integrations > [!WARNING] > > The 2.x integrations are not compatible with the 3.x Node.js integration. You > must follow the migration steps outlined below to use Node.js integrations. To take advantage of the AppSignal for Node.js 3.x out-of-the-box integration support, you'll first need to "undo" the integration installations that were necessary in the 2.x version. #### Remove AppSignal Package Dependent Code > [!TIP] > > The examples below are illustrative and based on AppSignal's 2.x and 3.x > integration documentation. The code in your application may differ from the > examples in this documentation. * [Apollo Server](#remove-apollo-server-integration) * [Express](#remove-express-integration) * [Koa.js](#remove-koa-js-integration) * [Next.js](#remove-next-js-integration) **Don't forget to [remove/uninstall the AppSignal integration package](#remove-integration-package)**. ### Remove Apollo Server Integration > [!WARNING] > > The 2.x `@appsignal/apollo-server` package is not compatible with the 3.x > Node.js integration. You must follow the migration steps outlined below if you > wish to use Apollo Server with our 3.x integration. Remove the 2.x initialization of the Appsignal Apollo Server package and plugin from your application, and replace it with the 3.x installation instructions. Your Apollo application will be instrumented automatically. #### 2.x ```javascript Node.js theme={null} import { createApolloPlugin } from "@appsignal/apollo-server"; import { ApolloServer, gql } from "apollo-server-express"; // or: const { createApolloPlugin } = require("@appsignal/apollo-server"); // or: const { ApolloServer, gql } = require("apollo-server-express"); const server = new ApolloServer({ /* ... */ plugins: [createApolloPlugin(appsignal)], }); ``` #### 3.x Apollo Server is instrumented automatically by the AppSignal for Node.js package. [Read 3.x GraphQL Integration Documentation](/nodejs/3.x/integrations/graphql) Once you've modified your integration code, you need to [remove the Apollo AppSignal package](#remove-apollo-server-integration) from your application. ### Remove Express Integration > [!WARNING] > > The 2.x `@appsignal/express` package is not compatible with the 3.x Node.js > integration. You must follow the migration steps outlined below if you wish to > use express with our 3.x integration. Remove the 2.x initialization of AppSignal Express package and middleware from your application, and replace it with the 3.x installation instructions. #### 2.x ```javascript Node.js theme={null} import express from "express"; // or: const express = require("express"); const { expressMiddleware, expressErrorHandler, } = require("@appsignal/express"); // your app code goes here // add this after all other express middleware, but before any routes app.use(expressMiddleware(appsignal)); // add this after all routes, but before any other error handlers app.use(expressErrorHandler(appsignal)); ``` #### 3.x ```javascript Node.js theme={null} import { expressErrorHandler } from "@appsignal/nodejs"; // or: const { expressErrorHandler } = require("@appsignal/nodejs"); const app = express(); // your app code goes here // add this after all routes, but before any other error handlers app.use(expressErrorHandler()); ``` [Read 3.x Express Integration Documentation](/nodejs/3.x/integrations/express) Once you've modified your integration code, you need to [remove the Appsignal Express package](#remove-express-integration) from your application. ### Remove Koa.js Integration > [!WARNING] > > The 2.x `@appsignal/koa` package is not compatible with the 3.x Node.js > integration. You must follow the migration steps outlined below if you wish to > use Koa.js with our 3.x integration. Remove the 2.x initialization of the Appsignal Koa package and instrumentation from your application. #### 2.x ```javascript Node.js theme={null} import appsignalKoa from "@appsignal/koa"; // or: const appsignalKoa = require("@appsignal/koa"); appsignal.instrument(appsignalKoa); ``` #### 3.x Koa.js is instrumented automatically by the AppSignal for Node.js package. [Read 3.x Koa.js Integration Documentation](/nodejs/3.x/integrations/koajs) Once you've modified your integration code, you need to [remove the Koa.js package](#remove-koa-js-integration) from your application. ### Remove Next.js Integration > [!WARNING] > > The 2.x `@appsignal/nextjs` package is not compatible with the 3.x Node.js > integration. You must follow the migration steps outlined below if you wish to > use Next.js with our 3.x integration. The "Web Vitals Reporting" feature has been deprecated and is no longer available on AppSignal for Node.js 3.x. #### 2.x ```javascript Node.js theme={null} import { getRequestHandler } from "@appsignal/nextjs"; // or: const { getRequestHandler } = require("@appsignal/nextjs"); ``` #### 3.x Next.js is instrumented automatically by the AppSignal for Node.js package. [Read 3.x Next.js Integration Documentation](/nodejs/3.x/integrations/nextjs) ### Remove Integration Package Once the imports and code dependent on those imports are removed, you need to uninstall the integration package. This can be done by running `npm uninstall`, like in the example below. ```bash Bash theme={null} npm uninstall @appsignal/express ``` The `npm uninstall` commands will remove package dependencies and update your application's `package.json` and npm's `package-lock.json` file. Replace `@appsignal/express` in the example above with the integration package name you are removing. #### AppSignal Integration Package Names | Integration | Package Name | | - | - | | Apollo Server | `@appsignal/apollo-server` | | Express | `@appsignal/express` | | Koa.js | `@appsignal/koa` | | Next.js | `@appsignal/nextjs` | ## The Tracer Object There's no longer a custom AppSignal tracer object. OpenTelemetry exposes a tracer provider which allows you to create new spans. #### 2.x: ```javascript Node.js theme={null} const tracer = appsignal.tracer(); ``` #### 3.x: ```javascript Node.js theme={null} import { trace } from "@opentelemetry/api"; // or: const { trace } = require("@opentelemetry/api"); const tracer = trace.getTracer("my-interesting-app"); ``` [Read more about tracers in the 3.x instrumentation documentation.](/nodejs/3.x/instrumentation/instrumentation) ## Spans There's no longer a custom AppSignal span object. AppSignal's tracer functions, such as `rootSpan()`, `createSpan()`, `currentSpan()` and `withSpan()` functions are no longer available. Spans must be created by calling the `startActiveSpan` method on a tracer object. New spans are automatically the children of the span they were created in. #### 2.x: ```javascript Node.js theme={null} tracer.withSpan(tracer.createSpan(), async (span) => { span.setName("your span's name"); // logic to trace here }); ``` #### 3.x: ```javascript Node.js theme={null} tracer.startActiveSpan("your span's name", async (span) => { /// logic to trace here span.end(); }); ``` [Read more about spans in the 3.x instrumentation documentation.](/nodejs/3.x/instrumentation/instrumentation) ### Span Attribute Helpers The helper functions used to set span attributes have also changed. `setSQL` has been replaced with `setBody`, `set` has been renamed to `setTag`, and additional helper functions have been added. `setName` has been removed, as spans must be given a name when they are created. #### 2.x ```javascript Node.js theme={null} const span = tracer.currentSpan(); span.setCategory("query.sql"); span.setSQL("SELECT * FROM users"); ``` #### 3.x ```javascript JavaScript theme={null} setCategory("query.sql"); setSQL("SELECT * FROM users"); ``` [Read more about spans attribute helpers in the 3.x instrumentation documentation.](/nodejs/3.x/instrumentation/instrumentation#helpers) ## Exception Handling Tracer and span objects are no longer needed when using `setError()` and `sendError()`. #### 2.x ```javascript Node.js theme={null} tracer.setError(err); tracer.sendError(err, (span) => { span.setName("daily.task"); span.set("user_id", user_id); }); ``` #### 3.x In `sendError()`, [helpers](/nodejs/3.x/instrumentation/instrumentation#helpers) can be used to add additional data to the error span. ```javascript Node.js theme={null} import { setError, sendError } from "@appsignal/nodejs"; // or: const { setError, sendError } = require("@appsignal/nodejs"); setError(err); sendError(err, () => { setTag("user_id", user_id); }); ``` [Read more about exception handling in the 3.x exception handling documentation](/nodejs/3.x/instrumentation/exception-handling) # AppSignal for Python Source: https://docs.appsignal.com/python AppSignal for Python sends error and performance data through OpenTelemetry. Start here for installation, configuration, custom instrumentation, and supported libraries. AppSignal supports [Python] applications through [OpenTelemetry](#opentelemetry). Once installed, the AppSignal package will send your application's error and performance data to AppSignal. ## OpenTelemetry OpenTelemetry is an open-source initiative that streamlines and standardizes telemetry data collection. OpenTelemetry supports multiple languages, including Python, and consists of multiple components: tracing, metrics, and logs. We support OpenTelemetry's tracing component in our Python integration for better error reporting and performance measurements. [Learn more about OpenTelemetry via the project's official website.][OpenTelemetry] ## Installation The [Python installation documentation](/python/installation) will guide you through the steps needed to install AppSignal. ## Configuration Our [Configuration documentation](/python/configuration) will guide you through the steps needed to configure AppSignal. ## Custom Instrumentation Our [Custom instrumentation](/python/instrumentation/instrumentation) documentation will walk you through all the steps needed to create custom instrumentation with AppSignal. ## Supported Libraries We currently offer support for the following Python libraries: * [Celery](/python/instrumentations/celery) * [Django](/python/instrumentations/django) * [FastAPI](/python/instrumentations/fastapi) * [Flask](/python/instrumentations/flask) * [Jinja2](/python/instrumentations/jinja2) * [MySQL](/python/instrumentations/mysql) * [Pika](/python/instrumentations/pika) * [PostgreSQL](/python/instrumentations/postgresql) * [Redis](/python/instrumentations/redis) * [Requests](/python/instrumentations/requests) * [Starlette](/python/instrumentations/starlette) * [SQLAlchemy](/python/instrumentations/sqlalchemy) * [SQLite](/python/instrumentations/sqlite) * [WSGI/ASGI](/python/instrumentations/wsgi) [Python]: https://www.python.org/ [OpenTelemetry]: https://opentelemetry.io/ # AppSignal for Python: Command-line tools Source: https://docs.appsignal.com/python/command-line The AppSignal Python package ships with several command-line tools. These tools make it easier to install AppSignal in an application, send deploy notifications and diagnose any problems with the installation. ## Install A command-line tool to install AppSignal in your Python application. Read more about the [appsignal install][cli-install] command-line tool. ## Diagnose A self-diagnostic tool that can be used to debug the installation and configuration of your AppSignal integration. It is one of the first tools that our support team requests you to run when debugging an issue. Read more about the [appsignal diagnose][cli-diagnose] command-line tool. ## Demo A command-line tool that sends demonstration traces to AppSignal. When the tool is run, it sends an error and performance trace from your machine to AppSignal. Read more about the [appsignal demo][cli-demo] command-line tool. [cli-install]: /python/command-line/install.html [cli-diagnose]: /python/command-line/diagnose.html [cli-demo]: /python/command-line/demo.html # AppSignal Python Configuration Source: https://docs.appsignal.com/python/configuration Configure AppSignal for Python, including the application environment, deploy reporting, the configuration file, and instrumentation packages. This documentation explains how to configure AppSignal. For more information on installing AppSignal, follow the steps in our [installation documentation](/python/installation/). See also [collector mode](/python/configuration/collector) to configure AppSignal for Python to send data through the AppSignal collector, which enables [logging](/logging/integrations/python) and [distributed tracing](/distributed-tracing). ### Application Environment By default, the AppSignal for Python integration will report the current application in the "development" environment. You can use the `environment` configuration option to set a different environment. For example, in your `__appsignal__.py` file: ```python Python theme={null} # __appsignal__.py appsignal = Appsignal( # ... environment="production" ) ``` You can also use the `APPSIGNAL_APP_ENV` environment variable. ### Reporting Deploys You can use [Deploy Markers](/application/markers/deploy-markers) to report new deploys of your Python application. You can combine Deploy Markers with [Backtrace Links](/application/backtrace-links) to directly link from AppSignal to the source code on platforms like GitHub and GitLab. Deploy markers can be configured using the `revision` config option or the `APP_REVISION` environment variable. We recommend using Git commit SHAs or a tag in your SCM. For example, for Git applications, add the following code to the `__appsignal__.py` file: ```python Python theme={null} # __appsignal__.py import subprocess revision = None try: revision = subprocess.check_output( "git rev-parse --short HEAD", shell=True, text=True ).strip() except subprocess.CalledProcessError: pass appsignal = Appsignal( # ... revision=revision ) ``` ## Importing the Configuration File The AppSignal for Python integration needs to be loaded and started in your application. To load and start the integration, import the `appsignal` module and call the `appsignal.start()` method on app start or in the `main` method. > [!TIP] > > AppSignal also supports popular web frameworks directly, such as > [Django](/python/instrumentations/django), > [Flask](/python/instrumentations/flask), > [FastAPI](/python/instrumentations/fastapi) or > [Starlette](/python/instrumentations/starlette). If you're using a web > framework we support directly, follow the instructions for that framework > instead of the generic instructions on this page. ```python Python theme={null} # Your app file # Add this import statement import appsignal def main(): # Add this method call appsignal.start() if __name__ == '__main__': main() ``` ## Add Instrumentation Packages The next step is to instrument Python libraries such as Django, Celery, etc. Instrumenting libraries will provide a broader set of monitoring data, allowing you to understand your application's performance better. You can read more about installing and configuring instrumentations in our [Python instrumentations documentation][instrumentations]. [Python language]: https://www.python.org/ [OpenTelemetry]: https://opentelemetry.io/ [instrumentations]: /python/instrumentations [django]: /python/instrumentations/django.html # AppSignal Python Collector Configuration Source: https://docs.appsignal.com/python/configuration/collector Use collector mode to send data to AppSignal through the [AppSignal Collector](/collector). [Logging](/logging/integrations/python) and [distributed tracing](/distributed-tracing) are only supported when sending data through the AppSignal collector. This page assumes that you have already followed [the installation instructions](/python/installation). ## Deploying a collector You can deploy your own collector by following the instructions in the [AppSignal Collector documentation](/collector/installation). You can also have AppSignal host a collector for you using the ["Hosted Collector"](https://appsignal.com/redirect-to/organization?to=admin/hosted_collectors) page in your organization's settings. > [!NOTE] > > When the collector runs on the same host as an application that reports to it, leave host metrics disabled for the collector. The application's AppSignal integration already reports [host metrics](/metrics/host-metrics) for that host. With host metrics enabled for both, the same host is reported twice. ## Configuring the collector Set [the `collector_endpoint` configuration option](/python/configuration/options#option-collector_endpoint) to your collector's base URL. When using a hosted collector, copy the "Collector URL" from the ["Hosted Collector"](https://appsignal.com/redirect-to/organization?to=admin/hosted_collectors) settings page. Set [the `service_name` option](/python/configuration/options#option-service_name) to identify this application in traces. Use a different value for each service. ```python title="__appsignal__.py" theme={null} from appsignal import Appsignal appsignal = Appsignal( # ... other settings ... collector_endpoint="https://collector.example", service_name="web-server", ) ``` ```sh title="Environment variables" theme={null} APPSIGNAL_COLLECTOR_ENDPOINT="https://collector.example" APPSIGNAL_SERVICE_NAME="web-server" ``` AppSignal for Python now sends its traces, metrics and logs to the configured collector. To check that AppSignal loaded these settings, run `python -m appsignal diagnose --no-send-report` and confirm that the `Configuration` section lists the expected `collector_endpoint` and `service_name`. Then send a request or run a job and confirm its trace appears in AppSignal. The bundled agent keeps running alongside the collector. It reports the data the collector does not: [host metrics](/metrics/host-metrics), [NGINX metrics](/metrics/nginx), [StatsD metrics](/standalone-agent/statsd) and [environment metadata](/application/environment-metadata). ## Migrating to collector mode Most configuration options have the same behavior in agent mode and collector mode. In collector mode, some data that was sent in agent mode as a single kind of data is split between multiple data types. Some configuration options that controlled whether that data was sent and how it was filtered have changed: | Agent mode | Collector mode | | - | - | | [`filter_parameters`](/python/configuration/options#option-filter_parameters) | [`filter_request_payload`](/python/configuration/options#option-filter_request_payload), [`filter_function_parameters`](/python/configuration/options#option-filter_function_parameters), [`filter_request_query_parameters`](/python/configuration/options#option-filter_request_query_parameters) | | [`send_params`](/python/configuration/options#option-send_params) | [`send_request_payload`](/python/configuration/options#option-send_request_payload), [`send_function_parameters`](/python/configuration/options#option-send_function_parameters), [`send_request_query_parameters`](/python/configuration/options#option-send_request_query_parameters) | When the collector mode options are not set, the agent mode option is used to derive a value for it, so an application that configured these config options for agent mode will still report the same data in collector mode. You can set the collector mode options to report each kind of data differently, such as filtering a background job's arguments but not a request's payload. AppSignal logs which values to set to keep reporting the same data, and the [diagnose report](/python/command-line/diagnose) shows them as loaded from `derived`. ### Parameters Collector mode reports three kinds of parameters, each with its own filter and send option: * The **request payload**: an incoming HTTP request's parameters, such as a form body. * The **function parameters**: the arguments a background job was given. * The **request query parameters**: an incoming HTTP request's parsed query string. Read [request parameters](/guides/custom-data/request-parameters) for more information on how to report parameters. # AppSignal for Python load order Source: https://docs.appsignal.com/python/configuration/load-order This documentation outlines how the AppSignal configuration is loaded in your Python application. There are two different methods for [configuring your AppSignal integration](/python/configuration), which can be used simultaneously: * Config file (`__appsignal__.py`) * Environment variables A list of available options can be found in the [Configuration options](/python/configuration/options) documentation. ## Load order The configuration is loaded in a four-step process: 1. [Package defaults - `default`](#1-package-defaults) 2. [System detected settings - `system`](#2-system-detected-settings) 3. [Environment variables - `env`](#3-environment-variables) 4. [Initial configuration - `initial`](#4-initial-configuration-given-to-appsignal) ## Package defaults First, the default configuration is loaded, which sets paths and enables certain features. This source will be listed under `default` in your application's config and is visible in the [Diagnose report](https://docs.appsignal.com/support/debugging.html). ## System detected settings The package detects what kind of system it's running on and configures itself accordingly. For example, if running inside a container-based system such as Docker or Heroku, the configuration option `running_in_container` is set to `true`. This source will be listed under `system` in your application's config and is visible in the [Diagnose report](https://docs.appsignal.com/support/debugging.html). ## Environment variables AppSignal will look for Configuration options set via Environment variables. The Environment variable value will override values for the same Configuration options defined in previous steps. ```bash Bash theme={null} export APPSIGNAL_APP_NAME="my custom app name" # start your app here ``` This source will be listed under `env` in your application's configuration, and is visible in the [Diagnose report](https://docs.appsignal.com/support/debugging.html). ## Initial configuration given to `Appsignal` Finally, the initial configuration is loaded via the `Appsignal` function called from the `__appsignal__.py` config file: ```ruby Ruby theme={null} # __appsignal__.py appsignal = Appsignal( active=True, name="My app name", push_api_key="00000000-0000-0000-0000-000000000000" ) ``` The values of Conig options defined in this step will override values for the same Configuration options defined in previous steps. This source will be listed under `initial` in your application's config and is visible in the [Diagnose report](https://docs.appsignal.com/support/debugging.html). # Python package configuration options Source: https://docs.appsignal.com/python/configuration/options The following list includes all configuration options with the name of the environment variable and the name of the key in the configuration file. For more information on how to configure AppSignal with a configuration file or system environment variables, see our [Configuration](/python/configuration) documentation. ## Available options * Required options * [`active`](#option-active) * [`environment`](#option-environment) * [`name`](#option-name) * [`push_api_key`](#option-push_api_key) * Options * [`bind_address`](#option-bind_address) * [`ca_file_path`](#option-ca_file_path) * [`collector_endpoint`](#option-collector_endpoint) * [`cpu_count`](#option-cpu_count) * [`disable_default_instrumentations`](#option-disable_default_instrumentations) * [`dns_servers`](#option-dns_servers) * [`enable_host_metrics`](#option-enable_host_metrics) * [`enable_minutely_probes`](#option-enable_minutely_probes) * [`enable_nginx_metrics`](#option-enable_nginx_metrics) * [`enable_statsd`](#option-enable_statsd) * [`endpoint`](#option-endpoint) * [`files_world_accessible`](#option-files_world_accessible) * [`filter_attributes`](#option-filter_attributes) * [`filter_function_parameters`](#option-filter_function_parameters) * [`filter_parameters`](#option-filter_parameters) * [`filter_request_payload`](#option-filter_request_payload) * [`filter_request_query_parameters`](#option-filter_request_query_parameters) * [`filter_session_data`](#option-filter_session_data) * [`host_role`](#option-host_role) * [`hostname`](#option-hostname) * [`http_proxy`](#option-http_proxy) * [`ignore_actions`](#option-ignore_actions) * [`ignore_errors`](#option-ignore_errors) * [`ignore_logs`](#option-ignore_logs) * [`ignore_namespaces`](#option-ignore_namespaces) * [`log`](#option-log) * [`log_level`](#option-log_level) * [`log_path`](#option-log_path) * [`logging_endpoint`](#option-logging_endpoint) * [`nginx_port`](#option-nginx_port) * [`opentelemetry_port`](#option-opentelemetry_port) * [`request_headers`](#option-request_headers) * [`response_headers`](#option-response_headers) * [`revision`](#option-revision) * [`running_in_container`](#option-running_in_container) * [`send_environment_metadata`](#option-send_environment_metadata) * [`send_function_parameters`](#option-send_function_parameters) * [`send_params`](#option-send_params) * [`send_request_payload`](#option-send_request_payload) * [`send_request_query_parameters`](#option-send_request_query_parameters) * [`send_session_data`](#option-send_session_data) * [`service_name`](#option-service_name) * [`statsd_port`](#option-statsd_port) * [`working_directory_path`](#option-working_directory_path) ## active | Field | Value | | - | - | | Config file key | `active` | | System environment key | `APPSIGNAL_ACTIVE` | | Required | yes | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `0.1.0` | ### Description Configure AppSignal to be active or not for a given environment. If AppSignal is not active, no data is reported for the app in the specified environment. ## environment | Field | Value | | - | - | | Config file key | `environment` | | System environment key | `APPSIGNAL_APP_ENV` | | Required | yes | | Type | `String` | | Default value | `development` | | Available since version | `0.1.0` | ### Description The environment of the app to be reported to AppSignal. > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## name | Field | Value | | - | - | | Config file key | `name` | | System environment key | `APPSIGNAL_APP_NAME` | | Required | yes | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.1.0` | ### Description Name of your application as it should be displayed on AppSignal.com. > [!NOTE] > > **Note**: Changing the name or environment of an existing app > will create a new app on AppSignal.com. ## push\_api\_key | Field | Value | | - | - | | Config file key | `push_api_key` | | System environment key | `APPSIGNAL_PUSH_API_KEY` | | Required | yes | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.1.0` | ### Description The organization-level authentication key to authenticate with our Push API. Read more about the [AppSignal Push API key](/appsignal/terminology#push-api-key). ## bind\_address | Field | Value | | - | - | | Config file key | `bind_address` | | System environment key | `APPSIGNAL_BIND_ADDRESS` | | Required | no | | Type | `String` | | Default value | `127.0.0.1` | | Available since version | `0.1.5` | ### Description A valid IPv4 address the AppSignal agent uses as a binding for its TCP and UDP servers. Use a specific address if you only want the agent to listen to requests made to that address. Set this option to `0.0.0.0` to allow to receive requests from hosts using any IP address. By default it only listens to requests made on the same host. This option is applied to all the agent servers (StatsD, OpenTelemetry and NGINX). ## ca\_file\_path | Field | Value | | - | - | | Config file key | `ca_file_path` | | System environment key | `APPSIGNAL_CA_FILE_PATH` | | Required | no | | Type | `String` | | Default value | Packaged `cacert.pem` file path. | | Available since version | `0.1.0` | ### Description Use this option to point to another certificate file if there's a problem connecting to our API. > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. > [!NOTE] > > When using [an external collector](#option-collector_endpoint), this configuration option does not have any effect on how the integration communicates with the external collector. It will still be used when communicating with AppSignal's servers. ## collector\_endpoint | Field | Value | | - | - | | Config file key | `collector_endpoint` | | System environment key | `APPSIGNAL_COLLECTOR_ENDPOINT` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `1.6.0` | ### Description The address of an externally deployed [AppSignal Collector](/collector). When set, the integration sends its traces, metrics and logs to the collector at this address. The AppSignal agent bundled with the integration keeps running alongside the collector. It reports the data that is not sent to the collector: [host metrics](/metrics/host-metrics), [NGINX metrics](/metrics/nginx), [StatsD metrics](/standalone-agent/statsd) and [environment metadata](/application/environment-metadata). > [!NOTE] > > This is an **experimental** configuration option. [Logging](/logging) **is > only available** when using an external collector. ## cpu\_count | Field | Value | | - | - | | Config file key | `cpu_count` | | System environment key | `APPSIGNAL_CPU_COUNT` | | Required | no | | Type | `Float` | | Default value | `undefined` | | Available since version | `1.2.0` | ### Description The available CPU capacity of the host, in number of CPUs. This is used to calculate the CPU usage percentage in the host metrics. If not set, the agent will attempt to automatically detect this from cgroups. The number of CPUs can be a fraction, e.g. `0.5`. ## disable\_default\_instrumentations | Field | Value | | - | - | | Config file key | `disable_default_instrumentations` | | System environment key | `APPSIGNAL_DISABLE_DEFAULT_INSTRUMENTATIONS` | | Required | no | | Type | `list(String)` or Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `0.1.0` | ### Description Allows you to disable the automatic instrumentation of default integrations: * `aiopg` * `asyncpg` * `celery` * `django` * `flask` * `mysql` * `mysqlclient` * `psycopg` * `psycopg2` * `pymysql` * `redis` * `jinja2` * `requests` * `sqlalchemy` * `sqlite3` * `logging` > [!NOTE] > > When using AppSignal for Python 1.5.4 or earlier, prefix each of these names > with `opentelemetry.instrumentation.`. For example, `jinja2` would be > specified as `opentelemetry.instrumentation.jinja2`. Note that instrumentations are only enabled if the corresponding OpenTelemetry instrumentation library is installed. To disable all automatic instrumentations, set the value to `True`. ## dns\_servers | Field | Value | | - | - | | Config file key | `dns_servers` | | System environment key | `APPSIGNAL_DNS_SERVERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `0.1.0` | ### Description Configure DNS servers for the AppSignal agent to use. ```sh Shell theme={null} # In the host environment export APPSIGNAL_DNS_SERVERS="8.8.8.8,8.8.4.4" ``` If you're affected by our [DNS timeouts](/support/known-issues/dns-timeouts), try setting a DNS server manually using this option that doesn't use more than **4** dots in the server name. * Acceptable values: `8.8.8.8`, `my.custom.local.server`. * Not acceptable values: `foo`, `my.awesome.custom.local.dns.server`. If the DNS server cannot be reached the agent will fall back on the host's DNS configuration and output a message in the `appsignal.log` file: `A problem occurred while setting DNS servers`. ## enable\_host\_metrics | Field | Value | | - | - | | Config file key | `enable_host_metrics` | | System environment key | `APPSIGNAL_ENABLE_HOST_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | \`\`true` / detected by system` | | Available since version | `0.1.0` | ### Description Set this option to `false` to disable [host metrics](/metrics/host-metrics) collection. On Heroku and Dokku host metrics are disabled by default. This is done because these systems will report inaccurate metrics from within the containers. Host metrics collection on these systems cannot be enabled. For Heroku, use the [Heroku log drain](/heroku/host-metrics) instead. ## enable\_minutely\_probes | Field | Value | | - | - | | Config file key | `enable_minutely_probes` | | System environment key | `APPSIGNAL_ENABLE_MINUTELY_PROBES` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.2.0` | ### Description Enables the [minutely probes](/python/instrumentation/minutely-probes) system. ## enable\_nginx\_metrics | Field | Value | | - | - | | Config file key | `enable_nginx_metrics` | | System environment key | `APPSIGNAL_ENABLE_NGINX_METRICS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `0.1.0` | ### Description Set to `true` to enable the NGINX metrics server. [See the NGINX metrics documentation for details.](/metrics/nginx) When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 27649. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## enable\_statsd | Field | Value | | - | - | | Config file key | `enable_statsd` | | System environment key | `APPSIGNAL_ENABLE_STATSD` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `false` | | Available since version | `0.1.0` | ### Description Enables the [StatsD server](/standalone-agent/statsd) in the AppSignal agent. When enabled, the AppSignal agent will listen to a `localhost`-bound server on port 8125. If you're running several AppSignal-instrumented applications in the same server, this configuration option can only be enabled in one of them. ## endpoint | Field | Value | | - | - | | Config file key | `endpoint` | | System environment key | `APPSIGNAL_PUSH_API_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://push.appsignal.com` | | Available since version | `0.1.0` | ### Description Configure the endpoint to send data to AppSignal. This setting will not have to be changed. ## files\_world\_accessible | Field | Value | | - | - | | Config file key | `files_world_accessible` | | System environment key | `APPSIGNAL_FILES_WORLD_ACCESSIBLE` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `0.1.0` | ### Description If this is set to `true` the [AppSignal working directory](/appsignal/how-appsignal-operates#working-directory) that is created is accessible for all users (Unix permissions `0666`). This is often necessary because processes for the same app run under a different user. Set to `false` to disable this behaviour (Unix permissions `0644`). ## filter\_attributes | Field | Value | | - | - | | Config file key | `filter_attributes` | | System environment key | `APPSIGNAL_FILTER_ATTRIBUTES` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.6.0` | ### Description List of OpenTelemetry span attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_function\_parameters | Field | Value | | - | - | | Config file key | `filter_function_parameters` | | System environment key | `APPSIGNAL_FILTER_FUNCTION_PARAMETERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.6.0` | | |
    • `1.8.0`: Its value is derived from the [`filter_parameters`](#option-filter_parameters) configuration option until this option is set.
    | ### Description List of function parameter attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_parameters | Field | Value | | - | - | | Config file key | `filter_parameters` | | System environment key | `APPSIGNAL_FILTER_PARAMETERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `0.1.0` | ### Description List of parameter keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. Read more about [parameter filtering](/application/parameter-filtering). > [!NOTE] > > **Agent only:** when using [an external collector](#option-collector_endpoint), this configuration option sets the default for the options below and has no other effect. > > Set the following configuration options to control how request payloads, request query parameters and function parameters are filtered: > > * [`filter_function_parameters`](#option-filter_function_parameters) > * [`filter_request_payload`](#option-filter_request_payload) > * [`filter_request_query_parameters`](#option-filter_request_query_parameters) ## filter\_request\_payload | Field | Value | | - | - | | Config file key | `filter_request_payload` | | System environment key | `APPSIGNAL_FILTER_REQUEST_PAYLOAD` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.6.0` | | |
    • `1.8.0`: Its value is derived from the [`filter_parameters`](#option-filter_parameters) configuration option until this option is set.
    | ### Description List of request payload attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_request\_query\_parameters | Field | Value | | - | - | | Config file key | `filter_request_query_parameters` | | System environment key | `APPSIGNAL_FILTER_REQUEST_QUERY_PARAMETERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.6.0` | | |
    • `1.8.0`: Its value is derived from the [`filter_parameters`](#option-filter_parameters) configuration option until this option is set.
    | ### Description List of request query parameter attributes to filter with AppSignal. Matching values are replaced with `[FILTERED]`. Read more about [parameter filtering](/application/parameter-filtering). > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [filter\_parameters](#option-filter_parameters) configuration > option for filtering data when using the agent. ## filter\_session\_data | Field | Value | | - | - | | Config file key | `filter_session_data` | | System environment key | `APPSIGNAL_FILTER_SESSION_DATA` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `0.1.0` | ### Description List of session data keys that should be ignored using AppSignal filtering. Their values will be replaced with `[FILTERED]` when transmitted to AppSignal. Read more about [session data filtering](/application/session-data-filtering). ## host\_role | Field | Value | | - | - | | Config file key | `host_role` | | System environment key | `APPSIGNAL_HOST_ROLE` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.2.2` | ### Description Group hosts by role and generate metrics based on this role. One such metric is the `reporting_hosts` counter metric. A good role indicates what the main role of the server is, like "webserver", "processor", "api", "database", "loadbalancer", etc. ## hostname | Field | Value | | - | - | | Config file key | `hostname` | | System environment key | `APPSIGNAL_HOSTNAME` | | Required | no | | Type | `String` | | Default value | detected from system | | Available since version | `0.1.0` | ### Description This overrides the server's hostname. Useful for when you're unable to set a custom hostname or when a nondescript id is generated for you on hosting services. ## http\_proxy | Field | Value | | - | - | | Config file key | `http_proxy` | | System environment key | `APPSIGNAL_HTTP_PROXY` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.1.0` | ### Description If you require the agent to connect to the Internet via a proxy set the complete proxy URL in this configuration key. > [!NOTE] > > When using [an external collector](#option-collector_endpoint), this configuration option does not have any effect on how the integration communicates with the external collector. It will still be used when communicating with AppSignal's servers. ## ignore\_actions | Field | Value | | - | - | | Config file key | `ignore_actions` | | System environment key | `APPSIGNAL_IGNORE_ACTIONS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `0.1.0` | ### Description With this config option you can specify a list of actions that will be ignored by AppSignal. Everything that happens including exceptions will not be transmitted to AppSignal. This can be useful to ignore health check endpoints or other actions that you don't want to monitor. Read more about [ignoring actions](/guides/filter-data/ignore-actions). ## ignore\_errors | Field | Value | | - | - | | Config file key | `ignore_errors` | | System environment key | `APPSIGNAL_IGNORE_ERRORS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `0.1.0` | ### Description List of error classes that will be ignored. Any exception raised with this error class will not be transmitted to AppSignal. Read more about [ignoring errors](/guides/filter-data/ignore-errors). ## ignore\_logs | Field | Value | | - | - | | Config file key | `ignore_logs` | | System environment key | `APPSIGNAL_IGNORE_LOGS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.7.0` | ### Description List of log messages that will be ignored. Any log message containing any of the elements of the list will not be transmitted to AppSignal. A small subset of regex syntax is supported, read more about it in our [Ignore Logs](/guides/filter-data/ignore-logs) guide. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). ## ignore\_namespaces | Field | Value | | - | - | | Config file key | `ignore_namespaces` | | System environment key | `APPSIGNAL_IGNORE_NAMESPACES` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `0.1.0` | ### Description List of namespaces that will be ignored. Any error raised or slow request that occurs in this namespace will not be send to AppSignal. Read more about [namespaces](/application/namespaces). ## log | Field | Value | | - | - | | Config file key | `log` | | System environment key | `APPSIGNAL_LOG` | | Required | no | | Type | `String` | | Default value | `file` | | Available since version | `0.1.0` | ### Description > [!NOTE] > > This option configures what logger that AppSignal's internal logging > functionality will use and does not affect the [logging feature](/logging). > > **Note**: The [AppSignal agent](/appsignal/how-appsignal-operates), > which is used by the integration, will always write to the "appsignal.log" file. Select which logger the AppSignal integration will use. Accepted values are `file` and `stdout`. See also the `log_path` configuration. * `file` (default) * Write all AppSignal logs to the file system. * `stdout` (default on [Heroku](https://heroku.com)) * Print AppSignal logs in the parent process' STDOUT instead of to a file. Useful with hosting solutions such as container systems and Heroku. > [!NOTE] > > When using [an external collector](#option-collector_endpoint), this configuration option does not have any effect on how the collector will emit logs. The integration will still follow this configuration option when emitting logs. ## log\_level | Field | Value | | - | - | | Config file key | `log_level` | | System environment key | `APPSIGNAL_LOG_LEVEL` | | Required | no | | Type | `String` | | Default value | `info` | | Available since version | `0.1.0` | ### Description > [!NOTE] > > This option sets the severity level of AppSignal's internal logger and does > not affect the [logging feature](/logging). Set the severity level of AppSignal's internal logger. If it is configured to "info" it will log all error, warning and info messages, but not log the debug messages. Setting it to the levels "debug" or "trace" is usually only needed on request from support. Setting the level to "debug"/"trace" could have a slight impact on the disk usage and IO, especially on high-traffic sites. CPU overhead is minimal with the debug option enabled. Accepted values: * error * warning * info * debug * trace > [!NOTE] > > When using [an external collector](#option-collector_endpoint), this configuration option does not have any effect on how the collector will emit logs. The integration will still follow this configuration option when emitting logs. ## log\_path | Field | Value | | - | - | | Config file key | `log_path` | | System environment key | `APPSIGNAL_LOG_PATH` | | Required | no | | Type | `String` | | Default value | `/tmp` | | Available since version | `0.1.0` | ### Description > [!NOTE] > > This option configures the location of AppSignal's internal logging file and > does not affect the [logging feature](/logging). > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. Override the location of the path (directory) where the `appsignal.log` file can be written to. > [!NOTE] > > When using [an external collector](#option-collector_endpoint), this configuration option does not have any effect on how the collector will emit logs. The integration will still follow this configuration option when emitting logs. ## logging\_endpoint | Field | Value | | - | - | | Config file key | `logging_endpoint` | | System environment key | `APPSIGNAL_LOGGING_ENDPOINT` | | Required | no | | Type | `String` | | Default value | `https://appsignal-endpoint.net` | | Available since version | `1.3.0` | ### Description Configure the endpoint AppSignal sends logs and check-ins to. This setting will not have to be changed. ## nginx\_port | Field | Value | | - | - | | Config file key | `nginx_port` | | System environment key | `APPSIGNAL_NGINX_PORT` | | Required | no | | Type | `Integer` | | Default value | `27649` | | Available since version | `1.5.4` | ### Description Configure the port on which the NGINX metrics server is exposed. When AppSignal receives NGINX metrics, it listens on a `localhost`-bound server, by default on port 27649. If you're running several AppSignal-instrumented applications in the same server with NGINX metrics enabled, use this option to configure each application to listen on a different port. ## opentelemetry\_port | Field | Value | | - | - | | Config file key | `opentelemetry_port` | | System environment key | `APPSIGNAL_OPENTELEMETRY_PORT` | | Required | no | | Type | `Integer` | | Default value | `8099` | | Available since version | `0.2.2` | ### Description Set this option to configure the OpenTelemetry HTTP server port of the AppSignal agent process. Configure this port if another process is already running on the machine that is also using this port to avoid conflicts. > [!NOTE] > > **Agent only:** when using [an external > collector](#option-collector_endpoint), this configuration option does not > have any effect. The port to use to send OpenTelemetry data to the external > collector can be specified as part of [the `collector_endpoint` configuration > option](#option-collector_endpoint). ## request\_headers | Field | Value | | - | - | | Config file key | `request_headers` | | System environment key | `APPSIGNAL_REQUEST_HEADERS` | | Required | no | | Type | `list(String)` | | Default value | `["accept", "accept-charset", "accept-encoding", "accept-language", "cache-control", "connection", "content-length", "range"]` | | Available since version | `0.1.0` | ### Description The `request_headers` config option contains a list of HTTP request headers which are read and stored by the AppSignal Python package. This `request_headers` config option is an *allowlist*, which means that it will only report headers as specified by this config option. If this config option is not configured it will use the AppSignal default. Setting it to `None` reports no request headers, the same as setting it to an empty list, because AppSignal only records a header this option names. To customize this list, add the config option with *all headers* you want reported. All header names should be written in lowercase characters. If the header name is `X-Custom-Header`, add it to this list as `x-custom-header`. Read our [request header collection](/guides/filter-data/filter-headers) guide for more information. To configure AppSignal to not store any HTTP request headers on AppSignal traces, configure the option with an empty list. ```python Python theme={null} # __appsignal__.py appsignal = Appsignal( # ...Other config opts request_headers=[] ) ``` ## response\_headers | Field | Value | | - | - | | Config file key | `response_headers` | | System environment key | `APPSIGNAL_RESPONSE_HEADERS` | | Required | no | | Type | `list(String)` | | Default value | `[]` | | Available since version | `1.6.0` | ### Description The `response_headers` config option contains a list of HTTP response headers which are read and stored by the AppSignal for Python package. This `response_headers` config option is an *allowlist*, which means that it will only report headers as specified by this config option. It names no headers by default, so no response headers are reported until it does. To customize this list, add the config option with *all headers* you want reported. All header names should be written in lowercase characters. If the header name is `X-Custom-Header`, add it to this list as `x-custom-header`. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). ## revision | Field | Value | | - | - | | Config file key | `revision` | | System environment key | `APP_REVISION` | | Required | no | | Type | `String` | | Default value | nil (This is unset by default) | | Available since version | `0.1.0` | | |
    • `0.2.0`: Auto detection for Render deploys.
    • `1.3.3`: Auto detection for Kamal deploys.
    • `1.4.1`: Auto detection for Scalingo deploys.
    • `1.7.0`: Auto detection when using an external collector.
    • `1.9.2`: Reads the `HEROKU_BUILD_COMMIT` environment variable.
    | ### Description Set the app revision to report the currently running version of your app. AppSignal will create a deploy marker when this value changes, and tag all incoming data with the current revision. The AppSignal integration automatically detects the deployed Git commit and uses it as the revision when you deploy using the following tools or providers: * Kamal * Render * Scalingo * Heroku, when the [Heroku Labs: Dyno Metadata](https://devcenter.heroku.com/articles/dyno-metadata) feature is enabled Set the `revision` config option to override the detected revision. Use a single value without spaces, such as a Git commit SHA (`abc0123`) or a version number (`1.2.3`). AppSignal builds links to your source code from this value. Read more about [choosing a revision value](/application/markers/deploy-markers#choosing-a-revision-value). Read more about deploy markers in the [deploy markers topic](/application/markers/deploy-markers). When more than one source sets the revision, the Ruby gem uses the first one in this list that is set: 1. The `revision` config option or the `APP_REVISION` environment variable. 2. The environment variable set by Heroku (`HEROKU_BUILD_COMMIT` or `HEROKU_SLUG_COMMIT`), Render (`RENDER_GIT_COMMIT`), Kamal (`KAMAL_VERSION`), or Scalingo (`CONTAINER_VERSION`), in that order. 3. The `REVISION` file in the application's root directory. ## running\_in\_container | Field | Value | | - | - | | Config file key | `running_in_container` | | System environment key | `APPSIGNAL_RUNNING_IN_CONTAINER` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | detected by agent | | Available since version | `0.1.0` | ### Description AppSignal expects to be running on the same machine between different deploys. Set this key to `true` if the application is running in a container, such as with Docker. Newer versions of the AppSignal integration automatically detect its container environment, so no manual configuration is necessary. If you're having trouble with the automatic detection, please [contact support](mailto:support@appsignal.com). This option is set to `true` automatically on [Heroku](http://heroku.com/). ## send\_environment\_metadata | Field | Value | | - | - | | Config file key | `send_environment_metadata` | | System environment key | `APPSIGNAL_SEND_ENVIRONMENT_METADATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `0.1.0` | ### Description Send environment metadata about the app. For more information please read about [environment metadata](/application/environment-metadata). ## send\_function\_parameters | Field | Value | | - | - | | Config file key | `send_function_parameters` | | System environment key | `APPSIGNAL_SEND_FUNCTION_PARAMETERS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.6.0` | | |
    • `1.8.0`: Its value is derived from the [`send_params`](#option-send_params) configuration option until this option is set.
    | ### Description Whether to send function parameters to AppSignal. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [send\_params](#option-send_params) configuration > option for sending data when not using the agent. ## send\_params | Field | Value | | - | - | | Config file key | `send_params` | | System environment key | `APPSIGNAL_SEND_PARAMS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `0.1.0` | ### Description Whether to skip sending request parameters to AppSignal. For more information please read about [send\_params](/application/parameter-filtering) in filtering request parameters. > [!NOTE] > > **Agent only:** when using [an external collector](#option-collector_endpoint), this configuration option sets the default for the options below and has no other effect. > > Set the following configuration options to control whether request payloads, request query parameters and function parameters are reported: > > * [`send_function_parameters`](#option-send_function_parameters) > * [`send_request_payload`](#option-send_request_payload) > * [`send_request_query_parameters`](#option-send_request_query_parameters) ## send\_request\_payload | Field | Value | | - | - | | Config file key | `send_request_payload` | | System environment key | `APPSIGNAL_SEND_REQUEST_PAYLOAD` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.6.0` | | |
    • `1.8.0`: Its value is derived from the [`send_params`](#option-send_params) configuration option until this option is set.
    | ### Description Whether to send request payload to AppSignal. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [send\_params](#option-send_params) configuration > option for sending data when not using the agent. ## send\_request\_query\_parameters | Field | Value | | - | - | | Config file key | `send_request_query_parameters` | | System environment key | `APPSIGNAL_SEND_REQUEST_QUERY_PARAMETERS` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `1.6.0` | | |
    • `1.8.0`: Its value is derived from the [`send_params`](#option-send_params) configuration option until this option is set.
    | ### Description Whether to send request query parameters to AppSignal. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). > > See the [send\_params](#option-send_params) configuration > option for sending data when not using the agent. ## send\_session\_data | Field | Value | | - | - | | Config file key | `send_session_data` | | System environment key | `APPSIGNAL_SEND_SESSION_DATA` | | Required | no | | Type | Boolean (`true` / `false`) | | Default value | `true` | | Available since version | `0.1.0` | ### Description Set this option to `false` to not send any session data with exception and performance traces. For more information please read about [request session data filtering](/application/session-data-filtering). ## service\_name | Field | Value | | - | - | | Config file key | `service_name` | | System environment key | `APPSIGNAL_SERVICE_NAME` | | Required | no | | Type | `String` | | Default value | \`\` | | Available since version | `1.6.0` | ### Description The service name helps AppSignal recognize different services for traces and groups the traces automatically in a namespace based on the service name. Choose a name that fits your application, such as `web-server`, `background-worker`, `email-service` or `authentication-service`. > [!NOTE] > > **Collector only:** this configuration option will only have an effect when using > [an external collector](#option-collector_endpoint). ## statsd\_port | Field | Value | | - | - | | Config file key | `statsd_port` | | System environment key | `APPSIGNAL_STATSD_PORT` | | Required | no | | Type | `Integer` | | Default value | `8125` | | Available since version | `0.2.2` | ### Description Set this option to configure the StatsD HTTP server port of the AppSignal agent process. Configure this port if another process is already running on the machine that is also using this port to avoid conflicts. ## working\_directory\_path | Field | Value | | - | - | | Config file key | `working_directory_path` | | System environment key | `APPSIGNAL_WORKING_DIRECTORY_PATH` | | Required | no | | Type | `String` | | Default value | detected by agent | | Available since version | `0.1.0` | ### Description Override the location where AppSignal for Python can store temporary files. Use this option if the default location is not suitable. See our [how AppSignal operates](/appsignal/how-appsignal-operates) page for more information about the purpose of this working directory. If you are running multiple applications using AppSignal on the same server, use this configuration option to select different working directories for every AppSignal instance, otherwise the two instances could conflict with one another. For more information on this scenario see our [running multiple applications on one host](/guides/application/multiple-applications-on-one-host) documentation. ```python Python theme={null} # __appsignal__.py appsignal = Appsignal( # Other config working_directory_path="/tmp/project_1" ) ``` > [!NOTE] > > **Note**: The specified path cannot contain Operating Specific file system > abstractions, such as the homedir symbol `~` for \*NIX systems. This will be > seen as a malformed path. # AppSignal Python Installation Source: https://docs.appsignal.com/python/installation Install the AppSignal package in a Python application, add instrumentation packages for your libraries, and configure it. This documentation walks you through the steps needed to add the AppSignal package to your application. New to AppSignal? We recommend following our [installation guide](/guides/new-application) first. ## Requirements Before you can run AppSignal, make sure your application's [Operating System is supported](/support/operating-systems). ## Installation First, [sign up](https://appsignal.com/users/sign_up) for an AppSignal account and add the AppSignal for Python integration package to your `requirements.txt` file: ```python Python theme={null} # requirements.txt appsignal ``` If you want to enable [distributed tracing](/distributed-tracing) and [logging](/logging/integrations/python), send your data through an [AppSignal Collector](/collector) by setting two options: * [`collector_endpoint`](/python/configuration/options#option-collector_endpoint): your collector's base URL. Create a collector on the ["Hosted Collector"](https://appsignal.com/redirect-to/organization?to=admin/hosted_collectors) page in your organization's settings and copy its "Collector URL", or [deploy your own](/collector/installation). Distributed tracing needs a hosted collector. * [`service_name`](/python/configuration/options#option-service_name): names this application in distributed traces, so a trace that crosses several services shows which one did what. Use a different value for each service. Then, install the package and run our automated install tool, which will create an `__appsignal__.py` file in your project: ```bash Bash theme={null} pip install -r requirements.txt python -m appsignal install ``` If the `pip` and `python` executables do not work, please use the `pip3` and `python3` executables instead. The install tool does not add the collector options. Add `collector_endpoint` and `service_name` to the `__appsignal__.py` file it creates, as shown in the [collector configuration guide](/python/configuration/collector#configuring-the-collector). ### Manual installation You can also skip the automated tool and create the `__appsignal__.py` file manually: ```python Python theme={null} from appsignal import Appsignal appsignal = Appsignal( name="My app name", push_api_key="my-push-api-key", active=True, collector_endpoint="https://collector.example", service_name="web-server", ) ``` ### Installing instrumentation packages The AppSignal package does not automatically instrument any libraries. AppSignal offers support for a number of popular Python libraries, you can learn more about how to instrument these libraries in our Instrumentations documentation: * [Celery](/python/instrumentations/celery) * [Django](/python/instrumentations/django) * [FastAPI](/python/instrumentations/fastapi) * [Flask](/python/instrumentations/flask) * [Jinja2](/python/instrumentations/jinja2) * [MySQL](/python/instrumentations/mysql) * [PostgreSQL](/python/instrumentations/postgresql) * [Redis](/python/instrumentations/redis) * [Requests](/python/instrumentations/requests) * [Starlette](/python/instrumentations/starlette) * [WSGI/ASGI](/python/instrumentations/wsgi) ## Configuration After installing AppSignal and all necessary packages, you can read the [Configuration documentation](/python/configuration) to learn how to report data to AppSignal. ## Upgrading New releases include bug and security fixes, so keep AppSignal up to date. To update, run `pip install --upgrade appsignal`, change the version in `requirements.txt` if you pin one, and redeploy. [Python language]: https://www.python.org/ [OpenTelemetry]: https://opentelemetry.io/ # Custom instrumentation for Python Source: https://docs.appsignal.com/python/instrumentation Overview of custom instrumentation for Python, covering spans and exception handling. AppSignal provides many ways to bring more insights in your application by adding more instrumentation or tagging the data that appears in AppSignal. * [Instrumentation](/python/instrumentation/instrumentation) * [Exception handling](/python/instrumentation/exception-handling) # Python exception handling Source: https://docs.appsignal.com/python/instrumentation/exception-handling AppSignal tries to record as many Python exceptions as possible. AppSignal is able to capture exceptions across your application with [our instrumentations](/python/instrumentations) that extend our support to many popular frameworks and background job packages. However, there may be scenarios where exceptions are raised that are not related to potential problems in your Python application, such as bots trying to automatically post forms or outdated links that might direct visitors to content that doesn't exist anymore. To avoid these errors from being raised as problems in AppSignal it's possible to add exception handling to your code or even let AppSignal completely ignore certain errors. ## Ignore errors The AppSignal configuration makes it possible to [ignore errors](/guides/filter-data/ignore-errors). By providing a list of specific errors AppSignal will not send alerts when these errors are raised. ## Exception handling Simply ignoring an error will silence notifications, but could potentially hide a bigger problem. For this reason we recommend you add exception handling with `try ... except` statements to your application. Using `try ... except` you can catch specific exceptions and add an alternative code path for when an exception occurs, such as rendering 404 pages or providing the user with more detailed error messages about what went wrong. For example, in a Django view file we can do the following: ```python Python theme={null} def show(request): try: user = Post.find(1) except RecordNotFound: return render(request, "not_found.html") ``` There's a couple of scenarios, such as when resources don't exist or when a form submission fails, that should be handled like this to provide proper HTTP responses to the end-user. If you want to report these caught errors to AppSignal, use the [`set_error`](#set_error) or [`send_error`](#send_error) helpers. ## set\_error Report errors, without having them crash your application. Using the `set_error` helper, the given error is set on the AppSignal trace, which reports the error on the trace (request / background job) to AppSignal. If you still want to track the error while catching it, you can use the `set_error` helper to add the exception to the current AppSignal trace. The error will be recorded in AppSignal, but your process will not crash. For example, in a Django view file we can do the following: ```python Python theme={null} from appsignal import set_error # In a Django view file def show(request): try: user = Post.find(1) except Post.DoesNotExist as error: set_error(error) return render(request, "not_found.html") ``` The exception will be tracked by AppSignal like any other error, and it allows you to provide custom error handling and fallbacks. > [!TIP] > > **Note:** This method only works when there is an AppSignal trace already > active. Otherwise the error will be ignored. This is true in most > automatically supported [instrumentations](/python/instrumentations) or when > using [custom instrumentation](/python/instrumentation). Please see > [`send_error`](#send_error) for sending errors without an active AppSignal > trace. ## send\_error AppSignal provides a mechanism to send errors to AppSignal without having to start a trace. This is useful for tracking errors that occur in code that's not in a web request or background job context, such as one off scripts or cron jobs. This is useful for apps that do not use our [instrumentations](/python/instrumentations) for this part of the app in which the error is raised. You can use the `send_error` method to directly send an exception to AppSignal from any place in your code without starting a trace first. ```python Python theme={null} from appsignal import send_error # In a script def perform(): try: user = Post.find(1) except Post.DoesNotExist as error: send_error(error) print("No post found!") ``` ### Additional metadata To add metadata to the sent error, use the `send_error_with_context` method. [Tags](/guides/tagging) and [other types of data customization](/guides/custom-data) can be added to the error this way. ```python Python theme={null} from appsignal import send_error_with_context, set_params # In a script def perform(): try: user = Post.find(1) except Post.DoesNotExist as error: # Using implicit current span with send_error_with_context(error): set_params({"abc": "def"}) # Using explicit `with` block span with send_error_with_context(error) as current_span: set_params({"abc": "def"}, current_span) print("No post found!") ``` # Python Custom Instrumentation Source: https://docs.appsignal.com/python/instrumentation/instrumentation Create spans with OpenTelemetry tracers in Python, and set the category, name, body, and root name with AppSignal helpers. Including custom instrumentation in your application can be helpful when identifying the specific lines of code causing performance problems. AppSignal for Python uses OpenTelemetry tracer objects; you can read more about Python traces in OpenTelemetry's [Python Cookbook][cookbook]. Traces are made of one or many spans. A Trace can be thought of as a directed acyclic graph (DAG) of spans: ![Trace diagram](https://mintcdn.com/appsignal-715f5a51/nF8c1Rwq1cS7b5hg/assets/images/abstract-trace.png?fit=max\&auto=format\&n=nF8c1Rwq1cS7b5hg\&q=85\&s=8e955df41909f6fadf6d607478d6badb) AppSignal specific attributes must be added to a span in order for it to be successfully parsed by AppSignal. Our set of [helper methods](#helper-methods) can be used to set these attributes. This documentation will explain how to create custom instrumentations by setting AppSignal specific attributes in your Python application's spans. ## Creating a span When adding custom instrumentation, first import the OpenTelemetry trace module in the file you want to add instrumentation to. ```python Python theme={null} from opentelemetry import trace ``` Then, using that trace module, create a new span: ```python Python theme={null} tracer = trace.get_tracer(__name__) with tracer.start_as_current_span("Span name"): # Here you can execute your app logic # And set AppSignal span details: from appsignal import set_category set_category("category.name") ``` Once you've retrieved the Span, you can use our [helper methods](#helper-methods) to assign the required attributes. More information about creating and getting Spans is available in [OpenTelemetry's Python Cookbook][cookbook]. ## One offs and Serverless When running one-off scripts or serverless functions, you need to manually initialize AppSignal and stop it at the end to ensure no data is lost. The `stop` helper will gracefully kill the agent process and wait a while to ensure all data is sent to the AppSignal servers. ```python Python theme={null} appsignal = Appsignal( active=True, name="My Python App", push_api_key="YOUR_PUSH_API_KEY", ) appsignal.start() # Your code here along with the instrumentation # ... appsignal.stop() ``` ## Helper methods The following helper methods set AppSignal specific attributes on spans that help group spans and improve how they're displayed in AppSignal. Other attributes are not supported on spans by AppSignal. ### `set_category` The span category is the name that appears in the performance event timeline for traces. It's also used to group spans together to create a breakdown per group on the trace detail page. ```python Python theme={null} from appsignal import set_category set_category("category.name") set_category("query.users") set_category("update.users") set_category("view.users") ``` The category is a string containing the child span event and group. The category should use a dot (`.`) to express the hierarchical inheritance of the event, with the highest unit last. For more information on span categories, please see the [event names guide](/api/event-names). Set a category on every span you instrument yourself. AppSignal reports a span it does not recognize under the category `unknown`, which groups it with every other unrecognized span. > [!WARNING] > > This helper has no effect when AppSignal reports to [a collector](/python/configuration/collector). ### `set_name` More details can be added to the span that are visible when hovering over the event in the event timeline. The span name is used to provide more information about the event, such as "Fetch users", the database from which they are fetched or the URL that was requested. ```python Python theme={null} from appsignal import set_name set_name("Fetch users") ``` If this method is not called, it will use the value with which `start_as_current_span` was called. ### `set_body` > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). The span's body can include additional information about the event, like the HTTP request, the connected host, etc. Be sure to sanitize the information before adding it to the span so no Personal Identifiable Information is sent to AppSignal. This information will be visible for the span when hovering over the event timeline. To store SQL queries in the span's body, please use the [`set_sql_body` helper](#set_sql_body) instead. ```python Python theme={null} from appsignal import set_body set_body("Span body") ``` ### `set_sql_body` > [!TIP] > > Available since Python package 0.3.2. Set a SQL query as the body of the span as it appears in the performance event timeline in the incident trace detail view. This is similar to the [`set_body` helper](#set_body), but is specialized for SQL queries. Any SQL query set as the body with this attribute will be sanitized to avoid sending PII (Personal Identifiable Information) data to our servers. See the [`set_body` helper](#set_body) for more details on how the body attribute works. When both the `set_body` and `set_sql_body` helpers are called on the same span, the `set_sql_body` helper's value is leading and the `set_body` helper's value will be ignored. ```python Python theme={null} from appsignal import set_sql_body set_body("SELECT * FROM users") ``` ### `set_root_name` > [!TIP] > > This attribute applies to the entire trace. It can be set on a child span, and does not need to be set on the uppermost parent span. This attribute can only be set once per trace. If it is set multiple times, only the attribute from one span in the trace is applied. Every trace is grouped under an HTTP endpoint, background job worker name, or task name. We call this group the "action name". To change this action name for the entire trace, use the `set_root_name` helper. Use an action name generic enough to group all traces from this part of the app, while not reporting different names every time. Set `GET /users/:id` (where `:id` the URL parameter name) as the action name, instead of `GET /users/123` (where `123` is the actual value made in the request). The latter would report a new incident for every unique request. ```python Python theme={null} from appsignal import set_root_name set_root_name("GET /custom") # With URL parameters set_root_name("GET /users/:id") ``` #### Example Use Case Your application has an endpoint called `GET /coffee`. ```python Python theme={null} def coffee(request): return render(request, "coffee.html", {}) ``` All requests to this endpoint will generate traces called `GET /coffee`, but your endpoint handles multiple actions: `coffee?action=buy`, and `coffee?action=sell`. ![Span Without Root Name](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/span-without-root-name.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=c17dd17713da423bac8d380df6274a1e) While they all use the `GET /coffee` endpoint, they are conceptually very different and so it would make sense for them to be grouped separately in AppSignal rather than in the same `GET /coffee` trace. To do this, you can use the `set_root_name` helper: ```python Python theme={null} from appsignal import set_root_name def coffee(request): if request.GET.action == "buy": set_root_name("Buy coffee") # Buy coffee... elif request.GET.action == "sell": set_root_name("Sell coffee") # Sell coffee... return render(request, "coffee.html", {}) ``` Using `set_root_name` will change the name of the root span, grouping the traces for the requests `coffee?action=buy` and `coffee?action=sell` into separate actions: ![Root Name Span](https://mintcdn.com/appsignal-715f5a51/4TRZP0Sq9Zq7PAPW/assets/images/screenshots/node/root-name-span.png?fit=max\&auto=format\&n=4TRZP0Sq9Zq7PAPW\&q=85\&s=2d6521845df3d5bcd8938900b4b643ac) ## Other trace data These helpers set data on the trace rather than on a single event: * [`set_error` and `send_error`](/python/instrumentation/exception-handling) report an error. * [`set_request_payload`, `set_request_query_parameters` and `set_function_parameters`](/guides/custom-data/request-parameters) report the parameters of a request or of a background job. * [`set_session_data`](/guides/custom-data/request-session-data) reports a request's session data. * [`set_header`](/guides/custom-data/request-headers) reports a request header. * [`set_custom_data`](/guides/custom-data/custom-data) reports data that fits none of the others. * [`set_tag`](/guides/tagging) tags the trace. * [`set_namespace`](/guides/namespaces) moves the trace into another namespace. [cookbook]: https://opentelemetry.io/docs/instrumentation/python/cookbook/ # Minutely probes Source: https://docs.appsignal.com/python/instrumentation/minutely-probes Minutely probes are a mechanism to periodically send custom metrics to AppSignal. In minutely intervals from when the probe was first created, a user-defined function can be called in which you can capture metrics to send them to AppSignal. Minutely probe functions are ran asynchronously. You can enable or disable minutely probes entirely with the [`enable_minutely_probes`](/python/configuration/options#option-enable_minutely_probes) config option. ## Registering probes To track custom metrics from your application, you can add your own probes. To register a probe, you must call the `probes.register()` method with two arguments: a probe name, and a function to be called once every minute. ```python Python theme={null} from appsignal import probes, set_gauge def set_database_size_gauge(): set_gauge("database_size", 10) probes.register("database", set_database_size_gauge) ``` To ensure all minutely probes are ran in a timely manner, it is important to avoid blocking for long periods inside a minutely probe function. ## Stateful probes A probe function can keep state in between executions by accepting it as an argument and returning it. This is useful to keep track of how values change over time: ```python Python theme={null} from appsignal import probes, set_gauge def set_user_signups_gauge(previous_user_count): current_user_count = User.objects.all().count() if previous_user_count is not None: set_gauge("user_signups", current_user_count - previous_user_count) return current_user_count probes.register("user_signups", set_user_signups_gauge) ``` The first time the minutely probe is called, `None` will be passed as the argument. In successive invocations, the value returned by the previous invocation will be passed to it as an argument. # Python Instrumentations Source: https://docs.appsignal.com/python/instrumentations This page lists all the libraries that AppSignal for Python supports. OpenTelemetry instrumentations that are not listed here may not work, report incomplete data or show up as "unknown" in the AppSignal interface. ## Supported Python Libraries * [Celery](/python/instrumentations/celery) * [Django](/python/instrumentations/django) * [FastAPI](/python/instrumentations/fastapi) * [Flask](/python/instrumentations/flask) * [Jinja2](/python/instrumentations/jinja2) * [MySQL](/python/instrumentations/mysql) * [Pika](/python/instrumentations/pika) * [PostgreSQL](/python/instrumentations/postgresql) * [Redis](/python/instrumentations/redis) * [Requests](/python/instrumentations/requests) * [Starlette](/python/instrumentations/starlette) * [SQLAlchemy](/python/instrumentations/sqlalchemy) * [SQLite](/python/instrumentations/sqlite) * [WSGI/ASGI](/python/instrumentations/wsgi) - [Celery](/python/instrumentations/celery) - [Django](/python/instrumentations/django) - [FastAPI](/python/instrumentations/fastapi) - [Flask](/python/instrumentations/flask) - [Jinja2](/python/instrumentations/jinja2) - [MySQL](/python/instrumentations/mysql) - [Pika](/python/instrumentations/pika) - [PostgreSQL](/python/instrumentations/postgresql) - [Redis](/python/instrumentations/redis) - [Requests](/python/instrumentations/requests) - [SQLAlchemy](/python/instrumentations/sqlalchemy) - [SQLite](/python/instrumentations/sqlite) - [Starlette](/python/instrumentations/starlette) - [WSGI/ASGI](/python/instrumentations/wsgi) # Celery Instrumentation Source: https://docs.appsignal.com/python/instrumentations/celery [Celery](https://github.com/celery/celery) is a simple, flexible, and reliable distributed system to process vast amounts of messages, while providing operations with the tools required to maintain such a system. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. First, install the `opentelemetry-instrumentation-celery` package. We also recommend installing the [Redis](/python/instrumentations/redis) instrumentation package. To add both instrumentation packages to your project, add the following lines to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-celery opentelemetry-instrumentation-redis ``` ## Setup Celery requires some extra setup, as it's an application component that's started separately. As shown in the example below, the `appsignal` module needs to be imported in the main file used to start Celery, and the `appsignal.start()` method needs to be called from a method with the `@worker_process_init.connect` decorator. In the example below, this initialization takes place in the `tasks.py` file. This file may be named differently in your application. ```python Python theme={null} # tasks.py # Import this file import appsignal from celery import Celery # Import this file from celery.signals import worker_process_init # Add the init_celery_tracing method with its annotation @worker_process_init.connect(weak=False) def init_celery_tracing(*args, **kwargs): appsignal.start() app = Celery('tasks', broker='redis://localhost') @app.task def slow_task(): # Do things ``` # Django Instrumentation Source: https://docs.appsignal.com/python/instrumentations/django [Django](https://www.djangoproject.com/) is a high-level Python web framework that encourages rapid development and clean, pragmatic design. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. First, install the `opentelemetry-instrumentation-django` package, as well as the `opentelemetry-instrumentation-wsgi` and `opentelemetry-instrumentation-asgi` packages. To add these packages to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-django opentelemetry-instrumentation-wsgi opentelemetry-instrumentation-asgi ``` To instrument queries performed via the Django ORM, install the instrumentation for the SQL database that your application uses: * [MySQL](/python/instrumentations/mysql) * [PostgreSQL](/python/instrumentations/postgresql) * [SQLite](/python/instrumentations/sqlite) > [!NOTE] > > The AppSignal for Python integration will automatically use this instrumentation when the corresponding package is installed. To disable this instrumentation without uninstalling the package, use the [`disable_default_instrumentations` configuration option](/python/configuration/options#option-disable_default_instrumentations). ## Development setup Django requires some extra setup, as it's usually the first thing started in an app. As shown in the example below, the `appsignal` module needs to be imported in the `manage.py` file. Then in the `main` method, the `appsignal.start` method needs to be called to initialize the instrumentation configured in the `__appsignal__.py` file. ```python Python theme={null} # manage.py #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" import os import sys # Add this import statement import appsignal def main(): """Run administrative tasks.""" os.environ.setdefault('DJANGO_SETTINGS_MODULE', '.settings') # Add this method call appsignal.start() try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(sys.argv) if __name__ == '__main__': main() ``` ## Production setup (WSGI/ASGI) In production, it is recommended to run Django using a WSGI or ASGI server, such as Gunicorn or Uvicorn. In this scenario, the `manage.py` file that is modified in the development setup above is never called. To instrument your application when started as a WSGI or ASGI server, add the following to your project's `wsgi.py` file, if using a WSGI server: ```python Python theme={null} # wsgi.py import os # Add this import statement import appsignal from django.core.wsgi import get_wsgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_app.settings') # Add this method call appsignal.start() application = get_wsgi_application() ``` Or to your project's `asgi.py` file, if using an ASGI server: ```python Python theme={null} # asgi.py import os # Add this import statement import appsignal from django.core.asgi import get_asgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_app.settings') # Add this method call appsignal.start() application = get_asgi_application() ``` ## Features By default, the Django instrumentation reports incoming request parameters, like query strings and routing parameters. > [!WARNING] > > 🔐 Do not send **Personal Identifiable Information (PII)** to AppSignal. Filter PII (e.g., names, emails) and use an ID, hash, or pseudonymized identifier instead. \ > \ > For **HIPAA-covered entities**, more info on signing a Business Associate Agreement (BAA) is available in our [Business Add-Ons documentation](/support/business-add-ons). # FastAPI Instrumentation Source: https://docs.appsignal.com/python/instrumentations/fastapi [FastAPI](https://fastapi.tiangolo.com/) is a modern, high-performance web framework for building APIs with Python. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. First, install the `opentelemetry-instrumentation-fastapi` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-fastapi ``` ## Setup Start AppSignal and define your FastAPI application. Then use the `FastAPIInstrumentor` to instrument your FastAPI application: ```python Python theme={null} # app.py from fastapi import FastAPI from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor import appsignal appsignal.start() app = FastAPI() # ... your app's code goes here ... FastAPIInstrumentor().instrument_app(app) ``` # Flask Instrumentation Source: https://docs.appsignal.com/python/instrumentations/flask [Flask](https://flask.palletsprojects.com/) is a lightweight web framework for Python that enables the development of web applications with simplicity and flexibility. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. First, install the `opentelemetry-instrumentation-flask` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-flask ``` ## Setup It's necessary to import **and start** the AppSignal client **before the Flask library is imported**. This ensures that the application instance is created with the automatic instrumentation applied. ```python Python theme={null} # app.py import appsignal appsignal.start() from flask import Flask # noqa: E402 app = Flask(__name__) # your app code ``` # Jinja2 Instrumentation Source: https://docs.appsignal.com/python/instrumentations/jinja2 ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. Install the `opentelemetry-instrumentation-jinja2` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-jinja2 ``` # MySQL Instrumentation Source: https://docs.appsignal.com/python/instrumentations/mysql ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. The installation instructions differ based on the MySQL adapter package you are using: * [`mysql`](#using-mysql) (from the `mysql-connector-python` package) * [`mysqlclient`](#using-mysqlclient) * [`pymysql`](#using-pymysql) > [!WARNING] > > When using [SQLAlchemy](/python/instrumentations/sqlalchemy), **do not** install these instrumentation packages. The instrumentation for SQLAlchemy will automatically instrument queries to the underlying database. Installing both instrumentation packages will result in duplicate events. ### Using `mysql` When using the `mysql-connector-python` MySQL adapter package (which is imported as `mysql`), install the `opentelemetry-instrumentation-mysql` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-mysql ``` ### Using `mysqlclient` When using the `mysqlclient` MySQL adapter package, install the `opentelemetry-instrumentation-mysqlclient` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-mysqlclient ``` ### Using `pymysql` When using the `pymysql` MySQL adapter package, install the `opentelemetry-instrumentation-pymysql` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-pymysql ``` # Pika Source: https://docs.appsignal.com/python/instrumentations/pika Pika is a Python implementation of the AMQP 0-9-1 protocol. The AppSignal for Python integration for [Pika](https://pika.readthedocs.io/en/stable/) instruments the sending and receiving of messages in your application. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. First, install the `opentelemetry-instrumentation-pika` package. ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-pika ``` If you run your consumers as separate processes, make sure to also import `appsignal` and call `appsignal.start()` before starting the Pika consumer processes, so that AppSignal can instrument the consumers' message processing. ## Features When using the Pika integration, AppSignal will create a performance trace for each message that is sent or received by a consumer. When a message is sent or received in an instrumented context, such as a web request or background job, AppSignal will display an event in the performance trace's event timeline representing the message sending or receiving. # PostgreSQL Instrumentation Source: https://docs.appsignal.com/python/instrumentations/postgresql ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. The installation instructions differ based on the PostgreSQL adapter package you are using: * [`aiopg`](#using-aiopg) * [`asyncpg`](#using-asyncpg) * [`psycopg2`](#using-psycopg2) * [`psycopg`](#using-psycopg) (version 3) > [!WARNING] > > When using [SQLAlchemy](/python/instrumentations/sqlalchemy), **do not** install these instrumentation packages. The instrumentation for SQLAlchemy will automatically instrument queries to the underlying database. Installing both instrumentation packages will result in duplicate events. ### Using `aiopg` When using the `aiopg` PostgreSQL adapter package, install the `opentelemetry-instrumentation-aiopg` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-aiopg ``` ### Using `asyncpg` When using the `asyncpg` PostgreSQL adapter package, install the `opentelemetry-instrumentation-asyncpg` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-asyncpg ``` ### Using `psycopg2` When using the `psycopg2` PostgreSQL adapter package, install the `opentelemetry-instrumentation-psycopg2` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-psycopg2 ``` ### Using `psycopg` When using the `psycopg` (version 3) PostgreSQL adapter package, install the `opentelemetry-instrumentation-psycopg` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-psycopg ``` # Redis Instrumentation Source: https://docs.appsignal.com/python/instrumentations/redis The Python interface to the [Redis](https://pypi.org/project/redis/) key-value store. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. Install the `opentelemetry-instrumentation-redis` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-redis ``` # Requests Instrumentation Source: https://docs.appsignal.com/python/instrumentations/requests ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. Install the `opentelemetry-instrumentation-requests` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-requests ``` # SQLAlchemy Instrumentation Source: https://docs.appsignal.com/python/instrumentations/sqlalchemy ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. > [!WARNING] > > When using SQLAlchemy, **do not** install the instrumentation packages for the > underlying database adapter (such as those for > [MySQL](/python/instrumentations/mysql), > [PostgreSQL](/python/instrumentations/postgresql) or > [SQLite](/python/instrumentations/sqlite)). The instrumentation for > SQLAlchemy will automatically instrument queries to the underlying database. > Installing both instrumentation packages will result in duplicate events. Install the `opentelemetry-instrumentation-sqlalchemy` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-sqlalchemy ``` # SQLite Instrumentation Source: https://docs.appsignal.com/python/instrumentations/sqlite ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. Install the `opentelemetry-instrumentation-sqlite3` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-sqlite3 ``` # Starlette Instrumentation Source: https://docs.appsignal.com/python/instrumentations/starlette [Starlette](https://www.starlette.io/) is a lightweight, high-performance web framework for building asynchronous Python applications. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. First, install the `opentelemetry-instrumentation-starlette` package. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt opentelemetry-instrumentation-starlette ``` ## Setup Start AppSignal and define your Starlette application. Then use the `StarletteInstrumentor` to instrument your Starlette application: ```python Python theme={null} # app.py from starlette.applications import Starlette from opentelemetry.instrumentation.starlette import StarletteInstrumentor import appsignal appsignal.start() # ... your application's code goes here ... app = Starlette( # ... ) StarletteInstrumentor().instrument_app(app) ``` # WSGI/ASGI Instrumentation Source: https://docs.appsignal.com/python/instrumentations/wsgi The WSGI and ASGI standards provide a common layer for the development of web frameworks and servers in Python. Most popular Python web frameworks follow these standards, allowing for any Python web application to be deployed with any Python web server. > [!TIP] > > ASGI support was added in version `0.1.4` of the AppSignal for Python package. AppSignal supports instrumentation for generic WSGI and ASGI web applications through OpenTelemetry. > [!TIP] > > AppSignal also supports popular web frameworks directly, such as > [Django](/python/instrumentations/django), > [Flask](/python/instrumentations/flask), > [FastAPI](/python/instrumentations/fastapi) or > [Starlette](/python/instrumentations/starlette). If you're using a web > framework we support directly, follow the instructions for that framework > instead of the generic WSGI/ASGI instructions on this page. ## Installation > [!NOTE] > > 🐍 Don't forget to [install the AppSignal for Python package](/python/installation) in your application first. First, install either the `opentelemetry-instrumentation-wsgi` or the `opentelemetry-instrumentation-asgi` package, depending the gateway interface used in the application. To add it to your project, add the following line to your `requirements.txt` file: ```python Python theme={null} # requirements.txt # For a WSGI application: opentelemetry-instrumentation-wsgi # For an ASGI application: opentelemetry-instrumentation-asgi ``` ## Setup In your application's entry point (usually named `main.py` or `app.py`), before your application is initialised, call `appsignal.start()` to start your application: ```python Python theme={null} import appsignal appsignal.start() # ... the rest of your code goes here ... ``` Then, import `OpenTelemetryMiddleware` from the corresponding OpenTelemetry instrumentation, and wrap your application with it: ```python Python theme={null} # For a WSGI application: from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware # For an ASGI application: from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware my_app = # ... your WSGI/ASGI application goes here ... my_app = OpenTelemetryMiddleware(my_app) ``` ## Grouping routes By default, a generic WSGI or ASGI instrumentation will not have the necessary context to understand how routing is structured in your application. As such, the performance traces that AppSignal receives will not be grouped correctly. You must add routing information to the OpenTelemetry span manually. One way to do so is by following OpenTelemetry's HTTP semantic conventions, setting the `http.route` attribute in your route handlers: ```python Python theme={null} from opentelemetry.trace import get_current_span def get_user_route_handler(): get_current_span().set_attribute("http.route", "/users/:user_id") # ... your route handler goes here ... ``` AppSignal will automatically use the value of this attribute and use it to group requests, along with the request method. For example, a GET request that is handled by this method will appear as `GET /users/:user_id` in the AppSignal performance traces panel. If you prefer to group requests in some other way (for example, by referring to the method or class that implements them) you can use the `appsignal.root_name` attribute: ```python Python theme={null} from opentelemetry.trace import get_current_span class UserHandlers: def show(): get_current_span().set_attribute("appsignal.root_name", "UserHandlers#show") # ... your route handler goes here ... ``` By using `appsignal.root_name`, the request method will not be used. The value provided (in this case, `UserHandlers#show`) will be used to group all requests handled by this method. # AppSignal for Ruby: Command-line tools Source: https://docs.appsignal.com/ruby/command-line The [AppSignal Ruby gem][gem] ships with several command-line tools. These tools make it easier to install AppSignal in an application, send deploy notifications and diagnose any problems with the installation. ## Install A command-line tool to install AppSignal in your Ruby application. Read more about the [appsignal install][cli-install] command-line tool. ## Diagnose A self-diagnostic tool that can be used to debug the installation and configuration of your AppSignal integration. It is one of the first tools that our support team requests you to run when debugging an issue. Read more about the [appsignal diagnose][cli-diagnose] command-line tool. ## Demo A command-line tool that sends demonstration traces to AppSignal. When the tool is run, it sends an error and performance trace from your machine to AppSignal. Read more about the [appsignal demo][cli-demo] command-line tool. [gem]: https://github.com/appsignal/appsignal-ruby [cli-install]: /ruby/command-line/install.html [cli-diagnose]: /ruby/command-line/diagnose.html [cli-demo]: /ruby/command-line/demo.html # AppSignal for Ruby: Demo tool Source: https://docs.appsignal.com/ruby/command-line/demo The AppSignal gem includes a command-line tool that sends demonstration traces to AppSignal. When the tool is run, it sends an error and performance trace from your machine to AppSignal. This command-line tool is useful for testing AppSignal on a system and validating your local configuration. The same test is also run during installation when using the [`appsignal install` command](/ruby/command-line/install). To learn more about how to use the demonstration command, visit the [Debugging page][debugging]. ## Usage To run the demonstration tool, run the following terminal command from your project's root folder: ```bash Bash theme={null} appsignal demo ``` If you want to make sure the config for a specific environment is used, you can use the optional [`--environment`](#available-options): ```bash Bash theme={null} appsignal demo --environment=production ``` ## Available Options | Option | Usage | Description | | - | - | - | | environment | `--environment=` | Set the environment to use in the command, e.g. `production` or `staging`. | [debugging]: /support/debugging.html # AppSignal for Ruby: Diagnose tool Source: https://docs.appsignal.com/ruby/command-line/diagnose The AppSignal Ruby gem includes a self-diagnostic tool that can be used to debug the installation and configuration of your AppSignal integration. It is one of the first tools that our support team requests you to run when debugging an issue. ## The diagnostic report You can use this diagnostic tool to test and validate your AppSignal installation. It outputs useful information to debug issues and it checks if AppSignal agent is able to run on the machine's architecture and communicate with the AppSignal servers. This diagnostic tool collects and outputs the following: * Information about the AppSignal gem. * Information about the host system and Ruby. * If the AppSignal [extension](/appsignal/how-appsignal-operates#extension) and [agent](/appsignal/how-appsignal-operates#agent) can run on the host system. * All configured config options (including default values). * If the configuration is valid and active. * If the Push API key is present and valid (internet connection required). * Where configuration option values originate from. * If the required system paths exist, are writable, and which user and group are owners. * Small parts of the tail from the available log files. You can read more about how to use the diagnose command in our [Debugging](/support/debugging) documentation. ## Submitting the report In gem version `2.2.0` and higher you will be prompted to send the report to AppSignal. If accepted the report will be send to our servers and you will receive a support token. When you [send this support token to us](mailto:support@appsignal.com) we will review the report and help you debug the issue. We've seen that copy-pasting the report output usually loses formatting and makes it harder to read, which is why it's send to our servers in the JSON format. In gem version `2.8.0` the option was added to view the report yourself on AppSignal.com. A link to the report is printed in the diagnose output. This web view will also show any validation problems and warnings our system detected. ## Usage On the command-line in your project run: ```bash Bash theme={null} appsignal diagnose ``` If you're experiencing an issue in production and need to send the report to AppSignal for support, you can run the following command to generate and send the report to our servers: ```bash Bash theme={null} bundle exec appsignal diagnose --environment=production --send-report ``` ## Options | Option | Description | | - | - | | [`--environment=`](#environment-option) | Set the environment to use in the command, e.g. `production` or `staging`. | | [`--[no-]send-report`](#report-submission-option) | Automatically send, or do not send the report. | | `--[no-]color` | Toggle the colorization of the output. | ### Environment option To select a specific environment with the CLI, run the below command: ```bash Bash theme={null} appsignal diagnose --environment=production ``` The environment option is useful when there is no default environment (non-Rails apps and apps configured with an [config file](/ruby/configuration/load-order#4-appsignal-yml-config-file)) or the default environment is not the one you want to diagnose. The diagnose tool will warn you when no environment is selected. ### Report submission option The options to [submit the report](#submitting-the-report) immediately, or not, were added to the AppSignal gem version `2.8.0`. Selecting whether or not to send the report with these options will no longer prompt this question, making it easier to use in non-interactive environments. To run diagnose and submit the report data to AppSignal, run the below command: ```bash Bash theme={null} appsignal diagnose --send-report ``` To run diagnose without sending the report data to AppSignal, run the below command: ```bash Bash theme={null} appsignal diagnose --no-send-report ``` ## Configuration output format ### Configuration option values format The configuration options are printed to the CLI as their inspected values. This means we print them as Ruby would in a console. * Strings values are printed with double quotes around them, e.g. `"My app name"`. * Booleans values are printed as their raw values: `true` and `false`. * Arrays values are printed as a collection of values surrounded by square brackets, e.g. `["HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET"]`. * Empty Arrays are printed as two square brackets: `[]`. * Nil values are printed as `nil`. ### Configuration sources The configuration section also displays the origin of config option values, which can help identify sources that override values defined in other config sources. You can read more about configuration sources their load order, and priority in the [configuration load order](/ruby/configuration/load-order) documentation. The configuration options are displayed based on the source of their values and the number of sources that set them, like in the below example: ```text Shell theme={null} Configuration # Option with a value loaded only from the default source send_params: true # Option with one source # A different source than the default source name: "My app name" (Loaded from file) # Option with multiple sources # Listed in order of priority (highest priority last) active: true Sources: default: false file: false env: true ``` [debugging]: /support/debugging.html # AppSignal for Ruby: Install Source: https://docs.appsignal.com/ruby/command-line/install Command-line tool to install AppSignal in a Ruby application. Documentation on usage, options and configuration methods. The documentation tells you everything you need to know about installing AppSignal via the command-line tool. ## Description The command-line tool helps with setting up the configuration for your application. Integration with Ruby applications not using the Rails framework requires additional steps, because the AppSignal installer does not know how your application is set up. We recommend you our [installation guide](/guides/new-application) when adding a new application to AppSignal. For Rails applications, full integration is automatic. For other frameworks, please refer to our [Integrations documentation](/ruby/integrations/). Once the installation is complete, run the [demo tool command](/ruby/command-line/demo) to verify that the installation was successful. The demo tool command sends sample data from your application to the AppSignal servers, which helps you verify that everything is working properly. ## Configuration methods There are two configuration methods provided by the command-line installer: 1. [Configuration via a configuration file](#1-configuration-file) 2. [Configuration via environment variables](#2-environment-variables). ### Configuration file AppSignal can be configured via a configuration file called `appsignal.rb` or `appsignal.yml`, located in your application in the `config/` directory. When choosing this option our installer will write your configuration to this file. When configuring your AppSignal integration via the configuration file, the Push API key you provide to the installer will be written into the `appsignal.yml` configuration file. We do not recommend adding this key to version control systems such as Git, SVN or Mercurial. Instead, use the `APPSIGNAL_PUSH_API_KEY` environment variable to store your API key. You can read more about configuring your application in our [configuration documentation](/ruby/configuration). ### Environment variables AppSignal can be configured through system environment variables. If you select this option, no [configuration file](#1-configuration-file) will be generated. You can read more about configuring your application in our [configuration documentation](/ruby/configuration). ## Usage To install appsignal via the command-line, navigate to your project directory and run the following command: ```bash Bash theme={null} appsignal install # For example appsignal install 1234-1234-1234-1234 ``` Your application's "Push API key" will be displayed in the [installation wizard](https://appsignal.com/redirect-to/organization?to=sites/new) and is also available in the administration section of your organization's settings, or via [this link](https://appsignal.com/redirect-to/organization?to=admin/api_keys). ## Available Options | Option | Usage | Description | | - | - | - | | color | `--[no-]color` | Toggle the colorization of the output. | # AppSignal for Browser Source: https://docs.appsignal.com/browser AppSignal for Browser reports front-end errors with breadcrumbs and web vitals from real users through the standalone @appsignal/browser package. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). Browser monitoring reports front-end errors with recent breadcrumbs and web vitals from real users. It is a separate section in AppSignal, alongside the traces, errors, and metrics your back-end integration reports. Data collection is handled by `@appsignal/browser`, a standalone package that does not depend on any other AppSignal package. ## What it collects > **[Errors](/browser/error-tracking)** > > Uncaught exceptions and unhandled promise rejections, with available stack traces, tags, and the route the user was on. > **[Breadcrumbs](/browser/breadcrumbs)** > > Navigation, clicks, network requests, and console warnings and errors before each error. Collected automatically after `init()`. > **[Web vitals](/browser/web-vitals)** > > LCP, INP, CLS, FCP, and TTFB from real users, aggregated per route and comparable across releases. To see browser and back-end work in one [trace](/browser/distributed-tracing), configure both sides. The Browser SDK sends trace context. The receiving API service needs instrumentation to read it and report spans. A matching 5xx response or timeout can still produce a browser error. Without back-end instrumentation, its trace has no back-end spans. ## Where to find it in AppSignal The Browser section of your application has two views: * **Errors** groups front-end errors into issues you can triage. Read more in [front-end errors in AppSignal](/browser-monitoring/errors). * **Performance** summarizes the five web vitals and breaks them down per route. Read more in [front-end performance in AppSignal](/browser-monitoring/performance). Front-end errors are reported to the `browser` [namespace](/guides/namespaces), which keeps them out of your back-end error lists and notification settings. For what browser monitoring covers as a feature, see the [browser monitoring overview](/browser-monitoring). ## Relation to AppSignal for JavaScript If you use [`@appsignal/javascript`](/front-end), follow the [migration guide](/browser/migration) when moving to `@appsignal/browser`. The new SDK has a different API. It collects breadcrumbs and web vitals after `init()` and reports errors to the `browser` namespace. ## Requirements * A browser that supports ES2020. The package targets ES2020 and does not ship polyfills. * CLS and INP require the browser's `layout-shift` and `event-timing` performance entry types, respectively. The SDK skips either metric when its entry type is unavailable. **Optional**: React 16.8 or later, if you want to use the error boundary shipped with the package. ## Next steps > **[Generate your snippet](https://appsignal.com/redirect-to/organization?to=sites/new/browser)** > > Let AppSignal build the install code with your Front-end API key filled in. > **[Install the package](/browser/installation)** > > Add `@appsignal/browser` to your application and start reporting. > **[Configuration options](/browser/configuration)** > > Every option, its type, and its default. > **[Filter what you send](/browser/privacy)** > > Scrub URLs, mask elements, and gate collection on user consent. > **[Migrate from AppSignal for JavaScript](/browser/migration)** > > Map the old API onto the new one. # Browser breadcrumbs Source: https://docs.appsignal.com/browser/breadcrumbs AppSignal for Browser records routes, clicks, requests, and console output before an error. Add your own breadcrumbs for anything else. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). A breadcrumb is one entry in a time-ordered trail of what happened in the browser before an error. Reproducing a front-end bug from a stack trace alone is often guesswork. It shows the previous route and what the user clicked. It also shows requests and console warnings or errors. Breadcrumbs are collected automatically after `init()`. Up to 25 breadcrumbs from the error context buffer travel with each reported error, including a breadcrumb for that error. You can read them in the issue's sample. ## What is collected These automatic categories can appear with an error report: | Category | Recorded | | - | - | | `navigation` | The URL at startup, then every `pushState`, `replaceState`, `popstate`, and `hashchange`, with both the previous and the new URL. | | `click` | A readable label for the element the user selected, for example `button "Submit"` or `link "Dashboard"`. Shortened to 50 characters. Also records where on the screen they selected it. | | `network` | Method, URL, status, and duration for `fetch` and `XMLHttpRequest` calls, plus the initial document load. Canceled requests are omitted. Includes a resource timing breakdown where the browser exposes one. | | `console` | Anything sent to `console.warn` and `console.error`, cut off after 200 characters. `console.log` is left alone. | | `long_task` | Any main-thread block longer than 50 ms, with script attribution where the browser provides it. | | `visibility` | The tab became hidden or visible. | | `error` | Each captured error, so an earlier error shows up in a later one's trail. | The [`breadcrumbs` options](/browser/configuration#breadcrumbs-network) can turn off network, console, click, and long-task collection. Navigation, visibility, and error breadcrumbs have no separate switch. ## Labeling elements Selection breadcrumbs describe the element the way a person would recognize it, rather than by its position in the page. AppSignal first looks for a `data-breadcrumb` attribute. Otherwise, it uses the element type and text, such as `button "Submit"`. If neither helps, it uses the tag and ID, such as `input#cvc`. When the automatic label is unhelpful, or when the visible text is something you would rather not send, set your own: ```html HTML theme={null} ``` The attribute is read from the element or any of its ancestors, so labeling a container covers everything inside it. ## Adding your own breadcrumbs Record anything else worth knowing with `addBreadcrumb()`: ```js JavaScript theme={null} import { addBreadcrumb } from "@appsignal/browser"; addBreadcrumb({ category: "checkout", message: "Payment method changed", data: { from: "card", to: "ideal" }, }); ``` | Option | Type | Description | | - | - | - | | `category` | `string` | A label to group the event under, for example `checkout` or `auth`. | | `message` | `string` | What happened. | | `data` | `object` | Optional key-value metadata. | Your own breadcrumbs travel with errors whatever category you give them. ## What the SDK does not capture automatically * **Request and response bodies.** The SDK does not read them from network calls. If a payload matters for debugging, add only the parts you need with `addBreadcrumb()`. * **Cookies.** The SDK reads and writes none. * **Query parameters in most SDK-created URL fields.** [`privacy.queryParamsAllowlist`](/browser/privacy#urls-and-query-parameters) removes them by default from navigation and `fetch`/`XMLHttpRequest` breadcrumbs. The initial document-load breadcrumb is an exception. * **Blocked `fetch` and `XMLHttpRequest` calls.** Calls matching [`privacy.networkBlocklist`](/browser/privacy#excluding-network-requests), and calls to AppSignal's own endpoint, leave no breadcrumb and are never reported as [failed requests](/browser/distributed-tracing#what-is-reported). The initial document-load breadcrumb is not covered by the blocklist. * **Text and elements you have masked.** Read more in [masking and blocking page elements](/browser/privacy#masking-and-blocking-page-elements). To filter or redact individual breadcrumbs as they are recorded, use [`beforeBreadcrumb`](/browser/privacy#filtering-errors-and-breadcrumbs). ## Reading network breadcrumbs A network breadcrumb reads as method, URL, and status whenever a response arrived, including `404` and `500` responses. An `(error)` suffix means no response arrived. The cause may be DNS, a refused connection, or a blocked request. A request that sent a `traceparent` header also records its trace ID in the breadcrumb. Its row shows an **Open trace** button, and selecting it opens the related trace's timeline. The timeline shows back-end spans only if the receiving service is [instrumented](/browser/distributed-tracing#before-you-start) and the trace is within your data retention. Otherwise, it reads "No backend spans found for this request". ![Breadcrumbs card with two network requests, a navigation, and an error. The pointer is on the icon next to GET /api/boom/, which returned 500, and shows the Open trace tooltip.](https://mintcdn.com/appsignal-715f5a51/qcNVjysU7GB972Yz/assets/images/screenshots/browser/breadcrumbs-open-trace.png?fit=max\&auto=format\&n=qcNVjysU7GB972Yz\&q=85\&s=a54109f696a2cc9d53c297ea63e67bc4) The Open trace button on a network breadcrumb that carries a trace ID. Cross-origin requests report no timing breakdown unless the server sends a `Timing-Allow-Origin` header. That is a browser restriction, not an AppSignal one. # AppSignal for Browser configuration options Source: https://docs.appsignal.com/browser/configuration Every option the AppSignal for Browser init() call accepts, from the Front-end API key to error sampling and breadcrumbs. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). Pass configuration to `init()` as one object. Only `key` is required. A second `init()` call is ignored until you call `destroy()`. Most applications change options in their next build. ```js appsignal.js theme={null} import { init } from "@appsignal/browser"; init({ key: "", endpoint: "https://appsignal-endpoint.net", active: process.env.NODE_ENV === "production", appVersion: "", tracePropagationTargets: ["api.example.com/**"], errors: { sampleRate: 1.0 }, breadcrumbs: { console: false }, privacy: { queryParamsAllowlist: ["utm_*", "page"], networkBlocklist: ["api.stripe.com/**"], dom: { blockElement: ["#card-form"] }, }, }); ``` ## `key` * **Type:** `string` * **Required** Your application's [Front-end API key](/browser/installation#find-your-front-end-api-key), which is meant to be exposed in public. It is not one of the Push keys your back-end integrations use. ## `endpoint` * **Type:** `string` * **Default value:** the current page's origin Where data is sent. Set it to `https://appsignal-endpoint.net`. If you proxy AppSignal traffic through your domain, leave it unset to use the current origin. A trailing slash is stripped. Errors are sent to `POST /ingest/browser/errors`, and web vitals to `POST /ingest/browser`. The key rides along as an `api_key` query parameter, which is worth knowing if you maintain a `connect-src` allowlist. ## `active` * **Type:** `boolean` * **Default value:** `true` The main on/off switch for the first `init()` call. When `false`, initialization returns without changing the page, starting timers, or making requests. A second `init()` call cannot switch off an SDK that is already running. Every other function does nothing too, so you can call them anywhere without checking first. Set this from your build environment so development, test, and CI runs send nothing: ```js JavaScript theme={null} init({ key: "", active: process.env.NODE_ENV === "production", // or import.meta.env.PROD }); ``` ## `appVersion` * **Type:** `string` The release tag, commit SHA, or deploy ID of the running build. It tags errors and web vitals for the Browser views' version filters. It also selects the [sourcemaps](/browser/error-tracking#sourcemaps) for backtraces. Read more in our [deploy markers guide](/application/markers/deploy-markers). ## `serviceName` * **Type:** `string` * **Default value:** `"Browser"` AppSignal uses this value as the service label for browser errors in a trace. For example, `serviceName: "Checkout UI"` shows `Checkout UI` instead of the default `Browser` in the trace timeline. Use a different value for each front end you monitor. The SDK sends it with every error report. See [distributed tracing for Browser](/browser/distributed-tracing). ## `tracePropagationTargets` * **Type:** `string[]` * **Default value:** `[]` Use this list to choose which API requests carry a `traceparent` header. Each pattern needs a host and a path. For example, `["api.example.com/**"]` matches every path on `api.example.com`. `api.example.com` alone matches nothing. If a matching request returns a 5xx response or times out, the SDK reports a browser error. To see back-end spans in its trace, [instrument the receiving service](/browser/distributed-tracing#before-you-start) to read the header. The default empty list adds no `traceparent` headers. See [distributed tracing for Browser](/browser/distributed-tracing) for setup and examples. ## `beforeError` * **Type:** `(event: IncomingError) => IncomingError | null` Called for errors that pass sampling and the global rate limit, before an error breadcrumb or report is created. Return `null` to drop the error, or change its fields to redact them. Read more in [filtering errors](/browser/privacy#filtering-errors-and-breadcrumbs). This callback must be synchronous. A returned promise is detected, logged as a `console.error`, and the error is dropped. ## `beforeBreadcrumb` * **Type:** `(breadcrumb: Breadcrumb) => Breadcrumb | null` Runs once for every breadcrumb, as it is recorded. Return `null` to throw it away, or change `message` and `data` to remove sensitive text. This runs often, so keep it fast. ## `errors.enabled` * **Type:** `boolean` * **Default value:** `true` Whether errors are reported at all. When `false`, the SDK still listens for them but sends nothing. ## `errors.sampleRate` * **Type:** `number` between `0` and `1` * **Default value:** `1.0` What share of errors to report. The choice is made at random for each error, so `0.25` reports roughly a quarter of them. This happens before the [rate limits](/browser/error-tracking#rate-limits) and before `beforeError` runs. ## `breadcrumbs.network` * **Type:** `boolean` * **Default value:** `true` Record breadcrumbs for `fetch` and `XMLHttpRequest` calls, except canceled requests. This option does not control the initial document-load breadcrumb. The SDK does not read request or response bodies. ## `breadcrumbs.console` * **Type:** `boolean` * **Default value:** `true` Record a breadcrumb for `console.warn` and `console.error`. `console.log` is not patched. ## `breadcrumbs.clicks` * **Type:** `boolean` * **Default value:** `true` Record a breadcrumb when a user selects an element. ## `breadcrumbs.longTasks` * **Type:** `boolean` * **Default value:** `true` Record a breadcrumb when the main thread is blocked for more than 50 ms. ## `privacy.queryParamsAllowlist` * **Type:** `string[]` * **Default value:** `[]` The query parameters to keep in recorded URLs. Use `*` to match several names at once, so `"utm_*"` keeps every UTM parameter. The default list is empty, which removes all of them. Read more in [privacy and filtering](/browser/privacy#urls-and-query-parameters). ## `privacy.networkBlocklist` * **Type:** `string[]` * **Default value:** `[]` Glob URL patterns for `fetch` and `XMLHttpRequest` calls that are not recorded as breadcrumbs or [failed request errors](/browser/distributed-tracing#what-is-reported). Matched against host and path. The calls still happen. This option does not filter the initial document-load breadcrumb. ## `privacy.dom.maskText` * **Type:** `string[]` * **Default value:** `[]` CSS selectors whose text content is replaced with `[masked]` in `click` breadcrumbs. The breadcrumb is still recorded, so you keep the fact that an interaction happened. ## `privacy.dom.blockElement` * **Type:** `string[]` * **Default value:** `[]` CSS selectors whose interactions are not recorded at all. Use this for card forms and other fields that should never surface. ## API reference Except for `init()`, these functions do nothing until the SDK has initialized with `active: true`. | Function | Description | | - | - | | `init(config)` | Start collection. Call once, as early as possible. Subsequent calls are ignored. | | `captureError(error)` | Report a caught error. The optional context argument is not included in ordinary error reports in this beta. Read more in [error tracking](/browser/error-tracking#reporting-errors-manually). | | `addBreadcrumb({ category, message, data? })` | Add your own breadcrumb to the timeline. | | `setRouteTemplate(template)` | Declare the route the user is on, for example `/users/:id`. Pass `null` to clear it. | | `setTags(tags)` | Attach tags to every error reported from now on. Merges with existing tags. | | `clearTags()` | Remove all tags. Tags outlive a reload, so call this on sign-out. | | `flush()` | Send buffered web vitals now. | | `destroy()` | Flush pending data and stop collection. Another `init()` call can start it again, including on the same page. | # Distributed tracing for Browser Source: https://docs.appsignal.com/browser/distributed-tracing See how a failed request in the browser connects to the back-end trace it started, so the error and the server-side work behind it read as one trace. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). A product page reports a failed `GET /api/boom/` request: HTTP 500. You know the request failed, but not why. [Distributed tracing](/distributed-tracing) follows that request from the browser into the back end that handled it and raised a `RuntimeError`. In this example, that is a Django app. Any back end that [supports distributed tracing](/distributed-tracing#availability-and-setup) works the same way. The [service map](/trace-page#service-map) shows both sides of that trace: ![Trace service map with two boxes, Browser and django, both marked with an error, connected by an 81 ms edge.](https://mintcdn.com/appsignal-715f5a51/Dd6j9BLrZGGvnmnD/assets/images/screenshots/browser/distributed-tracing-service-map.png?fit=max\&auto=format\&n=Dd6j9BLrZGGvnmnD\&q=85\&s=34693ed41ff4344c9a80827fbd60f3fd) The service map for this trace: the back-end error connected to the browser error that started it. To connect the browser error to work in the back end, set up both sides: 1. **Browser:** Add your API URL patterns to `tracePropagationTargets`. Matching requests carry a `traceparent` header. A 5xx response or qualifying timeout becomes a browser error. 2. **Receiving back end:** Instrument the service that handles those requests. The instrumentation reads `traceparent` and reports spans through an AppSignal hosted collector. Use a supported integration or OpenTelemetry instrumentation for its framework. Step 1 on its own only reports the browser error. Its timeline stays empty until the back end is instrumented in step 2, because the server spans come from that instrumentation, not from the browser SDK. Both steps are needed to see the request as one trace. > [!NOTE] > > Distributed tracing is a beta [AppSignal Labs](/labs) feature. The browser SDK needs no collector. The receiving service needs an AppSignal [hosted collector](/collector/hosted-vs-self-hosted#hosted-collector) for its spans. ## Before you start Your front end needs only the Browser SDK. The rest of the setup is in the back end: the service that handles your front end's requests. In the [example](#product-page-example) above, that is the Django service. It can be an API on its own host, or the same app that serves your pages. Set it up first, so its spans appear in the trace when a request fails: * **Report through a hosted collector.** On the [Hosted Collectors](https://appsignal.com/redirect-to/organization?to=admin/hosted_collectors) page in your organization settings, open a collector and copy its **Collector URL**. Send the service's data to that URL. If the list is empty, create a collector there first. Distributed tracing only works through a hosted collector. In [Python](/python/configuration/collector#configuring-the-collector) and [Ruby](/ruby/configuration/collector#configuring-the-collector), set the URL as the `collector_endpoint` option. Ruby also needs [the `appsignal-opentelemetry` gem](/ruby/configuration/collector#installing-the-opentelemetry-gems). * **Set a service name.** Give the service its own name. The trace uses it to tell the service apart from the browser and other services. Where you set it depends on the back end's language: * [Python](/python/configuration/options#option-service_name), [Ruby](/ruby/configuration/options#option-service_name), and [PHP](/php/configuration/options#option-service_name): the `service_name` option. * [Go](/go/configuration/options#option-service.name) and [Java](/java/configuration/options#option-service.name): the `service.name` resource attribute. * [Other OpenTelemetry setups](/opentelemetry/configuration/options#service-name): the `service.name` resource attribute. * **Instrument its HTTP server.** Use an integration for its framework that reads `traceparent` from incoming requests. That is how the service joins the browser's trace instead of starting its own. In Go, also [register a propagator](/go/installation#configure-opentelemetry-in-your-application) with `otel.SetTextMapPropagator`. * **Allow `traceparent` across origins.** A back end can be on another origin, such as `api.example.com` called from `www.example.com`. The browser may then send a [CORS preflight](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) before the request. Allow `traceparent` in the back end's response to the preflight. Otherwise the browser may block the request: ```http HTTP theme={null} Access-Control-Allow-Headers: content-type, traceparent ``` > [!WARNING] > > Node.js and Elixir are not supported yet. With a Node.js back end, such as Express or Next.js API routes, failed requests are still reported as browser errors. Their traces show no back-end spans. ## Enable it Add a pattern for each back-end host and path to `tracePropagationTargets`. The default empty list leaves tracing off: ```js appsignal.js theme={null} import { init } from "@appsignal/browser"; init({ key: "", endpoint: "https://appsignal-endpoint.net", appVersion: "", // Your API hosts, matched against host + pathname tracePropagationTargets: ["api.example.com/**"], // How this front end is named in a trace. Defaults to "Browser" serviceName: "Checkout UI", }); ``` Patterns match the host and path of each `fetch` and `XMLHttpRequest` call. Because the SDK hooks into those browser APIs, setup is the same in React, Vue, or plain JavaScript. That includes libraries built on them, such as axios. Patterns ignore the scheme and query string. A relative URL resolves against the page's address, so a call to `/api/orders` from `www.example.com` matches `www.example.com/api/**`. Use `*` within one path segment or `**` across segments. Include both a host and a path: | Pattern | Matches | | - | - | | `api.example.com/**` | Every request to `api.example.com` on the default port. | | `api.example.com:8443/**` | Every request to `api.example.com` on port 8443. Include the port when it is not the default. | | `*.example.com/**` | Every request to a subdomain of `example.com`. | | `api.example.com/v1/**` | Requests under `/v1` on `api.example.com`. | | `api.example.com` | Nothing. It has no path, so add `/**`. | | `/api/**` | Nothing. It has no host. | | `**/api/**` | That path on any host, including third parties you never meant to trace. Avoid it. | In the trace timeline, `serviceName` labels the browser error span. For example, `Checkout UI` identifies errors from your checkout front end. The default is `Browser`. Use a different name for each front end you monitor. The SDK sends the name with every error report. The [Browser SDK install flow](https://appsignal.com/redirect-to/organization?to=sites/new/browser) offers **Distributed tracing** as an option. It is off by default. Selecting it adds `tracePropagationTargets: ["api.example.com/**"]` to the browser snippet. Replace the example host with your back end's host, then [instrument the receiving service](#before-you-start). The wizard does not install or configure that service. To verify propagation, load a page that calls your API and inspect the request in your browser's Network panel. A matching request should carry a `traceparent` header. Then inspect a failed request in AppSignal to check that back-end spans appear in its trace. The SDK adds no header to a request made in `no-cors` mode, because the browser would strip it. Those requests are never reported as failed requests. ## What is reported The SDK reports these outcomes for a matching request that sent a `traceparent` header: * **A 5xx response** is reported as an `HTTPError`. * **A timeout** is reported as a `TimeoutError`. That is a `fetch` that rejects with a `TimeoutError`, as one bounded by `AbortSignal.timeout()` does. It is also an `XMLHttpRequest` whose `timeout` fires. The server may have received and traced a timed-out request. The message names the request and its outcome, for example `POST https://api.example.com/orders: HTTP 503` or `GET https://api.example.com/orders: timed out`. Besides everything an [ordinary browser error](/browser/error-tracking#what-is-reported) carries, the report includes: * **The request**, as `params.request`: the `url`, the `method`, the `status` when a response arrived, and the `duration_ms`. Query parameters are removed from the URL as set by your [allowlist](/browser/privacy#urls-and-query-parameters). * **The span**: the trace ID and span ID from the request's `traceparent`, with its start time and duration. AppSignal builds the browser's span from these, so it covers the request as the browser saw it. After a timeout, the back end's spans can run longer than the browser's span. * **The service name** you set, or `Browser`. Nothing is reported for: * A successful request. The header is sent, but the browser stays silent, so the back-end trace stands on its own. * A 4xx response. The SDK does not classify it as a failed request for tracing. * A request the browser could not deliver: refused, failed DNS, or blocked by an extension. No server handled it, so there is no back-end trace to join. * A timeout while the device is offline, which says nothing about the back end. * A request your code canceled. These requests can still leave a [network breadcrumb](/browser/breadcrumbs#reading-network-breadcrumbs), unless they match `privacy.networkBlocklist` or breadcrumb collection is disabled. A breadcrumb for a request that propagated context includes its trace ID. Its **Open trace** button opens that trace's timeline. A failed request goes through the same pipeline as every other error. `errors.enabled`, `errors.sampleRate`, the [rate limits](/browser/error-tracking#rate-limits), and the deduplication of repeats all apply. `beforeError` receives it as an `HTTPError` or `TimeoutError`, with the request under `context.request`. You can drop or redact it there. A request matching `privacy.networkBlocklist` is never reported. The SDK avoids reporting the same `fetch` rejection twice when it also reaches an unhandled rejection handler or `captureError()`. If your code throws a new error after a 500 response, that error has its own trace. The failed request remains a separate report. ## Reading it in AppSignal Failed requests appear in the Errors view of the Browser section as `HTTPError` and `TimeoutError` issues. They are grouped by the route the user was on, like every other front-end error. Read more in [front-end errors in AppSignal](/browser-monitoring/errors). Open an issue to see its message, breadcrumbs, and tags in the side panel. Its **Sample** tab also shows the trace: the **Trace service map**, **Trace timeline**, and related log lines. Select **Fullscreen** in the **Trace timeline** card to open the view below. If the preview omits spans, the button reads **All spans**. **Open full trace page**, the icon next to the issue number, opens the full issue page. In the fullscreen timeline, `Browser` labels the browser span's service. Select that span to see the request and error details. In the [product page example](#product-page-example), `GET /api/boom/` returned HTTP 500. In the [trace timeline](/trace-page#trace-timeline), you can follow the failed request from the browser into the Django service: * `Browser` shows an `HTTPError` on `/product/chocolate-stroopwafel` (85 ms). The selected span's details show the request URL and HTTP 500 response. * Beneath it, `django` shows `GET api/boom/` with a `RuntimeError` (81 ms). * The Django request contains two `SELECT` spans and a `POST` span, with their durations. ![Trace timeline linking an 85 ms browser HTTPError for GET /api/boom/ (HTTP 500) to an 81 ms Django RuntimeError, with SELECT and POST child spans.](https://mintcdn.com/appsignal-715f5a51/Dd6j9BLrZGGvnmnD/assets/images/screenshots/browser/distributed-tracing-trace-timeline.png?fit=max\&auto=format\&n=Dd6j9BLrZGGvnmnD\&q=85\&s=7bee604479952a0a8d48422852810a59) The failed browser request and related Django spans in one trace. ## Joining a trace your code started Your application may already set a valid `traceparent` on a request, for example through an OpenTelemetry browser SDK. AppSignal for Browser then leaves that header alone, and a failed request joins the trace your code started. This holds for `fetch` and `XMLHttpRequest` alike. On the issue's **Traces** tab, open the [trace timeline](/trace-page#trace-timeline) in fullscreen to inspect the back-end work. # Browser error tracking Source: https://docs.appsignal.com/browser/error-tracking How AppSignal for Browser reports uncaught errors and unhandled rejections, groups them, and handles manual reports, sourcemaps, and noise. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). Once `init()` has run, AppSignal for Browser reports uncaught errors on its own. There is nothing to wrap and no handler to register. It listens for two things on the page's main `window`: * Errors your code throws and never catches, through the `error` event. * Promises that fail with nothing to handle the failure, through the `unhandledrejection` event. The SDK starts sending each error when it is caught, without waiting for a web-vitals batch. Delivery still depends on the browser and network. ## What is reported * **Error name and message.** The kind of error, for example `TypeError`, and the message it came with. * **Backtrace.** The stack trace, one line per frame. Empty if the browser gives none. * **Action.** The route the error happened on. Errors are grouped by this. * **Revision.** The `appVersion` you set. Used to filter by version and to find the right sourcemaps. * **Tags.** Whatever you set with `setTags()`. * **Service name.** The `serviceName` you set, or `Browser`. It labels the front end among the services of a trace. * **Breadcrumbs.** Up to 25 recent [breadcrumbs](/browser/breadcrumbs) that help explain the error. * **URL and user agent.** The page the error happened on, with query parameters removed as set by your [allowlist](/browser/privacy#urls-and-query-parameters), and the browser's user agent. A rejected promise can contain a value other than an `Error`. The SDK turns that value into an error message when it can. Errors are reported to the `browser` [namespace](/guides/namespaces), which keeps them separate from your back-end errors and their notification settings. ## How errors are grouped Errors group by action. This is the template set with `setRouteTemplate()`, or the raw page path when none was set. Declaring a template is what stops an ID-heavy route from fragmenting into one error group per ID: ```js JavaScript theme={null} import { setRouteTemplate } from "@appsignal/browser"; // Every error on this route now groups under "/orders/:id" setRouteTemplate("/orders/:id"); ``` Call it on each router navigation. It is the same value [web vitals are attributed to](/browser/web-vitals#how-values-are-attributed-to-routes), so one call covers both. ## Reporting errors manually Use `captureError()` for errors you catch yourself. It goes through the same pipeline as an uncaught error, including breadcrumbs, tags, sampling, and `beforeError`: ```js JavaScript theme={null} import { captureError } from "@appsignal/browser"; try { await submitOrder(order); } catch (error) { captureError(error); } ``` The current SDK accepts a second context argument, but does not include it in ordinary error reports. Use [`setTags()`](#tags) for values that should appear on subsequent errors. React applications can catch render errors with the [error boundary](/browser/react) instead of wrapping components by hand. ## Failed requests With [`tracePropagationTargets`](/browser/configuration#tracepropagationtargets) set, a request to your API that answers 5xx or times out is reported on its own. It arrives as an `HTTPError` or a `TimeoutError`, carrying the trace ID the request sent to the back end. If the back end continued the trace, its spans appear beneath the browser error in the trace timeline. Read more in [distributed tracing for Browser](/browser/distributed-tracing). ## Tags Tags are string key-values attached to every error reported from that point on. They are what you filter and search errors by in AppSignal: ```js JavaScript theme={null} import { setTags, clearTags } from "@appsignal/browser"; // After authentication, once the values are known setTags({ plan: user.plan, org_id: user.orgId }); // On sign-out. Tags survive a reload, so clear them explicitly clearTags(); ``` Each call adds to the tags you already set rather than replacing them. Values become text. An empty value removes its tag. You can keep up to 32 tags; the oldest is dropped when needed. Long values are shortened to 256 bytes when they arrive. Read more in our [tagging guide](/application/tagging). A few tag names do more than filter. The `country_code`, `country`, and `browser` tags produce [attribute distributions](/guides/tagging/attribute-distributions). You can turn any tag into a link with [link templates](/application/link-templates). ## Rate limits A page stuck in a loop can throw thousands of errors a second. Two limits stop the SDK from becoming the problem it is meant to report: * **The same error over and over.** The message and first stack line determine whether two errors are repeats. AppSignal reports it at most five times every 10 seconds. * **Too many errors at once.** No more than 100 errors are reported every 10 seconds in total. This catches a page throwing many *different* errors, which the first limit would miss. If errors go missing while a page is misbehaving, one of these two is why. To send fewer errors on purpose instead, set [`errors.sampleRate`](/browser/configuration#errors-samplerate). ## Sourcemaps A minified bundle produces stack traces full of one-letter names and enormous line numbers. [Sourcemaps](/front-end/sourcemaps) turn those back into the file names, functions, and line numbers you wrote. Each error sends `appVersion` as its revision. AppSignal uses it to find the sourcemaps for that build. Without it, stack traces stay minified. If your sourcemaps are public, sitting next to your JavaScript files, there is nothing more to do. If you would rather not publish them, upload them to the [sourcemaps API endpoint](/api/sourcemaps) using the same revision. ## Errors that are not reported > [!WARNING] > > Some errors never reach the SDK. Most of these are browser restrictions > rather than AppSignal limitations, and each has a workaround. **Errors from scripts on another domain.** When a script loaded from somewhere else throws, the browser refuses to share the details. All your page sees is the message `Script error.`, with no stack trace and no line number. The SDK drops these opaque errors because they contain no useful detail. To capture CDN script errors, send an `Access-Control-Allow-Origin` header from the CDN. Add `crossorigin="anonymous"` to the script tags. **Errors inside iframes.** The SDK listens only on the `window` where it runs. To monitor an iframe you control, initialize the SDK inside that frame too. The parent page cannot capture errors from a cross-origin iframe. **Errors before `init()`.** Anything that throws before `init()` runs is missed. Import your AppSignal setup first, ahead of other libraries and your own code. ## Filtering out browser noise Some errors come from the browser or its extensions, not from your code, and you cannot fix them. The install flow's **Error filtering** option drops them with `beforeError`: ```js appsignal.js theme={null} import { init } from "@appsignal/browser"; const IGNORED = [ /ResizeObserver loop/, /^Script error\.?$/, /-extension:\/\//, /webkit-masked-url/, ]; init({ key: "", beforeError: (error) => { const text = [error.message, error.stack, error.filename].join(" "); return IGNORED.some((pattern) => pattern.test(text)) ? null : error; }, }); ``` Each pattern is checked against the error's message, stack trace, and file name: * `ResizeObserver loop`: a browser notice that resize notifications were deferred to the next frame. It is usually harmless. * `Script error.`: an error from a script on another domain, with no detail to debug. The SDK already drops those that arrive without a stack trace. * `-extension://`: an error from a browser extension, such as a `chrome-extension://` or `moz-extension://` script. * `webkit-masked-url`: the address Safari shows in place of an extension's script. Add a pattern to `IGNORED` for any other error you have decided to ignore. A dropped error leaves no breadcrumb and is not counted as a repeat. It does count towards the [limit](#rate-limits) of 100 errors every 10 seconds. Read more in [filtering errors and breadcrumbs](/browser/privacy#filtering-errors-and-breadcrumbs). ## Reviewing errors in AppSignal The Errors view groups these into issues you can filter by version and time range, assign, and get notified about. Read more in [front-end errors in AppSignal](/browser-monitoring/errors). # Installing AppSignal for Browser Source: https://docs.appsignal.com/browser/installation Install @appsignal/browser, initialize it with your Front-end API key, and verify that front-end errors and web vitals arrive in AppSignal. > [!NOTE] > > Browser monitoring is a beta [AppSignal Labs](/labs) feature. The > `@appsignal/browser` package is published under the `beta` tag on npm, and its > configuration and API may still change between beta releases. Share feedback > in our [Discord community](https://discord.gg/EjF6ykYx63). Use this guide to add browser error tracking and web vitals to your application. The Plain JS and React examples also cover distributed tracing, error filtering, masking, and tags. You can generate code for your application in the [Browser SDK install flow](https://appsignal.com/redirect-to/organization?to=sites/new/browser), or follow the examples below. If you have not added your application to AppSignal yet, follow the [new application guide](/guides/new-application) first. ## Find your Front-end API key Find the **Front-end API key** under **Front-end error monitoring** on your application's [Push & deploy settings](https://appsignal.com/redirect-to/app?to=api_keys). Use the key for the application and environment you want to monitor. This key is meant to be included in browser code. It is different from the Push API keys used by back-end integrations. The install flow puts your key in the generated code. In the examples below, replace `` with your own key. ## Generate the snippet in AppSignal The [Browser SDK install flow](https://appsignal.com/redirect-to/organization?to=sites/new/browser) lets you choose **Plain JS** or **React** and select which features to include. It starts with **Route template** selected. The complete examples below include every option: | Options | What gets included in your snippet | | - | - | | Route template | `setRouteTemplate()` runs when your route changes, so `/users/42` can be reported as `/users/:id`. | | Distributed tracing | Adds `tracePropagationTargets` so matching API requests carry a `traceparent` header. Replace the example host with your own. This configures the browser only; the receiving API service also needs [tracing instrumentation](/browser/distributed-tracing#before-you-start). | | Error filtering | `beforeError` drops errors that match the example browser and extension patterns. Adjust the patterns for your application. | | Error tags | `setTags()` adds values such as a plan or tenant to errors after sign-in. | | Sensitive data masking | `privacy.dom` masks text or excludes click breadcrumbs from selected elements. Replace the example CSS selectors with your own. | The install flow generates Browser SDK code. Selecting **Distributed tracing** does not instrument your API service. To see its spans alongside a browser request error, follow the [back-end setup](/browser/distributed-tracing#before-you-start) as well. Both versions also show how to report an error you catch yourself. The React version includes an error boundary for render errors. ## Install the package Install AppSignal for Browser from the `beta` tag. Distributed tracing and failed-request reporting require version 1.0.0-beta.7 or later. The install flow currently shows an unversioned command; use one of these commands for the beta release: ```sh npm theme={null} npm install @appsignal/browser@beta ``` ```sh yarn theme={null} yarn add @appsignal/browser@beta ``` ```sh pnpm theme={null} pnpm add @appsignal/browser@beta ``` Commit your lockfile and review the snippet when you upgrade during the beta. ## Initialize the SDK Import your AppSignal setup before the application code you want to monitor. Replace `process.env.NODE_ENV` and `process.env.APP_REVISION` with the equivalent values from your build system. Set `appVersion` to your release tag or commit SHA so AppSignal can match errors to [sourcemaps](/browser/error-tracking#sourcemaps). These examples include all install flow options. Replace `api.example.com/**` with your API host and path for [distributed tracing](/browser/distributed-tracing#enable-it). Replace the CSS selectors, tags, and router example with values from your application. **Plain JS** **1. Initialize AppSignal in `appsignal.js`.** ```js appsignal.js theme={null} import { init } from "@appsignal/browser"; const IGNORED = [ /ResizeObserver loop/, /^Script error\.?$/, /-extension:\/\//, /webkit-masked-url/, ]; init({ key: "", endpoint: "https://appsignal-endpoint.net", // Inactive builds send nothing. Replace these with your build values. active: process.env.NODE_ENV === "production", appVersion: process.env.APP_REVISION, // Match your API host and path. tracePropagationTargets: ["api.example.com/**"], privacy: { // Mask text or exclude clicks on these elements. dom: { maskText: [".user-email"], blockElement: ["#card-form"] }, }, beforeError: (error) => { const text = [error.message, error.stack, error.filename].join(" "); return IGNORED.some((pattern) => pattern.test(text)) ? null : error; }, }); ``` Import it first in your entry point: ```js main.js theme={null} import "./appsignal"; // Start your application after this import. ``` **2. Report route changes from your router.** Replace `router.on` with your router's navigation hook. Report the initial route too, then report its template on each navigation. ```js router.js theme={null} import { setRouteTemplate } from "@appsignal/browser"; router.on("navigate", (route) => { setRouteTemplate(route.pattern); // "/users/:id", not "/users/42" }); ``` **3. Add tags after sign-in.** Use values from the signed-in user or account. Call [`clearTags()`](/browser/configuration#api-reference) on sign-out to clear stored tags. ```js account.js theme={null} import { setTags } from "@appsignal/browser"; setTags({ plan: "pro", tenant: "acme" }); ``` **4. Report errors you catch yourself.** Replace `save()` with your own operation. ```js save.js theme={null} import { captureError } from "@appsignal/browser"; try { save(); } catch (error) { captureError(error); } ``` **React** **1. Initialize AppSignal in `appsignal.js`.** Import this file before your React application starts. ```js appsignal.js theme={null} import { init } from "@appsignal/browser"; const IGNORED = [ /ResizeObserver loop/, /^Script error\.?$/, /-extension:\/\//, /webkit-masked-url/, ]; init({ key: "", endpoint: "https://appsignal-endpoint.net", // Inactive builds send nothing. Replace these with your build values. active: process.env.NODE_ENV === "production", appVersion: process.env.APP_REVISION, // Match your API host and path. tracePropagationTargets: ["api.example.com/**"], privacy: { // Mask text or exclude clicks on these elements. dom: { maskText: [".user-email"], blockElement: ["#card-form"] }, }, beforeError: (error) => { const text = [error.message, error.stack, error.filename].join(" "); return IGNORED.some((pattern) => pattern.test(text)) ? null : error; }, }); ``` Import it first in your entry point: ```js main.jsx theme={null} import "./appsignal"; // Start your React application after this import. ``` **2. Report route changes.** Render `RouteReporter` inside your router and pass its current route template as `routePattern`. React hooks must run inside a component. ```jsx RouteReporter.jsx theme={null} import { useEffect } from "react"; import { setRouteTemplate } from "@appsignal/browser"; export function RouteReporter({ routePattern }) { useEffect(() => { setRouteTemplate(routePattern); // "/users/:id", not "/users/42" }, [routePattern]); return null; } ``` See the [React route examples](/browser/react#reporting-the-current-route) for React Router and Next.js. **3. Add tags after sign-in.** Use values from the signed-in user or account. Call [`clearTags()`](/browser/configuration#api-reference) on sign-out to clear stored tags. ```js account.js theme={null} import { setTags } from "@appsignal/browser"; setTags({ plan: "pro", tenant: "acme" }); ``` **4. Catch render errors at your app root.** The boundary reports render errors that do not reach the browser's global error handler. ```jsx AppRoot.jsx theme={null} import { captureError } from "@appsignal/browser"; import { ErrorBoundary } from "@appsignal/browser/react"; This page didn't load. Reload to try again.

    } >
    ``` **5. Report errors you catch yourself.** Replace `save()` with your own operation. ```js save.js theme={null} import { captureError } from "@appsignal/browser"; try { save(); } catch (error) { captureError(error); } ``` **If you only need error tracking, breadcrumbs, and web vitals**, you can start with a smaller `appsignal.js` file. Replace `` with your release tag or commit SHA: ```js appsignal.js theme={null} import { init } from "@appsignal/browser"; init({ key: "", endpoint: "https://appsignal-endpoint.net", active: process.env.NODE_ENV === "production", appVersion: "", }); ``` Import `appsignal.js` first in your entry point, as shown above. This smaller setup does not add `traceparent` headers to your API requests. For every setup, `active: false` stops the SDK from collecting or sending data. `endpoint` defaults to the current page's origin; set it to `https://appsignal-endpoint.net` unless you proxy AppSignal requests through your own domain. See [all configuration options](/browser/configuration). ## Install without a bundler If your site loads JavaScript with ` ``` Replace the version in the URL when you upgrade. A fixed version prevents an unexpected SDK change on your site. ## Report the current route Use this step for a single-page application with routes such as `/users/42`. Pass the route template, such as `/users/:id`, when your router navigates. AppSignal uses it to group errors and web vitals by route. The full examples above show where to call `setRouteTemplate()`. If you do not set a route template, the SDK reports the current page path. That means `/users/42` and `/users/43` can appear as separate error groups. See [React route examples](/browser/react#reporting-the-current-route) for React Router and Next.js. ## Verify the installation 1. Run a build with `active` set to `true`. You can temporarily use `active: true` in development. 2. Open the page and run this code in the browser console: ```js JavaScript theme={null} setTimeout(() => { throw new Error("AppSignal test error"); }, 0); ``` The timer lets the error reach the page's global error handler. An error thrown directly in the console is usually handled by the console itself. 3. Open **Browser > Errors** in AppSignal and find **AppSignal test error**. Web vitals appear after the SDK flushes them, such as when the page becomes hidden or the route changes. If no data appears, see [Browser troubleshooting](/browser/troubleshooting). ## Content Security Policy If your site uses a Content Security Policy, allow the configured AppSignal endpoint in its `connect-src` directive. For example, add the endpoint to your existing allowed sources: ```http HTTP theme={null} Content-Security-Policy: connect-src 'self' https://appsignal-endpoint.net ``` ## Assets hosted on a CDN Use this step if your site's JavaScript loads from another origin, such as a CDN. Without cross-origin access, the browser may report only `Script error.` with no stack or line number. The SDK drops those opaque errors because they cannot be traced back to your code. Serve the script with an `Access-Control-Allow-Origin` header that permits your page's origin, and add `crossorigin="anonymous"` to the script tag: ```html HTML theme={null} ``` ```erb Rails theme={null} <%= javascript_include_tag "application", :crossorigin => :anonymous %> ``` ## Uninstall 1. Remove the `appsignal.js` import and other `@appsignal/browser` calls from your code. Remove any `ErrorBoundary` imported from `@appsignal/browser/react`. 2. Remove the package and update your lockfile with `npm uninstall @appsignal/browser`, `yarn remove @appsignal/browser`, or `pnpm remove @appsignal/browser`. If you installed the UMD build, remove its `