# Apitally CLI and skill for agents Source: https://docs.apitally.io/agents/cli-and-skill Give coding agents access to your API metrics and request logs for agent-driven investigations and analyses. The Apitally CLI makes API metrics and request log data accessible to coding agents such as Claude Code, Cursor, and Codex. An accompanying skill teaches agents how to use the CLI effectively, so they can answer questions that go beyond what the pre-built dashboards cover. While primarily designed for agents, the CLI works equally well directly in your terminal or as part of scripts and automations. The CLI is a single Rust binary with a bundled [DuckDB](https://duckdb.org/) engine and no runtime dependencies. It's open-source and also published as an npm package, so you can run it with `npx` without prior installation. ## Capabilities * Retrieve API metrics with various aggregation options and filters * Retrieve request logs with filters and field selection, including headers and payloads * Fetch full details about specific API requests, including application logs and traces * Load data into a local DuckDB database and run arbitrary SQL queries against it * List apps, consumers, and endpoints in your team All commands output newline-delimited JSON to stdout by default. For example use cases, see the [release announcement](https://apitally.io/blog/apitally-cli-and-skill-for-agents). ## Agent skill The skill bundles instructions and reference material that allow agents to use the CLI efficiently, without digging through documentation or `--help` text on every invocation. It includes guidance on key concepts, an investigation workflow, a full command reference, and the schemas of the DuckDB tables the CLI writes to. It follows the open [Agent Skills](https://agents.md/) standard and works with Claude Code, Cursor, Codex, and other compatible agents. The skill lives alongside the CLI in the [GitHub repository](https://github.com/apitally/cli/tree/main/skills/apitally-cli). ## Installation ### For agents Install the `apitally-cli` skill using the [skills CLI](https://github.com/vercel-labs/skills): ```bash theme={null} npx skills add apitally/cli ``` Once installed, agents will pick up the skill automatically when you mention Apitally or ask it to investigate API metrics or request logs. Agents will invoke the CLI through `npx`, so it doesn't need to be installed separately. ### For humans The CLI can be used via `npx`, no installation required: ```bash theme={null} npx @apitally/cli ``` To use the `apitally` binary directly, install it with the standalone installer: ```bash theme={null} # macOS and Linux curl -fsSL https://apitally.io/cli/install.sh | sh ``` ```bash theme={null} # Windows powershell -ExecutionPolicy Bypass -c "irm https://apitally.io/cli/install.ps1 | iex" ``` You can also download the binary for your platform from the [latest release](https://github.com/apitally/cli/releases/latest) on GitHub. ## Authentication The CLI uses the Apitally [API](/api-reference) under the hood and therefore requires a team-scoped API key. Authenticate using a browser-based flow that creates and saves an API key to `~/.apitally/auth.json`: ```bash theme={null} npx @apitally/cli auth ``` If you already have an API key, you can provide it directly: ```bash theme={null} npx @apitally/cli auth --api-key "your-api-key" ``` You can also set the API key via the `APITALLY_API_KEY` environment variable, or pass `--api-key` to any command. ## Commands | Command | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------- | | `auth` | Configure API key | | `whoami` | Check authentication and show team info | | `apps` | List all apps in your team | | `consumers` | List consumers for an app | | `endpoints` | List endpoints for an app, with method and path filters | | `metrics` | Fetch metrics for an app, with filters and different aggregation options | | `request-logs` | Fetch request log data, with filters and field selection | | `request-details` | Fetch full details for a specific request and response, including headers, payloads, application logs, and traces | | `sql` | Run SQL queries against a local DuckDB database | | `reset-db` | Drop and recreate all tables in the local DuckDB database | Run `npx @apitally/cli --help` for detailed usage information, or refer to the [command reference](https://github.com/apitally/cli/blob/main/skills/apitally-cli/references/commands.md) in the skill. ## DuckDB database Most commands accept a `--db` flag. When set, data is written to a local DuckDB database instead of being printed as NDJSON to stdout. The database can then be queried with the `sql` command. The database defaults to `~/.apitally/data.duckdb` if no other path is provided (e.g. `--db ./my-investigation.duckdb`). It is created automatically on first use, and data is retained between sessions. When writing to tables, existing records are updated rather than duplicated. For the schemas of the tables the CLI writes to, see the [DuckDB table reference](https://github.com/apitally/cli/blob/main/skills/apitally-cli/references/duckdb_tables.md) in the skill. # Application logs Source: https://docs.apitally.io/api-logs-traces/application-logs View application logs in the context of API requests. The Apitally SDKs can instrument various logging libraries to automatically capture logs emitted by your application during request handling. These are associated with the corresponding request and displayed in the request details in the request logs. Log capture must be explicitly enabled alongside request logging. See the [setup guide](/setup-guides) for your framework for instructions. Application logs Click on a log entry to see the full message, in case it's truncated. ## Supported loggers The following loggers are instrumented automatically if used in your application: * Python * logging (standard library) * loguru * JavaScript * console * Pino * Winston * Logger in NestJS * Built-in logging methods in hapi * Go * slog (standard library, must use context-aware logging) * .NET * Microsoft.Extensions.Logging (standard library) * Java * Logback # API request logs Source: https://docs.apitally.io/api-logs-traces/request-logs Log, find and inspect individual API requests and responses. Request logs The request logs show a chronological list of all requests made to your API and allow you to inspect request and response details such as the URL, headers, payloads and more. Clicking on the timeline graph at the top allows you to quickly jump to a specific time point. Hold down the Cmd/Alt key and drag on the chart to zoom into a specific time range. ## Enable logging By default, our SDKs don't capture request logs. You must explicitly enable request logging in your application and configure what should be included in the logs. There are various options for excluding or masking sensitive data. Learn more in the [setup guide](/setup-guides) for your specific framework. ## Filter options Request log filters The filter panel offers the following options to filter and search the request logs: * Consumer / consumer group * Client IP address * HTTP method * Endpoint path * URL (partial match) * Request / response payload (partial match) * Request / response size * Response status code * Response time You can also save filters to quickly switch between different views. Saved filters can be shared with other team members. ## Request details Clicking on a request in the log opens a modal with more detailed information, including parameters, headers, payloads, and more.
Request log item - Details Request log item - Response body
## Export data The request logs include a button to export logged requests to a CSV file. The current dashboard filters are applied automatically. The exported file can include up to 1 million requests. # Traces Source: https://docs.apitally.io/api-logs-traces/traces Get a breakdown of time spent during the handling of each request. When a request takes longer than expected, traces help you understand exactly where the time is being spent. Whether it's a slow database query, an external API call, or a custom operation in your code, traces provide the visibility you need to identify and resolve bottlenecks. If enabled, you'll find traces in the request details in the request logs. Traces A trace consists of one or more spans, each representing an operation such as a database query or HTTP call. Spans are visualized as horizontal bars, with their width reflecting their duration relative to the total response time of the request. Click on a span to view its attributes in the table below, which can include details such as the database query, the HTTP method and URL of an external request, or any custom attributes your instrumentation has added. ## Enable tracing Tracing must be explicitly enabled in your application alongside request logging. The Apitally SDKs integrate with [OpenTelemetry](https://opentelemetry.io/) and capture any spans created during request handling. See the [setup guide](/setup-guides) for your framework to learn how to enable tracing and instrument libraries like database drivers and HTTP clients. # API consumer insights Source: https://docs.apitally.io/api-metrics/consumers Track API adoption and usage by individual consumers. Consumers dashboard Apitally allows you to track API adoption and helps you understand how individual consumers use your API. To use this feature, your application must provide a consumer identifier for each request. Check out the [setup guide](/setup-guides) for your framework to learn how to do this. The chart at the top of the *Consumers* page shows the number of unique API consumers that have made requests to your API over time, broken down by new and returning consumers. You can select from different time periods in the dropdown above, and filter by environment. The table below the chart lists all API consumers, including sparkline graphs for a quick overview of their requests. ## Consumer details Consumer details Clicking on a row in the consumer table brings up the consumer details screen, which has a *Requests* and an *Errors* tab. On the *Requests* tab you'll see consumer-specific metrics, a chart showing the consumers' requests over time, and a log of the most recent requests by that consumer. On the *Errors* tab you get an overview of the types of errors encountered by the consumer, including a chart showing errors over time and a log of the most recent errors. ## Consumer groups You also have the option to create and analyze groups of consumers. For example, if you have both internal and external API consumers, you could create two groups to understand their API usage separately. Each API consumer can only be assigned to one group at a time. Assigning a consumer to a new group will remove it from their current group. You can choose between viewing individual API consumers and consumer groups on the *Consumers* page using the toggle at the top of the page. # API endpoint insights Source: https://docs.apitally.io/api-metrics/endpoints Understand the usage and performance of individual API endpoints. By clicking on a row in the [endpoints table](/api-metrics/traffic#endpoints-table) on the traffic dashboard, you can access detailed insights into the usage and performance of that specific API endpoint. The endpoint details are presented in a tabbed interface with the sections described below. ## Requests Traffic - Endpoint - Requests The *Requests* tab provides different breakdowns of the requests made to the API endpoint. At the top you see a summary with the following metrics: * Total requests * Requests per minute * Successful requests * Client errors * Server errors Below the summary, you find a bar chart showing the distribution of requests over time, broken down by response status code. You can hover over the bars to see the exact number of requests for each status code. By clicking on the bars of dragging to select a range, you can zoom in on a specific time period. The horizontal bar chart at the bottom shows which API consumers have been making the most requests to this endpoint (top 10). Again, this is broken down by status codes. You can filter to one of the consumers by clicking on the respective bar. ## Errors Traffic - Endpoint - Errors The *Errors* tab provides details about failed requests to your API endpoint. Requests are considered unsuccessful if the response status code is in the 4xx or 5xx range, and the specific status code has not been marked as expected. At the top you see a breakdown of unsuccessful status codes returned by the endpoint, along with the number of occurrences and the percentage of all requests. You can click on the status codes to navigate to the [errors dashboard](/api-metrics/errors), which provides more details about that specific error. An area chart shows a trend of client and server error rates over time. The error rates are calculated as the number of failed requests divided by the total number of requests. If the endpoint returned validation errors to consumers, the table below provides details about those errors. That includes the fields that failed validation, the error messages, and the number of occurrences. If there were any server errors, another table provides details about the exception type and message, the number of occurrences and a stacktrace. ## Response times Traffic - Endpoint - Response times The *Response times* tab provides insights into the performance of the API endpoint, measured by the time it takes to respond to requests. In the summary at the top you see the 50th, 75th and 95th percentile of response times. The area chart below shows how these percentiles have been trending over time. Additionally you see a histogram of response times, providing a full picture of the distribution of response times for the endpoint, including any outliers. ## Data transferred Traffic - Endpoint - Data transferred The *Data transferred* tab provides insights into the size of payloads received and sent by the API endpoint. These are based on the `Content-Length` headers in the requests and responses. The summary at the top includes the total amount of data transferred in the selected period as well as the average sizes of requests and responses. The bar chart below shows the distribution of data transferred over time, broken down by incoming (requests) and outgoing (responses). There are also histograms of the request and response sizes, so you can get a full picture of their distribution, including any outliers. # API errors dashboard Source: https://docs.apitally.io/api-metrics/errors Understand the frequency, causes and impact of API errors. Errors dashboard The *Errors* dashboard provides an overview of the error responses returned by your API. The bar chart at the top shows the distribution of errors over time, broken down by client and server errors. When you hover over the bars, you'll see a tooltip with the number of occurrences of each specific status code. The table below lists all `4xx` and `5xx` status codes returned by your endpoints and is sorted by the number of occurrences. Clicking on a row opens up a modal with further insights about that type of error.
Error occurrences Error details
This includes a summary with the total number of occurrences, the number of affected API consumers and the time of the last occurrence. A bar chart shows the frequency of the error over time and a second, horizontal bar chart displays the number of occurrences per API consumer, helping you identify which consumers are most affected by the error. For validation and server errors, the modal includes a *Details* tab that provides additional information about the error. ## Validation errors Many frameworks offer built-in validation for incoming requests, or are compatible with third-party validation libraries. Apitally detects commonly used libraries and automatically captures validation error details. This can help you refine validation rules or reveal issues on the consumer side. This is currently supported for the following frameworks: * FastAPI (using pydantic) * Django Ninja (using pydantic) * Litestar (using pydantic, attrs or other modeling libraries) * Express (using express-validator or Joi + celebrate) * Fastify (using Ajv) * NestJS (using class-validator) * Hono (using Zod) * AdonisJS (using VineJS) * Elysia * Chi (using validator) * Echo (using validator) * Fiber (using validator) * Gin (using validator) ## Server errors If a `500 Internal Server Error` response is caused by an unhandled exception in your code, Apitally automatically captures the error message and stack trace. You can review those in the *Details* tab of the error modal. ## Expected errors In some applications, certain client errors are just part of normal operation. You might not want these errors included in error rate metrics or combined with other failed requests. Apitally allows you to mark specific `4xx` status codes as expected for certain API endpoints. This prevents them from being counted as errors in error rate calculations, and requests with these response status codes are considered successful. To do this, simply select *Mark as expected* from the dropdown menu in the errors table. ## Sentry integration If your team has set up the Sentry integration under *Settings > Integrations*, links to the Sentry issues created for captured exceptions will appear in the server error details. # Apps overview Source: https://docs.apitally.io/api-metrics/overview View key API metrics for all your apps at a glance. Apps overview with sparklines When you open the Apitally dashboard, you first land on the *Apps* page. Here you see an overview of key API metrics for all your applications, including sparkline graphs that help you quickly identify unexpected spikes or drops. Clicking on a metric or graph takes you to the relevant dashboard with more details: Traffic dashboard Errors dashboard Performance dashboard Consumers dashboard # API performance dashboard Source: https://docs.apitally.io/api-metrics/performance Measure user satisfaction with API response times using Apdex scores. Performance dashboard The Apitally SDKs measure the time it takes your route handler functions to respond to API requests. On the *Performance* dashboard, you can analyze these response times and the derived Apdex score for your whole API and individual endpoints. ## Response time distribution The performance dashboard shows the 50th, 75th and 95th percentiles of API response times, helping you understand their distribution. For example, if the 95th percentile is high while the 50th and 75th percentile are low, it means that a small percentage of requests take a long time to complete. When you click on an endpoint in the table, you can also see the response time distribution for that endpoint as a histogram. Performance dashboard - Endpoint response times ## Apdex score The Apdex score is an open industry standard to measure user satisfaction with an application's response times. The score is based on a response time threshold (T) and four counts: * Satisfied: Response time is less than or equal to T. * Tolerating: Response time is greater than T but less than or equal to 4T. * Frustrated: Response time is greater than 4T. The Apdex score is calculated as: ${\displaystyle\text{Apdex score} = \frac{\text{Satisfied} + 0.5 \cdot \text{Tolerating} + 0 \cdot \text{Frustrated}}{\text{Total}}}$ Apdex scores range from 0 to 1, with 0 meaning that users were frustrated with all response times, and 1 meaning that users were satisfied with all response times. ### Configure the threshold By default, Apitally assumes a response time threshold (T) of 500 ms. You can configure this threshold for your whole application and override it for individual endpoints. To configure the threshold for your whole application, go to the *Apps* page, select *Edit app* and change the *Response time threshold* field under *Performance metrics*. To override the threshold for an individual endpoint, open the *Endpoint settings* from the dropdown in the endpoints table and update the *Response time threshold* field. # Resources dashboard Source: https://docs.apitally.io/api-metrics/resources Monitor CPU and memory usage, correlate it with API traffic. Resources dashboard The *Resources* dashboard displays your application's CPU and memory usage over time. This data is collected automatically by the Apitally SDK and aggregated across all running instances within each environment. Each chart displays the average value as a line and the range between minimum and maximum values as a shaded area. The current average and maximum values are shown in the top-right corner of each chart. ## CPU utilization The CPU utilization chart shows the percentage of CPU time used by your application process. Since this is measured per-process and not relative to available cores, the value can exceed 100% for multi-threaded applications utilizing multiple CPU cores. ## Memory usage The memory usage chart displays the resident set size (RSS) of your application process, which represents the actual physical memory being used. ## Overlay traffic Toggle *Overlay traffic* to display a requests per minute area chart overlaid on the resource charts. This helps you identify how spikes in API traffic affect CPU and memory usage. # API traffic dashboard Source: https://docs.apitally.io/api-metrics/traffic Track API usage metrics globally and per endpoint. Traffic dashboard The Traffic dashboard provides insights into the overall traffic to your API as well as usage of each API endpoint. ## Traffic metrics The top section of the dashboard focuses on the following API metrics: * Total requests (broken down by response status code on hover) * Requests per minute (RPM) * Error rate * Data transferred (received and sent) Clicking on the metrics toggles between different charts showing trends over time. ## Endpoints table The table lists all endpoints of your API along with their traffic metrics. The Apitally SDKs use introspection to discover all endpoints defined in your application, even if they haven't been called yet. By default, the table is ordered by request count, with the most used endpoint at the top. It can be searched and sorted by any of the other metrics too. Clicking on an endpoint in this table opens a modal with detailed [endpoint insights](/api-metrics/endpoints). A red triangle with an exclamation mark next to the error rate indicates that server errors have occurred on that endpoint. ## Filters The dashboard includes a range of filtering options. These are persistent and will remain active when you navigate to another dashboard. ### Time period You can view data for a specific time period using several methods: * Select a standard period (e.g. *24 hours* or *30 days*) from the dropdown menu. * Click and drag across the chart to select a custom range. * Click a single bar on the chart to focus on that interval. * Choose *Custom* from the dropdown to manually enter a start and end date. ### Environment By default, the dashboard displays metrics from all environments. To view data for a specific environment, select it from the environment filter dropdown. ### Filter pane Traffic dashboard filtering options Clicking the *Filter* button opens a side pane with additional filtering options: * API consumer or consumer group * HTTP method (e.g. `GET`, `POST`) * Endpoint path (supports wildcards) * Response status code (e.g. `200`, `4xx`) ### Save filters You can save filters to quickly switch between different views. Saved filters can be shared with other team members. ## Exclude endpoints Traffic from automated services, such as health checks, can skew your metrics and hide important insights. You can exclude affected endpoints (e.g. `/health`) from metrics by opening the *Endpoint settings* from the dropdown menu in the endpoints table and enabling the *Exclude requests* toggle. ## Export data The dashboard includes a button to export the underlying data to a CSV file. Current filters are applied automatically. Data can be aggregated in hourly or daily intervals. # Custom alerts Source: https://docs.apitally.io/api-monitoring/alerts Set thresholds for API metrics, get notified when they are breached. Apitally allows you to automatically monitor API metrics and get notified when they breach a configured threshold. This eliminates the need to manually check the dashboard and provides a first line of defense against potential issues. Custom alert details ## Create alerts You can create a new custom alert in these simple steps: 1. Choose a name for your alert, and optionally add a description. Both will be shown in alert notifications to help you quickly see what's going on. 2. Select the app and the environment you want to monitor. 3. Select a metric and set the threshold value and condition (e.g. "greater than 100"). See below for a list of available metrics. 4. Choose an aggregation window and the frequency at which the alert condition should be evaluated. There are additional options for more complex alerting needs, such as filtering, cron scheduling and delaying notifications. These are described in the sections below. Create alert modal ### Available metrics * Requests per minute * Total requests * Data transferred (requests and responses) * Data sent (responses) * Data received (requests) * Consumers (unique) * Errors (client & server errors) * Client errors * Server errors * Error rate * Response time p50 * Response time p75 * Response time p95 * Apdex score * CPU utilization (avg) * CPU utilization (max) * Memory usage (avg) * Memory usage (max) ### Filter options You can narrow down the scope of your alerts using the following filters: * *Consumer:* Monitor a specific API consumer. * *Consumer group:* Track metrics for a group of consumers. * *Endpoint:* Alert on a specific API endpoint. These filters can be found under *Additional filters* when creating or editing an alert. ### Cron schedule While the default check frequency is set using the *Check every* field, you can define more complex schedules using [cron expressions](https://en.wikipedia.org/wiki/Cron#Cron_expression) under the *Advanced options* section. The cron schedule will override the basic check frequency when specified. Examples of cron expressions: * `*/5 9-17 * * 1-5`: Check every 5 minutes between 9 AM and 5 PM on weekdays. * `5 * * * *`: Check 5 minutes past the hour every hour. * `0 9 * * *`: Check every day at 9 AM. You can write and test your cron expressions on [crontab guru](https://crontab.guru/). ### Tune notifications Apitally provides several options for controlling the frequency and timing of alert notifications: * *Aggregation window:* Define the time period over which metrics are aggregated during evaluation. Selecting a longer period can smooth out transient spikes. * *Check every / Cron schedule for checks:* Set how often or when exactly to evaluate the alert conditions. * *Notify after triggered:* Control how long a threshold must be breached before sending notifications. * *Notify after resolved:* Specify when to send resolution notifications after conditions return to normal. This can reduce noise when conditions fluctuate around the threshold. Tuning these settings helps prevent alert fatigue from transient issues while ensuring you're notified of persistent problems. ## Slack integration Apitally integrates with Slack to send alert notifications to a channel in your Slack workspace. You can set up the Slack integration under *Settings > Integrations*. ## Microsoft Teams integration Apitally also offers an integration with Microsoft Teams for alert notifications using the Incoming Webhook connector. To set this up, navigate to *Settings > Integrations* and then follow the instructions on the screen. # API uptime monitoring Source: https://docs.apitally.io/api-monitoring/uptime Get notified immediately when your API is down. ## Uptime checks Apitally automatically checks whether your applications are running and sending heartbeats every minute. If Apitally stops receiving heartbeats from an environment, it will send you an alert. You can disable alerts for specific environments. Uptime Note that your application may be unavailable to users even when it's sending heartbeats, for example due to a network issue. That's where health checks come in. ## Health checks Health checks monitor your application's availability by sending HTTP GET requests to a specified endpoint in 1 minute intervals. If the endpoint returns a successful response within 5 seconds, your application is considered healthy. Configure health checks We recommend you use a dedicated health check endpoint that doesn't require authentication. If a health check request fails or times out, Apitally will retry the request once before sending you an alert. The alert includes details about the failed request to help you diagnose the issue quickly. # Introduction Source: https://docs.apitally.io/api-reference Programmatically access logs and metrics for your apps. The Apitally API lets you programmatically access request logs and traffic metrics for your apps. Use it to export data for analysis, or integrate with your own systems. API access requires the Premium plan. ## Endpoints * [List apps](/api-reference/apps/list-apps): Retrieve all apps in your team. * [List consumers](/api-reference/consumers/list-consumers): Retrieve all consumers for an app. * [Get request logs](/api-reference/request-logs/get-request-logs): Retrieve request log data for an app. * [Get traffic](/api-reference/traffic/get-traffic): Retrieve aggregated traffic metrics for an app. ## Authentication The API uses API keys for authentication. Include your API key in the `Api-Key` header. ```bash theme={null} curl -H "Api-Key: your-api-key" https://api.apitally.io/v1/apps ``` You can manage API keys in the Apitally dashboard under **Settings > API keys**. Keys are scoped to a team and grant access to all apps within that team. ## Rate limits The API allows up to 100 requests per minute per API key. Rate limit information is included in response headers: * `X-RateLimit-Limit`: Maximum requests allowed per minute * `X-RateLimit-Remaining`: Requests remaining in the current window * `X-RateLimit-Reset`: Unix timestamp when the limit resets If you exceed the limit, the API returns a `429 Too Many Requests` response. ## Pagination Endpoints that return lists use cursor-based pagination. Responses include: * `data`: Array of items for the current page * `has_more`: Boolean indicating whether more items exist * `next_token`: Token to fetch the next page (only present if `has_more` is `true`) Use the `limit` query parameter to control page size (default 100, max 1000). To fetch the next page, pass the `next_token` value from the previous response: ```bash theme={null} curl -H "Api-Key: your-api-key" \ "https://api.apitally.io/v1/apps/123/request-logs?limit=100&next_token=abc123" ``` # List Apps Source: https://docs.apitally.io/api-reference/apps/list-apps https://api.apitally.io/openapi.json get /v1/apps List apps and their environments. # List Consumers Source: https://docs.apitally.io/api-reference/consumers/list-consumers https://api.apitally.io/openapi.json get /v1/apps/{app_id}/consumers List API consumers for an app. Ordered by ID (descending). With pagination. # List Endpoints Source: https://docs.apitally.io/api-reference/endpoints/list-endpoints https://api.apitally.io/openapi.json get /v1/apps/{app_id}/endpoints List API endpoints for an app. Ordered by path and method. # Get Traffic Source: https://docs.apitally.io/api-reference/metrics/get-traffic https://api.apitally.io/openapi.json get /v1/apps/{app_id}/traffic Get API traffic data for an app. Grouped by hour or by day. With pagination. Traffic to endpoints that have been excluded in the dashboard is excluded here as well. # Get Request Details Source: https://docs.apitally.io/api-reference/request-logs/get-request-details https://api.apitally.io/openapi.json get /v1/apps/{app_id}/request-logs/{request_uuid} Get detailed information about a specific request, including headers, body, application logs, and spans. # Get Request Logs Source: https://docs.apitally.io/api-reference/request-logs/get-request-logs https://api.apitally.io/openapi.json get /v1/apps/{app_id}/request-logs Get request log data for an app. With pagination. Requests to endpoints that have been excluded in the dashboard are excluded here as well. # Data privacy Source: https://docs.apitally.io/data-privacy How Apitally handles data collection, storage, and retention. Apitally is built with a strong focus on data privacy. We hold ourselves to these principles: * Collect only the data that's required, and nothing more * Require explicit user opt-in for any feature that could capture sensitive data * Offer extensive configuration options to control data collection, masking and filtering * Provide full transparency about what data is collected and how it's handled Because all Apitally SDKs are open-source, you can verify yourself how they work and what data they collect. ## Data collection This is a complete overview of the data collected by Apitally. The configuration options mentioned throughout this page are in `snake_case` notation, as used in Python. Check out the [SDK reference](/sdk-reference) for your language to see the equivalent parameter names. The [setup guide](/setup-guides) for each framework also includes configuration examples. *= Potentially sensitive and not collected by default.* ### Application metadata The following data is collected once on application startup. HTTP method and path of all routes registered in your application. Example: ```json theme={null} [ {"method": "GET", "path": "/v1/orders"}, {"method": "GET", "path": "/v1/orders/{orderId}"}, {"method": "POST", "path": "/v1/orders"} ] ``` Versions of the Apitally SDK, your framework and runtime. Example: ```json theme={null} { "apitally": "0.21.3", "fastapi": "0.121.1", "starlette": "0.49.3", "python": "3.13.9" } ``` ### Metrics & analytics The following data is collected for each request handled by your application and immediately aggregated on the client-side. Method and path of the endpoint that handled the request. Example: `POST /v1/orders` Status code of the response. Example: `200 OK` Size of the request body. Recorded as a histogram in 1 KB buckets. Example: `5 KB` Size of the response body. Recorded as a histogram in 1 KB buckets. Example: `5 KB` Time elapsed between start and finish of the route handler invokation for the request. Recorded as a histogram in 10 ms buckets. Example: `80 ms` Consumer }> Consumer identifier, and optionally name and group, as provided by your own implementation. See the [setup guide](/setup-guides) for your framework for how to associate requests with consumers. Example: ```json theme={null} { "identifier": "john.doe@example.com", "name": "John Doe", "group": "Users" } ``` Details about validation errors leading to a `4xx` response. Includes error type, message and field name. Doesn't include the invalid value. Only captured if a supported framework is used. See [here](/api-metrics/errors#validation-errors) for details. Example: ```json theme={null} [ {"loc": "query.title", "msg": "ensure this value has at least 3 characters", "type": "value_error.any_str.min_length"} ] ``` Exception message and stack trace. May also include a Sentry event ID, if available. Only captured if an unhandled exception occurred during request handling, leading to a `500 Internal Server Error` response. Example: ``` File 'app/api/endpoints.py', line 89, in get_item item = items_list[position] IndexError: 'List index out of range' ``` ### Request logs The following data is collected for each request handled by your application, if request logging is enabled. Method and path of the endpoint that handled the request. Example: `POST /v1/orders` The full request URL. Query parameters can be stripped by disabling `log_query_params` (enabled by default). Default masking rules apply to query parameters. Additional masking rules can be specified using `mask_query_params`. Example: `https://api.example.com/v1/books?search=api+design` Example: `200 OK` Size of the request body in bytes. Example: `4786 bytes` Request headers }> Only collected if enabled via `log_request_headers` (disabled by default). Default masking rules apply. Additional masking rules can be specified using `mask_headers`. Example: ``` Host: api.example.com Authorization: ****** X-Real-Ip: 147.98.24.101 ``` Request body }> Only collected if enabled via `log_request_body` (disabled by default). Default masking rules apply. Additional masking rules can be specified using `mask_body_fields` and `mask_request_body_callback`. Example: ```json theme={null} {"message":"Hello world"} ``` Size of the response body in bytes. Example: `4678 bytes` Can be disabled via `log_response_headers` (enabled by default). Default masking rules apply. Additional masking rules can be specified using `mask_headers`. Example: ``` Content-Type: application/json Content-Length: 36 ``` Response body }> Only collected if enabled via `log_response_body` (disabled by default). Default masking rules apply. Additional masking rules can be specified using `mask_body_fields` and `mask_response_body_callback`. Example: ```json theme={null} {"message":"Hello world"} ``` Time elapsed between start and finish of the route handler invokation for the request. Example: `82 ms` Consumer }> Consumer identifier, and optionally name and group, as provided by your own implementation. See the [setup guide](/setup-guides) for your framework for how to associate requests with consumers. Example: ```json theme={null} { "identifier": "john.doe@example.com", "name": "John Doe", "group": "Users" } ``` Application logs }> Log messages emitted by the application during request handling. Only collected if enabled via `capture_logs` (disabled by default). Example: ```json theme={null} [ {"timestamp": "2025-12-01T12:34:56.000Z", "message": "Example 1", "level": "info"}, {"timestamp": "2025-12-01T12:34:56.001Z", "message": "Example 2", "level": "warning"} ] ``` Traces }> OpenTelemetry spans created by the application during request handling. Only collected if enabled via `capture_traces` (disabled by default). Example: ```json theme={null} [ { "span_id": "a1b2c3d4e5f60001", "name": "GET /v1/orders/{orderId}", "kind": "INTERNAL", "start_time": 1735689600000000000, "end_time": 1735689600082000000 }, { "span_id": "a1b2c3d4e5f60002", "parent_span_id": "a1b2c3d4e5f60001", "name": "SELECT orders", "kind": "CLIENT", "start_time": 1735689600001000000, "end_time": 1735689600045000000, "attributes": {"db.system": "postgresql"} } ] ``` Exception message and stack trace. May also include a Sentry event ID, if available. Only captured if an unhandled exception occurred during request handling, leading to a `500 Internal Server Error` response. Can be disabled via `log_exception` (enabled by default). Example: ``` File 'app/api/endpoints.py', line 89, in get_item item = items_list[position] IndexError: 'List index out of range' ``` ## Data masking The Apitally SDKs mask common sensitive query parameters, headers and request/response body fields on the client side based on the below default patterns (regular expressions). You can add additional patterns using the configuration options mentioned below. Patterns are case-insensitive and match anywhere within the name. ### Query parameters ``` auth api-?key secret token password pwd ``` You can add additional patterns via the `mask_query_params` option. ### Headers ``` auth api-?key secret token cookie ``` You can add additional patterns via the `mask_headers` option. ### Body fields ``` password pwd token secret auth card[-_ ]?number ccv ssn ``` You can add additional patterns via the `mask_body_fields` option. For more granular control you can also specify callback functions via `mask_request_body_callback` and `mask_response_body_callback`. ## Data filtering The Apitally SDK automatically excludes requests to common static assets and health check endpoints from the request logs (not metrics) using the patterns below. They are applied to the request path. ``` /_?healthz?$ /_?health[_-]?checks?$ /_?heart[_-]?beats?$ /ping$ /ready$ /live$ /favicon(?:-[\w-]+)?\.(ico|png|svg)$ /apple-touch-icon(?:-[\w-]+)?\.png$ /robots\.txt$ /sitemap\.xml$ /manifest\.json$ /site\.webmanifest$ /service-worker\.js$ /sw\.js$ /\.well-known/ ``` You can add additional patterns for exclusion via the `exclude_paths` option. For more granular control you can also provide a callback function via `exclude_callbacks`. These exclusions don't impact metrics. If you'd like to exclude certain endpoints from metrics, you can mark them as excluded in the dashboard. See [here](/api-metrics/traffic#exclude-endpoints) for details. ## Data transit Apitally uses HTTPS and TLS to send data from your application, running the Apitally SDK, to our servers. ## Data storage Apitally stores data in a ClickHouse database hosted on DigitalOcean in the US. The underlying block storage volume is encrypted at rest. Database backups are created hourly and are stored in a private Spaces bucket. Data in Spaces is also encrypted at rest. ## Data retention Apitally retains aggregated metrics for 13 months, allowing you to analyze long-term trends. Request and application log data is retained for 15 days. When an app is deleted in the Apitally dashboard, all associated data is deleted from the database, but is still included in previously created backups. Database backups are kept for 7 days. ## Compliance Apitally currently doesn't hold certifications like SOC 2 or ISO 27001, and is not HIPAA compliant yet. Please reach out if you need help documenting Apitally as a vendor for your own compliance requirements. # How it works Source: https://docs.apitally.io/how-it-works Seamless integration with our open-source SDKs. Apitally integrates with your application via a lightweight middleware or plugin, provided by one of our open-source SDKs. The SDKs send data directly to Apitally, without the need for additional infrastructure or agents, and without affecting the performance of your application. The diagram below illustrates how the SDKs works. Diagram showing how the Apitally SDKs works Diagram showing how the Apitally SDKs works The SDKs include the following functionality: * Introspection of your application to capture metadata about available endpoints * Lightweight middleware that captures request and response data * Instrumentation of logging libraries to capture application logs * OpenTelemetry integration to capture traces during request handling * Non-blocking client that handles communication with Apitally The client is designed to be resilient to temporary network failures when communicating with Apitally and will retry sending data for up to 1 hour. ## On startup When your application starts and the Apitally middleware is initialized, it introspects your application to capture metadata about all available endpoints. This metadata is then sent to Apitally in a once-off request. ## During runtime When your application handles a request, the middleware times the invokation of the request handler and captures metadata about the request and response, such as the HTTP method, matched route, and the HTTP status code. If the response is a validation error (status 400 or 422), the middleware inspects the response body for further details about the error. The captured metadata is then passed to the client which immediately aggregates it with previously received data. The client synchronizes the aggregated data with Apitally in one minute intervals. If request logging is enabled, the client writes the request and response data to a compressed temporary file on disk. During the next synchronization interval, the client reads the log file and streams the compressed data to Apitally. Communication with Apitally happens asynchronously and doesn't interfere with your application's request handling. ## Server side When Apitally receives data from your application, it puts it in a queue for asynchronous processing. The data should be processed and visible on the dashboard within a few seconds. Data is retained at 1-minute granularity for 32 days and then aggregated to 30-minute intervals. We delete data completely after 13 months. # Introduction Source: https://docs.apitally.io/introduction Apitally makes API monitoring and analytics simple. Get API metrics, request logs, traces, and alerts by adding just a few lines of code. Apitally overview slideshow ## Explore Find out whether Apitally meets your requirements. Metrics, request logs, traces, monitoring, and more. Learn how Apitally integrates with your application. Learn how Apitally handles data collection, masking, storage, etc. ## Get started Set up Apitally for your API in under 5 minutes. [Sign up](https://app.apitally.io/?signup) to create an account if you don't have one yet. Then click the *Create app* button on the dashboard. Provide a name and select your framework. Follow the instructions on the dashboard to add the Apitally middleware to your application. It's just a small dependency to install and a few lines of code to copy & paste. Deploy your application, or restart it if you're testing locally. You'll see the first data in the dashboard within a few seconds. For a complete setup guide, select your framework from the options below. } href="/setup-guides/blacksheep" /> } href="/setup-guides/django-ninja" /> } href="/setup-guides/django-rest-framework" /> } href="/setup-guides/fastapi" /> } href="/setup-guides/flask" /> } href="/setup-guides/litestar" /> } href="/setup-guides/starlette" /> } href="/setup-guides/adonisjs" /> } href="/setup-guides/elysia" /> } href="/setup-guides/express" /> } href="/setup-guides/fastify" /> } href="/setup-guides/h3" /> } href="/setup-guides/hapi" /> } href="/setup-guides/hono" /> } href="/setup-guides/koa" /> } href="/setup-guides/nestjs" /> } href="/setup-guides/chi" /> } href="/setup-guides/echo" /> } href="/setup-guides/fiber" /> } href="/setup-guides/gin" /> } href="/setup-guides/spring-boot" /> } href="/setup-guides/aspnet-core" /> } href="/setup-guides/fastapi-cloudflare-workers" > Cloudflare Workers } href="/setup-guides/hono-cloudflare-workers" > Cloudflare Workers If your framework is not listed here, please [let us know](/support) and we'll consider adding support for it. # Overview Source: https://docs.apitally.io/sdk-reference Install and configure the Apitally SDK for your framework. ## Standard SDKs For apps with long-running processes. These SDKs include a client that sends data to Apitally in the background. ## Serverless SDKs For apps running on Cloudflare Workers. These SDKs rely on [Logpush](https://developers.cloudflare.com/workers/observability/logs/logpush/) to send data to Apitally. # Configuration Source: https://docs.apitally.io/sdk-reference/dotnet/configuration Configure the Apitally SDK for .NET. You can configure Apitally when registering the service in your `Program.cs` file or in your `appsettings.json` file. ```csharp Program.cs {6-9} theme={null} using Apitally; var builder = WebApplication.CreateBuilder(args); builder.Services.AddApitally(options => { options.ClientId = "your-client-id"; options.Env = "dev"; options.RequestLogging.Enabled = true; // other parameters ... }); var app = builder.Build(); app.UseApitally(); ``` ```json appsettings.json {3-8} theme={null} { "Apitally": { "ClientId": "your-client-id", "Env": "dev", "RequestLogging": { "Enabled": true, // other parameters ... } } } ``` ## Parameters The following configuration parameters are available. Only `ClientId` and `Env` are required. | Parameter | Description | Type | | :--------------- | :---------------------------------------------------------------------------------------------------------------- | :---------------------- | | `ClientId` | Client ID for your application. Find it on the *Setup instructions* page for your app. | `string` | | `Env` | Name of the environment, e.g. `prod` or `dev`. The environment will be automatically created if it doesn't exist. | `string` | | `RequestLogging` | Configuration for request logging. See table below. | `RequestLoggingOptions` | The `RequestLogging` parameter is an object with the following properties: | Parameter | Description | Type | Default | | :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------- | :------ | | `Enabled` | Whether request logging is enabled. | `bool` | `false` | | `IncludeQueryParams` | Whether to include query parameters in the logs. If disabled, these will be stripped from the request URLs logged. | `bool` | `true` | | `IncludeRequestHeaders` | Whether to include request headers in the logs. Default masking for common sensitive headers (e.g. `Authorization`) applies. | `bool` | `false` | | `IncludeRequestBody` | Whether to include the request body in the logs. Only JSON and text are supported, up to 50 KB. | `bool` | `false` | | `IncludeResponseHeaders` | Whether to include response headers in the logs. | `bool` | `true` | | `IncludeResponseBody` | Whether to include the response body in the logs. Only JSON and text are supported, up to 50 KB. | `bool` | `false` | | `IncludeException` | Whether to include exception details in the logs. | `bool` | `true` | | `CaptureLogs` | Whether to capture application logs emitted during request handling. | `bool` | `false` | | `CaptureTraces` | Whether to enable tracing using `System.Diagnostics`. | `bool` | `false` | | `QueryParamMaskPatterns` | List of regular expressions for matching query parameters to mask. These are in addition to the default masking patterns. | `List` | `[]` | | `HeaderMaskPatterns` | List of regular expressions for matching headers to mask. These are in addition to the default masking patterns. | `List` | `[]` | | `BodyFieldMaskPatterns` | List of regular expressions for matching request/response body fields to mask. These are in addition to the default masking patterns. | `List` | `[]` | | `PathExcludePatterns` | List of regular expressions for matching paths to exclude from logging. | `List` | `[]` | | `MaskRequestBody` | Function to mask sensitive data in the request body. Return `null` to mask the whole body. | `Func` | - | | `MaskResponseBody` | Function to mask sensitive data in the response body. Return `null` to mask the whole body. | `Func` | - | | `ShouldExclude` | Function to determine whether a request should be excluded from logging. Return `true` to exclude the request. | `Func` | - | # Masking and filtering Source: https://docs.apitally.io/sdk-reference/dotnet/masking-filtering Mask sensitive data and exclude requests from logging with the Apitally SDK for .NET. When request logging is enabled, the Apitally SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don't want to log. ## Default masking and exclusion The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named `password`, `token`, `secret`, or headers like `Authorization` are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as `/robots.txt` or `/healthz`. See the [data privacy](/data-privacy#data-masking) page for complete lists of default masking and exclusion patterns. ## Mask sensitive data You can extend the default masking rules by providing additional regular expressions via the `QueryParamMaskPatterns`, `HeaderMaskPatterns`, and `BodyFieldMaskPatterns` properties. Patterns are case-insensitive and match anywhere within the name. Use `^` and `$` anchors for exact matches. For more control over request and response body masking, you can provide callback functions via the `MaskRequestBody` and `MaskResponseBody` properties. The functions receive the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return the masked body as `byte[]`, or `null` to mask the entire body. ```csharp Program.cs example {12-18} theme={null} using Apitally; var builder = WebApplication.CreateBuilder(args); builder.Services.AddApitally(options => { options.ClientId = "your-client-id"; options.Env = "dev"; options.RequestLogging.Enabled = true; options.RequestLogging.IncludeRequestHeaders = true; options.RequestLogging.IncludeRequestBody = true; options.RequestLogging.IncludeResponseBody = true; // Mask specific query parameters, headers and body fields options.RequestLogging.QueryParamMaskPatterns = ["^card_number$", "^account_id$"]; options.RequestLogging.HeaderMaskPatterns = ["^X-Custom-Key$", "^X-Internal-"]; options.RequestLogging.BodyFieldMaskPatterns = ["^credit_card$", "social_security"]; // Mask request and response body using custom logic (see examples below) options.RequestLogging.MaskRequestBody = MaskRequestBody; options.RequestLogging.MaskResponseBody = MaskResponseBody; }); var app = builder.Build(); app.UseApitally(); ``` ```json appsettings.json example {10-12} theme={null} { "Apitally": { "ClientId": "your-client-id", "Env": "dev", "RequestLogging": { "Enabled": true, "IncludeRequestHeaders": true, "IncludeRequestBody": true, "IncludeResponseBody": true, "QueryParamMaskPatterns": ["^card_number$", "^account_id$"], "HeaderMaskPatterns": ["^X-Custom-Key$", "^X-Internal-"], "BodyFieldMaskPatterns": ["^credit_card$", "social_security"] } } } ``` ```csharp Callback function examples theme={null} using System.Text; using System.Text.Json; using Apitally.Models; byte[]? MaskRequestBody(Request request) { // Mask entire request body for admin endpoints if (request.Path?.StartsWith("/admin/") == true) { return null; } // Otherwise, return the original request body return request.Body; } byte[]? MaskResponseBody(Request request, Response response) { // Mask entire response body for admin endpoints if (request.Path?.StartsWith("/admin/") == true) { return null; } // Mask specific fields in user profile responses if (request.Path?.StartsWith("/users/") == true && response.Body != null) { try { var json = Encoding.UTF8.GetString(response.Body); var data = JsonSerializer.Deserialize>(json); if (data != null) { if (data.ContainsKey("email")) { data["email"] = "******"; } if (data.ContainsKey("phone")) { data["phone"] = "******"; } return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(data)); } } catch (JsonException) { // If parsing fails, return original body } } // Otherwise, return the original response body return response.Body; } ``` Callbacks are applied before pattern-based field masking. The returned body is still masked using the default and custom `BodyFieldMaskPatterns` patterns. ## Exclude requests You can exclude requests from logging using path patterns (regular expressions) via the `PathExcludePatterns` property. Like the masking patterns, these are case-insensitive and match anywhere within the request path. Use `^` and `$` anchors for exact matches. Alternatively, you can provide a callback function with custom exclusion logic via the `ShouldExclude` property. The function receives the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return `true` to exclude the request from logging, or `false` to include it. ```csharp Program.cs example {9-12} theme={null} using Apitally; var builder = WebApplication.CreateBuilder(args); builder.Services.AddApitally(options => { options.ClientId = "your-client-id"; options.Env = "dev"; options.RequestLogging.Enabled = true; // Exclude paths matching certain patterns options.RequestLogging.PathExcludePatterns = ["/admin/", "/internal/"]; // Exclude requests using custom logic (see example below) options.RequestLogging.ShouldExclude = ShouldExcludeRequest; }); var app = builder.Build(); app.UseApitally(); ``` ```json appsettings.json example {7} theme={null} { "Apitally": { "ClientId": "your-client-id", "Env": "dev", "RequestLogging": { "Enabled": true, "PathExcludePatterns": ["/admin/", "/internal/"] } } } ``` ```csharp Callback function example theme={null} using Apitally.Models; bool ShouldExcludeRequest(Request request, Response response) { // Exclude requests from a specific consumer if (request.Consumer == "internal-service") { return true; } // Exclude successful requests (only log failures) if (response.StatusCode < 400) { return true; } return false; } ``` Excluded requests won't be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the [dashboard](/api-metrics/traffic#exclude-endpoints). ## Callback arguments The `Request` object passed to callback functions has the following properties: | Property | Description | Type | | :---------- | :--------------------------------------------------------- | :--------- | | `Timestamp` | Unix timestamp of the request. | `double` | | `Method` | HTTP method of the request. | `string` | | `Path` | Path of the matched endpoint, if applicable. | `string?` | | `Url` | Full URL of the request. | `string` | | `Headers` | Array of key-value pairs representing the request headers. | `Header[]` | | `Size` | Size of the request body in bytes. | `long?` | | `Consumer` | Identifier of the consumer making the request. | `string?` | | `Body` | Raw request body. | `byte[]?` | The `Response` object passed to `MaskResponseBody` and `ShouldExclude` has the following properties: | Property | Description | Type | | :------------- | :---------------------------------------------------------- | :--------- | | `StatusCode` | HTTP status code of the response. | `int` | | `ResponseTime` | Time taken to respond to the request in seconds. | `double` | | `Headers` | Array of key-value pairs representing the response headers. | `Header[]` | | `Size` | Size of the response body in bytes. | `long?` | | `Body` | Raw response body. | `byte[]?` | # .NET SDK reference Source: https://docs.apitally.io/sdk-reference/dotnet/overview Overview of the Apitally SDK for .NET. apitally/apitally-dotnet Apitally ## Installation ```shell theme={null} dotnet add package Apitally ``` ## Supported frameworks The .NET SDK currently supports the web frameworks listed below. If your framework is not listed, please [let us know](/support) and we'll consider adding support for it. Click on a framework for a detailed setup guide. } href="/setup-guides/aspnet-core" /> # Tracing instrumentation Source: https://docs.apitally.io/sdk-reference/dotnet/tracing Instrument your .NET application for tracing in Apitally. When tracing is enabled, the Apitally SDK captures [Activities](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-concepts) during request handling and attaches them to request logs. This allows you to see exactly what happened during each request, including database queries, HTTP calls to external services, and custom operations. The SDK uses the native `System.Diagnostics.Activity` API, which is the same API that [OpenTelemetry for .NET](https://opentelemetry.io/docs/languages/dotnet/) is built on. This means OpenTelemetry is not required, but any existing OpenTelemetry instrumentation will work seamlessly. ## Enable tracing To enable tracing, set `CaptureTraces` to `true` in your request logging configuration: ```csharp Program.cs {5-6} theme={null} builder.Services.AddApitally(options => { options.ClientId = "your-client-id"; options.Env = "dev"; options.RequestLogging.Enabled = true; options.RequestLogging.CaptureTraces = true; }); ``` ```json appsettings.json {6-7} theme={null} { "Apitally": { "ClientId": "your-client-id", "Env": "dev", "RequestLogging": { "Enabled": true, "CaptureTraces": true } } } ``` ## Instrument libraries `HttpClient` and some other .NET libraries include built-in Activity instrumentation, so they generate spans automatically without any additional setup. Other libraries require OpenTelemetry instrumentation packages. For example: | Library | Instrumentation package | | :-------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- | | Entity Framework Core | [`OpenTelemetry.Instrumentation.EntityFrameworkCore`](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.EntityFrameworkCore) | | SqlClient | [`OpenTelemetry.Instrumentation.SqlClient`](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.SqlClient) | | Npgsql | [`Npgsql.OpenTelemetry`](https://www.nuget.org/packages/Npgsql.OpenTelemetry) | | StackExchange.Redis | [`OpenTelemetry.Instrumentation.StackExchangeRedis`](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.StackExchangeRedis) | See the [OpenTelemetry registry](https://opentelemetry.io/ecosystem/registry/?language=dotnet\&component=instrumentation) for more instrumentation packages. ## Create custom spans For custom operations that aren't covered by library instrumentation, you can create spans manually using the `System.Diagnostics` API. First, create an `ActivitySource` for your application (typically as a static field): ```csharp theme={null} using System.Diagnostics; public static class Telemetry { public static readonly ActivitySource Source = new("MyApp"); } ``` Then use `StartActivity` to create spans: ```csharp theme={null} public async Task ProcessOrderAsync(int orderId) { using var activity = Telemetry.Source.StartActivity("ProcessOrder"); activity?.SetTag("order.id", orderId); // ... } ``` # Configuration Source: https://docs.apitally.io/sdk-reference/go/configuration Configure the Apitally SDK for Go. You can configure Apitally using the `Config` struct passed to the `Middleware` function. ```go Chi {10-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/chi" "github.com/go-chi/chi/v5" ) func main() { r := chi.NewRouter() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // other parameters ... r.Use(apitally.Middleware(r, config)) } ``` ```go Echo {10-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/echo" "github.com/labstack/echo/v4" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // other parameters ... e.Use(apitally.Middleware(e, config)) } ``` ```go Fiber {10-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/fiber" "github.com/gofiber/fiber/v2" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // other parameters ... app.Use(apitally.Middleware(app, config)) } ``` ```go Gin {10-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // other parameters ... r.Use(apitally.Middleware(r, config)) } ``` See the [setup guides](/setup-guides#go) for more examples. ## Parameters The following are the fields of the `Config` struct. | Parameter | Description | Type | | :--------------- | :---------------------------------------------------------------------------------------------------------------- | :---------------------- | | `ClientId` | Client ID for your application. Find it on the *Setup instructions* page for your app. | `string` | | `Env` | Name of the environment, e.g. `prod` or `dev`. The environment will be automatically created if it doesn't exist. | `string` | | `RequestLogging` | Configuration options for request logging. See table below. | `*RequestLoggingConfig` | | `AppVersion` | The current version of your application, e.g. `1.0.0`. | `string` | The `RequestLogging` field is a pointer to a `RequestLoggingConfig` struct with the following fields: | Parameter | Description | Type | Default | | :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------- | :------ | | `Enabled` | Whether request logging is enabled. | `bool` | `false` | | `LogQueryParams` | Whether to include query parameters in the logs. If disabled, these will be stripped from the request URLs logged. | `bool` | `true` | | `LogRequestHeaders` | Whether to include request headers in the logs. Default masking for common sensitive headers (e.g. `Authorization`) applies. | `bool` | `false` | | `LogRequestBody` | Whether to include the request body in the logs. Only JSON and text are supported, up to 50 KB. | `bool` | `false` | | `LogResponseHeaders` | Whether to include response headers in the logs. | `bool` | `true` | | `LogResponseBody` | Whether to include the response body in the logs. Only JSON and text are supported, up to 50 KB. | `bool` | `false` | | `LogPanic` | Whether to log information when a panic occurs during request handling. | `bool` | `false` | | `CaptureLogs` | Whether to capture application logs emitted during request handling. | `bool` | `false` | | `CaptureTraces` | Whether to enable tracing with OpenTelemetry. | `bool` | `false` | | `MaskQueryParams` | List of regular expressions for matching query parameters to mask. These are in addition to the default masking patterns. | `[]*regexp.Regexp` | `nil` | | `MaskHeaders` | List of regular expressions for matching headers to mask. These are in addition to the default masking patterns. | `[]*regexp.Regexp` | `nil` | | `MaskBodyFields` | List of regular expressions for matching request/response body fields to mask. These are in addition to the default masking patterns. | `[]*regexp.Regexp` | `nil` | | `MaskRequestBodyCallback` | Callback function for masking the request body. Takes one parameter `request` and returns the request body as `[]byte` or `nil`. | `func(request *Request) []byte` | `nil` | | `MaskResponseBodyCallback` | Callback function for masking the response body. Takes two parameters `request` and `response` and returns the response body as `[]byte` or `nil`. | `func(request *Request, response *Response) []byte` | `nil` | | `ExcludePaths` | List of regular expressions for matching paths to exclude from logging. | `[]*regexp.Regexp` | `nil` | | `ExcludeCallback` | Callback function for excluding requests from logging. Takes two parameters `request` and `response` and returns `true`, if the request should be excluded, or `false` otherwise. | `func(request *Request, response *Response) bool` | `nil` | # Masking and filtering Source: https://docs.apitally.io/sdk-reference/go/masking-filtering Mask sensitive data and exclude requests from logging with the Apitally SDK for Go. When request logging is enabled, the Apitally SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don't want to log. ## Default masking and exclusion The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named `password`, `token`, `secret`, or headers like `Authorization` are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as `/robots.txt` or `/healthz`. See the [data privacy](/data-privacy#data-masking) page for complete lists of default masking and exclusion patterns. ## Mask sensitive data You can extend the default masking rules by providing additional regular expressions via the `MaskQueryParams`, `MaskHeaders`, and `MaskBodyFields` fields. Patterns match anywhere within the name. Use `^` and `$` anchors for exact matches, and the `(?i)` flag for case-insensitive matching. For more control over request and response body masking, you can provide callback functions via the `MaskRequestBodyCallback` and `MaskResponseBodyCallback` fields. The functions receive the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return the masked body as `[]byte`, or `nil` to mask the entire body. ```go Chi example {19-34} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/chi" "github.com/go-chi/chi/v5" ) func main() { r := chi.NewRouter() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true // Mask specific query parameters, headers and body fields config.RequestLogging.MaskQueryParams = []*regexp.Regexp{ regexp.MustCompile(`(?i)^card_number$`), regexp.MustCompile(`(?i)^account_id$`), } config.RequestLogging.MaskHeaders = []*regexp.Regexp{ regexp.MustCompile(`(?i)^X-Custom-Key$`), regexp.MustCompile(`(?i)^X-Internal-`), } config.RequestLogging.MaskBodyFields = []*regexp.Regexp{ regexp.MustCompile(`(?i)^credit_card$`), regexp.MustCompile(`(?i)social_security`), } // Mask request and response body using custom logic (see examples below) config.RequestLogging.MaskRequestBodyCallback = maskRequestBody config.RequestLogging.MaskResponseBodyCallback = maskResponseBody r.Use(apitally.Middleware(r, config)) } ``` ```go Echo example {19-34} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/echo" "github.com/labstack/echo/v4" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true // Mask specific query parameters, headers and body fields config.RequestLogging.MaskQueryParams = []*regexp.Regexp{ regexp.MustCompile(`(?i)^card_number$`), regexp.MustCompile(`(?i)^account_id$`), } config.RequestLogging.MaskHeaders = []*regexp.Regexp{ regexp.MustCompile(`(?i)^X-Custom-Key$`), regexp.MustCompile(`(?i)^X-Internal-`), } config.RequestLogging.MaskBodyFields = []*regexp.Regexp{ regexp.MustCompile(`(?i)^credit_card$`), regexp.MustCompile(`(?i)social_security`), } // Mask request and response body using custom logic (see examples below) config.RequestLogging.MaskRequestBodyCallback = maskRequestBody config.RequestLogging.MaskResponseBodyCallback = maskResponseBody e.Use(apitally.Middleware(e, config)) } ``` ```go Fiber example {19-34} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/fiber" "github.com/gofiber/fiber/v2" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true // Mask specific query parameters, headers and body fields config.RequestLogging.MaskQueryParams = []*regexp.Regexp{ regexp.MustCompile(`(?i)^card_number$`), regexp.MustCompile(`(?i)^account_id$`), } config.RequestLogging.MaskHeaders = []*regexp.Regexp{ regexp.MustCompile(`(?i)^X-Custom-Key$`), regexp.MustCompile(`(?i)^X-Internal-`), } config.RequestLogging.MaskBodyFields = []*regexp.Regexp{ regexp.MustCompile(`(?i)^credit_card$`), regexp.MustCompile(`(?i)social_security`), } // Mask request and response body using custom logic (see examples below) config.RequestLogging.MaskRequestBodyCallback = maskRequestBody config.RequestLogging.MaskResponseBodyCallback = maskResponseBody app.Use(apitally.Middleware(app, config)) } ``` ```go Gin example {19-34} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true // Mask specific query parameters, headers and body fields config.RequestLogging.MaskQueryParams = []*regexp.Regexp{ regexp.MustCompile(`(?i)^card_number$`), regexp.MustCompile(`(?i)^account_id$`), } config.RequestLogging.MaskHeaders = []*regexp.Regexp{ regexp.MustCompile(`(?i)^X-Custom-Key$`), regexp.MustCompile(`(?i)^X-Internal-`), } config.RequestLogging.MaskBodyFields = []*regexp.Regexp{ regexp.MustCompile(`(?i)^credit_card$`), regexp.MustCompile(`(?i)social_security`), } // Mask request and response body using custom logic (see examples below) config.RequestLogging.MaskRequestBodyCallback = maskRequestBody config.RequestLogging.MaskResponseBodyCallback = maskResponseBody r.Use(apitally.Middleware(r, config)) } ``` ```go Callback function examples theme={null} import ( "encoding/json" "strings" apitally "github.com/apitally/apitally-go/chi" ) func maskRequestBody(request *apitally.Request) []byte { // Mask entire request body for admin endpoints if strings.HasPrefix(request.Path, "/admin/") { return nil } // Otherwise, return the original request body return request.Body } func maskResponseBody(request *apitally.Request, response *apitally.Response) []byte { // Mask entire response body for admin endpoints if strings.HasPrefix(request.Path, "/admin/") { return nil } // Mask specific fields in user profile responses if strings.HasPrefix(request.Path, "/users/") && response.Body != nil { var data map[string]any if err := json.Unmarshal(response.Body, &data); err == nil { if _, ok := data["email"]; ok { data["email"] = "******" } if _, ok := data["phone"]; ok { data["phone"] = "******" } if maskedBody, err := json.Marshal(data); err == nil { return maskedBody } } } // Otherwise, return the original response body return response.Body } ``` Callbacks are applied before pattern-based field masking. The returned body is still masked using the default and custom `MaskBodyFields` patterns. ## Exclude requests You can exclude requests from logging using path patterns (regular expressions) via the `ExcludePaths` field. Like the masking patterns, these match anywhere within the request path. Use `^` and `$` anchors for exact matches, and the `(?i)` flag for case-insensitive matching. Alternatively, you can provide a callback function with custom exclusion logic via the `ExcludeCallback` field. The function receives the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return `true` to exclude the request from logging, or `false` to include it. ```go Chi example {16-22} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/chi" "github.com/go-chi/chi/v5" ) func main() { r := chi.NewRouter() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // Exclude paths matching certain patterns config.RequestLogging.ExcludePaths = []*regexp.Regexp{ regexp.MustCompile(`(?i)/admin/`), regexp.MustCompile(`(?i)/internal/`), } // Exclude requests using custom logic (see example below) config.RequestLogging.ExcludeCallback = excludeRequest r.Use(apitally.Middleware(r, config)) } ``` ```go Echo example {16-22} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/echo" "github.com/labstack/echo/v4" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // Exclude paths matching certain patterns config.RequestLogging.ExcludePaths = []*regexp.Regexp{ regexp.MustCompile(`(?i)/admin/`), regexp.MustCompile(`(?i)/internal/`), } // Exclude requests using custom logic (see example below) config.RequestLogging.ExcludeCallback = excludeRequest e.Use(apitally.Middleware(e, config)) } ``` ```go Fiber example {16-22} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/fiber" "github.com/gofiber/fiber/v2" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // Exclude paths matching certain patterns config.RequestLogging.ExcludePaths = []*regexp.Regexp{ regexp.MustCompile(`(?i)/admin/`), regexp.MustCompile(`(?i)/internal/`), } // Exclude requests using custom logic (see example below) config.RequestLogging.ExcludeCallback = excludeRequest app.Use(apitally.Middleware(app, config)) } ``` ```go Gin example {16-22} theme={null} package main import ( "regexp" apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true // Exclude paths matching certain patterns config.RequestLogging.ExcludePaths = []*regexp.Regexp{ regexp.MustCompile(`(?i)/admin/`), regexp.MustCompile(`(?i)/internal/`), } // Exclude requests using custom logic (see example below) config.RequestLogging.ExcludeCallback = excludeRequest r.Use(apitally.Middleware(r, config)) } ``` ```go Callback function example theme={null} import apitally "github.com/apitally/apitally-go/chi" func excludeRequest(request *apitally.Request, response *apitally.Response) bool { // Exclude requests from a specific consumer if request.Consumer == "internal-service" { return true } // Exclude successful requests (only log failures) if response.StatusCode < 400 { return true } return false } ``` Excluded requests won't be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the [dashboard](/api-metrics/traffic#exclude-endpoints). ## Callback arguments The `Request` struct passed to callback functions has the following fields: | Field | Description | Type | | :---------- | :--------------------------------------------------------- | :------------ | | `Timestamp` | Unix timestamp of the request. | `float64` | | `Method` | HTTP method of the request. | `string` | | `Path` | Path of the matched endpoint, if applicable. | `string` | | `URL` | Full URL of the request. | `string` | | `Headers` | Array of key-value pairs representing the request headers. | `[][2]string` | | `Size` | Size of the request body in bytes. | `int64` | | `Consumer` | Identifier of the consumer making the request. | `string` | | `Body` | Raw request body. | `[]byte` | The `Response` struct passed to `MaskResponseBodyCallback` and `ExcludeCallback` has the following fields: | Field | Description | Type | | :------------- | :---------------------------------------------------------- | :------------ | | `StatusCode` | HTTP status code of the response. | `int` | | `ResponseTime` | Time taken to respond to the request in seconds. | `float64` | | `Headers` | Array of key-value pairs representing the response headers. | `[][2]string` | | `Size` | Size of the response body in bytes. | `int64` | | `Body` | Raw response body. | `[]byte` | # Go SDK reference Source: https://docs.apitally.io/sdk-reference/go/overview Overview of the Apitally SDK for Go. apitally/apitally-go ## Installation The Apitally SDK for Go is published as individual packages for each supported framework. ```shell theme={null} go get github.com/apitally/apitally-go/{yourFramework} ``` Replace the `{yourFramework}` placeholder with the name of your framework. The options are: * `chi` * `echo` * `fiber` * `gin` ## Supported frameworks The Go SDK currently supports the web frameworks listed below. If your framework is not listed, please [let us know](/support) and we'll consider adding support for it. Click on a framework for a detailed setup guide. } href="/setup-guides/chi" /> } href="/setup-guides/echo" /> } href="/setup-guides/fiber" /> } href="/setup-guides/gin" /> # Tracing instrumentation Source: https://docs.apitally.io/sdk-reference/go/tracing Instrument your Go application with OpenTelemetry for tracing in Apitally. When tracing is enabled, the Apitally SDK captures [OpenTelemetry](https://opentelemetry.io/docs/languages/go/) spans during request handling and attaches them to request logs. This allows you to see exactly what happened during each request, including database queries, HTTP calls to external services, and custom operations. If you have an existing OpenTelemetry setup, the SDK automatically registers itself as a span processor with the global `TracerProvider`. Otherwise, it creates its own. Any spans created using the standard OpenTelemetry API or by instrumentation libraries will be captured. ## Enable tracing To enable tracing, set `CaptureTraces` to `true` in your middleware configuration: ```go Chi {13-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/chi" "github.com/go-chi/chi/v5" ) func main() { r := chi.NewRouter() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.CaptureTraces = true r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ``` ```go Echo {13-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/echo" "github.com/labstack/echo/v4" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.CaptureTraces = true e.Use(apitally.Middleware(e, config)) // ... rest of your code ... } ``` ```go Fiber {13-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/fiber" "github.com/gofiber/fiber/v2" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.CaptureTraces = true app.Use(apitally.Middleware(app, config)) // ... rest of your code ... } ``` ```go Gin {13-14} theme={null} package main import ( apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() config := apitally.NewConfig("your-client-id") config.Env = "dev" config.RequestLogging.Enabled = true config.RequestLogging.CaptureTraces = true r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ``` ## Instrument libraries To capture spans from HTTP clients, database drivers, and other libraries, use the corresponding OpenTelemetry instrumentation libraries. For example, to instrument outgoing HTTP requests using `otelhttp`: ```shell theme={null} go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp ``` ```go theme={null} import ( "net/http" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) client := &http.Client{ Transport: otelhttp.NewTransport(http.DefaultTransport), } ``` See the [OpenTelemetry registry](https://opentelemetry.io/ecosystem/registry/?language=go\&component=instrumentation) for a complete list of available instrumentation libraries. ## Create custom spans For custom operations that aren't covered by library instrumentation, you can create spans manually using the standard OpenTelemetry API: ```go theme={null} import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" ) var tracer = otel.Tracer("my-app") func processOrder(ctx context.Context, orderID string) error { ctx, span := tracer.Start(ctx, "process_order") defer span.End() span.SetAttributes(attribute.String("order_id", orderID)) // ... } ``` Make sure to pass the `ctx` returned by `tracer.Start()` to any child operations to maintain the span hierarchy. # Configuration Source: https://docs.apitally.io/sdk-reference/java/configuration Configure the Apitally SDK for Java. You can configure Apitally in your `application.yml` file. ```yaml application.yml {2-6} theme={null} apitally: client-id: "your-client-id" env: "dev" request-logging: enabled: true # other parameters ... ``` ## Parameters The following configuration parameters are available. Only `client-id` and `env` are required. | Parameter | Description | Type | | :----------------------------- | :---------------------------------------------------------------------------------------------------------------- | :------- | | `client-id` | Client ID for your application. Find it on the *Setup instructions* page for your app. | `string` | | `env` | Name of the environment, e.g. `prod` or `dev`. The environment will be automatically created if it doesn't exist. | `string` | | `request-logging` | Configuration for request logging. See table below. | `object` | The `request-logging` parameter is an object with the following properties: | Parameter | Description | Type | Default | | :--------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------ | :------------- | :------ | | `enabled` | Whether request logging is enabled. | `boolean` | `false` | | `query-params-included` | Whether to include query parameters in the logs. If disabled, these will be stripped from the request URLs logged. | `boolean` | `true` | | `request-headers-included` | Whether to include request headers in the logs. Default masking for common sensitive headers (e.g. `Authorization`) applies. | `boolean` | `false` | | `request-body-included` | Whether to include the request body in the logs. Only JSON and text are supported, up to 50 KB. | `boolean` | `false` | | `response-headers-included` | Whether to include response headers in the logs. | `boolean` | `true` | | `response-body-included` | Whether to include the response body in the logs. Only JSON and text are supported, up to 50 KB. | `boolean` | `false` | | `log-capture-enabled` | Whether to capture application logs emitted during request handling. | `boolean` | `false` | | `query-param-mask-patterns` | List of regular expressions for matching query parameters to mask. These are in addition to the default masking patterns. | `List` | `[]` | | `header-mask-patterns` | List of regular expressions for matching headers to mask. These are in addition to the default masking patterns. | `List` | `[]` | | `body-field-mask-patterns` | List of regular expressions for matching request/response body fields to mask. These are in addition to the default masking patterns. | `List` | `[]` | | `path-exclude-patterns` | List of regular expressions for matching paths to exclude from logging. | `List` | `[]` | | `callbacks-class` | Fully qualified name of a class implementing `RequestLoggingCallbacks` for custom masking and exclusion logic. | `string` | - | # Masking and filtering Source: https://docs.apitally.io/sdk-reference/java/masking-filtering Mask sensitive data and exclude requests from logging with the Apitally SDK for Java. When request logging is enabled, the Apitally SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don't want to log. ## Default masking and exclusion The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named `password`, `token`, `secret`, or headers like `Authorization` are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as `/robots.txt` or `/healthz`. See the [data privacy](/data-privacy#data-masking) page for complete lists of default masking and exclusion patterns. ## Mask sensitive data You can extend the default masking rules by providing additional regular expressions via the `query-param-mask-patterns`, `header-mask-patterns`, and `body-field-mask-patterns` properties. Patterns are case-insensitive and match anywhere within the name. Use `^` and `$` anchors for exact matches. For more control over request and response body masking, you can implement the `RequestLoggingCallbacks` interface and specify the class name via the `callbacks-class` property. The callback methods receive the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return the masked body as `byte[]`, or `null` to mask the entire body. ```yaml Configuration example {9-20} theme={null} apitally: client-id: "your-client-id" env: "dev" request-logging: enabled: true request-headers-included: true request-body-included: true response-body-included: true # Mask specific query parameters, headers and body fields query-param-mask-patterns: - "^card_number$" - "^account_id$" header-mask-patterns: - "^X-Custom-Key$" - "^X-Internal-" body-field-mask-patterns: - "^credit_card$" - "social_security" # Mask request and response body using custom logic (see example below) callbacks-class: "com.example.MyRequestLoggingCallbacks" ``` ```java Callbacks class example theme={null} import io.apitally.common.RequestLoggingCallbacks; import io.apitally.common.dto.Request; import io.apitally.common.dto.Response; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; public class MyRequestLoggingCallbacks implements RequestLoggingCallbacks { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public byte[] maskRequestBody(Request request) { // Mask entire request body for admin endpoints if (request.getPath() != null && request.getPath().startsWith("/admin/")) { return null; } // Otherwise, return the original request body return request.getBody(); } @Override public byte[] maskResponseBody(Request request, Response response) { // Mask entire response body for admin endpoints if (request.getPath() != null && request.getPath().startsWith("/admin/")) { return null; } // Mask specific fields in user profile responses if (request.getPath() != null && request.getPath().startsWith("/users/") && response.getBody() != null) { try { @SuppressWarnings("unchecked") HashMap data = objectMapper.readValue(response.getBody(), HashMap.class); if (data.containsKey("email")) { data.put("email", "******"); } if (data.containsKey("phone")) { data.put("phone", "******"); } return objectMapper.writeValueAsBytes(data); } catch (Exception e) { // If parsing fails, return original body } } // Otherwise, return the original response body return response.getBody(); } } ``` Callbacks are applied before pattern-based field masking. The returned body is still masked using the default and custom `body-field-mask-patterns` patterns. ## Exclude requests You can exclude requests from logging using path patterns (regular expressions) via the `path-exclude-patterns` property. Like the masking patterns, these are case-insensitive and match anywhere within the request path. Use `^` and `$` anchors for exact matches. Alternatively, you can implement the `shouldExclude` method in your `RequestLoggingCallbacks` class with custom exclusion logic. The method receives the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return `true` to exclude the request from logging, or `false` to include it. ```yaml Configuration example {6-11} theme={null} apitally: client-id: "your-client-id" env: "dev" request-logging: enabled: true # Exclude paths matching certain patterns path-exclude-patterns: - "/admin/" - "/internal/" # Exclude requests using custom logic (see example below) callbacks-class: "com.example.MyRequestLoggingCallbacks" ``` ```java Callbacks class example theme={null} import io.apitally.common.RequestLoggingCallbacks; import io.apitally.common.dto.Request; import io.apitally.common.dto.Response; public class MyRequestLoggingCallbacks implements RequestLoggingCallbacks { @Override public boolean shouldExclude(Request request, Response response) { // Exclude requests from a specific consumer if ("internal-service".equals(request.getConsumer())) { return true; } // Exclude successful requests (only log failures) if (response.getStatusCode() < 400) { return true; } return false; } } ``` Excluded requests won't be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the [dashboard](/api-metrics/traffic#exclude-endpoints). ## Callback arguments The `Request` object passed to callback methods has the following getter methods: | Method | Description | Type | | :--------------- | :--------------------------------------------------------- | :--------- | | `getTimestamp()` | Unix timestamp of the request. | `double` | | `getMethod()` | HTTP method of the request. | `String` | | `getPath()` | Path of the matched endpoint, if applicable. | `String` | | `getUrl()` | Full URL of the request. | `String` | | `getHeaders()` | Array of key-value pairs representing the request headers. | `Header[]` | | `getSize()` | Size of the request body in bytes. | `Long` | | `getConsumer()` | Identifier of the consumer making the request. | `String` | | `getBody()` | Raw request body. | `byte[]` | The `Response` object passed to `maskResponseBody` and `shouldExclude` has the following getter methods: | Method | Description | Type | | :------------------ | :---------------------------------------------------------- | :--------- | | `getStatusCode()` | HTTP status code of the response. | `int` | | `getResponseTime()` | Time taken to respond to the request in seconds. | `double` | | `getHeaders()` | Array of key-value pairs representing the response headers. | `Header[]` | | `getSize()` | Size of the response body in bytes. | `Long` | | `getBody()` | Raw response body. | `byte[]` | # Java SDK reference Source: https://docs.apitally.io/sdk-reference/java/overview Overview of the Apitally SDK for Java. apitally/apitally-java io.apitally/apitally ## Installation ```xml Maven theme={null} io.apitally apitally [0.1.0,) ``` ```groovy Gradle theme={null} dependencies { implementation 'io.apitally:apitally:+' } ``` ## Supported frameworks The Java SDK currently supports the web frameworks listed below. If your framework is not listed, please [let us know](/support) and we'll consider adding support for it. Click on a framework for a detailed setup guide. } href="/setup-guides/spring-boot" /> # Configuration Source: https://docs.apitally.io/sdk-reference/javascript-serverless/configuration Configure the Apitally Serverless SDK for JavaScript. ```javascript Hono {7-10} theme={null} import { Hono } from "hono"; import { useApitally } from "@apitally/serverless/hono"; const app = new Hono(); useApitally(app, { logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // other parameters ... }); ``` ## Parameters The following configuration parameters are available. | Parameter | Description | Type | Default | | :------------------- | :------------------------------------------------------------------------------------------------------------------------------------- | :--------- | :------ | | `enabled` | Whether to enable the Apitally integration. | `boolean` | `true` | | `logRequestHeaders` | Whether to include request headers in the logs. Default masking for common sensitive headers (e.g. `Authorization`) applies. | `boolean` | `false` | | `logRequestBody` | Whether to include the request body in the logs. Only JSON and text are supported, up to 10 KB. | `boolean` | `false` | | `logResponseHeaders` | Whether to include response headers in the logs. | `boolean` | `true` | | `logResponseBody` | Whether to include the response body in the logs. Only JSON and text are supported, up to 10 KB. | `boolean` | `false` | | `maskHeaders` | Array of regular expressions for matching headers to mask. These are in addition to the default masking patterns. | `RegExp[]` | `[]` | | `maskBodyFields` | Array of regular expressions for matching request/response body fields to mask. These are in addition to the default masking patterns. | `RegExp[]` | `[]` | | `excludePaths` | Array of regular expressions for matching paths to exclude from logging. | `RegExp[]` | `[]` | # Masking and filtering Source: https://docs.apitally.io/sdk-reference/javascript-serverless/masking-filtering Mask sensitive data and exclude requests from logging with the Apitally Serverless SDK for JavaScript. The Apitally Serverless SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don't want to log. ## Default masking and exclusion The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named `password`, `token`, `secret`, or headers like `Authorization` are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as `/robots.txt` or `/healthz`. See the [data privacy](/data-privacy#data-masking) page for complete lists of default masking and exclusion patterns. ## Mask sensitive data You can extend the default masking rules by providing additional regular expressions via the `maskHeaders` and `maskBodyFields` parameters. Patterns match anywhere within the name. Use `^` and `$` anchors for exact matches, and the `i` flag for case-insensitive matching. ```javascript Configuration example {10-12} theme={null} import { Hono } from "hono"; import { useApitally } from "@apitally/serverless/hono"; const app = new Hono(); useApitally(app, { logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific headers and body fields maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], }); ``` ## Exclude requests You can exclude requests from logging using path patterns (regular expressions) via the `excludePaths` parameter. Like the masking patterns, these match anywhere within the request path. Use `^` and `$` anchors for exact matches, and the `i` flag for case-insensitive matching. ```javascript Configuration example {7-8} theme={null} import { Hono } from "hono"; import { useApitally } from "@apitally/serverless/hono"; const app = new Hono(); useApitally(app, { // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], }); ``` Excluded requests won't be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the [dashboard](/api-metrics/traffic#exclude-endpoints). # JavaScript Serverless SDK reference Source: https://docs.apitally.io/sdk-reference/javascript-serverless/overview Overview of the Apitally Serverless SDK for JavaScript. apitally/apitally-js-serverless @apitally/serverless ## Installation ```shell theme={null} npm install @apitally/serverless ``` ## Supported frameworks The JavaScript Serverless SDK currently supports the web frameworks listed below. If your framework is not listed, please [let us know](/support) and we'll consider adding support for it. Click on a framework for a detailed setup guide. } href="/setup-guides/hono-cloudflare-workers" > Cloudflare Workers # Configuration Source: https://docs.apitally.io/sdk-reference/javascript/configuration Configure the Apitally SDK for JavaScript. ## Configuration You can configure Apitally via a configuration object. ```javascript Hono {7-12} theme={null} import { Hono } from "hono"; import { useApitally } from "apitally/hono"; const app = new Hono(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // other parameters ... }, }); ``` ```javascript NestJS {9-14} theme={null} import { NestFactory } from "@nestjs/core"; import { useApitally } from "apitally/nestjs"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // other parameters ... }, }); } ``` ```javascript Express {7-12} theme={null} import express from "express"; import { useApitally } from "apitally/express"; const app = express(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // other parameters ... }, }); ``` ```javascript Fastify {7-12} theme={null} import Fastify from "fastify"; import { apitallyPlugin } from "apitally/fastify"; const fastify = Fastify({ logger: true }); await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // other parameters ... }, }); ``` See the [setup guides](/setup-guides#javascript) for more examples. ## Parameters The following configuration parameters are available. Only `clientId` and `env` are required. | Parameter | Description | Type | Default | | :--------------- | :---------------------------------------------------------------------------------------------------------------- | :------- | :------ | | `clientId` | Client ID for your application. Find it on the *Setup instructions* page for your app. | `string` | | | `env` | Name of the environment, e.g. `prod` or `dev`. The environment will be automatically created if it doesn't exist. | `string` | `dev` | | `requestLogging` | Configuration options for request logging. See table below. | `object` | | | `appVersion` | The current version of your application, e.g. `1.0.0`. | `string` | | | `logger` | A custom logger instance. If not provided, a default logger is created automatically. | `object` | | The `requestLogging` parameter is an object with the following properties: | Parameter | Description | Type | Default | | :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------- | :------ | | `enabled` | Whether request logging is enabled. | `boolean` | `false` | | `logQueryParams` | Whether to include query parameters in the logs. If disabled, these will be stripped from the request URLs logged. | `boolean` | `true` | | `logRequestHeaders` | Whether to include request headers in the logs. Default masking for common sensitive headers (e.g. `Authorization`) applies. | `boolean` | `false` | | `logRequestBody` | Whether to include the request body in the logs. Only JSON and text are supported, up to 50 KB. | `boolean` | `false` | | `logResponseHeaders` | Whether to include response headers in the logs. | `boolean` | `true` | | `logResponseBody` | Whether to include the response body in the logs. Only JSON and text are supported, up to 50 KB. | `boolean` | `false` | | `logException` | Whether to include exception details in the logs. | `boolean` | `true` | | `captureLogs` | Whether to capture application logs emitted during request handling. | `boolean` | `false` | | `captureTraces` | Whether to enable tracing with OpenTelemetry. | `boolean` | `false` | | `maskQueryParams` | Array of regular expressions for matching query parameters to mask. These are in addition to the default masking patterns. | `RegExp[]` | `[]` | | `maskHeaders` | Array of regular expressions for matching headers to mask. These are in addition to the default masking patterns. | `RegExp[]` | `[]` | | `maskBodyFields` | Array of regular expressions for matching request/response body fields to mask. These are in addition to the default masking patterns. | `RegExp[]` | `[]` | | `maskRequestBodyCallback` | Callback function for masking the request body. Takes one parameter `request` and returns the request body as `Buffer` or `null`. | `Function` | - | | `maskResponseBodyCallback` | Callback function for masking the response body. Takes two parameters `request` and `response` and returns the response body as `Buffer` or `null`. | `Function` | - | | `excludePaths` | Array of regular expressions for matching paths to exclude from logging. | `RegExp[]` | `[]` | | `excludeCallback` | Callback function for excluding requests from logging. Takes two parameters `request` and `response` and returns `true`, if the request should be excluded, or `false` otherwise. | `Function` | - | # Masking and filtering Source: https://docs.apitally.io/sdk-reference/javascript/masking-filtering Mask sensitive data and exclude requests from logging with the Apitally SDK for JavaScript. When request logging is enabled, the Apitally SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don't want to log. ## Default masking and exclusion The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named `password`, `token`, `secret`, or headers like `Authorization` are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as `/robots.txt` or `/healthz`. See the [data privacy](/data-privacy#data-masking) page for complete lists of default masking and exclusion patterns. ## Mask sensitive data You can extend the default masking rules by providing additional regular expressions via the `maskQueryParams`, `maskHeaders`, and `maskBodyFields` parameters. Patterns match anywhere within the name. Use `^` and `$` anchors for exact matches, and the `i` flag for case-insensitive matching. For more control over request and response body masking, you can provide callback functions via the `maskRequestBodyCallback` and `maskResponseBodyCallback` parameters. The functions receive the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return the masked body as `Buffer`, or `null` to mask the entire body. ```javascript Hono example {14-20} theme={null} import { Hono } from "hono"; import { useApitally } from "apitally/hono"; const app = new Hono(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, }, }); ``` ```javascript NestJS example {16-22} theme={null} import { NestFactory } from "@nestjs/core"; import { useApitally } from "apitally/nestjs"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, }, }); } ``` ```javascript Express example {14-20} theme={null} import express from "express"; import { useApitally } from "apitally/express"; const app = express(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, }, }); ``` ```javascript Fastify example {14-20} theme={null} import Fastify from "fastify"; import { apitallyPlugin } from "apitally/fastify"; const fastify = Fastify({ logger: true }); await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, // Mask specific query parameters, headers and body fields maskQueryParams: [/^card_number$/i, /^account_id$/i], maskHeaders: [/^X-Custom-Key$/i, /^X-Internal-/i], maskBodyFields: [/^credit_card$/i, /social_security/i], // Mask request and response body using custom logic (see examples below) maskRequestBodyCallback: maskRequestBody, maskResponseBodyCallback: maskResponseBody, }, }); ``` ```javascript Callback function examples theme={null} function maskRequestBody(request) { // Mask entire request body for admin endpoints if (request.path?.startsWith("/admin/")) { return null; } // Otherwise, return the original request body return request.body; } function maskResponseBody(request, response) { // Mask entire response body for admin endpoints if (request.path?.startsWith("/admin/")) { return null; } // Mask specific fields in user profile responses if (request.path?.startsWith("/users/") && response.body) { try { const data = JSON.parse(response.body.toString()); if (typeof data === "object" && data !== null) { if ("email" in data) { data.email = "******"; } if ("phone" in data) { data.phone = "******"; } return Buffer.from(JSON.stringify(data)); } } catch { // If parsing fails, return original body } } // Otherwise, return the original response body return response.body; } ``` Callbacks are applied before pattern-based field masking. The returned body is still masked using the default and custom `maskBodyFields` patterns. ## Exclude requests You can exclude requests from logging using path patterns (regular expressions) via the `excludePaths` parameter. Like the masking patterns, these match anywhere within the request path. Use `^` and `$` anchors for exact matches, and the `i` flag for case-insensitive matching. Alternatively, you can provide a callback function with custom exclusion logic via the `excludeCallback` parameter. The function receives the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return `true` to exclude the request from logging, or `false` to include it. ```javascript Hono example {11-14} theme={null} import { Hono } from "hono"; import { useApitally } from "apitally/hono"; const app = new Hono(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, }, }); ``` ```javascript NestJS example {13-16} theme={null} import { NestFactory } from "@nestjs/core"; import { useApitally } from "apitally/nestjs"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, }, }); } ``` ```javascript Express example {11-14} theme={null} import express from "express"; import { useApitally } from "apitally/express"; const app = express(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, }, }); ``` ```javascript Fastify example {11-14} theme={null} import Fastify from "fastify"; import { apitallyPlugin } from "apitally/fastify"; const fastify = Fastify({ logger: true }); await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, // Exclude paths matching certain patterns excludePaths: [/\/admin\//i, /\/internal\//i], // Exclude requests using custom logic (see example below) excludeCallback: excludeRequest, }, }); ``` ```javascript Callback function example theme={null} function excludeRequest(request, response) { // Exclude requests from a specific consumer if (request.consumer === "internal-service") { return true; } // Exclude successful requests (only log failures) if (response.statusCode < 400) { return true; } return false; } ``` Excluded requests won't be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the [dashboard](/api-metrics/traffic#exclude-endpoints). ## Callback arguments The `request` object passed to callback functions has the following properties: | Property | Description | Type | | :---------- | :--------------------------------------------------------- | :-------------------- | | `timestamp` | Unix timestamp of the request. | `number` | | `method` | HTTP method of the request. | `string` | | `path` | Path of the matched endpoint, if applicable. | `string \| undefined` | | `url` | Full URL of the request. | `string` | | `headers` | Array of key-value pairs representing the request headers. | `[string, string][]` | | `size` | Size of the request body in bytes. | `number \| undefined` | | `consumer` | Identifier of the consumer making the request. | `string \| undefined` | | `body` | Raw request body. | `Buffer \| undefined` | The `response` object passed to `maskResponseBodyCallback` and `excludeCallback` has the following properties: | Property | Description | Type | | :------------- | :---------------------------------------------------------- | :-------------------- | | `statusCode` | HTTP status code of the response. | `number` | | `responseTime` | Time taken to respond to the request in seconds. | `number` | | `headers` | Array of key-value pairs representing the response headers. | `[string, string][]` | | `size` | Size of the response body in bytes. | `number \| undefined` | | `body` | Raw response body. | `Buffer \| undefined` | # JavaScript SDK reference Source: https://docs.apitally.io/sdk-reference/javascript/overview Overview of the Apitally SDK for JavaScript. apitally/apitally-js apitally Running Hono on Cloudflare Workers? Use our [Serverless SDK](/sdk-reference/javascript-serverless/overview) instead. ## Installation ```shell theme={null} npm install apitally ``` ## Supported frameworks The JavaScript SDK currently supports the web frameworks listed below. If your framework is not listed, please [let us know](/support) and we'll consider adding support for it. Click on a framework for a detailed setup guide. } href="/setup-guides/adonisjs" /> } href="/setup-guides/elysia" /> } href="/setup-guides/express" /> } href="/setup-guides/fastify" /> } href="/setup-guides/h3" /> } href="/setup-guides/hapi" /> } href="/setup-guides/hono" /> } href="/setup-guides/koa" /> } href="/setup-guides/nestjs" /> # Tracing instrumentation Source: https://docs.apitally.io/sdk-reference/javascript/tracing Instrument your JavaScript application with OpenTelemetry for tracing in Apitally. When tracing is enabled, the Apitally SDK captures [OpenTelemetry](https://opentelemetry.io/docs/languages/js/) spans during request handling and attaches them to request logs. This allows you to see exactly what happened during each request, including database queries, HTTP calls to external services, and custom operations. ## Enable tracing To enable tracing, set `captureTraces` to `true` in your request logging configuration: ```javascript Hono {10-11} theme={null} import { Hono } from "hono"; import { useApitally } from "apitally/hono"; const app = new Hono(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, captureTraces: true, }, }); ``` ```javascript NestJS {12-13} theme={null} import { NestFactory } from "@nestjs/core"; import { useApitally } from "apitally/nestjs"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, captureTraces: true, }, }); } ``` ```javascript Express {10-11} theme={null} import express from "express"; import { useApitally } from "apitally/express"; const app = express(); useApitally(app, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, captureTraces: true, }, }); ``` ```javascript Fastify {10-11} theme={null} import Fastify from "fastify"; import { apitallyPlugin } from "apitally/fastify"; const fastify = Fastify({ logger: true }); await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", requestLogging: { enabled: true, captureTraces: true, }, }); ``` ## Set up OpenTelemetry To capture spans from libraries like HTTP clients and database drivers, you need to set up OpenTelemetry instrumentation. First, install the required packages: ```shell theme={null} npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node ``` Then create an `instrumentation.ts` file (or `instrumentation.mjs` for JavaScript) that initializes the OpenTelemetry SDK with the `ApitallySpanProcessor` and auto-instrumentations: ```javascript instrumentation.ts / instrumentation.mjs {3,6} theme={null} import { NodeSDK } from "@opentelemetry/sdk-node"; import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node"; import { ApitallySpanProcessor } from "apitally/otel"; const sdk = new NodeSDK({ spanProcessors: [new ApitallySpanProcessor()], instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); ``` No trace exporter is required. The `ApitallySpanProcessor` collects spans and attaches them to request logs instead. Finally, run your application with the `--import` flag to load the instrumentation before your application code: ```shell TypeScript theme={null} npx tsx --import ./instrumentation.ts app.ts ``` ```shell JavaScript theme={null} node --import ./instrumentation.mjs app.js ``` See the official [OpenTelemetry guide for Node.js](https://opentelemetry.io/docs/languages/js/getting-started/nodejs/) for more details. ## Create custom spans For custom operations that aren't covered by library instrumentation, you can [create spans](https://opentelemetry.io/docs/languages/js/instrumentation/#create-spans) manually using the `startActiveSpan` method from the standard OpenTelemetry API. ```javascript theme={null} import { trace } from "@opentelemetry/api"; const tracer = trace.getTracer("my-app"); async function processOrder(orderId) { await tracer.startActiveSpan("process_order", async (span) => { span.setAttribute("order_id", orderId); // ... span.end(); }); } ``` # Configuration Source: https://docs.apitally.io/sdk-reference/python-serverless/configuration Configure the Apitally Serverless SDK for Python. ```python FastAPI {7-10} theme={null} from fastapi import FastAPI from apitally_serverless.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, log_request_headers=True, log_request_body=True, log_response_body=True, # other parameters ... ) ``` ## Parameters The following configuration parameters are available. | Parameter | Description | Type | Default | | :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------ | :---------- | :------ | | `enabled` | Whether to enable the Apitally integration. | `bool` | `True` | | `log_request_headers` | Whether to include request headers in the logs. Default masking for common sensitive headers (e.g. `Authorization`) applies. | `bool` | `False` | | `log_request_body` | Whether to include the request body in the logs. Only JSON and text are supported, up to 10 KB. | `bool` | `False` | | `log_response_headers` | Whether to include response headers in the logs. | `bool` | `True` | | `log_response_body` | Whether to include the response body in the logs. Only JSON and text are supported, up to 10 KB. | `bool` | `False` | | `mask_headers` | List of regular expressions for matching headers to mask. These are in addition to the default masking patterns. | `list[str]` | `[]` | | `mask_body_fields` | List of regular expressions for matching request/response body fields to mask. These are in addition to the default masking patterns. | `list[str]` | `[]` | | `exclude_paths` | List of regular expressions for matching paths to exclude from logging. | `list[str]` | `[]` | # Masking and filtering Source: https://docs.apitally.io/sdk-reference/python-serverless/masking-filtering Mask sensitive data and exclude requests from logging with the Apitally Serverless SDK for Python. The Apitally Serverless SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don't want to log. ## Default masking and exclusion The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named `password`, `token`, `secret`, or headers like `Authorization` are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as `/robots.txt` or `/healthz`. See the [data privacy](/data-privacy#data-masking) page for complete lists of default masking and exclusion patterns. ## Mask sensitive data You can extend the default masking rules by providing additional regular expressions via the `mask_headers` and `mask_body_fields` parameters. Patterns are case-insensitive and match anywhere within the name. Use `^` and `$` anchors for exact matches. ```python Configuration example {10-12} theme={null} from fastapi import FastAPI from apitally_serverless.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, log_request_headers=True, log_request_body=True, log_response_body=True, # Mask specific headers and body fields mask_headers=[r"^X-Custom-Key$", r"^X-Internal-"], mask_body_fields=[r"^credit_card$", r"social_security"], ) ``` ## Exclude requests You can exclude requests from logging using path patterns (regular expressions) via the `exclude_paths` parameter. Like the masking patterns, these are case-insensitive and match anywhere within the request path. Use `^` and `$` anchors for exact matches. ```python Configuration example {7-8} theme={null} from fastapi import FastAPI from apitally_serverless.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, # Exclude paths matching certain patterns exclude_paths=[r"/admin/", r"/internal/"], ) ``` Excluded requests won't be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the [dashboard](/api-metrics/traffic#exclude-endpoints). # Python Serverless SDK reference Source: https://docs.apitally.io/sdk-reference/python-serverless/overview Overview of the Apitally Serverless SDK for Python. apitally/apitally-py-serverless apitally-serverless ## Installation ```shell theme={null} uv add apitally-serverless ``` ## Supported frameworks The Python Serverless SDK currently supports the web frameworks listed below. If your framework is not listed, please [let us know](/support) and we'll consider adding support for it. Click on a framework for a detailed setup guide. } href="/setup-guides/fastapi-cloudflare-workers" > Cloudflare Workers # Configuration Source: https://docs.apitally.io/sdk-reference/python/configuration Configure the Apitally SDK for Python. ```python FastAPI {7-10} theme={null} from fastapi import FastAPI from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", enable_request_logging=True, # other parameters ... ) ``` ```python Django {2-5} theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", "enable_request_logging": True, # other parameters ... } ``` ```python Flask {7-10} theme={null} from flask import Flask from apitally.flask import ApitallyMiddleware app = Flask(__name__) app.wsgi_app = ApitallyMiddleware( app, client_id="your-client-id", env="dev", enable_request_logging=True, # other parameters ... ) ``` See the [setup guides](/setup-guides#python) for more examples. ## Parameters The following configuration parameters are available. Only `client_id` and `env` are required. | Parameter | Description | Type | Default | | :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------- | :------ | | `client_id` | Client ID for your application. Find it on the *Setup instructions* page for your app. | `string` | | | `env` | Name of the environment, e.g. `prod` or `dev`. The environment will be automatically created if it doesn't exist. | `string` | `dev` | | `app_version` | The current version of your application, e.g. `1.0.0`. | `string` | `None` | | `enable_request_logging` | Whether request logging is enabled. | `bool` | `False` | | `log_query_params` | Whether to include query parameters in the logs. If disabled, these will be stripped from the request URLs logged. | `bool` | `True` | | `log_request_headers` | Whether to include request headers in the logs. Default masking for common sensitive headers (e.g. `Authorization`) applies. | `bool` | `False` | | `log_request_body` | Whether to include the request body in the logs. Only JSON and text are supported, up to 50 KB. | `bool` | `False` | | `log_response_headers` | Whether to include response headers in the logs. | `bool` | `True` | | `log_response_body` | Whether to include the response body in the logs. Only JSON and text are supported, up to 50 KB. | `bool` | `False` | | `log_exception` | Whether to include exception details in the logs. | `bool` | `True` | | `capture_logs` | Whether to capture application logs emitted during request handling. | `bool` | `False` | | `capture_traces` | Whether to enable tracing with OpenTelemetry. | `bool` | `False` | | `mask_query_params` | List of regular expressions for matching query parameters to mask. These are in addition to the default masking patterns. | `list[str]` | `[]` | | `mask_headers` | List of regular expressions for matching headers to mask. These are in addition to the default masking patterns. | `list[str]` | `[]` | | `mask_body_fields` | List of regular expressions for matching request/response body fields to mask. These are in addition to the default masking patterns. | `list[str]` | `[]` | | `mask_request_body_callback` | Callback function for masking the request body. Takes one parameter `request` and returns the request body as `bytes` or `None`. | `Callable` | `None` | | `mask_response_body_callback` | Callback function for masking the response body. Takes two parameters `request` and `response` and returns the response body as `bytes` or `None`. | `Callable` | `None` | | `exclude_paths` | List of regular expressions for matching paths to exclude from logging. | `list[str]` | `[]` | | `exclude_callback` | Callback function for excluding requests from logging. Takes two parameters `request` and `response` and returns `True`, if the request should be excluded, or `False` otherwise. | `Callable` | `None` | # Masking and filtering Source: https://docs.apitally.io/sdk-reference/python/masking-filtering Mask sensitive data and exclude requests from logging with the Apitally SDK for Python. When request logging is enabled, the Apitally SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don't want to log. ## Default masking and exclusion The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named `password`, `token`, `secret`, or headers like `Authorization` are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as `/robots.txt` or `/healthz`. See the [data privacy](/data-privacy#data-masking) page for complete lists of default masking and exclusion patterns. ## Mask sensitive data You can extend the default masking rules by providing additional regular expressions via the `mask_query_params`, `mask_headers`, and `mask_body_fields` parameters. Patterns are case-insensitive and match anywhere within the name. Use `^` and `$` anchors for exact matches. For more control over request and response body masking, you can provide callback functions via the `mask_request_body_callback` and `mask_response_body_callback` parameters. The functions receive the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return the masked body as `bytes`, or `None` to mask the entire body. ```python FastAPI example {13-19} theme={null} from fastapi import FastAPI from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", enable_request_logging=True, log_request_headers=True, log_request_body=True, log_response_body=True, # Mask specific query parameters, headers and body fields mask_query_params=[r"^card_number$", r"^account_id$"], mask_headers=[r"^X-Custom-Key$", r"^X-Internal-"], mask_body_fields=[r"^credit_card$", r"social_security"], # Mask request and response body using custom logic (see examples below) mask_request_body_callback=mask_request_body, mask_response_body_callback=mask_response_body, ) ``` ```python Django example {8-14} theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", "enable_request_logging": True, "log_request_headers": True, "log_request_body": True, "log_response_body": True, # Mask specific query parameters, headers and body fields "mask_query_params": [r"^card_number$", r"^account_id$"], "mask_headers": [r"^X-Custom-Key$", r"^X-Internal-"], "mask_body_fields": [r"^credit_card$", r"social_security"], # Mask request and response body using custom logic (see examples below) "mask_request_body_callback": mask_request_body, "mask_response_body_callback": mask_response_body, } ``` ```python Flask example {13-19} theme={null} from flask import Flask from apitally.flask import ApitallyMiddleware app = Flask(__name__) app.wsgi_app = ApitallyMiddleware( app, client_id="your-client-id", env="dev", enable_request_logging=True, log_request_headers=True, log_request_body=True, log_response_body=True, # Mask specific query parameters, headers and body fields mask_query_params=[r"^card_number$", r"^account_id$"], mask_headers=[r"^X-Custom-Key$", r"^X-Internal-"], mask_body_fields=[r"^credit_card$", r"social_security"], # Mask request and response body using custom logic (see examples below) mask_request_body_callback=mask_request_body, mask_response_body_callback=mask_response_body, ) ``` ```python Callback function examples theme={null} import json def mask_request_body(request: dict) -> bytes | None: # Mask entire request body for admin endpoints if request["path"] and request["path"].startswith("/admin/"): return None # Otherwise, return the original request body return request["body"] def mask_response_body(request: dict, response: dict) -> bytes | None: # Mask entire response body for admin endpoints if request["path"] and request["path"].startswith("/admin/"): return None # Mask specific fields in user profile responses if request["path"] and request["path"].startswith("/users/") and response["body"]: try: data = json.loads(response["body"]) if isinstance(data, dict): if "email" in data: data["email"] = "******" if "phone" in data: data["phone"] = "******" return json.dumps(data).encode() except (json.JSONDecodeError, UnicodeDecodeError): pass # Otherwise, return the original response body return response["body"] ``` Callbacks are applied before pattern-based field masking. The returned body is still masked using the default and custom `mask_body_fields` patterns. ## Exclude requests You can exclude requests from logging using path patterns (regular expressions) via the `exclude_paths` parameter. Like the masking patterns, these are case-insensitive and match anywhere within the request path. Use `^` and `$` anchors for exact matches. Alternatively, you can provide a callback function with custom exclusion logic via the `exclude_callback` parameter. The function receives the captured request and response data as arguments (see [callback arguments](#callback-arguments) below) and should return `True` to exclude the request from logging, or `False` to include it. ```python FastAPI example {10-13} theme={null} from fastapi import FastAPI from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", enable_request_logging=True, # Exclude paths matching certain patterns exclude_paths=[r"/admin/", r"/internal/"], # Exclude requests using custom logic (see example below) exclude_callback=exclude_request, ) ``` ```python Django example {5-8} theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", "enable_request_logging": True, # Exclude paths matching certain patterns "exclude_paths": [r"/admin/", r"/internal/"], # Exclude requests using custom logic (see example below) "exclude_callback": exclude_request, } ``` ```python Flask example {10-13} theme={null} from flask import Flask from apitally.flask import ApitallyMiddleware app = Flask(__name__) app.wsgi_app = ApitallyMiddleware( app, client_id="your-client-id", env="dev", enable_request_logging=True, # Exclude paths matching certain patterns exclude_paths=[r"/admin/", r"/internal/"], # Exclude requests using custom logic (see example below) exclude_callback=exclude_request, ) ``` ```python Callback function example theme={null} def exclude_request(request: dict, response: dict) -> bool: # Exclude requests from a specific consumer if request["consumer"] == "internal-service": return True # Exclude successful requests (only log failures) if response["status_code"] < 400: return True return False ``` Excluded requests won't be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the [dashboard](/api-metrics/traffic#exclude-endpoints). ## Callback arguments The `request` dict passed to callback functions has the following keys: | Key | Description | Type | | :---------- | :-------------------------------------------------------- | :---------------------- | | `timestamp` | Unix timestamp of the request. | `float` | | `method` | HTTP method of the request. | `str` | | `path` | Path of the matched endpoint, if applicable. | `str \| None` | | `url` | Full URL of the request. | `str` | | `headers` | List of key-value pairs representing the request headers. | `list[tuple[str, str]]` | | `size` | Size of the request body in bytes. | `int \| None` | | `consumer` | Identifier of the consumer making the request. | `str \| None` | | `body` | Raw request body. | `bytes \| None` | The `response` dict passed to `mask_response_body_callback` and `exclude_callback` has the following keys: | Key | Description | Type | | :-------------- | :--------------------------------------------------------- | :---------------------- | | `status_code` | HTTP status code of the response. | `int` | | `response_time` | Time taken to respond to the request in seconds. | `float` | | `headers` | List of key-value pairs representing the response headers. | `list[tuple[str, str]]` | | `size` | Size of the response body in bytes. | `int \| None` | | `body` | Raw response body. | `bytes \| None` | # Python SDK reference Source: https://docs.apitally.io/sdk-reference/python/overview Overview of the Apitally SDK for Python. apitally/apitally-py apitally Running FastAPI on Cloudflare Workers? Use our [Serverless SDK](/sdk-reference/python-serverless/overview) instead. ## Installation The Apitally SDK for Python uses extras to install the correct dependencies for each framework. ```shell pip theme={null} pip install "apitally[]" ``` ```shell uv theme={null} uv add "apitally[]" ``` ```shell poetry theme={null} poetry add "apitally[]" ``` Replace the `` placeholder with the extra for your framework. The options are: * `blacksheep` * `django_ninja` * `django_rest_framework` * `fastapi` * `flask` * `litestar` * `starlette` ## Supported frameworks The Python SDK currently supports the web frameworks listed below. If your framework is not listed, please [let us know](/support) and we'll consider adding support for it. Click on a framework for a detailed setup guide. } href="/setup-guides/blacksheep" /> } href="/setup-guides/django-ninja" /> } href="/setup-guides/django-rest-framework" /> } href="/setup-guides/fastapi" /> } href="/setup-guides/flask" /> } href="/setup-guides/litestar" /> } href="/setup-guides/starlette" /> # Tracing instrumentation Source: https://docs.apitally.io/sdk-reference/python/tracing Instrument your Python application with OpenTelemetry for tracing in Apitally. When tracing is enabled, the Apitally SDK captures [OpenTelemetry](https://opentelemetry.io/docs/languages/python/) spans during request handling and attaches them to request logs. This allows you to see exactly what happened during each request, including database queries, HTTP calls to external services, and custom operations. If you have an existing OpenTelemetry setup, the SDK automatically registers itself as a span processor with the global `TracerProvider`. Otherwise, it creates its own. Any spans created using the standard OpenTelemetry API or by instrumentation libraries will be captured. ## Enable tracing To enable tracing, set `capture_traces` to `True` in your middleware configuration: ```python FastAPI {9-10} theme={null} from fastapi import FastAPI from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", enable_request_logging=True, capture_traces=True, ) ``` ```python Django {4-5} theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", "enable_request_logging": True, "capture_traces": True, } ``` ```python Flask {9-10} theme={null} from flask import Flask from apitally.flask import ApitallyMiddleware app = Flask(__name__) app.wsgi_app = ApitallyMiddleware( app, client_id="your-client-id", env="dev", enable_request_logging=True, capture_traces=True, ) ``` ## Instrument libraries The SDK provides helper functions in `apitally.otel` to instrument popular libraries. These are thin wrappers around the official OpenTelemetry instrumentation packages, which need to be installed separately. | Library | Function | Required package | | :--------------------- | :------------------------ | :----------------------------------------- | | httpx | `instrument_httpx()` | `opentelemetry-instrumentation-httpx` | | requests | `instrument_requests()` | `opentelemetry-instrumentation-requests` | | SQLAlchemy | `instrument_sqlalchemy()` | `opentelemetry-instrumentation-sqlalchemy` | | psycopg 3 | `instrument_psycopg()` | `opentelemetry-instrumentation-psycopg` | | psycopg2 | `instrument_psycopg2()` | `opentelemetry-instrumentation-psycopg2` | | asyncpg | `instrument_asyncpg()` | `opentelemetry-instrumentation-asyncpg` | | mysql-connector-python | `instrument_mysql()` | `opentelemetry-instrumentation-mysql` | | redis-py | `instrument_redis()` | `opentelemetry-instrumentation-redis` | | PyMongo | `instrument_pymongo()` | `opentelemetry-instrumentation-pymongo` | | botocore (AWS SDK) | `instrument_botocore()` | `opentelemetry-instrumentation-botocore` | To get started, first install the required packages for the libraries you want to instrument. For example, to instrument `httpx` and `sqlalchemy`: ```shell pip theme={null} pip install opentelemetry-instrumentation-httpx opentelemetry-instrumentation-sqlalchemy ``` ```shell uv theme={null} uv add opentelemetry-instrumentation-httpx opentelemetry-instrumentation-sqlalchemy ``` ```shell poetry theme={null} poetry add opentelemetry-instrumentation-httpx opentelemetry-instrumentation-sqlalchemy ``` Then call the instrumentation functions at application startup. Some functions accept an optional client, connection or engine argument to instrument a specific instance instead of all instances globally. ```python theme={null} from apitally.otel import instrument_httpx, instrument_sqlalchemy instrument_httpx() instrument_sqlalchemy(engine) ``` ## Create custom spans For custom operations that aren't covered by library instrumentation, you can create spans manually using the helpers provided by the SDK. These are thin wrappers around the standard OpenTelemetry API, which you can also use directly. ### `@instrument` decorator Use the `@instrument` decorator to automatically create a span for a function. It works with both sync and async functions: ```python theme={null} from apitally.otel import instrument @instrument def process_order(order_id: int) -> None: ... ``` ### `span()` context manager Use the `span()` context manager to trace code blocks within a function: ```python theme={null} from apitally.otel import span def checkout(cart_id: int) -> None: with span("validate_cart") as s: s.set_attribute("cart_id", cart_id) # Validation logic here ... with span("process_payment"): # Payment logic here ... ``` # Overview Source: https://docs.apitally.io/setup-guides Get started with Apitally in less than 5 minutes. Choose your framework from the options below for a detailed setup guide. } href="/setup-guides/blacksheep" /> } href="/setup-guides/django-ninja" /> } href="/setup-guides/django-rest-framework" /> } href="/setup-guides/fastapi" /> } href="/setup-guides/flask" /> } href="/setup-guides/litestar" /> } href="/setup-guides/starlette" /> } href="/setup-guides/adonisjs" /> } href="/setup-guides/elysia" /> } href="/setup-guides/express" /> } href="/setup-guides/fastify" /> } href="/setup-guides/h3" /> } href="/setup-guides/hapi" /> } href="/setup-guides/hono" /> } href="/setup-guides/koa" /> } href="/setup-guides/nestjs" /> } href="/setup-guides/chi" /> } href="/setup-guides/echo" /> } href="/setup-guides/fiber" /> } href="/setup-guides/gin" /> } href="/setup-guides/spring-boot" /> } href="/setup-guides/aspnet-core" /> } href="/setup-guides/fastapi-cloudflare-workers" > Cloudflare Workers } href="/setup-guides/hono-cloudflare-workers" > Cloudflare Workers If your framework is not listed here, please [let us know](/support) and we'll consider adding support for it. # Setup guide for AdonisJS Source: https://docs.apitally.io/setup-guides/adonisjs Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [AdonisJS](https://adonisjs.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Install the [Apitally SDK](/sdk-reference/javascript/overview) in your AdonisJS project. ```shell theme={null} npm install apitally ``` Then configure Apitally by running the below Ace command. You'll be prompted to enter the client ID for your app. You'll find it on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```shell theme={null} node ace configure apitally/adonisjs ``` This command will automatically: * Create a config file at `config/apitally.ts` * Register the Apitally provider in `adonisrc.ts` * Add the Apitally middleware to `start/kernel.ts` * Add environment variables to `.env` and `start/env.ts` Finally, to capture validation and server errors, modify your exception handler in `app/exceptions/handler.ts`: ```javascript {2,6} theme={null} import { ExceptionHandler, HttpContext } from '@adonisjs/core/http' import { captureError } from 'apitally/adonisjs' export default class HttpExceptionHandler extends ExceptionHandler { async report(error: unknown, ctx: HttpContext) { captureError(error, ctx) return super.report(error, ctx) } } ```
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard.
## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in a [custom middleware](https://docs.adonisjs.com/guides/basics/middleware#creating-middleware). ```javascript Identifier only theme={null} import { HttpContext } from '@adonisjs/core/http' import { NextFn } from '@adonisjs/core/types/http' import { setConsumer } from 'apitally/adonisjs' export default class ApitallyConsumerMiddleware { async handle(ctx: HttpContext, next: NextFn) { if (ctx.auth.isAuthenticated) { setConsumer(ctx, ctx.auth.user!.email) } await next() } } ``` ```javascript With name and group theme={null} import { HttpContext } from '@adonisjs/core/http' import { NextFn } from '@adonisjs/core/types/http' import { setConsumer } from 'apitally/adonisjs' export default class ApitallyConsumerMiddleware { async handle(ctx: HttpContext, next: NextFn) { if (ctx.auth.isAuthenticated) { setConsumer(ctx, { identifier: String(ctx.auth.user!.id), name: ctx.auth.user!.fullName, // optional group: ctx.auth.user!.organization, // optional }) } await next() } } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import { defineConfig } from 'apitally/adonisjs' const apitallyConfig = defineConfig({ clientId: 'your-client-id', env: 'dev', // or 'prod' etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }) export default apitallyConfig; ``` ```javascript Advanced example theme={null} import { defineConfig } from 'apitally/adonisjs' const apitallyConfig = defineConfig({ clientId: 'your-client-id', env: 'dev', // or 'prod' etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.url?.startsWith('/admin/') ? null : request.body, maskResponseBodyCallback: (request, response) => request.url?.startsWith('/admin/') ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === 'some-consumer', }, }) export default apitallyConfig; ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for ASP.NET Core Source: https://docs.apitally.io/setup-guides/aspnet-core Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [ASP.NET Core](https://dotnet.microsoft.com/en-us/apps/aspnet) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/dotnet/overview) in your project: ```shell theme={null} dotnet add package Apitally ``` Register the required services and middleware for Apitally in your `Program.cs` file and provide the `ClientId` for your app. You'll find the `ClientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. You can also configure Apitally in your `appsettings.json` file, if you prefer. ```csharp Program.cs theme={null} using Apitally; var builder = WebApplication.CreateBuilder(args); builder.Services.AddApitally(options => { options.ClientId = "your-client-id"; options.Env = "dev"; // or "prod" etc. }); var app = builder.Build(); app.UseApitally(); // ... rest of your middleware configuration ``` ```json appsettings.json theme={null} { "Apitally": { "ClientId": "your-client-id", "Env": "dev" } } ``` Add the Apitally middleware before any other middleware to ensure it wraps the entire stack. Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, set the `ApitallyConsumer` item in the request context. You can do this in middleware, for example: ```csharp Identifier only theme={null} app.Use(async (context, next) => { if (context.User.Identity.IsAuthenticated) { context.Items["ApitallyConsumer"] = context.User.Identity.Name; } await next(); }); ``` ```csharp With name and group theme={null} using Apitally; using System.Security.Claims; app.Use(async (context, next) => { if (context.User.Identity.IsAuthenticated) { context.Items["ApitallyConsumer"] = new ApitallyConsumer { Identifier = context.User.Identity.Name, Name = context.User.FindFirst(ClaimTypes.Name)?.Value, Group = context.User.FindFirst(ClaimTypes.Role)?.Value, }; } await next(); }); ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. Check out the SDK reference to learn more about the request logging configuration options. ```json Basic example theme={null} { "Apitally": { "ClientId": "your-client-id", "Env": "dev", "RequestLogging": { "Enabled": true, "IncludeRequestHeaders": true, "IncludeRequestBody": true, "IncludeResponseBody": true, "CaptureLogs": true, "CaptureTraces": false // requires instrumentation } } } ``` ```json Advanced example theme={null} { "Apitally": { "ClientId": "your-client-id", "Env": "dev", "RequestLogging": { "Enabled": true, "IncludeQueryParams": true, "IncludeRequestHeaders": true, "IncludeRequestBody": true, "IncludeResponseHeaders": true, "IncludeResponseBody": true, "IncludeException": true, "CaptureLogs": true, "CaptureTraces": false // requires instrumentation, // Mask query parameters using regex "QueryParamMaskPatterns": [ "^card_number$" ], // Mask headers using regex "HeaderMaskPatterns": [ "^X-Sensitive-Header$" ], // Mask request/response body fields using regex "BodyFieldMaskPatterns": [ "^sensitive_field$" ], // Exclude paths from request logging using regex (common health check paths are excluded by default) "PathExcludePatterns": [ "/metrics$" ] } } } ``` ```csharp Callbacks example theme={null} builder.Services.PostConfigure(options => { // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body options.RequestLogging.MaskRequestBody = request => request.Path.StartsWith("/admin/") ? null : request.Body; options.RequestLogging.MaskResponseBody = (request, response) => request.Path.StartsWith("/admin/") ? null : response.Body; // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request options.RequestLogging.ShouldExclude = (request, response) => request.Consumer == "some-consumer"; }); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `CaptureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/dotnet/tracing) for further instructions. # Setup guide for BlackSheep Source: https://docs.apitally.io/setup-guides/blacksheep Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [BlackSheep](https://www.neoteroi.dev/blacksheep/) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/python/overview) in your project with the extra. ```shell pip theme={null} pip install "apitally[blacksheep]" ``` ```shell poetry theme={null} poetry add "apitally[blacksheep]" ``` ```shell uv theme={null} uv add "apitally[blacksheep]" ``` Add the Apitally middleware to your BlackSheep application and provide the `client_id` for your app. You'll find the `client_id` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```python theme={null} from blacksheep import Application from apitally.blacksheep import use_apitally app = Application() use_apitally( app, client_id="your-client-id", env="dev", # or "prod" etc. ) ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, provide a callback function that takes a [`Request`](https://www.neoteroi.dev/blacksheep/requests/#the-request-class) object as an argument and returns a consumer identifier, an `ApitallyConsumer` object or `None`. Alternatively, you can set the `apitally_consumer` claim on the `request.identity` object, for example in your authentication handler. ```python Callback theme={null} from blacksheep import Application, Request from apitally.blacksheep import use_apitally def get_consumer(request: Request) -> str | None: if request.identity.is_authenticated: return request.identity.sub return None app = Application() use_apitally( app, client_id="your-client-id", env="dev", # or "prod" etc. consumer_callback=get_consumer, ) ``` ```python Callback (with name and group) theme={null} from blacksheep import Application, Request from apitally.blacksheep import use_apitally, ApitallyConsumer def get_consumer(request: Request) -> ApitallyConsumer | None: if request.identity.is_authenticated: return ApitallyConsumer( identifier=request.identity.sub, name=request.identity.get("name"), # optional group=request.identity.get("role"), # optional ) return None app = Application() use_apitally( app, client_id="your-client-id", env="dev", # or "prod" etc. consumer_callback=get_consumer, ) ``` ```python Claim on identity theme={null} from blacksheep import Request from guardpost import AuthenticationHandler, Identity class ExampleAuthHandler(AuthenticationHandler): async def authenticate(self, context: Request) -> Identity | None: header_value = context.get_first_header(b"Authorization") if header_value: claims = { "name": "John Doe", "email": "john.doe@example.com", "apitally_consumer": "john.doe@example.com", } context.identity = Identity(claims, "MOCK") return context.identity else: context.identity = None return context.identity ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```python Basic example theme={null} from blacksheep import Application from apitally.blacksheep import use_apitally app = Application() use_apitally( app, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_request_headers=True, log_request_body=True, log_response_body=True, capture_logs=True, capture_traces=False, # requires instrumentation ) ``` ```python Advanced example theme={null} from blacksheep import Application from apitally.blacksheep import use_apitally app = Application() use_apitally( app, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_query_params=True, log_request_headers=True, log_request_body=True, log_response_headers=True, log_response_body=True, log_exception=True, capture_logs=True, capture_traces=False, # requires instrumentation # Mask query parameters using regex mask_query_params=[r"^card_number$"], # Mask headers using regex mask_headers=[r"^X-Sensitive-Header$"], # Mask request/response body fields using regex mask_body_fields=[r"^sensitive_field$"], # Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) # The callback should return None to mask the whole body, or return the (modified) raw body mask_request_body_callback=lambda request: None if request["path"].startswith("/admin/") else request["body"], mask_response_body_callback=lambda request, response: None if request["path"].startswith("/admin/") else response["body"], # Exclude paths from request logging using regex (common health check paths are excluded by default) exclude_paths=[r"/metrics$"], # Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) # The callback should return True to exclude the request exclude_callback=lambda request, response: request["consumer"] == "some-consumer", ) ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `capture_traces` to `True` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/python/tracing) for further instructions. # Setup guide for Chi Source: https://docs.apitally.io/setup-guides/chi Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Chi](https://go-chi.io) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Add the [Apitally SDK](/sdk-reference/go/overview) to the dependencies in your Chi project. ```shell theme={null} go get github.com/apitally/apitally-go/chi-v5 ``` Add the Apitally middleware to your Chi application and provide the `ClientId` for your app. You'll find the `ClientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```go theme={null} package main import ( apitally "github.com/apitally/apitally-go/chi-v5" "github.com/go-chi/chi/v5" ) func main() { r := chi.NewRouter() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, use the `SetConsumerIdentifier` or `SetConsumer` function, for example in a middleware. ```go {8} Identifier only theme={null} func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Your authentication logic here // ... if user.IsAuthenticated() { // Use the authenticated identity as consumer identifier apitally.SetConsumerIdentifier(r, user.Identifier) } next.ServeHTTP(w, r) }) } ``` ```go {7-11} With name and group theme={null} func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Your authentication logic here // ... if user.IsAuthenticated() { apitally.SetConsumer(r, apitally.Consumer{ Identifier: user.Email, Name: user.Name, // optional Group: user.Group, // optional }) } next.ServeHTTP(w, r) }) } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Capture validation errors If you're using the `go-playground/validator/v10` package to validate incoming data, you can use the `CaptureValidationError` function to record validation errors. This gives you visibility into the validation errors returned by your API endpoints. ```go {29} theme={null} package main import ( "encoding/json" "net/http" apitally "github.com/apitally/apitally-go/chi-v5" "github.com/go-chi/chi/v5" "github.com/go-playground/validator/v10" ) type HelloRequest struct { Name string `json:"name" validate:"required"` } func main() { r := chi.NewRouter() validate := validator.New() // ... r.Post("/hello", func(w http.ResponseWriter, r *http.Request) { var req HelloRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if err := validate.Struct(req); err != nil { apitally.CaptureValidationError(r, err) http.Error(w, err.Error(), http.StatusBadRequest) return } json.NewEncoder(w).Encode(map[string]string{"message": "Hello, " + req.Name + "!"}) }) // ... } ``` ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```go Basic example theme={null} package main import ( apitally "github.com/apitally/apitally-go/chi-v5" "github.com/go-chi/chi/v5" ) func main() { r := chi.NewRouter() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ``` ```go Advanced example theme={null} package main import ( "regexp" "strings" apitally "github.com/apitally/apitally-go/chi-v5" "github.com/go-chi/chi/v5" ) func main() { r := chi.NewRouter() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogQueryParams = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseHeaders = true config.RequestLogging.LogResponseBody = true config.RequestLogging.LogPanic = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation // Mask query parameters using regex config.RequestLogging.MaskQueryParams = []*regexp.Regexp{regexp.MustCompile(`^card_number$`)} // Mask headers using regex config.RequestLogging.MaskHeaders = []*regexp.Regexp{regexp.MustCompile(`^X-Sensitive-Header$`)} // Mask request/response body fields using regex config.RequestLogging.MaskBodyFields = []*regexp.Regexp{regexp.MustCompile(`^sensitive_field$`)} // Exclude paths from request logging using regex (common health check paths are excluded by default) config.RequestLogging.ExcludePaths = []*regexp.Regexp{regexp.MustCompile(`/metrics$`)} // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return nil to mask the whole body, or return the (modified) raw body config.RequestLogging.MaskRequestBodyCallback = func(request *apitally.Request) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return request.Body } config.RequestLogging.MaskResponseBodyCallback = func(request *apitally.Request, response *apitally.Response) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return response.Body } // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request config.RequestLogging.ExcludeCallback = func(request *apitally.Request, response *apitally.Response) bool { return request.Consumer == "some-consumer" } r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `CaptureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/go/tracing) for further instructions. # Setup guide for Django Ninja Source: https://docs.apitally.io/setup-guides/django-ninja Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Django Ninja](https://django-ninja.dev) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/python/overview) in your project with the extra. ```shell pip theme={null} pip install "apitally[django_ninja]" ``` ```shell poetry theme={null} poetry add "apitally[django_ninja]" ``` ```shell uv theme={null} uv add "apitally[django_ninja]" ``` Activate the Apitally middleware in your Django application by appending it to the end of the [`MIDDLEWARE`](https://docs.djangoproject.com/en/4.2/topics/http/middleware/#activating-middleware) list in your Django settings. Then configure the Apitally middleware by adding `APITALLY_MIDDLEWARE` to your settings file and including the `client_id` for your app. You'll find the `client_id` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```python theme={null} MIDDLEWARE = [ "apitally.django.ApitallyMiddleware", # Other middleware ... ] APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "include_django_views": False, # Set to True to include regular Django views } ```
If you're using Gunicorn or uWSGI to serve your app in production, please review the [known issues](#known-issues) section below.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, provide a callback function in the middleware settings that takes a [`HttpRequest`](https://docs.djangoproject.com/en/4.2/ref/request-response/#httprequest-objects) object as an argument and returns a consumer identifier, an `ApitallyConsumer` object or `None`. ```python Callback theme={null} from django.http import HttpRequest def identify_consumer(request: HttpRequest) -> str | None: if request.user.is_authenticated: return request.user.username return None ``` ```python Callback (with name and group) theme={null} from django.http import HttpRequest from apitally.django import ApitallyConsumer def identify_consumer(request: HttpRequest) -> ApitallyConsumer | None: if request.user.is_authenticated: return ApitallyConsumer( identifier=request.user.username, name=f"{request.user.first_name} {request.user.last_name}", group=request.user.groups.first().name, ) return None ``` ```python Middleware settings theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "consumer_callback": "your_project.api.utils.identify_consumer", } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```python Basic example theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "enable_request_logging": True, "log_request_headers": True, "log_request_body": True, "log_response_body": True, "capture_logs": True, "capture_traces": False, # requires instrumentation } ``` ```python Advanced example theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "enable_request_logging": True, "log_query_params": True, "log_request_headers": True, "log_request_body": True, "log_response_headers": True, "log_response_body": True, "log_exception": True, "capture_logs": True, "capture_traces": False, # requires instrumentation # Mask query parameters using regex "mask_query_params": [r"^card_number$"], # Mask headers using regex "mask_headers": [r"^X-Sensitive-Header$"], # Mask request/response body fields using regex "mask_body_fields": [r"^sensitive_field$"], # Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) # The callback should return None to mask the whole body, or return the (modified) raw body "mask_request_body_callback": lambda request: None if request["path"].startswith("/admin/") else request["body"], "mask_response_body_callback": lambda request, response: None if request["path"].startswith("/admin/") else response["body"], # Exclude paths from request logging using regex (common health check paths are excluded by default) "exclude_paths": [r"/metrics$"], # Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) # The callback should return True to exclude the request "exclude_callback": lambda request, response: request["consumer"] == "some-consumer", } ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `capture_traces` to `True` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/python/tracing) for further instructions. ## Known issues * When running Django with Gunicorn, the option `preload_app` must be set to `False`. Otherwise, the Apitally client will not work correctly. * When running Django with uWSGI, the options `--enable-threads` and `--lazy-apps` must be set. Otherwise, the Apitally client will not work correctly. # Setup guide for Django REST Framework Source: https://docs.apitally.io/setup-guides/django-rest-framework Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Django REST Framework](https://www.django-rest-framework.org) (DRF) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/python/overview) in your project with the extra. ```shell pip theme={null} pip install "apitally[django_rest_framework]" ``` ```shell poetry theme={null} poetry add "apitally[django_rest_framework]" ``` ```shell uv theme={null} uv add "apitally[django_rest_framework]" ``` Activate the Apitally middleware in your Django application by appending it to the end of the [`MIDDLEWARE`](https://docs.djangoproject.com/en/4.2/topics/http/middleware/#activating-middleware) list in your Django settings. Then configure the Apitally middleware by adding `APITALLY_MIDDLEWARE` to your settings file and including the `client_id` for your app. You'll find the `client_id` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```python theme={null} MIDDLEWARE = [ "apitally.django.ApitallyMiddleware", # Other middleware ... ] APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "include_django_views": False, # Set to True to include regular Django views } ```
If you're using Gunicorn or uWSGI to serve your app in production, please review the [known issues](#known-issues) section below.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, provide a callback function in the middleware settings that takes a [`HttpRequest`](https://docs.djangoproject.com/en/4.2/ref/request-response/#httprequest-objects) object as an argument and returns a consumer identifier, an `ApitallyConsumer` object or `None`. ```python Callback theme={null} from django.http import HttpRequest def identify_consumer(request: HttpRequest) -> str | None: if request.user.is_authenticated: return request.user.username return None ``` ```python Callback (with name and group) theme={null} from django.http import HttpRequest from apitally.django import ApitallyConsumer def identify_consumer(request: HttpRequest) -> ApitallyConsumer | None: if request.user.is_authenticated: return ApitallyConsumer( identifier=request.user.username, name=f"{request.user.first_name} {request.user.last_name}", group=request.user.groups.first().name, ) return None ``` ```python Middleware settings theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "consumer_callback": "your_project.api.utils.identify_consumer", } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```python Basic example theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "enable_request_logging": True, "log_request_headers": True, "log_request_body": True, "log_response_body": True, "capture_logs": True, "capture_traces": False, # requires instrumentation } ``` ```python Advanced example theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "enable_request_logging": True, "log_query_params": True, "log_request_headers": True, "log_request_body": True, "log_response_headers": True, "log_response_body": True, "log_exception": True, "capture_logs": True, "capture_traces": False, # requires instrumentation # Mask query parameters using regex "mask_query_params": [r"^card_number$"], # Mask headers using regex "mask_headers": [r"^X-Sensitive-Header$"], # Mask request/response body fields using regex "mask_body_fields": [r"^sensitive_field$"], # Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) # The callback should return None to mask the whole body, or return the (modified) raw body "mask_request_body_callback": lambda request: None if request["path"].startswith("/admin/") else request["body"], "mask_response_body_callback": lambda request, response: None if request["path"].startswith("/admin/") else response["body"], # Exclude paths from request logging using regex (common health check paths are excluded by default) "exclude_paths": [r"/metrics$"], # Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) # The callback should return True to exclude the request "exclude_callback": lambda request, response: request["consumer"] == "some-consumer", } ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Advanced settings * By default, only DRF endpoints are included in Apitally. To also include regular Django views you can set `include_django_views` to `True`. Useful if your API includes endpoints not implemented using DRF. * To limit Apitally to specific parts of a large monolithic application, set the `urlconfs` parameter to a list of Django URL configuration modules you'd like to include. ```python theme={null} APITALLY_MIDDLEWARE = { "client_id": "your-client-id", "env": "dev", # or "prod" etc. "include_django_views": True, "urlconfs": ["your_project.api.urls"], } ``` ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `capture_traces` to `True` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/python/tracing) for further instructions. ## Known issues * When running Django with Gunicorn, the option `preload_app` must be set to `False`. Otherwise, the Apitally client will not work correctly. * When running Django with uWSGI, the options `--enable-threads` and `--lazy-apps` must be set. Otherwise, the Apitally client will not work correctly. # Setup guide for Echo Source: https://docs.apitally.io/setup-guides/echo Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Echo](https://echo.labstack.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Add the [Apitally SDK](/sdk-reference/go/overview) to the dependencies in your Echo project. ```shell v5 theme={null} go get github.com/apitally/apitally-go/echo-v5 ``` ```shell v4 theme={null} go get github.com/apitally/apitally-go/echo-v4 ``` Add the Apitally middleware to your Echo application and provide the `ClientId` for your app. You'll find the `ClientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```go v5 theme={null} package main import ( apitally "github.com/apitally/apitally-go/echo-v5" "github.com/labstack/echo/v5" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. e.Use(apitally.Middleware(e, config)) // ... rest of your code ... } ``` ```go v4 theme={null} package main import ( apitally "github.com/apitally/apitally-go/echo-v4" "github.com/labstack/echo/v4" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. e.Use(apitally.Middleware(e, config)) // ... rest of your code ... } ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, use the `SetConsumerIdentifier` or `SetConsumer` function, for example in a middleware. ```go {8} Identifier only theme={null} func authMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { // Your authentication logic here // ... if user.IsAuthenticated() { // Use the authenticated identity as consumer identifier apitally.SetConsumerIdentifier(c, user.Identifier) } return next(c) } } ``` ```go {7-11} With name and group theme={null} func authMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { // Your authentication logic here // ... if user.IsAuthenticated() { apitally.SetConsumer(c, apitally.Consumer{ Identifier: user.Email, Name: user.Name, // optional Group: user.Group, // optional }) } return next(c) } } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Capture validation errors If you're using the `go-playground/validator/v10` package to validate incoming data, you can use the `CaptureValidationError` function to record validation errors. This gives you visibility into the validation errors returned by your API endpoints. ```go {25} theme={null} package main import ( apitally "github.com/apitally/apitally-go/echo-v5" "github.com/labstack/echo/v5" "github.com/go-playground/validator/v10" ) type HelloRequest struct { Name string `json:"name" validate:"required"` } func main() { e := echo.New() validate := validator.New() // ... e.POST("/hello", func(c *echo.Context) error { var req HelloRequest if err := c.Bind(&req); err != nil { return c.JSON(400, map[string]string{"error": err.Error()}) } if err := validate.Struct(req); err != nil { apitally.CaptureValidationError(c, err) return c.JSON(400, map[string]string{"error": err.Error()}) } return c.JSON(200, map[string]string{"message": "Hello, " + req.Name + "!"}) }) // ... } ``` ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```go Basic example theme={null} package main import ( apitally "github.com/apitally/apitally-go/echo-v5" "github.com/labstack/echo/v5" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation e.Use(apitally.Middleware(e, config)) // ... rest of your code ... } ``` ```go Advanced example theme={null} package main import ( "regexp" "strings" apitally "github.com/apitally/apitally-go/echo-v5" "github.com/labstack/echo/v5" ) func main() { e := echo.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogQueryParams = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseHeaders = true config.RequestLogging.LogResponseBody = true config.RequestLogging.LogPanic = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation // Mask query parameters using regex config.RequestLogging.MaskQueryParams = []*regexp.Regexp{regexp.MustCompile(`^card_number$`)} // Mask headers using regex config.RequestLogging.MaskHeaders = []*regexp.Regexp{regexp.MustCompile(`^X-Sensitive-Header$`)} // Mask request/response body fields using regex config.RequestLogging.MaskBodyFields = []*regexp.Regexp{regexp.MustCompile(`^sensitive_field$`)} // Exclude paths from request logging using regex (common health check paths are excluded by default) config.RequestLogging.ExcludePaths = []*regexp.Regexp{regexp.MustCompile(`/metrics$`)} // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return nil to mask the whole body, or return the (modified) raw body config.RequestLogging.MaskRequestBodyCallback = func(request *apitally.Request) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return request.Body } config.RequestLogging.MaskResponseBodyCallback = func(request *apitally.Request, response *apitally.Response) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return response.Body } // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request config.RequestLogging.ExcludeCallback = func(request *apitally.Request, response *apitally.Response) bool { return request.Consumer == "some-consumer" } e.Use(apitally.Middleware(e, config)) // ... rest of your code ... } ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `CaptureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/go/tracing) for further instructions. # Setup guide for Elysia Source: https://docs.apitally.io/setup-guides/elysia Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Elysia](https://elysiajs.com/) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/javascript/overview) in your Elysia project. ```shell theme={null} bun add apitally ``` Add the Apitally plugin to your Elysia application and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript theme={null} import { Elysia } from "elysia"; import { apitallyPlugin } from "apitally/elysia"; const app = new Elysia() .use( apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. }), ) .get("/", () => "hello"); ``` Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Set the `apitally.consumer` property to associate requests with consumers, for example in a `derive` lifecycle function. ```javascript Identifier only theme={null} app.derive(async ({ apitally, jwt, cookie: { auth } }) => { const profile = await jwt.verify(auth); apitally.consumer = profile.name; }); ``` ```javascript With name and group theme={null} app.derive(async ({ apitally, jwt, cookie: { auth } }) => { const profile = await jwt.verify(auth); apitally.consumer = { identifier: profile.id, name: profile.name, group: profile.role, }; }); ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import { Elysia } from "elysia"; import { apitallyPlugin } from "apitally/elysia"; const app = new Elysia() .use( apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }), ) .get("/", () => "hello"); ``` ```javascript Advanced example theme={null} import { Elysia } from "elysia"; import { apitallyPlugin } from "apitally/elysia"; const app = new Elysia() .use( apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }), ) .get("/", () => "hello"); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for Express Source: https://docs.apitally.io/setup-guides/express Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Express](https://expressjs.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/javascript/overview) in your Express project. ```shell npm theme={null} npm install apitally ``` ```shell yarn theme={null} yarn add apitally ``` Add the Apitally middleware to your Express application using the `useApitally` function and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript ESM theme={null} import express from "express"; import { useApitally } from "apitally/express"; const app = express(); app.use(express.json()); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); ``` ```javascript CommonJS theme={null} const express = require("express"); const { useApitally } = require("apitally/express"); const app = express(); app.use(express.json()); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in a middleware. ```javascript Identifier only theme={null} import { setConsumer } from "apitally/express"; app.use(function (req, res, next) { if (req.user) { setConsumer(req, req.user.username); } next() }) ``` ```javascript With name and group theme={null} import { setConsumer } from "apitally/express"; app.use(function (req, res, next) { if (req.user) { setConsumer(req, { identifier: req.user.username, name: `${req.user.first_name} ${req.user.last_name}`, // optional group: req.user.group, // optional }); } next() }) ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Capture server errors The Apitally SDK installs an error handler that captures server error details automatically. It is added to the bottom of the middleware stack. However, if your application already has custom error handlers that return a response and don't call `next(err)`, you need to add the following line of code for Apitally to capture server error details. ```javascript {2} theme={null} app.use(function (err, req, res, next) { res.locals.serverError = err; // Your custom error handling logic ... }); ``` ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import express from "express"; import { useApitally } from "apitally/express"; const app = express(); app.use(express.json()); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }); ``` ```javascript Advanced example theme={null} import express from "express"; import { useApitally } from "apitally/express"; const app = express(); app.use(express.json()); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. ## Known issues * `@sentry/node` v7 is incompatible with Apitally. It's instrumentation logic erases metadata on Express routers that Apitally requires. To resolve this, please upgrade `@sentry/node` to v8. # Setup guide for FastAPI Source: https://docs.apitally.io/setup-guides/fastapi Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [FastAPI](https://fastapi.tiangolo.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts Running FastAPI on Cloudflare Workers? Follow [this setup guide](/setup-guides/fastapi-cloudflare-workers) instead. ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/python/overview) in your project with the extra. ```shell pip theme={null} pip install "apitally[fastapi]" ``` ```shell poetry theme={null} poetry add "apitally[fastapi]" ``` ```shell uv theme={null} uv add "apitally[fastapi]" ``` Add the Apitally middleware to your FastAPI application and provide the `client_id` for your app. You'll find the `client_id` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```python theme={null} from fastapi import FastAPI from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", # or "prod" etc. ) ```
If you're also using other middlewares, add the `ApitallyMiddleware` last, so that it wraps the existing stack of middlewares.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `set_consumer` function to associate requests with consumers, for example in a dependency, middleware or directly in your endpoint functions. ```python Dependency theme={null} from typing import Annotated from fastapi import FastAPI, Depends, Request from apitally.fastapi import set_consumer def identify_consumer(request: Request, current_user: Annotated[User, Depends(get_current_user)]) -> None: set_consumer( request, identifier=current_user.user_id, name=current_user.name, # optional group=current_user.group, # optional ) app = FastAPI(dependencies=[Depends(identify_consumer)]) ``` ```python Endpoint function theme={null} from typing import Annotated from fastapi import FastAPI, Depends, Request from apitally.fastapi import set_consumer app = FastAPI() @app.get("/items") async def list_items(request: Request, current_user: Annotated[User, Depends(get_current_user)]) -> list[str]: set_consumer( request, identifier=current_user.user_id, name=current_user.name, # optional group=current_user.group, # optional ) return ["item1"] ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```python Basic example theme={null} from fastapi import FastAPI from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_request_headers=True, log_request_body=True, log_response_body=True, capture_logs=True, capture_traces=False, # requires instrumentation ) ``` ```python Advanced example theme={null} from fastapi import FastAPI from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_query_params=True, log_request_headers=True, log_request_body=True, log_response_headers=True, log_response_body=True, log_exception=True, capture_logs=True, capture_traces=False, # requires instrumentation # Mask query parameters using regex mask_query_params=[r"^card_number$"], # Mask headers using regex mask_headers=[r"^X-Sensitive-Header$"], # Mask request/response body fields using regex mask_body_fields=[r"^sensitive_field$"], # Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) # The callback should return None to mask the whole body, or return the (modified) raw body mask_request_body_callback=lambda request: None if request["path"].startswith("/admin/") else request["body"], mask_response_body_callback=lambda request, response: None if request["path"].startswith("/admin/") else response["body"], # Exclude paths from request logging using regex (common health check paths are excluded by default) exclude_paths=[r"/metrics$"], # Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) # The callback should return True to exclude the request exclude_callback=lambda request, response: request["consumer"] == "some-consumer", ) ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `capture_traces` to `True` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/python/tracing) for further instructions. # Setup guide for FastAPI on Cloudflare Workers Source: https://docs.apitally.io/setup-guides/fastapi-cloudflare-workers Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [FastAPI](https://fastapi.tiangolo.com) application running on [Cloudflare Workers](https://developers.cloudflare.com/workers/languages/python/) to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Create Logpush job Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and navigate to *Analytics & Logs > Logpush*. Create a [Logpush](https://developers.cloudflare.com/workers/observability/logs/logpush/) job with the following settings: | Setting | Value | | ---------------------------- | ------------------------------------------------------------------------------------------------ | | Destination | HTTP destination | | HTTP endpoint | `https://hub.apitally.io/v2/{client-id}/{env}/logpush` | | Dataset | Workers trace events | | If logs match... | Filtered logs:
EventType equals `fetch` and
ScriptName equals `{your-worker-name}` | | Send the following fields... | General:
Event, EventTimestampMs, Logs | In the HTTP endpoint, replace `{client-id}` with your app's client ID and `{env}` with the environment (e.g. `prod` or `dev`). In the filter criteria, replace `{your-worker-name}` with the name of your Worker, as specified in your Wrangler config. ## Add middleware Next, install the [Apitally Serverless SDK](/sdk-reference/python-serverless/overview) in your project. ```shell theme={null} uv add apitally-serverless ``` Add the Apitally middleware to your FastAPI application. ```python theme={null} from fastapi import FastAPI from apitally_serverless.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware(ApitallyMiddleware) ```
If you're also using other middlewares, add the `ApitallyMiddleware` last, so that it wraps the existing stack of middlewares.
## Configure Worker Enable [Workers Logs](https://developers.cloudflare.com/workers/observability/logs/workers-logs/) and [Logpush](https://developers.cloudflare.com/workers/observability/logs/logpush/) in your Wrangler configuration file. ```toml wrangler.toml theme={null} logpush = true [observability] enabled = true head_sampling_rate = 1 [observability.logs] invocation_logs = true ``` ```json wrangler.json theme={null} { "logpush": true, "observability": { "enabled": true, "head_sampling_rate": 1, "logs": { "invocation_logs": true } } } ``` Then, deploy your application to Cloudflare Workers. ```shell theme={null} uv run pywrangler deploy ``` At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard after the first request is handled. It can take 2-3 minutes for requests to show up in Apitally due to how Cloudflare Logpush batches log data before sending it. Also note that Cloudflare Logpush doesn't include requests from local development environments, so you won't see them in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `set_consumer` function to associate requests with consumers, for example in a dependency, middleware or directly in your endpoint functions. ```python Dependency theme={null} from typing import Annotated from fastapi import FastAPI, Depends, Request from apitally_serverless.fastapi import set_consumer def identify_consumer(request: Request, current_user: Annotated[User, Depends(get_current_user)]) -> None: set_consumer( request, identifier=current_user.user_id, name=current_user.name, # optional group=current_user.group, # optional ) app = FastAPI(dependencies=[Depends(identify_consumer)]) ``` ```python Endpoint function theme={null} from typing import Annotated from fastapi import FastAPI, Depends, Request from apitally_serverless.fastapi import set_consumer app = FastAPI() @app.get("/items") async def list_items(request: Request, current_user: Annotated[User, Depends(get_current_user)]) -> list[str]: set_consumer( request, identifier=current_user.user_id, name=current_user.name, # optional group=current_user.group, # optional ) return ["item1"] ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging With the serverless SDK, request logging is enabled by default, however request headers and request/response bodies are not included unless explicitly enabled. The SDK automatically applies [default masking rules](/data-privacy#data-masking) for common sensitive headers and request/response body fields. You can configure additional masking rules and exclude certain requests from logging. ```python Basic example theme={null} from fastapi import FastAPI from apitally_serverless.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, log_request_headers=True, log_request_body=True, log_response_body=True, ) ``` ```python Advanced example theme={null} from fastapi import FastAPI from apitally_serverless.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware( ApitallyMiddleware, log_request_headers=True, log_request_body=True, log_response_headers=True, log_response_body=True, # Mask headers using regex mask_headers=[r"^X-Sensitive-Header$"], # Mask request/response body fields using regex mask_body_fields=[r"^sensitive_field$"], # Exclude paths from request logging using regex exclude_paths=[r"/health$", r"/metrics$"], ) ``` The *Request logs* dashboard now shows individual requests handled by your application, including headers and payloads, if enabled. You can filter, search, and inspect them in detail. # Setup guide for Fastify Source: https://docs.apitally.io/setup-guides/fastify Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Fastify](https://fastify.dev) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add plugin Next, install the [Apitally SDK](/sdk-reference/javascript/overview) and the [fastify-plugin](https://www.npmjs.com/package/fastify-plugin) package in your Fastify project. ```shell npm theme={null} npm install apitally fastify-plugin ``` ```shell yarn theme={null} yarn add apitally fastify-plugin ``` Register the Apitally plugin with your Fastify application and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript ESM theme={null} import Fastify from "fastify"; import { apitallyPlugin } from "apitally/fastify"; const fastify = Fastify({ logger: true }); await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); ``` ```javascript CommonJS theme={null} const fastify = require("fastify")({ logger: true }); const { apitallyPlugin } = require("apitally/fastify"); fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); // Wrap your routes in a plugin, so Apitally can detect them fastify.register((instance, opts, done) => { instance.get("/", (request, reply) => { reply.send("hello"); }); done(); }); ```
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard.
## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in an `onRequest` hook. ```javascript Identifier only theme={null} import { setConsumer } from "apitally/fastify"; fastify.addHook("onRequest", async (request, reply) => { try { await request.jwtVerify(); // Assuming @fastify/jwt is used for authentication setConsumer(request, request.user.name); } catch (err) { reply.send(err); } }); ``` ```javascript With name and group theme={null} import { setConsumer } from "apitally/fastify"; fastify.addHook("onRequest", async (request, reply) => { try { await request.jwtVerify(); // Assuming @fastify/jwt is used for authentication setConsumer(request, { identifier: request.user.id.toString(), name: request.user.name, // optional group: request.user.group, // optional }); } catch (err) { reply.send(err); } }); ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import Fastify from "fastify"; import { apitallyPlugin } from "apitally/fastify"; const fastify = Fastify({ logger: true }); await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }); ``` ```javascript Advanced example theme={null} import Fastify from "fastify"; import { apitallyPlugin } from "apitally/fastify"; const fastify = Fastify({ logger: true }); await fastify.register(apitallyPlugin, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for Fiber Source: https://docs.apitally.io/setup-guides/fiber Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Fiber](https://gofiber.io) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Add the [Apitally SDK](/sdk-reference/go/overview) to the dependencies in your Fiber project. ```shell v3 theme={null} go get github.com/apitally/apitally-go/fiber-v3 ``` ```shell v2 theme={null} go get github.com/apitally/apitally-go/fiber-v2 ``` Add the Apitally middleware to your Fiber application and provide the `ClientId` for your app. You'll find the `ClientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```go v3 theme={null} package main import ( apitally "github.com/apitally/apitally-go/fiber-v3" "github.com/gofiber/fiber/v3" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. app.Use(apitally.Middleware(app, config)) // ... rest of your code ... } ``` ```go v2 theme={null} package main import ( apitally "github.com/apitally/apitally-go/fiber-v2" "github.com/gofiber/fiber/v2" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. app.Use(apitally.Middleware(app, config)) // ... rest of your code ... } ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, use the `SetConsumerIdentifier` or `SetConsumer` function, for example in a middleware. ```go {7} Identifier only theme={null} func authMiddleware(c fiber.Ctx) error { // Your authentication logic here // ... if user.IsAuthenticated() { // Use the authenticated identity as consumer identifier apitally.SetConsumerIdentifier(c, user.Identifier) } return c.Next() } ``` ```go {6-10} With name and group theme={null} func authMiddleware(c fiber.Ctx) error { // Your authentication logic here // ... if user.IsAuthenticated() { apitally.SetConsumer(c, apitally.Consumer{ Identifier: user.Email, Name: user.Name, // optional Group: user.Group, // optional }) } return c.Next() } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Capture validation errors If you're using the `go-playground/validator/v10` package to validate incoming data, you can use the `CaptureValidationError` function to record validation errors. This gives you visibility into the validation errors returned by your API endpoints. ```go {23} theme={null} package main import ( apitally "github.com/apitally/apitally-go/fiber-v3" "github.com/gofiber/fiber/v3" "github.com/go-playground/validator/v10" ) type HelloRequest struct { Name string `json:"name" validate:"required"` } func main() { app := fiber.New() validate := validator.New() app.Post("/hello", func(c fiber.Ctx) error { var req HelloRequest if err := c.Bind().Body(&req); err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } if err := validate.Struct(req); err != nil { apitally.CaptureValidationError(c, err) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } return c.Status(fiber.StatusOK).JSON(fiber.Map{ "message": "Hello, " + req.Name + "!", }) }) // ... } ``` ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```go Basic example theme={null} package main import ( apitally "github.com/apitally/apitally-go/fiber-v3" "github.com/gofiber/fiber/v3" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation app.Use(apitally.Middleware(app, config)) // ... rest of your code ... } ``` ```go Advanced example theme={null} package main import ( "regexp" "strings" apitally "github.com/apitally/apitally-go/fiber-v3" "github.com/gofiber/fiber/v3" ) func main() { app := fiber.New() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogQueryParams = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseHeaders = true config.RequestLogging.LogResponseBody = true config.RequestLogging.LogPanic = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation // Mask query parameters using regex config.RequestLogging.MaskQueryParams = []*regexp.Regexp{regexp.MustCompile(`^card_number$`)} // Mask headers using regex config.RequestLogging.MaskHeaders = []*regexp.Regexp{regexp.MustCompile(`^X-Sensitive-Header$`)} // Mask request/response body fields using regex config.RequestLogging.MaskBodyFields = []*regexp.Regexp{regexp.MustCompile(`^sensitive_field$`)} // Exclude paths from request logging using regex (common health check paths are excluded by default) config.RequestLogging.ExcludePaths = []*regexp.Regexp{regexp.MustCompile(`/metrics$`)} // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return nil to mask the whole body, or return the (modified) raw body config.RequestLogging.MaskRequestBodyCallback = func(request *apitally.Request) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return request.Body } config.RequestLogging.MaskResponseBodyCallback = func(request *apitally.Request, response *apitally.Response) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return response.Body } // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request config.RequestLogging.ExcludeCallback = func(request *apitally.Request, response *apitally.Response) bool { return request.Consumer == "some-consumer" } app.Use(apitally.Middleware(app, config)) // ... rest of your code ... } ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `CaptureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/go/tracing) for further instructions. # Setup guide for Flask Source: https://docs.apitally.io/setup-guides/flask Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Flask](https://flask.palletsprojects.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/python/overview) in your project with the extra. ```shell pip theme={null} pip install "apitally[flask]" ``` ```shell poetry theme={null} poetry add "apitally[flask]" ``` ```shell uv theme={null} uv add "apitally[flask]" ``` Add the Apitally middleware to your Flask application and provide the `client_id` for your app. You'll find the `client_id` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```python theme={null} from flask import Flask from apitally.flask import ApitallyMiddleware app = Flask(__name__) app.wsgi_app = ApitallyMiddleware( app, client_id="your-client-id", env="dev", # or "prod" etc. ) ```
If you're also using other middlewares, add the `ApitallyMiddleware` last, so that it wraps the existing stack of middlewares.
If you're using Gunicorn or uWSGI to serve your app in production, please review the [known issues](#known-issues) section below. Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `set_consumer` function to associate requests with consumers, for example within a [`before_request`](https://flask.palletsprojects.com/en/2.2.x/api/#flask.Flask.before_request) function or directly in your endpoint functions. ```python Before request theme={null} from flask import g from apitally.flask import set_consumer @app.before_request def identify_consumer(): if g.current_user: set_consumer( identifier=g.current_user["email"], name=g.current_user["name"], # optional group=g.current_user["role"], # optional ) ``` ```python Endpoint function theme={null} from flask import g from apitally.flask import set_consumer @app.route("/items") def list_items(): if g.current_user: set_consumer( identifier=g.current_user["email"], name=g.current_user["name"], # optional group=g.current_user["role"], # optional ) return ["item1"] ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```python Basic example theme={null} from flask import Flask from apitally.flask import ApitallyMiddleware app = Flask(__name__) app.wsgi_app = ApitallyMiddleware( app, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_request_headers=True, log_request_body=True, log_response_body=True, capture_logs=True, capture_traces=False, # requires instrumentation ) ``` ```python Advanced example theme={null} from flask import Flask from apitally.flask import ApitallyMiddleware app = Flask(__name__) app.wsgi_app = ApitallyMiddleware( app, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_query_params=True, log_request_headers=True, log_request_body=True, log_response_headers=True, log_response_body=True, log_exception=True, capture_logs=True, capture_traces=False, # requires instrumentation # Mask query parameters using regex mask_query_params=[r"^card_number$"], # Mask headers using regex mask_headers=[r"^X-Sensitive-Header$"], # Mask request/response body fields using regex mask_body_fields=[r"^sensitive_field$"], # Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) # The callback should return None to mask the whole body, or return the (modified) raw body mask_request_body_callback=lambda request: None if request["path"].startswith("/admin/") else request["body"], mask_response_body_callback=lambda request, response: None if request["path"].startswith("/admin/") else response["body"], # Exclude paths from request logging using regex (common health check paths are excluded by default) exclude_paths=[r"/metrics$"], # Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) # The callback should return True to exclude the request exclude_callback=lambda request, response: request["consumer"] == "some-consumer", ) ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `capture_traces` to `True` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/python/tracing) for further instructions. ## Known issues * When running Flask with Gunicorn, the option `preload_app` must be set to `False`. Otherwise, the Apitally client will not work correctly. * When running Flask with uWSGI, the options `--enable-threads` and `--lazy-apps` must be set. Otherwise, the Apitally client will not work correctly. # Setup guide for Gin Source: https://docs.apitally.io/setup-guides/gin Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Gin](https://gin-gonic.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Add the [Apitally SDK](/sdk-reference/go/overview) to the dependencies in your Gin project. ```shell theme={null} go get github.com/apitally/apitally-go/gin ``` Add the Apitally middleware to your Gin application and provide the `ClientId` for your app. You'll find the `ClientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```go theme={null} package main import ( apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, use the `SetConsumerIdentifier` or `SetConsumer` function, for example in a middleware. ```go {8} Identifier only theme={null} func authMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Your authentication logic here // ... if user.IsAuthenticated() { // Use the authenticated identity as consumer identifier apitally.SetConsumerIdentifier(c, user.Identifier) } c.Next() } } ``` ```go {7-11} With name and group theme={null} func authMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Your authentication logic here // ... if user.IsAuthenticated() { apitally.SetConsumer(c, apitally.Consumer{ Identifier: user.Email, Name: user.Name, // optional Group: user.Group, // optional }) } c.Next() } } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Capture validation errors In order to get insights into validation errors returned by your API endpoints, you can capture them using the `CaptureValidationError` function. ```go {18} theme={null} package main import ( "net/http" apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // ... r.POST("/hello", func(c *gin.Context) { var req struct { Name string `json:"name" binding:"required"` } if err := c.BindJSON(&req); err != nil { apitally.CaptureValidationError(c, err) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "message": "Hello, " + req.Name + "!", }) }) // ... } ``` ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```go Basic example theme={null} package main import ( apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseBody = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ``` ```go Advanced example theme={null} package main import ( "regexp" "strings" apitally "github.com/apitally/apitally-go/gin" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() config := apitally.NewConfig("your-client-id") config.Env = "dev" // or "prod" etc. config.RequestLogging.Enabled = true config.RequestLogging.LogQueryParams = true config.RequestLogging.LogRequestHeaders = true config.RequestLogging.LogRequestBody = true config.RequestLogging.LogResponseHeaders = true config.RequestLogging.LogResponseBody = true config.RequestLogging.LogPanic = true config.RequestLogging.CaptureLogs = true config.RequestLogging.CaptureTraces = false // requires instrumentation // Mask query parameters using regex config.RequestLogging.MaskQueryParams = []*regexp.Regexp{regexp.MustCompile(`^card_number$`)} // Mask headers using regex config.RequestLogging.MaskHeaders = []*regexp.Regexp{regexp.MustCompile(`^X-Sensitive-Header$`)} // Mask request/response body fields using regex config.RequestLogging.MaskBodyFields = []*regexp.Regexp{regexp.MustCompile(`^sensitive_field$`)} // Exclude paths from request logging using regex (common health check paths are excluded by default) config.RequestLogging.ExcludePaths = []*regexp.Regexp{regexp.MustCompile(`/metrics$`)} // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return nil to mask the whole body, or return the (modified) raw body config.RequestLogging.MaskRequestBodyCallback = func(request *apitally.Request) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return request.Body } config.RequestLogging.MaskResponseBodyCallback = func(request *apitally.Request, response *apitally.Response) []byte { if strings.HasPrefix(request.Path, "/admin/") { return nil // Mask the whole body for admin endpoints } return response.Body } // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request config.RequestLogging.ExcludeCallback = func(request *apitally.Request, response *apitally.Response) bool { return request.Consumer == "some-consumer" } r.Use(apitally.Middleware(r, config)) // ... rest of your code ... } ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `CaptureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/go/tracing) for further instructions. # Setup guide for H3 v2 Source: https://docs.apitally.io/setup-guides/h3 Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [H3](https://h3.dev) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts Apitally only works with H3 v2 (currently in beta). ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add plugin Next, install the [Apitally SDK](/sdk-reference/javascript/overview) in your H3 project. ```shell npm theme={null} npm install apitally ``` ```shell yarn theme={null} yarn add apitally ``` Register the Apitally plugin with your H3 application and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript Using instance config theme={null} import { H3 } from "h3"; import { apitallyPlugin } from "apitally/h3"; const app = new H3({ plugins: [ apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. }), ], }); ``` ```javascript Register later theme={null} import { H3 } from "h3"; import { apitallyPlugin } from "apitally/h3"; const app = new H3(); app.register( apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. }) ); ``` Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in a middleware. ```javascript Identifier only theme={null} import { setConsumer } from "apitally/h3"; app.use((event) => { setConsumer(event, event.context.auth?.username); }); ``` ```javascript With name and group theme={null} import { setConsumer } from "apitally/h3"; app.use((event) => { setConsumer(event, { identifier: event.context.auth?.username, name: event.context.auth?.fullname, group: event.context.auth?.role, }); }); ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import { H3 } from "h3"; import { apitallyPlugin } from "apitally/h3"; const app = new H3({ plugins: [ apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }), ], }); ``` ```javascript Advanced example theme={null} import { H3 } from "h3"; import { apitallyPlugin } from "apitally/h3"; const app = new H3({ plugins: [ apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }), ], }); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for hapi Source: https://docs.apitally.io/setup-guides/hapi Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [hapi](https://hapi.dev) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Register plugin Next, install the [Apitally SDK](/sdk-reference/javascript/overview) in your hapi project. ```shell npm theme={null} npm install apitally ``` ```shell yarn theme={null} yarn add apitally ``` Register the Apitally plugin with your hapi application and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript ESM theme={null} import Hapi from "@hapi/hapi"; import { apitallyPlugin } from "apitally/hapi"; const init = async () => { const server = Hapi.server({ port: 3000, host: "localhost", }); await server.register({ plugin: apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. }), }); }; init(); ``` ```javascript CommonJS theme={null} const Hapi = require("@hapi/hapi"); const { apitallyPlugin } = require("apitally/hapi"); const init = async () => { const server = Hapi.server({ port: 3000, host: "localhost", }); await server.register({ plugin: apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. }), }); }; init(); ``` Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in an `onPostAuth` lifecycle method. ```javascript Identifier only theme={null} import { setConsumer } from "apitally/hapi"; server.ext("onPostAuth", (request, h) => { if (request.auth.isAuthenticated) { setConsumer(request, request.auth.credentials.user); } return h.continue; }); ``` ```javascript With name and group theme={null} import { setConsumer } from "apitally/hapi"; server.ext("onPostAuth", (request, h) => { if (request.auth.isAuthenticated) { const credentials = request.auth.credentials; setConsumer(request, { identifier: credentials.id, name: credentials.name, // optional group: credentials.group, // optional }); } return h.continue; }); ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import Hapi from "@hapi/hapi"; import { apitallyPlugin } from "apitally/hapi"; const init = async () => { const server = Hapi.server({ port: 3000, host: "localhost", }); await server.register({ plugin: apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }), }); }; init(); ``` ```javascript Advanced example theme={null} import Hapi from "@hapi/hapi"; import { apitallyPlugin } from "apitally/hapi"; const init = async () => { const server = Hapi.server({ port: 3000, host: "localhost", }); await server.register({ plugin: apitallyPlugin({ clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }), }); }; init(); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for Hono Source: https://docs.apitally.io/setup-guides/hono Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Hono](https://hono.dev) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts Running Hono on Cloudflare Workers? Follow [this setup guide](/setup-guides/hono-cloudflare-workers) instead. ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/javascript/overview) in your Hono project. ```shell npm theme={null} npm install apitally ``` ```shell yarn theme={null} yarn add apitally ``` Add the Apitally middleware to your Hono application using the `useApitally` function and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript theme={null} import { Hono } from "hono"; import { useApitally } from "apitally/hono"; const app = new Hono(); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in a middleware. ```javascript Identifier only theme={null} import { setConsumer } from "apitally/hono"; app.use(async (c, next) => { const consumerIdentifier = c.get("jwtPayload")?.sub; setConsumer(c, consumerIdentifier); await next(); }); ``` ```javascript With name and group theme={null} import { setConsumer } from "apitally/hono"; app.use(async (c, next) => { const payload = c.get("jwtPayload"); if (payload) { setConsumer(c, { identifier: payload.sub, name: payload.name, // optional group: payload.group, // optional }); } await next(); }); ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import { Hono } from "hono"; import { useApitally } from "apitally/hono"; const app = new Hono(); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }); ``` ```javascript Advanced example theme={null} import { Hono } from "hono"; import { useApitally } from "apitally/hono"; const app = new Hono(); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for Hono on Cloudflare Workers Source: https://docs.apitally.io/setup-guides/hono-cloudflare-workers Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Hono](https://hono.dev) application running on [Cloudflare Workers](https://developers.cloudflare.com/workers/) to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Create Logpush job Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and navigate to *Analytics & Logs > Logpush*. Create a [Logpush](https://developers.cloudflare.com/workers/observability/logs/logpush/) job with the following settings: | Setting | Value | | ---------------------------- | ------------------------------------------------------------------------------------------------ | | Destination | HTTP destination | | HTTP endpoint | `https://hub.apitally.io/v2/{client-id}/{env}/logpush` | | Dataset | Workers trace events | | If logs match... | Filtered logs:
EventType equals `fetch` and
ScriptName equals `{your-worker-name}` | | Send the following fields... | General:
Event, EventTimestampMs, Logs | In the HTTP endpoint, replace `{client-id}` with your app's client ID and `{env}` with the environment (e.g. `prod` or `dev`). In the filter criteria, replace `{your-worker-name}` with the name of your Worker, as specified in your Wrangler config. ## Add middleware Next, install the [Apitally Serverless SDK](/sdk-reference/javascript-serverless/overview) in your project. ```shell npm theme={null} npm install @apitally/serverless ``` ```shell yarn theme={null} yarn add @apitally/serverless ``` Add the Apitally middleware to your Hono application using the `useApitally` function. ```javascript theme={null} import { Hono } from "hono"; import { useApitally } from "@apitally/serverless/hono"; const app = new Hono(); useApitally(app); // Ensure route handlers are registered after useApitally() ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
## Configure Worker Enable [Workers Logs](https://developers.cloudflare.com/workers/observability/logs/workers-logs/) and [Logpush](https://developers.cloudflare.com/workers/observability/logs/logpush/) in your Wrangler configuration file. ```toml wrangler.toml theme={null} logpush = true [observability] enabled = true head_sampling_rate = 1 [observability.logs] invocation_logs = true ``` ```json wrangler.json theme={null} { "logpush": true, "observability": { "enabled": true, "head_sampling_rate": 1, "logs": { "invocation_logs": true } } } ``` Then, deploy your application to Cloudflare Workers. ```shell theme={null} wrangler deploy ``` At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard after the first request is handled. It can take 2-3 minutes for requests to show up in Apitally due to how Cloudflare Logpush batches log data before sending it. Also note that Cloudflare Logpush doesn't include requests from local development environments, so you won't see them in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in a middleware. ```javascript Identifier only theme={null} import { setConsumer } from "@apitally/serverless/hono"; app.use(async (c, next) => { const consumerIdentifier = c.get("jwtPayload")?.sub; setConsumer(c, consumerIdentifier); await next(); }); ``` ```javascript With name and group theme={null} import { setConsumer } from "@apitally/serverless/hono"; app.use(async (c, next) => { const payload = c.get("jwtPayload"); if (payload) { setConsumer(c, { identifier: payload.sub, name: payload.name, // optional group: payload.group, // optional }); } await next(); }); ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging With the serverless SDK, request logging is enabled by default, however request headers and request/response bodies are not included unless explicitly enabled. The SDK automatically applies [default masking rules](/data-privacy#data-masking) for common sensitive headers and request/response body fields. You can configure additional masking rules and exclude certain requests from logging. ```javascript Basic example theme={null} import { Hono } from "hono"; import { useApitally } from "@apitally/serverless/hono"; const app = new Hono(); useApitally(app, { logRequestHeaders: true, logRequestBody: true, logResponseBody: true, }); ``` ```javascript Advanced example theme={null} import { Hono } from "hono"; import { useApitally } from "@apitally/serverless/hono"; const app = new Hono(); useApitally(app, { logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Exclude paths from request logging using regex excludePaths: [/\/health$/, /\/metrics$/], }); ``` The *Request logs* dashboard now shows individual requests handled by your application, including headers and payloads, if enabled. You can filter, search, and inspect them in detail. # Setup guide for Koa Source: https://docs.apitally.io/setup-guides/koa Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Koa](https://koajs.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/javascript/overview) in your Koa project. ```shell npm theme={null} npm install apitally ``` ```shell yarn theme={null} yarn add apitally ``` Add the Apitally middleware to your Koa application using the `useApitally` function and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript ESM theme={null} import Koa from "koa"; import { useApitally } from "apitally/koa"; const app = new Koa(); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); ``` ```javascript CommonJS theme={null} const Koa = require("koa"); const { useApitally } = require("apitally/koa"); const app = new Koa(); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in a middleware. ```javascript Identifier only theme={null} import { setConsumer } from "apitally/koa"; app.use(function (ctx, next) { if (ctx.isAuthenticated()) { setConsumer(ctx, ctx.state.user.username); } next() }) ``` ```javascript With name and group theme={null} import { setConsumer } from "apitally/koa"; app.use(function (ctx, next) { if (ctx.isAuthenticated()) { setConsumer(ctx, { identifier: ctx.state.user.username, name: `${ctx.state.user.firstName} ${ctx.state.user.lastName}`, // optional group: ctx.state.user.group, // optional }); } next() }) ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import Koa from "koa"; import { useApitally } from "apitally/koa"; const app = new Koa(); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }); ``` ```javascript Advanced example theme={null} import Koa from "koa"; import { useApitally } from "apitally/koa"; const app = new Koa(); useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for Litestar Source: https://docs.apitally.io/setup-guides/litestar Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Litestar](https://litestar.dev/) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add plugin Next, install the [Apitally SDK](/sdk-reference/python/overview) in your project with the extra. ```shell pip theme={null} pip install "apitally[litestar]" ``` ```shell poetry theme={null} poetry add "apitally[litestar]" ``` ```shell uv theme={null} uv add "apitally[litestar]" ``` Add the Apitally plugin to your Litestar application and provide the `client_id` for your app. You'll find the `client_id` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```python theme={null} from litestar import Litestar from apitally.litestar import ApitallyPlugin apitally_plugin = ApitallyPlugin( client_id="your-client-id", env="dev", # or "prod" etc. ) app = Litestar(route_handlers=[...], plugins=[apitally_plugin]) ```
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard.
## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `set_consumer` function to associate requests with consumers, for example in a `before_request` life cycle hook or directly in your route handler functions. Alternatively, provide a callback function to the `ApitallyPlugin` that takes a [`Request`](https://docs.litestar.dev/latest/reference/connection.html#litestar.connection.Request) object as an argument and returns a consumer identifier, an `ApitallyConsumer` object or `None`. ```python Life cycle hook theme={null} from litestar import Litestar from litestar.connection import Request from apitally.litestar import set_consumer async def before_request_handler(request: Request) -> None: if request.user.is_authenticated: set_consumer( request, identifier=request.user.identity, name=request.user.name, # optional group=request.user.role, # optional ) app = Litestar( route_handlers=[...], before_request=before_request_handler, plugins=[apitally_plugin] ) ``` ```python Callback function theme={null} from litestar.connection import Request from apitally.litestar import ApitallyPlugin, ApitallyConsumer def get_consumer(request: Request) -> ApitallyConsumer | None: if request.user.is_authenticated: return ApitallyConsumer( identifier=request.user.identity, name=request.user.name, # optional group=request.user.role, # optional ) return None apitally_plugin = ApitallyPlugin( client_id="your-client-id", env="dev", # or "prod" etc. consumer_callback=get_consumer, ) ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```python Basic example theme={null} from litestar import Litestar from apitally.litestar import ApitallyPlugin apitally_plugin = ApitallyPlugin( client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_request_headers=True, log_request_body=True, log_response_body=True, capture_logs=True, capture_traces=False, # requires instrumentation ) app = Litestar(route_handlers=[...], plugins=[apitally_plugin]) ``` ```python Advanced example theme={null} from litestar import Litestar from apitally.litestar import ApitallyPlugin apitally_plugin = ApitallyPlugin( client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_query_params=True, log_request_headers=True, log_request_body=True, log_response_headers=True, log_response_body=True, log_exception=True, capture_logs=True, capture_traces=False, # requires instrumentation # Mask query parameters using regex mask_query_params=[r"^card_number$"], # Mask headers using regex mask_headers=[r"^X-Sensitive-Header$"], # Mask request/response body fields using regex mask_body_fields=[r"^sensitive_field$"], # Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) # The callback should return None to mask the whole body, or return the (modified) raw body mask_request_body_callback=lambda request: None if request["path"].startswith("/admin/") else request["body"], mask_response_body_callback=lambda request, response: None if request["path"].startswith("/admin/") else response["body"], # Exclude paths from request logging using regex (common health check paths are excluded by default) exclude_paths=[r"/metrics$"], # Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) # The callback should return True to exclude the request exclude_callback=lambda request, response: request["consumer"] == "some-consumer", ) app = Litestar(route_handlers=[...], plugins=[apitally_plugin]) ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `capture_traces` to `True` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/python/tracing) for further instructions. # Setup guide for NestJS Source: https://docs.apitally.io/setup-guides/nestjs Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [NestJS](https://nestjs.com) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/javascript/overview) in your NestJS project. ```shell npm theme={null} npm install apitally ``` ```shell yarn theme={null} yarn add apitally ``` Add the Apitally middleware to your NestJS application using the `useApitally` function and provide the `clientId` for your app. You'll find the `clientId` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```javascript ESM theme={null} import { NestFactory } from "@nestjs/core"; import { useApitally } from "apitally/nestjs"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); // ... } bootstrap(); ``` ```javascript CommonJS theme={null} const { NestFactory } = require("@nestjs/core"); const { useApitally } = require("apitally/nestjs"); const { AppModule } = require("./app.module"); async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. }); // ... } bootstrap(); ```
Add the Apitally middleware before any other middleware to ensure it wraps the entire stack.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `setConsumer` function to associate requests with consumers, for example in an authorization guard. ```javascript Identifier only theme={null} import { Injectable } from '@nestjs/common'; import { setConsumer } from "apitally/nestjs"; @Injectable() export class AuthGuard { async canActivate(context) { const request = context.switchToHttp().getRequest(); const result = authenticateRequest(request); // assuming this sets request.user if (result && request.user) { setConsumer(request, request.user.username); } return result; } } ``` ```javascript With name and group theme={null} import { Injectable } from '@nestjs/common'; import { setConsumer } from "apitally/nestjs"; @Injectable() export class AuthGuard { async canActivate(context) { const request = context.switchToHttp().getRequest(); const result = authenticateRequest(request); // assuming this sets request.user if (result && request.user) { setConsumer(request, { identifier: request.user.username, name: request.user.fullName, // optional group: request.user.role, // optional }); } return result; } } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```javascript Basic example theme={null} import { NestFactory } from "@nestjs/core"; import { useApitally } from "apitally/nestjs"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logRequestHeaders: true, logRequestBody: true, logResponseBody: true, captureLogs: true, captureTraces: false, // requires instrumentation }, }); // ... } bootstrap(); ``` ```javascript Advanced example theme={null} import { NestFactory } from "@nestjs/core"; import { useApitally } from "apitally/nestjs"; import { AppModule } from "./app.module"; async function bootstrap() { const app = await NestFactory.create(AppModule); await useApitally(app, { clientId: "your-client-id", env: "dev", // or "prod" etc. requestLogging: { enabled: true, logQueryParams: true, logRequestHeaders: true, logRequestBody: true, logResponseHeaders: true, logResponseBody: true, logException: true, captureLogs: true, captureTraces: false, // requires instrumentation // Mask query parameters using regex maskQueryParams: [/^card_number$/i], // Mask headers using regex maskHeaders: [/^X-Sensitive-Header$/i], // Mask request/response body fields using regex maskBodyFields: [/^sensitive_field$/i], // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body maskRequestBodyCallback: (request) => request.path?.startsWith("/admin/") ? null : request.body, maskResponseBodyCallback: (request, response) => request.path?.startsWith("/admin/") ? null : response.body, // Exclude paths from request logging using regex (common health check paths are excluded by default) excludePaths: [/\/metrics$/], // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request excludeCallback: (request, response) => request.consumer === "some-consumer", }, }); // ... } bootstrap(); ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `captureTraces` to `true` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/javascript/tracing) for further instructions. # Setup guide for Spring Boot Source: https://docs.apitally.io/setup-guides/spring-boot Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Spring Boot](https://spring.io/projects/spring-boot) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Enable Apitally Add the [Apitally SDK](/sdk-reference/java/overview) to your project's dependencies. ```xml Maven theme={null} io.apitally apitally [0.1.0,) ``` ```groovy Gradle theme={null} dependencies { implementation 'io.apitally:apitally:+' } ``` Next, add the `@UseApitally` annotation to your Spring Boot application class. ```java Application.java {6} theme={null} import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import io.apitally.spring.UseApitally; @UseApitally @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` Then configure Apitally in your `application.yml` file and provide the client ID for your app. You'll find the client ID on the *Setup instructions* page in the Apitally dashboard, which is displayed immediately after creating the app. ```yaml application.yml theme={null} apitally: client-id: "your-client-id" env: "dev" # or "prod" etc. ``` Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. To associate requests with consumers, set the `apitallyConsumer` attribute on the request. You could do this in a filter or interceptor, for example. ```java Identifier only theme={null} import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class ConsumerIdentificationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated()) { request.setAttribute("apitallyConsumer", auth.getName()); } chain.doFilter(request, response); } } ``` ```java With name and group theme={null} import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import io.apitally.spring.ApitallyConsumer; public class ConsumerIdentificationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated()) { User user = (User) auth.getPrincipal(); request.setAttribute("apitallyConsumer", new ApitallyConsumer( user.getUsername(), // identifier user.getFullName(), // name user.getRole() // group )); } chain.doFilter(request, response); } } ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. Check out the SDK reference to learn more about the request logging configuration options. ```yaml Basic example theme={null} apitally: client-id: "your-client-id" env: "dev" # or "prod" etc. request-logging: enabled: true request-headers-included: true request-body-included: true response-body-included: true log-capture-enabled: true ``` ```yaml Advanced example theme={null} apitally: client-id: "your-client-id" env: "dev" # or "prod" etc. request-logging: enabled: true query-params-included: true request-headers-included: true request-body-included: true response-headers-included: true response-body-included: true exception-included: true log-capture-enabled: true # Mask query parameters using regex query-param-mask-patterns: - "^card_number$" # Mask headers using regex header-mask-patterns: - "^X-Sensitive-Header$" # Mask request/response body fields using regex body-field-mask-patterns: - "^sensitive_field$" # Exclude paths from request logging using regex (common health check paths are excluded by default) path-exclude-patterns: - "/metrics$" # Use callbacks for advanced masking and exclusion logic callbacks-class: "com.example.MyRequestLoggingCallbacks" ``` ```java RequestLoggingCallbacks.java theme={null} import io.apitally.common.RequestLoggingCallbacks; import io.apitally.common.dto.Request; import io.apitally.common.dto.Response; public class MyRequestLoggingCallbacks implements RequestLoggingCallbacks { @Override public byte[] maskRequestBody(Request request) { // Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) // The callback should return null to mask the whole body, or return the (modified) raw body if (request.getPath().startsWith("/admin/")) { return null; // Mask the whole body for admin endpoints } return request.getBody(); } @Override public byte[] maskResponseBody(Request request, Response response) { if (request.getPath().startsWith("/admin/")) { return null; // Mask the whole body for admin endpoints } return response.getBody(); } @Override public boolean shouldExclude(Request request, Response response) { // Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) // The callback should return true to exclude the request return "some-consumer".equals(request.getConsumer()); } } ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. # Setup guide for Starlette Source: https://docs.apitally.io/setup-guides/starlette Just a few simple steps to get started with Apitally. This page guides you through the steps of configuring your [Starlette](https://www.starlette.io) application to work with Apitally. If you don't have an account yet, now would be a good time to [sign up](https://app.apitally.io/?signup). Once you're done with this guide, you will be able to: * Get detailed metrics on API usage, errors, and performance * Track API adoption and usage by individual consumers * Log individual API requests, responses, and correlated application logs * See what's causing slow API requests with traces * Monitor uptime and set up custom alerts ## Create app To get started, create a new app in the [Apitally dashboard](https://app.apitally.io/apps) and select as your framework. Create app You can also configure the environments (e.g. `prod` and `dev`) for your app, or simply accept the defaults. After submitting, you will see tailored setup instructions for your app. These include code snippets you can copy and paste into your project. The **client ID** provided in the setup instructions uniquely identifies your app for the purpose of data ingestion only. It does not grant any kind of read access to your data. ## Add middleware Next, install the [Apitally SDK](/sdk-reference/python/overview) in your project with the extra. ```shell pip theme={null} pip install "apitally[starlette]" ``` ```shell poetry theme={null} poetry add "apitally[starlette]" ``` ```shell uv theme={null} uv add "apitally[starlette]" ``` Add the Apitally middleware to your Starlette application and provide the `client_id` for your app. You'll find the `client_id` on the *Setup instructions* page for your app in the Apitally dashboard, which is displayed immediately after creating the app. ```python theme={null} from starlette.applications import Starlette from apitally.starlette import ApitallyMiddleware app = Starlette(routes=[...]) app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", # or "prod" etc. ) ```
If you're also using other middlewares, add the `ApitallyMiddleware` last, so that it wraps the existing stack of middlewares.
Deploy your application with these changes, or restart if you're testing locally. At this point the basic setup for your application is complete and you will start seeing data in the Apitally dashboard. ## Identify consumers To analyze and filter API traffic by consumers, you can associate requests with consumer identifiers in your application. In most cases, use the authenticated identity to identify the consumer. The identifier should be a string, such as a username, email address, or any other unique identifier. Optionally, you can also provide a display name and group for each consumer. Use the `set_consumer` function to associate requests with consumers, for example in a middleware or directly in your endpoint functions. Alternatively, you can provide a callback function to the `ApitallyMiddleware` that takes a [`Request`](https://www.starlette.io/requests/) object as an argument and returns a consumer identifier, an `ApitallyConsumer` object or `None`. ```python Using set_consumer theme={null} from starlette.requests import Request from apitally.starlette import set_consumer def list_items(request: Request): if request.user.is_authenticated: set_consumer( request, identifier=request.user.identity, name=request.user.display_name, # optional group="Customers", # optional ) return ["item1"] ``` ```python Callback function theme={null} from starlette.requests import Request from apitally.starlette import ApitallyConsumer def get_consumer(request: Request) -> ApitallyConsumer | None: if request.user.is_authenticated: return ApitallyConsumer( identifier=request.user.identity, name=request.user.display_name, # optional group="Customers", # optional ) return None app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", # or "prod" etc. consumer_callback=get_consumer, ) ``` The *Consumers* dashboard now shows all consumers that have made requests to your application. You can also filter other dashboards by consumer. ## Configure request logging Logging of individual requests and responses is disabled by default to protect potentially sensitive data. If you enable it, you can configure in detail what parts of the request and response should be logged. You can also mask sensitive information (e.g. in headers) and exclude certain requests from logging. The SDK applies [default masking rules](/data-privacy#data-masking) for common sensitive headers, query parameters and request/response body fields. ```python Basic example theme={null} from starlette.applications import Starlette from apitally.starlette import ApitallyMiddleware app = Starlette(routes=[...]) app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_request_headers=True, log_request_body=True, log_response_body=True, capture_logs=True, capture_traces=False, # requires instrumentation ) ``` ```python Advanced example theme={null} from starlette.applications import Starlette from apitally.starlette import ApitallyMiddleware app = Starlette(routes=[...]) app.add_middleware( ApitallyMiddleware, client_id="your-client-id", env="dev", # or "prod" etc. enable_request_logging=True, log_query_params=True, log_request_headers=True, log_request_body=True, log_response_headers=True, log_response_body=True, log_exception=True, capture_logs=True, capture_traces=False, # requires instrumentation # Mask query parameters using regex mask_query_params=[r"^card_number$"], # Mask headers using regex mask_headers=[r"^X-Sensitive-Header$"], # Mask request/response body fields using regex mask_body_fields=[r"^sensitive_field$"], # Mask request/response body with custom logic via callbacks (e.g. for admin endpoints) # The callback should return None to mask the whole body, or return the (modified) raw body mask_request_body_callback=lambda request: None if request["path"].startswith("/admin/") else request["body"], mask_response_body_callback=lambda request, response: None if request["path"].startswith("/admin/") else response["body"], # Exclude paths from request logging using regex (common health check paths are excluded by default) exclude_paths=[r"/metrics$"], # Exclude requests from logging with custom logic via callback (e.g. exclude requests from a specific consumer) # The callback should return True to exclude the request exclude_callback=lambda request, response: request["consumer"] == "some-consumer", ) ``` The *Request logs* dashboard now shows individual requests handled by your application. You can filter, search, and inspect them in detail. ## Enable tracing Tracing gives you a detailed breakdown of time spent during the handling of each request, showing the duration of database queries, HTTP calls, and other operations. To enable tracing, set `capture_traces` to `True` and instrument the libraries you want to trace with OpenTelemetry. See the [tracing guide](/sdk-reference/python/tracing) for further instructions. # Support Source: https://docs.apitally.io/support Where to go for help and sharing feedback. If you already have access to the Apitally dashboard, the easiest way to reach out for support is to hit the *Get in touch* button in the sidebar. Alternatively, choose one of the options below. Send us an email. Create an issue or discussion. Chat with us and the community. Regardless of the method you choose, we're here to help you get the most out of Apitally and will respond as soon as we can. # Usage limits Source: https://docs.apitally.io/usage-limits Understand the limits, quotas, and usage-based billing in Apitally. You can track your current usage against your plan's limits and quotas in the dashboard under *Settings > Usage*. Apitally has **no limits** on the number of requests processed for API metrics. ## Limits Depending on your plan, there are hard limits on the number of apps and team members, as well as a usage limit on API consumers. If you exceed a usage limit, your team will be notified and given a 7-day grace period. If usage remains above the limit after the grace period, Apitally will stop ingesting data for your apps until usage drops below the limit or you upgrade your plan. Your dashboard and historical data remain accessible. ### API consumers The API consumers limit is based on the number of unique consumers that have made requests to your API within a rolling 24-hour period. This limit only applies if your application provides a consumer identifier for each request. See the [setup guide](/setup-guides) for your framework to learn how. ## Monthly quotas Monthly quotas apply to request logs, application logs and spans in traces. Quotas are based on calendar months and reset at the start of each month. If you exceed a monthly quota, Apitally stops ingesting new request logs, application logs or spans (depending on which quota was exceeded) until the start of the next month. Your API metrics are not affected. You can exclude certain requests from logging using custom exclusion rules to reduce your usage and stay within quotas. Check out the [SDK reference](/sdk-reference) for details. ### Usage-based billing On the Starter and Premium plans, you can enable usage-based billing under *Settings > Billing* in the dashboard. With usage-based billing enabled, data ingestion continues beyond your monthly quotas, and you are charged for the additional requests, logs or spans. Usage-based billing is disabled by default.