diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..636b5fb --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,55 @@ +name: Deploy Antora Documentation + +on: + push: + branches: + - main + paths: + - 'docs/**' + - 'antora-playbook.yml' + - '.github/workflows/deploy-docs.yml' + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build Antora site + run: npm run docs + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./build/site + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 3dc7b36..60ddccb 100644 --- a/.gitignore +++ b/.gitignore @@ -12,9 +12,16 @@ logs # Lock files *.lock +# Node modules +node_modules/ + playbook/target .vscode + +# Antora build output +build/ + .tfvars # Local .terraform directories @@ -29,8 +36,8 @@ crash.log crash.*.log # Exclude all .tfvars files, which are likely to contain sensitive data, such as -# password, private keys, and other secrets. These should not be part of version -# control as they are data points which are potentially sensitive and subject +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject # to change depending on the environment. *.tfvars *.tfvars.json @@ -44,4 +51,4 @@ override.tf.json # Ignore transient lock info files created by terraform apply .terraform.tfstate.lock.info -.claude \ No newline at end of file +.claude diff --git a/README.md b/README.md new file mode 100644 index 0000000..2b0a625 --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +# Redis Enterprise Observability + +Comprehensive monitoring and observability solutions for Redis Enterprise deployments. + +## Overview + +This repository provides pre-built dashboards, metrics configurations, and integration guides for monitoring Redis Enterprise across multiple observability platforms. + +## Supported Platforms + +- **Grafana** - Visualization and analytics +- **Prometheus** - Metrics collection and time-series storage +- **Dynatrace** - Full-stack monitoring +- **New Relic** - Application performance monitoring +- **Splunk** - Log analytics and SIEM +- **Kibana** - Elasticsearch visualization + +## Documentation + +📚 **[View the complete documentation](https://redis-field-engineering.github.io/redis-enterprise-observability/)** + +The documentation includes: +- Quick start guides +- Platform-specific integration instructions +- Dashboard catalog +- Monitoring best practices +- Alerting configuration +- Metrics reference +- Troubleshooting guides + +### Building Documentation Locally + +```bash +# Install dependencies +npm install + +# Generate documentation site +npm run docs + +# View the site +open build/site/index.html + +# Or serve locally +npm run docs:serve +# Visit http://localhost:8080 +``` + +## Quick Start + +1. Choose your observability platform +2. Follow the platform-specific guide in the [documentation](https://redis-field-engineering.github.io/redis-enterprise-observability/) +3. Import pre-built dashboards from the catalog +4. Configure alerting based on your requirements + +## Repository Structure + +``` +. +├── docs/ # Antora documentation source +│ ├── antora.yml # Component descriptor +│ └── modules/ROOT/ +│ ├── pages/ # Documentation pages (AsciiDoc) +│ └── nav.adoc # Navigation menu +├── grafana/ # Grafana dashboards +├── prometheus/ # Prometheus configurations +├── dynatrace/ # Dynatrace integrations +├── newrelic/ # New Relic dashboards +├── splunk/ # Splunk configurations +└── kibana/ # Kibana dashboards +``` + +## Contributing + +Contributions are welcome! Please: + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Submit a pull request + +For documentation contributions, see [docs/README.md](docs/README.md). + +## Resources + +- [Redis Enterprise Documentation](https://docs.redis.com/latest/rs/) +- [Redis Cloud Documentation](https://docs.redis.com/latest/rc/) +- [Antora Documentation](https://docs.antora.org/) + +## License + +See [LICENSE](LICENSE) for details. diff --git a/antora-playbook.yml b/antora-playbook.yml new file mode 100644 index 0000000..f6f6933 --- /dev/null +++ b/antora-playbook.yml @@ -0,0 +1,24 @@ +site: + title: Redis Enterprise Observability + start_page: redis-enterprise-observability::index.adoc + url: https://redis-field-engineering.github.io/redis-enterprise-observability + +content: + sources: + - url: . + branches: HEAD + start_path: docs + +ui: + bundle: + url: https://github.com/redis/antora-ui-redis/releases/latest/download/ui-bundle.zip + snapshot: true + supplemental_files: + - path: ui.yml + contents: | + static_files: + - .nojekyll + - path: .nojekyll + +output: + dir: ./build/site diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..5962773 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,65 @@ +# Redis Enterprise Observability Documentation + +This directory contains the Antora-based documentation for Redis Enterprise Observability. + +## Building the Documentation + +### Prerequisites + +- Node.js (LTS version recommended) +- npm + +### Build Commands + +```bash +# Install dependencies (if not already installed) +npm install + +# Generate documentation site +npm run docs + +# Serve the site locally (requires http-server) +npm run docs:serve +``` + +The generated site will be available at `build/site/index.html` or http://localhost:8080 when using the serve command. + +## Documentation Structure + +The documentation follows Antora's standard structure: + +``` +docs/ +├── antora.yml # Component descriptor +└── modules/ + └── ROOT/ + ├── nav.adoc # Navigation menu + ├── pages/ # Documentation pages (AsciiDoc) + │ ├── index.adoc + │ ├── platforms/ + │ ├── dashboards/ + │ ├── guides/ + │ └── reference/ + ├── images/ # Images and screenshots + ├── examples/ # Code examples + └── attachments/ # Downloadable files +``` + +## Writing Documentation + +- Documentation is written in AsciiDoc format (`.adoc` files) +- Place new pages in the appropriate `pages/` subdirectory +- Update `nav.adoc` to add pages to the navigation menu +- Use cross-references with `xref:` to link between pages + +## Contributing + +1. Add or modify `.adoc` files in `docs/modules/ROOT/pages/` +2. Update navigation in `docs/modules/ROOT/nav.adoc` if adding new pages +3. Build and test locally with `npm run docs` +4. Submit a pull request with your changes + +## Resources + +- [Antora Documentation](https://docs.antora.org/) +- [AsciiDoc Syntax](https://docs.asciidoctor.org/asciidoc/latest/) diff --git a/docs/antora.yml b/docs/antora.yml new file mode 100644 index 0000000..fdca29a --- /dev/null +++ b/docs/antora.yml @@ -0,0 +1,5 @@ +name: redis-enterprise-observability +version: latest +title: Redis Enterprise Observability +nav: +- modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc new file mode 100644 index 0000000..58b4fc3 --- /dev/null +++ b/docs/modules/ROOT/nav.adoc @@ -0,0 +1,22 @@ +* xref:index.adoc[Overview] +* xref:quick-start.adoc[Quick Start] + +.Platforms +* xref:platforms/grafana.adoc[Grafana] +* xref:platforms/prometheus.adoc[Prometheus] +* xref:platforms/dynatrace.adoc[Dynatrace] +* xref:platforms/newrelic.adoc[New Relic] +* xref:platforms/splunk.adoc[Splunk] +* xref:platforms/kibana.adoc[Kibana] + +.Dashboards +* xref:dashboards/catalog.adoc[Dashboard Catalog] + +.Guides +* xref:guides/monitoring-redis-cloud.adoc[Monitoring Redis Cloud] +* xref:guides/alerting.adoc[Alerting] +* xref:guides/troubleshooting.adoc[Troubleshooting] + +.Reference +* xref:reference/metrics.adoc[Metrics Reference] +* xref:reference/configuration.adoc[Configuration] diff --git a/docs/modules/ROOT/pages/dashboards/catalog.adoc b/docs/modules/ROOT/pages/dashboards/catalog.adoc new file mode 100644 index 0000000..95e54d5 --- /dev/null +++ b/docs/modules/ROOT/pages/dashboards/catalog.adoc @@ -0,0 +1,164 @@ += Dashboard Catalog + +Browse the complete collection of pre-built dashboards for Redis Enterprise monitoring. + +== Overview + +This catalog contains ready-to-use dashboards for various observability platforms. Each dashboard provides comprehensive monitoring of Redis Enterprise clusters, databases, and nodes. + +NOTE: All dashboards listed below are from the v2 collection, which is recommended for all deployments. If you need legacy v1 dashboards, see the xref:#legacy-dashboards[Legacy Dashboards] section. + +== Grafana Dashboards (v2) + +=== Kickstart Collection +Production-ready dashboards for immediate deployment: + +* *Cluster Dashboard*: `grafana_v2/dashboards/kickstart/cluster.json` - High-level cluster health and performance +* *Database Dashboard*: `grafana_v2/dashboards/kickstart/database.json` - Detailed database metrics and operations +* *Node Dashboard*: `grafana_v2/dashboards/kickstart/node.json` - Node-level resource utilization +* *Shard Dashboard*: `grafana_v2/dashboards/kickstart/shard.json` - Shard-level monitoring and health +* *Active-Active Dashboard*: `grafana_v2/dashboards/kickstart/active-active.json` - Active-Active replication monitoring +* *System Security Dashboard*: `grafana_v2/dashboards/kickstart/sys-sec.json` - Security and system metrics + +=== Grafana v9-11 Collection +Optimized for Grafana versions 9-11: + +==== Basic Dashboards +* *Cluster*: `grafana_v2/dashboards/grafana_v9-11/software/basic/redis-software-cluster-dashboard_v9-11.json` +* *Database*: `grafana_v2/dashboards/grafana_v9-11/software/basic/redis-software-database-dashboard_v9-11.json` +* *Node*: `grafana_v2/dashboards/grafana_v9-11/software/basic/redis-software-node-dashboard_v9-11.json` +* *Shard*: `grafana_v2/dashboards/grafana_v9-11/software/basic/redis-software-shard-dashboard_v9-11.json` +* *Active-Active*: `grafana_v2/dashboards/grafana_v9-11/software/basic/redis-software-active-active-dashboard_v9-11.json` +* *Synchronization*: `grafana_v2/dashboards/grafana_v9-11/software/basic/redis-software-synchronization-overview_v9-11.json` + +==== Extended Dashboards +* *Database Extended*: `grafana_v2/dashboards/grafana_v9-11/software/extended/redis-software-database-extended-dashboard_v9-11.json` - Comprehensive database analysis + +==== Workflow Dashboards +Database-focused operational views: + +* *All Databases*: `grafana_v2/dashboards/grafana_v9-11/workflow/databases/redis-software-cluster-databases_v9-11.json` +* *Database CPU*: `grafana_v2/dashboards/grafana_v9-11/workflow/databases/redis-software-cluster-database-cpu_v9-11.json` +* *Database Memory*: `grafana_v2/dashboards/grafana_v9-11/workflow/databases/redis-software-cluster-database-memory_v9-11.json` +* *Database Latency*: `grafana_v2/dashboards/grafana_v9-11/workflow/databases/redis-software-cluster-database-latency_v9-11.json` +* *Database Requests*: `grafana_v2/dashboards/grafana_v9-11/workflow/databases/redis-software-cluster-database-requests_v9-11.json` + +==== Module-Specific Dashboards +* *RediSearch QPS*: `grafana_v2/dashboards/grafana_v9-11/search/RediSearchQPS.json` + +=== Alert Dashboard +* *Redis Alert Dashboard*: `grafana_v2/alerts/redis-alert-dashboard.json` - Centralized alert visualization + +== Dynatrace Dashboards (v2) + +=== Generation 3 Dashboards +Latest Dynatrace dashboard generation: + +* *Directory*: `dynatrace_v2/gen-3-dashboards/` +* *Description*: AI-powered monitoring with automatic baselining and anomaly detection +* *Features*: Full-stack observability, Davis AI integration + +=== Kickstarter +* *Directory*: `dynatrace_v2/kickstarter/` +* *Description*: Quick-start templates for rapid deployment + +See the https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/dynatrace_v2[dynatrace_v2 README^] for detailed information. + +== New Relic Dashboards (v2) + +=== Dashboard Collection +* *Directory*: `newrelic_v2/dashboards/` +* *Description*: Comprehensive monitoring with NRQL queries +* *Features*: Custom widgets, alert correlation, APM integration + +=== Kickstarter +* *Directory*: `newrelic_v2/kickstarter/` +* *Description*: Pre-configured setup for quick deployment + +See the https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/newrelic_v2[newrelic_v2 README^] for configuration details. + +== Datadog Dashboards (v2) + +=== Kickstarter +* *Directory*: `datadog_v2/kickstarter/` +* *Description*: Ready-to-use Datadog monitoring setup +* *Features*: APM integration, log correlation, custom metrics + +See the https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/datadog_v2[datadog_v2 README^] for setup instructions. + +== Prometheus Alert Rules (v2) + +Production-ready alert definitions: + +* *All Alerts*: `prometheus_v2/rules/alerts.yml` - Comprehensive alert suite +* *Capacity Alerts*: `prometheus_v2/rules/capacity-alerts.yml` - Capacity planning and thresholds +* *Connection Alerts*: `prometheus_v2/rules/connection-alerts.yml` - Connection monitoring +* *Latency Alerts*: `prometheus_v2/rules/latency-alerts.yml` - Performance thresholds +* *Node Alerts*: `prometheus_v2/rules/node-alerts.yml` - Node health monitoring +* *Shard Alerts*: `prometheus_v2/rules/shard-alerts.yml` - Shard-level alerts +* *Synchronization Alerts*: `prometheus_v2/rules/synchronization-alerts.yml` - Replication monitoring +* *Throughput Alerts*: `prometheus_v2/rules/throughput-alerts.yml` - Throughput thresholds +* *Utilization Alerts*: `prometheus_v2/rules/utilization-alerts.yml` - Resource utilization + +== Splunk Dashboards + +=== Redis Enterprise Analytics +* *File*: `splunk/analytics-dashboard.xml` +* *Description*: Enterprise analytics with SPL queries +* *Features*: Historical trending, capacity planning, anomaly detection + +== Kibana Dashboards + +=== Redis Enterprise Metrics +* *File*: `kibana/metrics-dashboard.ndjson` +* *Description*: Visualization of metrics in Elasticsearch +* *Features*: Custom visualizations, Canvas integration + +== Importing Dashboards + +See the platform-specific guides for import instructions: + +* xref:platforms/grafana.adoc[Grafana Import Guide] +* xref:platforms/dynatrace.adoc[Dynatrace Import Guide] +* xref:platforms/newrelic.adoc[New Relic Import Guide] +* xref:platforms/splunk.adoc[Splunk Import Guide] +* xref:platforms/kibana.adoc[Kibana Import Guide] + +== Customization + +All dashboards can be customized to fit your specific needs: + +* Modify time ranges and refresh intervals +* Add or remove panels +* Adjust thresholds and alert conditions +* Create dashboard variables for filtering + +[#legacy-dashboards] +== Legacy Dashboards (v1) + +WARNING: The v1 dashboards are provided for compatibility with older deployments only. We recommend upgrading to v2 dashboards for the latest features and improvements. + +=== Grafana v1 (Legacy) +* *Directory*: `grafana/dashboards/` +* *Note*: Basic cluster, database, and node monitoring dashboards + +=== Dynatrace v1 (Legacy) +* *Directory*: `dynatrace/` +* *Note*: Earlier generation dashboards + +=== New Relic v1 (Legacy) +* *Directory*: `newrelic/` +* *Note*: Legacy integration setup + +=== Prometheus v1 (Legacy) +* *Directory*: `prometheus/` +* *Note*: Original Prometheus configurations and rules + +== Contributing + +To contribute new dashboards or improvements: + +. Fork the repository +. Add your dashboard to the appropriate v2 platform directory +. Update this catalog +. Submit a pull request diff --git a/docs/modules/ROOT/pages/guides/alerting.adoc b/docs/modules/ROOT/pages/guides/alerting.adoc new file mode 100644 index 0000000..455a06d --- /dev/null +++ b/docs/modules/ROOT/pages/guides/alerting.adoc @@ -0,0 +1,463 @@ += Alerting Guide + +Configure effective alerts for Redis Enterprise monitoring. + +== Overview + +Proactive alerting helps identify and resolve issues before they impact users. This guide covers alert configuration across different platforms. + +== Alert Philosophy + +=== What to Alert On + +Alert on conditions that: + +* Require immediate action +* Indicate user-facing impact +* Signal impending capacity issues +* Show significant deviation from baseline + +=== What Not to Alert On + +Avoid alerts for: + +* Normal operational variations +* Self-healing transient issues +* Informational metrics +* Low-urgency capacity planning + +== Critical Alerts + +=== Database Unavailable + +*Condition*: Database is down or unreachable + +[source,promql] +---- +redis_enterprise_database_up == 0 +---- + +*Severity*: Critical + +*Action*: Investigate immediately, check cluster health + +=== Memory Usage Critical + +*Condition*: Memory usage > 90% + +[source,promql] +---- +(redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) > 0.9 +---- + +*Severity*: Critical + +*Action*: Investigate memory usage, consider scaling + +=== High Latency + +*Condition*: P99 latency > 100ms (adjust threshold for use case) + +[source,promql] +---- +redis_enterprise_database_latency_p99 > 0.1 +---- + +*Severity*: High + +*Action*: Check for slow commands, investigate load + +== Warning Alerts + +=== Memory Usage High + +*Condition*: Memory usage > 80% + +[source,promql] +---- +(redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) > 0.8 +---- + +*Severity*: Warning + +*Action*: Plan for capacity increase + +=== Connection Count High + +*Condition*: Connections approaching limit + +[source,promql] +---- +redis_enterprise_database_connections > 9000 +---- + +*Severity*: Warning + +*Action*: Review connection pooling, investigate leaks + +=== Eviction Rate Increasing + +*Condition*: Keys being evicted due to memory pressure + +[source,promql] +---- +rate(redis_enterprise_database_evicted_keys[5m]) > 10 +---- + +*Severity*: Warning + +*Action*: Investigate memory usage patterns + +== Platform-Specific Configuration + +=== Prometheus Alertmanager + +==== Alert Rules Configuration + +Create `/etc/prometheus/rules/redis-enterprise-alerts.yml`: + +[source,yaml] +---- +groups: + - name: redis_enterprise_critical + interval: 30s + rules: + - alert: RedisEnterpriseDatabaseDown + expr: redis_enterprise_database_up == 0 + for: 1m + labels: + severity: critical + component: database + annotations: + summary: "Redis Enterprise database {{ $labels.database }} is down" + description: "Database {{ $labels.database }} in cluster {{ $labels.cluster }} has been unavailable for more than 1 minute" + runbook_url: "https://docs.example.com/runbooks/database-down" + + - alert: RedisEnterpriseMemoryCritical + expr: | + (redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) > 0.95 + for: 5m + labels: + severity: critical + component: memory + annotations: + summary: "Redis database {{ $labels.database }} memory critical" + description: "Database {{ $labels.database }} is using {{ $value | humanizePercentage }} of its memory limit" + + - alert: RedisEnterpriseClusterNodeDown + expr: redis_enterprise_node_up == 0 + for: 2m + labels: + severity: critical + component: node + annotations: + summary: "Redis Enterprise node {{ $labels.node }} is down" + description: "Cluster node {{ $labels.node }} in {{ $labels.cluster }} has been down for 2 minutes" + + - name: redis_enterprise_warning + interval: 1m + rules: + - alert: RedisEnterpriseHighMemoryUsage + expr: | + (redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) > 0.80 + for: 10m + labels: + severity: warning + component: memory + annotations: + summary: "Redis database {{ $labels.database }} high memory usage" + description: "Database {{ $labels.database }} is using {{ $value | humanizePercentage }} of memory" + + - alert: RedisEnterpriseHighLatency + expr: redis_enterprise_database_latency_p99 > 0.1 + for: 5m + labels: + severity: warning + component: performance + annotations: + summary: "High latency on {{ $labels.database }}" + description: "P99 latency is {{ $value }}s on database {{ $labels.database }}" + + - alert: RedisEnterpriseHighEvictionRate + expr: rate(redis_enterprise_database_evicted_keys[5m]) > 100 + for: 10m + labels: + severity: warning + component: memory + annotations: + summary: "High eviction rate on {{ $labels.database }}" + description: "Database {{ $labels.database }} is evicting {{ $value | humanize }} keys/sec" + + - alert: RedisEnterpriseHighConnectionCount + expr: redis_enterprise_database_connections > 9000 + for: 5m + labels: + severity: warning + component: connections + annotations: + summary: "High connection count on {{ $labels.database }}" + description: "Database {{ $labels.database }} has {{ $value }} connections (limit is 10000)" + + - alert: RedisEnterpriseReplicationLag + expr: redis_enterprise_database_replication_lag > 30 + for: 5m + labels: + severity: warning + component: replication + annotations: + summary: "Replication lag detected on {{ $labels.database }}" + description: "Replication lag is {{ $value }}s on database {{ $labels.database }}" +---- + +==== Alertmanager Configuration + +Create `/etc/alertmanager/alertmanager.yml`: + +[source,yaml] +---- +global: + resolve_timeout: 5m + slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK' + pagerduty_url: 'https://events.pagerduty.com/v2/enqueue' + +# Routing tree +route: + group_by: ['cluster', 'alertname', 'severity'] + group_wait: 30s + group_interval: 5m + repeat_interval: 4h + receiver: 'redis-team' + + routes: + # Critical alerts go to PagerDuty and Slack + - match: + severity: critical + receiver: 'pagerduty-critical' + continue: true + group_wait: 10s + repeat_interval: 1h + + - match: + severity: critical + receiver: 'slack-critical' + continue: false + + # Warning alerts go to Slack and create tickets + - match: + severity: warning + receiver: 'slack-warnings' + group_wait: 2m + repeat_interval: 12h + +# Inhibition rules +inhibit_rules: + # Inhibit warning memory alerts if critical memory alert is firing + - source_match: + severity: 'critical' + component: 'memory' + target_match: + severity: 'warning' + component: 'memory' + equal: ['cluster', 'database'] + + # Inhibit database alerts if node is down + - source_match: + alertname: 'RedisEnterpriseClusterNodeDown' + target_match_re: + alertname: 'RedisEnterpriseDatabase.*' + equal: ['cluster'] + +# Receivers +receivers: + - name: 'redis-team' + email_configs: + - to: 'redis-team@example.com' + from: 'alertmanager@example.com' + smarthost: 'smtp.example.com:587' + auth_username: 'alertmanager' + auth_password: 'password' + headers: + Subject: '[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}' + + - name: 'pagerduty-critical' + pagerduty_configs: + - service_key: 'YOUR_PAGERDUTY_SERVICE_KEY' + severity: '{{ if eq .CommonLabels.severity "critical" }}critical{{ else }}error{{ end }}' + description: '{{ .GroupLabels.alertname }}: {{ .CommonAnnotations.summary }}' + details: + firing: '{{ .Alerts.Firing | len }}' + resolved: '{{ .Alerts.Resolved | len }}' + cluster: '{{ .GroupLabels.cluster }}' + + - name: 'slack-critical' + slack_configs: + - channel: '#redis-critical' + username: 'Alertmanager' + icon_emoji: ':rotating_light:' + title: ':fire: Critical Alert' + text: | + *Alert:* {{ .GroupLabels.alertname }} + *Severity:* {{ .CommonLabels.severity }} + *Cluster:* {{ .GroupLabels.cluster }} + *Summary:* {{ .CommonAnnotations.summary }} + *Description:* {{ .CommonAnnotations.description }} + actions: + - type: button + text: 'View in Prometheus' + url: 'http://prometheus:9090/alerts' + - type: button + text: 'Runbook' + url: '{{ .CommonAnnotations.runbook_url }}' + + - name: 'slack-warnings' + slack_configs: + - channel: '#redis-alerts' + username: 'Alertmanager' + icon_emoji: ':warning:' + title: 'Warning Alert' + text: | + *Alert:* {{ .GroupLabels.alertname }} + *Summary:* {{ .CommonAnnotations.summary }} + {{ range .Alerts }} + - Database: {{ .Labels.database }} + {{ end }} +---- + +==== Testing Alerts + +[source,bash] +---- +# Send a test alert to Alertmanager +curl -X POST http://localhost:9093/api/v1/alerts \ + -H "Content-Type: application/json" \ + -d '[{ + "labels": { + "alertname": "TestAlert", + "severity": "warning", + "cluster": "test-cluster", + "database": "test-db" + }, + "annotations": { + "summary": "This is a test alert", + "description": "Testing alert routing and notifications" + }, + "startsAt": "'$(date -u +%Y-%m-%dT%H:%M:%S.000Z)'", + "endsAt": "'$(date -u -d '+5 minutes' +%Y-%m-%dT%H:%M:%S.000Z)'" + }]' + +# Check Alertmanager status +curl http://localhost:9093/api/v1/status + +# List active alerts +curl http://localhost:9093/api/v1/alerts + +# Silence an alert +curl -X POST http://localhost:9093/api/v1/silences \ + -H "Content-Type: application/json" \ + -d '{ + "matchers": [ + {"name": "alertname", "value": "RedisEnterpriseHighMemoryUsage", "isRegex": false}, + {"name": "database", "value": "test-db", "isRegex": false} + ], + "startsAt": "'$(date -u +%Y-%m-%dT%H:%M:%S.000Z)'", + "endsAt": "'$(date -u -d '+2 hours' +%Y-%m-%dT%H:%M:%S.000Z)'", + "createdBy": "admin", + "comment": "Planned maintenance" + }' +---- + +=== Grafana Alerts + +. Open dashboard panel +. Click "Alert" tab +. Define alert condition +. Configure notification channels +. Save alert rule + +=== Dynatrace Alerts + +Dynatrace provides AI-powered anomaly detection. Configure custom events: + +. Navigate to Settings > Anomaly Detection +. Create custom event for Redis Enterprise metrics +. Define baseline and thresholds +. Set alerting profile + +=== New Relic Alerts + +Create NRQL alert conditions: + +[source,sql] +---- +SELECT average(redis_enterprise_database_used_memory) +FROM Metric +WHERE database = 'production' +FACET database +---- + +=== Splunk Alerts + +Create alerts from SPL searches: + +[source,spl] +---- +index=metrics metric_name=redis_enterprise_database_up value=0 +| stats count by database, cluster +---- + +== Alert Routing + +=== Notification Channels + +Configure multiple channels based on severity: + +* *Critical*: PagerDuty, phone, SMS +* *High*: Slack, email, PagerDuty +* *Warning*: Email, Slack, ticket system + +=== On-Call Escalation + +Define escalation policies: + +. Primary on-call: Immediate notification +. Secondary on-call: After 10 minutes +. Team lead: After 30 minutes +. Management: After 1 hour (for critical) + +== Alert Tuning + +=== Reducing False Positives + +* Use appropriate time windows (for: 5m) +* Set realistic thresholds based on baseline +* Implement hysteresis to avoid flapping +* Use rate() instead of instantaneous values + +=== Testing Alerts + +Validate alert configuration: + +. Trigger alerts in non-production environment +. Verify notification delivery +. Test escalation policies +. Document runbooks for each alert + +== Runbooks + +Create runbooks for each alert type: + +=== Database Down Runbook + +. Check cluster status: `rladmin status` +. Verify node health +. Review logs for errors +. Attempt failover if needed +. Escalate to Redis support if unresolved + +=== High Memory Runbook + +. Identify large keys: `redis-cli --bigkeys` +. Review eviction policy +. Check for memory leaks +. Plan capacity increase +. Enable compression if applicable + +== Next Steps + +* xref:guides/troubleshooting.adoc[Troubleshooting guide] +* xref:reference/metrics.adoc[Metrics reference] +* xref:dashboards/catalog.adoc[Dashboard catalog] diff --git a/docs/modules/ROOT/pages/guides/monitoring-redis-cloud.adoc b/docs/modules/ROOT/pages/guides/monitoring-redis-cloud.adoc new file mode 100644 index 0000000..2127fc7 --- /dev/null +++ b/docs/modules/ROOT/pages/guides/monitoring-redis-cloud.adoc @@ -0,0 +1,127 @@ += Monitoring Redis Cloud + +Guide to monitoring Redis Enterprise Cloud deployments. + +== Overview + +Redis Enterprise Cloud is the fully-managed cloud service. This guide covers specific considerations for monitoring cloud deployments. + +== Prerequisites + +* Redis Cloud subscription (any tier) +* API access enabled in Redis Cloud console +* Observability platform configured + +== Redis Cloud API Access + +=== Generating API Keys + +. Log in to Redis Cloud console +. Navigate to Account Settings > API Keys +. Click "Generate API Key" +. Save the key securely (it's only shown once) + +=== API Endpoints + +Redis Cloud exposes metrics via REST API: + +[source,bash] +---- +curl -X GET "https://api.redislabs.com/v1/subscriptions/{subscription-id}/databases" \ + -H "x-api-key: ${API_KEY}" \ + -H "x-api-secret-key: ${API_SECRET}" +---- + +== Metrics Collection + +=== Using Prometheus + +Configure Prometheus to scrape Redis Cloud metrics: + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-cloud' + static_configs: + - targets: ['api.redislabs.com'] + metrics_path: '/v1/subscriptions/{subscription-id}/metrics' + bearer_token: '' +---- + +=== Using Native Integrations + +Redis Cloud supports native integrations with: + +* Datadog +* Prometheus +* New Relic (coming soon) + +Configure integrations in the Redis Cloud console under Observability. + +== Key Metrics for Cloud + +Focus on these metrics for Redis Cloud: + +* *Database availability* - Uptime and connectivity +* *Request rate* - Operations per second +* *Latency* - Read/write response times +* *Memory usage* - Used vs. allocated memory +* *Network throughput* - Ingress/egress traffic + +== Cloud-Specific Considerations + +=== Multi-Region Deployments + +For Active-Active databases: + +* Monitor replication lag between regions +* Track conflict resolution metrics +* Watch cross-region latency + +=== Autoscaling + +Redis Cloud can autoscale based on usage: + +* Monitor scaling events +* Track memory usage trends +* Set alerts for scale-up triggers + +=== Backup Monitoring + +Monitor backup operations: + +* Backup success/failure status +* Backup duration and size +* Point-in-time recovery availability + +== Alerting for Cloud + +Recommended alerts: + +* Database unavailability +* Memory usage > 80% +* Latency > 10ms (adjust for use case) +* Connection failures +* Backup failures + +== Troubleshooting + +=== High Latency + +. Check Redis Cloud status page +. Verify network connectivity +. Review connection pooling settings +. Check for slow commands + +=== Memory Pressure + +. Review eviction policy +. Analyze key size distribution +. Consider upgrading plan +. Enable dataset compression if applicable + +== Next Steps + +* xref:guides/alerting.adoc[Configure alerting] +* xref:reference/metrics.adoc[Metrics reference] +* xref:guides/troubleshooting.adoc[Troubleshooting guide] diff --git a/docs/modules/ROOT/pages/guides/troubleshooting.adoc b/docs/modules/ROOT/pages/guides/troubleshooting.adoc new file mode 100644 index 0000000..c717186 --- /dev/null +++ b/docs/modules/ROOT/pages/guides/troubleshooting.adoc @@ -0,0 +1,230 @@ += Troubleshooting Guide + +Common issues and solutions for Redis Enterprise monitoring. + +== Overview + +This guide helps diagnose and resolve common monitoring and observability issues. + +== No Metrics Data + +=== Symptom +Dashboards show no data or "No data" messages. + +=== Possible Causes + +==== Metrics Endpoint Not Accessible + +*Diagnosis*: +[source,bash] +---- +curl http://:8070/metrics +---- + +*Solution*: Verify firewall rules allow access to port 8070 + +==== Prometheus Not Scraping + +*Diagnosis*: +[source,bash] +---- +# Check Prometheus targets +curl http://localhost:9090/api/v1/targets +---- + +*Solution*: Verify scrape configuration in `prometheus.yml` + +==== Authentication Issues + +*Diagnosis*: Check Prometheus logs for 401/403 errors + +*Solution*: Verify credentials in scrape configuration + +== Incorrect Metric Values + +=== Symptom +Metrics show unexpected or incorrect values. + +=== Possible Causes + +==== Time Zone Issues + +*Solution*: Ensure Prometheus, Grafana, and Redis Enterprise are using consistent time zones (UTC recommended) + +==== Aggregation Issues + +*Problem*: Using sum() when avg() is appropriate + +*Solution*: Review PromQL queries and aggregation functions + +==== Unit Conversion + +*Problem*: Memory shown in bytes instead of GB + +*Solution*: Apply unit conversion in queries or dashboard panel settings + +== High Cardinality Issues + +=== Symptom +Prometheus performance degradation, high memory usage. + +=== Cause +Too many unique label combinations in metrics. + +=== Solution + +. Identify high cardinality metrics: ++ +[source,bash] +---- +promtool tsdb analyze /path/to/prometheus/data +---- + +. Review and reduce unnecessary labels +. Implement metric relabeling: ++ +[source,yaml] +---- +metric_relabel_configs: + - source_labels: [__name__] + regex: 'redis_enterprise_.*' + action: keep +---- + +== Dashboard Performance Issues + +=== Symptom +Dashboards load slowly or time out. + +=== Solutions + +==== Optimize Time Range + +* Reduce default time range +* Use shorter refresh intervals +* Implement query result caching + +==== Optimize Queries + +* Use recording rules for complex calculations +* Add rate() instead of querying raw counters +* Limit cardinality in queries + +==== Use Recording Rules + +Create recording rules for frequently used queries: + +[source,yaml] +---- +groups: +- name: redis_enterprise_recordings + interval: 30s + rules: + - record: job:redis_enterprise_ops_per_sec:rate5m + expr: rate(redis_enterprise_database_total_ops[5m]) +---- + +== Alert Fatigue + +=== Symptom +Too many alerts, reducing effectiveness. + +=== Solutions + +==== Adjust Thresholds + +* Review historical data to set realistic thresholds +* Implement dynamic thresholds based on patterns + +==== Add Alert Conditions + +Use `for:` clause to require sustained conditions: + +[source,yaml] +---- +- alert: HighMemory + expr: memory_usage > 80 + for: 10m # Alert only if high for 10 minutes +---- + +==== Implement Alert Grouping + +Group related alerts to reduce notification volume: + +[source,yaml] +---- +group_by: ['cluster', 'alertname'] +group_wait: 30s +group_interval: 5m +---- + +== Redis Cloud Specific Issues + +=== API Rate Limiting + +*Symptom*: 429 errors from Redis Cloud API + +*Solution*: +* Increase scrape interval +* Implement exponential backoff +* Contact Redis support for rate limit increase + +=== SSL/TLS Certificate Issues + +*Symptom*: Certificate validation errors + +*Solution*: +[source,yaml] +---- +tls_config: + insecure_skip_verify: false # Set true only for testing + ca_file: /path/to/ca.crt +---- + +== Data Retention Issues + +=== Symptom +Historical data missing or incomplete. + +=== Solutions + +==== Increase Prometheus Retention + +[source,bash] +---- +prometheus \ + --storage.tsdb.retention.time=90d \ + --storage.tsdb.retention.size=100GB +---- + +==== Implement Downsampling + +Use recording rules to create downsampled metrics for long-term storage. + +==== Configure Remote Storage + +Forward metrics to long-term storage: + +[source,yaml] +---- +remote_write: + - url: "https://long-term-storage.example.com/api/v1/write" +---- + +== Getting Help + +If issues persist: + +. Check Redis Enterprise logs +. Review platform-specific documentation +. Contact Redis support with: + * Cluster version and configuration + * Metrics endpoint samples + * Platform details (Prometheus/Grafana versions) + * Error messages and logs + +== Next Steps + +* xref:guides/alerting.adoc[Alerting guide] +* xref:reference/metrics.adoc[Metrics reference] +* xref:platforms/prometheus.adoc[Prometheus configuration] diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc new file mode 100644 index 0000000..4685004 --- /dev/null +++ b/docs/modules/ROOT/pages/index.adoc @@ -0,0 +1,41 @@ += Redis Enterprise Observability + +Monitor and observe your Redis Enterprise deployments with pre-built dashboards and integrations for popular observability platforms. + +== Overview + +This project provides comprehensive monitoring solutions for Redis Enterprise, including: + +* Pre-configured dashboards for multiple platforms +* Metrics exporters and collectors +* Alert definitions and templates +* Integration guides for popular observability tools + +IMPORTANT: This documentation focuses on our v2 dashboards and configurations, which feature improved metrics, better visualizations, and enhanced alert rules. V2 is recommended for all deployments. Legacy v1 resources are available in the xref:dashboards/catalog.adoc#legacy-dashboards[Dashboard Catalog]. + +== Supported Platforms + +* xref:platforms/grafana.adoc[Grafana] - Visualization and analytics +* xref:platforms/prometheus.adoc[Prometheus] - Metrics collection and storage +* xref:platforms/dynatrace.adoc[Dynatrace] - Full-stack monitoring +* xref:platforms/newrelic.adoc[New Relic] - Application performance monitoring +* xref:platforms/splunk.adoc[Splunk] - Log analytics and SIEM +* xref:platforms/kibana.adoc[Kibana] - Elasticsearch visualization + +== Getting Started + +Ready to start monitoring? Check out the xref:quick-start.adoc[Quick Start Guide] to get up and running in 5 minutes. + +== Key Features + +* *Pre-built Dashboards* - Import ready-to-use dashboards for your platform +* *Comprehensive Metrics* - Monitor cluster health, performance, and capacity +* *Flexible Integration* - Works with Redis Enterprise Cloud and self-hosted deployments +* *Alert Templates* - Get notified of issues before they impact users +* *Best Practices* - Built on Redis engineering expertise + +== Resources + +* xref:dashboards/catalog.adoc[Dashboard Catalog] +* xref:guides/monitoring-redis-cloud.adoc[Monitoring Redis Cloud] +* xref:reference/metrics.adoc[Metrics Reference] diff --git a/docs/modules/ROOT/pages/platforms/dynatrace.adoc b/docs/modules/ROOT/pages/platforms/dynatrace.adoc new file mode 100644 index 0000000..8aa4cf8 --- /dev/null +++ b/docs/modules/ROOT/pages/platforms/dynatrace.adoc @@ -0,0 +1,76 @@ += Dynatrace Integration + +Full-stack monitoring of Redis Enterprise with Dynatrace. + +== Overview + +Dynatrace provides automated, AI-powered monitoring for Redis Enterprise deployments. + +NOTE: This guide uses v2 dashboards (Generation 3), which are recommended for all deployments. For legacy v1 dashboards, see the xref:dashboards/catalog.adoc#legacy-dashboards[Legacy Dashboards] section in the catalog. + +== Prerequisites + +* Dynatrace account (SaaS or Managed) +* Dynatrace OneAgent or ActiveGate +* API token with metrics ingestion permissions + +== Installation + +=== Using Dynatrace OneAgent + +The OneAgent automatically discovers and monitors Redis Enterprise processes when installed on the same host. + +. Install OneAgent on Redis Enterprise nodes +. OneAgent will automatically detect Redis processes +. Metrics will appear in Dynatrace within minutes + +=== Using Prometheus Integration + +For containerized or remote deployments: + +. Configure Prometheus to scrape Redis Enterprise +. Set up Dynatrace Prometheus integration +. Configure metrics ingestion + +== Example Configurations + +=== Production-Ready Templates + +Complete extension and dashboard files are available in the GitHub repository: + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/dynatrace_v2[Dynatrace Extension^] +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/dynatrace_v2/src/extension.yaml[extension.yaml^] - Complete metric definitions (1700+ lines) +*** Defines all Redis Enterprise v2 metrics +*** Includes metric metadata, units, and descriptions +*** Organized by category: cluster, node, endpoint, shard, replication, Active-Active +** https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/dynatrace_v2/src/dashboards[Dashboard Templates^] - Pre-built dashboards + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/dynatrace[Legacy v1 Extension^] - For older Redis Enterprise versions + +TIP: The extension.yaml file provides a complete catalog of available metrics. Review it to understand which metrics to monitor and customize for your environment. + +== Dashboard Configuration + +Import the Redis Enterprise dashboard template: + +. Navigate to Dashboards in Dynatrace +. Click "Import Dashboard" +. Upload the JSON template from this repository +. Configure data source mapping + +== Alerting + +Dynatrace provides AI-powered anomaly detection for Redis Enterprise metrics. + +Recommended alert configurations: + +* Memory usage anomalies +* Connection spikes +* Replication lag +* Database unavailability + +== Next Steps + +* xref:dashboards/catalog.adoc[View dashboard catalog] +* xref:guides/alerting.adoc[Configure alerts] +* xref:reference/metrics.adoc[Metrics reference] diff --git a/docs/modules/ROOT/pages/platforms/grafana.adoc b/docs/modules/ROOT/pages/platforms/grafana.adoc new file mode 100644 index 0000000..dff5d9d --- /dev/null +++ b/docs/modules/ROOT/pages/platforms/grafana.adoc @@ -0,0 +1,409 @@ += Grafana Integration + +Monitor Redis Enterprise with Grafana dashboards and Prometheus data sources. + +== Overview + +Grafana provides powerful visualization capabilities for Redis Enterprise metrics. This integration uses Prometheus as the data source. + +NOTE: This guide uses v2 dashboards, which are recommended for all deployments. If you need legacy v1 dashboards, see the xref:dashboards/catalog.adoc#legacy-dashboards[Legacy Dashboards] section in the catalog. + +== Prerequisites + +* Grafana instance (v8.0 or later recommended) +* Prometheus configured to scrape Redis Enterprise metrics +* Access to import dashboards in Grafana + +== Installation + +=== Step 1: Configure Prometheus Data Source + +==== Via Grafana UI + +. Log in to your Grafana instance +. Navigate to Configuration > Data Sources +. Click "Add data source" +. Select "Prometheus" +. Configure the data source: + * *Name*: `Redis-Enterprise-Prometheus` + * *URL*: `http://prometheus:9090` (or your Prometheus URL) + * *Access*: `Server` (recommended) or `Browser` +. Click "Save & Test" + +==== Via Configuration File + +Create or edit `/etc/grafana/provisioning/datasources/prometheus.yml`: + +[source,yaml] +---- +apiVersion: 1 + +datasources: + - name: Redis-Enterprise-Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + jsonData: + timeInterval: 30s + queryTimeout: 60s + httpMethod: POST + editable: false +---- + +==== Via Docker Compose + +[source,yaml] +---- +version: '3.8' + +services: + grafana: + image: grafana/grafana:latest + ports: + - "3000:3000" + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin + - GF_USERS_ALLOW_SIGN_UP=false + volumes: + - grafana-data:/var/lib/grafana + - ./provisioning:/etc/grafana/provisioning + depends_on: + - prometheus + + prometheus: + image: prom/prometheus:latest + ports: + - "9090:9090" + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + - prometheus-data:/prometheus + +volumes: + grafana-data: + prometheus-data: +---- + +=== Step 2: Import Dashboards + +==== Manual Import via UI + +. Navigate to Dashboards > Import (or press `d` then `i`) +. Upload the dashboard JSON file from this repository +. Configure the dashboard: + * Select your Prometheus data source + * Set a unique ID (or leave blank for auto-generation) + * Choose a folder +. Click "Import" + +==== Programmatic Import via API + +[source,bash] +---- +# Set Grafana credentials +GRAFANA_URL="http://localhost:3000" +GRAFANA_USER="admin" +GRAFANA_PASSWORD="admin" + +# Import dashboard +curl -X POST "$GRAFANA_URL/api/dashboards/db" \ + -H "Content-Type: application/json" \ + -u "$GRAFANA_USER:$GRAFANA_PASSWORD" \ + -d @redis-enterprise-cluster-overview.json +---- + +==== Provisioning Dashboards + +Create `/etc/grafana/provisioning/dashboards/redis-enterprise.yml`: + +[source,yaml] +---- +apiVersion: 1 + +providers: + - name: 'Redis Enterprise' + orgId: 1 + folder: 'Redis Enterprise' + type: file + disableDeletion: false + updateIntervalSeconds: 30 + allowUiUpdates: true + options: + path: /var/lib/grafana/dashboards/redis-enterprise +---- + +Place dashboard JSON files in `/var/lib/grafana/dashboards/redis-enterprise/`. + +== Example Configurations + +=== Production-Ready Templates + +Complete dashboard and configuration files are available in the GitHub repository: + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/grafana_v2[Grafana Dashboards^] - Full JSON dashboard definitions +** Cluster overview dashboards +** Database performance dashboards +** Node monitoring dashboards +** Active-Active replication dashboards + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/grafana_v2/demo_v2[Complete Demo Environment^] - Working docker-compose setup +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/grafana_v2/demo_v2/docker-compose.yml[docker-compose.yml^] - Full stack (Prometheus + Grafana + Redis) +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/grafana_v2/demo_v2/prometheus.yml[prometheus.yml^] - Pre-configured scrape settings + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/grafana_v2/kickstart_v2[Kickstart Environment^] - Quick production setup + +TIP: Import the complete dashboard JSON files directly into Grafana rather than recreating panels manually. All dashboards include pre-configured variables and alert templates. + +== Available Dashboards + +See the xref:dashboards/catalog.adoc[Dashboard Catalog] for the complete list of Grafana dashboards. + +== Configuration + +=== Dashboard Variables + +Most dashboards include template variables for dynamic filtering. + +==== Creating Variables + +Example variable configuration for cluster selection: + +[source,text] +---- +Name: cluster +Label: Cluster +Type: Query +Data source: Redis-Enterprise-Prometheus +Query: label_values(redis_enterprise_cluster_health, cluster) +Regex: .* +Multi-value: true +Include All option: true +---- + +Example variable for database selection: + +[source,text] +---- +Name: database +Label: Database +Type: Query +Data source: Redis-Enterprise-Prometheus +Query: label_values(redis_enterprise_database_up{cluster="$cluster"}, database) +Refresh: On Dashboard Load +Multi-value: true +Include All option: true +---- + +==== Using Variables in Queries + +Use variables in your panel queries: + +[source,promql] +---- +# Filter by selected cluster and database +redis_enterprise_database_ops_per_sec{cluster="$cluster", database="$database"} + +# Multi-value variable example +redis_enterprise_database_ops_per_sec{cluster=~"$cluster", database=~"$database"} + +# With regex +redis_enterprise_database_ops_per_sec{cluster=~"$cluster", database=~"$database|prod-.*"} +---- + +=== Panel Configuration Examples + +==== Operations Per Second Graph + +[source,json] +---- +{ + "title": "Operations Per Second", + "targets": [ + { + "expr": "rate(redis_enterprise_database_total_ops{cluster=\"$cluster\", database=\"$database\"}[5m])", + "legendFormat": "{{database}} - {{cluster}}", + "refId": "A" + } + ], + "type": "timeseries", + "options": { + "legend": { + "calcs": ["mean", "max", "last"], + "displayMode": "table" + } + } +} +---- + +==== Memory Usage Gauge + +[source,json] +---- +{ + "title": "Memory Usage", + "targets": [ + { + "expr": "(redis_enterprise_database_used_memory{cluster=\"$cluster\", database=\"$database\"} / redis_enterprise_database_memory_limit{cluster=\"$cluster\", database=\"$database\"}) * 100", + "refId": "A" + } + ], + "type": "gauge", + "options": { + "reduceOptions": { + "values": false, + "calcs": ["lastNotNull"] + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { "value": 0, "color": "green" }, + { "value": 80, "color": "yellow" }, + { "value": 90, "color": "red" } + ] + } + } +} +---- + +==== Stat Panel for Database Count + +[source,json] +---- +{ + "title": "Active Databases", + "targets": [ + { + "expr": "count(redis_enterprise_database_up{cluster=\"$cluster\"} == 1)", + "refId": "A" + } + ], + "type": "stat", + "options": { + "colorMode": "value", + "graphMode": "area", + "orientation": "auto" + } +} +---- + +=== Alerting Configuration + +==== Create Alert Rule via UI + +. Open a dashboard panel +. Click the panel title > Edit +. Go to the Alert tab +. Click "Create Alert" +. Configure alert conditions: + +[source,text] +---- +Alert Name: High Memory Usage +Evaluate every: 1m +For: 5m + +Conditions: +WHEN avg() OF query(A, 5m, now) IS ABOVE 90 + +Query A: +(redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) * 100 +---- + +==== Alert via Configuration + +[source,yaml] +---- +# /etc/grafana/provisioning/alerting/redis-enterprise.yml +apiVersion: 1 + +groups: + - name: redis-enterprise-alerts + folder: Redis Enterprise + interval: 1m + rules: + - uid: redis-high-memory + title: Redis Enterprise High Memory Usage + condition: A + data: + - refId: A + queryType: prometheus + relativeTimeRange: + from: 300 + to: 0 + datasourceUid: redis-prometheus + model: + expr: (redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) * 100 > 90 + intervalMs: 1000 + maxDataPoints: 43200 + noDataState: NoData + execErrState: Error + for: 5m + annotations: + description: "Database {{ $labels.database }} memory usage is {{ $value }}%" + labels: + severity: warning +---- + +=== Notification Channels + +Configure notification channels in `/etc/grafana/provisioning/notifiers/slack.yml`: + +[source,yaml] +---- +apiVersion: 1 + +notifiers: + - name: redis-alerts-slack + type: slack + uid: slack-redis + org_id: 1 + is_default: false + send_reminder: true + frequency: 4h + settings: + url: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK + recipient: '#redis-alerts' + username: Grafana +---- + +=== Refresh Intervals + +Configure refresh intervals based on use case: + +[source,json] +---- +{ + "refresh": "30s", // For production monitoring + "time": { + "from": "now-6h", + "to": "now" + } +} +---- + +Recommended intervals: + +* *Production monitoring*: `30s` - `1m` +* *Development*: `1m` - `5m` +* *Historical analysis*: `false` (disable auto-refresh) +* *Troubleshooting*: `10s` - `30s` + +== Troubleshooting + +=== No Data Displayed + +* Verify Prometheus is scraping Redis Enterprise metrics +* Check data source configuration +* Ensure time range includes recent data + +=== Missing Metrics + +* Confirm Redis Enterprise exporter is running +* Check Prometheus scrape configuration +* Verify metrics endpoint is accessible + +== Next Steps + +* xref:guides/alerting.adoc[Configure Grafana alerts] +* xref:dashboards/catalog.adoc[Explore dashboard catalog] +* xref:reference/metrics.adoc[Review metrics reference] diff --git a/docs/modules/ROOT/pages/platforms/kibana.adoc b/docs/modules/ROOT/pages/platforms/kibana.adoc new file mode 100644 index 0000000..f8f38a5 --- /dev/null +++ b/docs/modules/ROOT/pages/platforms/kibana.adoc @@ -0,0 +1,68 @@ += Kibana Integration + +Visualize Redis Enterprise metrics with Kibana and the Elastic Stack. + +== Overview + +Kibana provides visualization capabilities for Redis Enterprise metrics stored in Elasticsearch. + +== Prerequisites + +* Elasticsearch cluster +* Kibana instance (matching Elasticsearch version) +* Metricbeat or Logstash for metrics ingestion + +== Installation + +=== Using Metricbeat + +Configure Metricbeat to collect Prometheus metrics: + +[source,yaml] +---- +metricbeat.modules: +- module: prometheus + period: 30s + hosts: [":8070"] + metrics_path: /metrics +---- + +=== Using Logstash + +Configure Logstash with Prometheus input plugin: + +[source,ruby] +---- +input { + prometheus { + url => "http://:8070/metrics" + } +} +---- + +== Dashboard Import + +. Navigate to Management > Stack Management > Saved Objects +. Click "Import" +. Upload the NDJSON file from this repository +. Configure index pattern + +== Index Patterns + +Create index patterns for Redis Enterprise metrics: + +* Pattern: `metricbeat-*` or `redis-enterprise-metrics-*` +* Time field: `@timestamp` + +== Visualization Examples + +* Line charts for operations per second +* Gauge for memory usage percentage +* Heat maps for request latency +* Tables for database statistics + +== Next Steps + +* xref:dashboards/catalog.adoc[Dashboard catalog] +* xref:guides/alerting.adoc[Configure alerting] +* xref:reference/metrics.adoc[Metrics reference] diff --git a/docs/modules/ROOT/pages/platforms/newrelic.adoc b/docs/modules/ROOT/pages/platforms/newrelic.adoc new file mode 100644 index 0000000..21faa92 --- /dev/null +++ b/docs/modules/ROOT/pages/platforms/newrelic.adoc @@ -0,0 +1,391 @@ += New Relic Integration + +Monitor Redis Enterprise with New Relic's application performance monitoring platform. + +== Overview + +New Relic provides comprehensive monitoring and alerting for Redis Enterprise clusters. + +NOTE: This guide uses v2 dashboards and configurations, which are recommended for all deployments. For legacy v1 resources, see the xref:dashboards/catalog.adoc#legacy-dashboards[Legacy Dashboards] section in the catalog. + +== Prerequisites + +* New Relic account +* New Relic Infrastructure agent or Prometheus integration +* License key from New Relic + +== Installation Options + +=== Option 1: New Relic Infrastructure Agent + +==== Install Infrastructure Agent + +[source,bash] +---- +# Add New Relic repository (Ubuntu/Debian) +curl -s https://download.newrelic.com/infrastructure_agent/gpg/newrelic-infra.gpg | sudo apt-key add - +sudo printf "deb https://download.newrelic.com/infrastructure_agent/linux/apt focal main" | sudo tee /etc/apt/sources.list.d/newrelic-infra.list + +# Install agent +sudo apt-get update +sudo apt-get install newrelic-infra -y + +# Configure with license key +echo "license_key: YOUR_LICENSE_KEY" | sudo tee /etc/newrelic-infra.yml +sudo systemctl restart newrelic-infra +---- + +==== Configure Prometheus Integration + +Create `/etc/newrelic-infra/integrations.d/prometheus-config.yml`: + +[source,yaml] +---- +integrations: + - name: nri-prometheus + config: + # Redis Enterprise metrics endpoint + standalone_urls: + - http://redis-cluster.example.com:8070/metrics + + # Scrape interval + scrape_duration: "30s" + + # Optional: Add custom labels + transformations: + - description: "Add cluster label" + add_attributes: + - cluster: "production" + + # Optional: Filter metrics + emitters: + - prometheus + + verbose: false + audit: false +---- + +=== Option 2: Prometheus Remote Write + +Configure Prometheus to forward metrics to New Relic: + +[source,yaml] +---- +# In prometheus.yml +global: + external_labels: + cluster: 'production' + environment: 'prod' + +remote_write: + - url: https://metric-api.newrelic.com/prometheus/v1/write?prometheus_server=redis-enterprise-prod + bearer_token: YOUR_NEW_RELIC_LICENSE_KEY + + # Queue configuration for reliability + queue_config: + capacity: 10000 + max_shards: 50 + max_samples_per_send: 5000 + batch_send_deadline: 5s + max_retries: 3 + min_backoff: 30ms + max_backoff: 100ms + + # Optional: Filter what to send + write_relabel_configs: + # Only send Redis Enterprise metrics + - source_labels: [__name__] + regex: 'redis_enterprise_.*' + action: keep +---- + +=== Option 3: New Relic Kubernetes Integration + +For Redis Enterprise on Kubernetes: + +[source,yaml] +---- +apiVersion: v1 +kind: ConfigMap +metadata: + name: nri-prometheus-config + namespace: newrelic +data: + config.yaml: | + cluster_name: "redis-k8s-cluster" + audit: false + scrape_enabled_label: "prometheus.io/scrape" + + transformations: + - description: "General processing rules" + add_attributes: + - environment: "production" + + targets: + - description: "Redis Enterprise pods" + urls: + - "http://redis-enterprise-cluster:8070/metrics" + interval: 30s +---- + +== Example Configurations + +=== Production-Ready Templates + +Complete configuration files are available in the GitHub repository: + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/newrelic_v2[New Relic Configurations^] +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/newrelic_v2/config/prometheus.yml[prometheus.yml^] - Prometheus remote write template +** https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/newrelic_v2/kickstarter[Kickstarter Scripts^] - Automated deployment tools +** https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/newrelic_v2/kickstarter/terraform[Terraform Modules^] - AWS and GCP deployment examples + +* Dashboard JSON files for import into New Relic One + +TIP: The Prometheus configuration template includes placeholder comments showing exactly where to add your cluster hostname and New Relic bearer token. + +== Dashboard Import + +. Navigate to Dashboards in New Relic One +. Click "Import dashboard" +. Upload the JSON file from this repository +. Configure data source and account + +== Querying Metrics + +=== NRQL Query Examples + +Use NRQL (New Relic Query Language) to query Redis Enterprise metrics: + +[source,sql] +---- +-- Operations per second by database +SELECT average(redis_enterprise_database_ops_per_sec) +FROM Metric +WHERE cluster = 'production' +FACET database +TIMESERIES AUTO + +-- Memory usage percentage +SELECT (average(redis_enterprise_database_used_memory) / + average(redis_enterprise_database_memory_limit)) * 100 +AS 'Memory Usage %' +FROM Metric +WHERE cluster = 'production' +FACET database +TIMESERIES AUTO + +-- Database availability +SELECT sum(redis_enterprise_database_up) +FROM Metric +WHERE cluster = 'production' +FACET database +TIMESERIES AUTO + +-- Top 5 databases by operations +SELECT average(redis_enterprise_database_ops_per_sec) AS 'Ops/Sec' +FROM Metric +WHERE cluster = 'production' +FACET database +LIMIT 5 + +-- Connection count over time +SELECT average(redis_enterprise_database_connections) +FROM Metric +WHERE cluster = 'production' AND database = 'prod-cache' +TIMESERIES AUTO + +-- P99 Latency trend +SELECT percentile(redis_enterprise_database_latency, 99) AS 'P99 Latency' +FROM Metric +WHERE cluster = 'production' +FACET database +TIMESERIES 5 minutes +---- + +=== Creating Custom Dashboards + +Example dashboard configuration via API: + +[source,bash] +---- +# Create dashboard via New Relic API +curl -X POST 'https://api.newrelic.com/graphql' \ + -H 'Api-Key: YOUR_USER_API_KEY' \ + -H 'Content-Type: application/json' \ + -d '{ + "query": "mutation { + dashboardCreate( + accountId: YOUR_ACCOUNT_ID, + dashboard: { + name: \"Redis Enterprise Monitoring\", + permissions: PRIVATE, + pages: [{ + name: \"Overview\", + widgets: [{ + title: \"Operations Per Second\", + visualization: { + id: \"viz.line\" + }, + rawConfiguration: { + nrqlQueries: [{ + accountId: YOUR_ACCOUNT_ID, + query: \"SELECT average(redis_enterprise_database_ops_per_sec) FROM Metric FACET database TIMESERIES\" + }] + } + }] + }] + } + ) { + entityResult { + guid + } + } + }" + }' +---- + +== Alerting + +=== Create Alert Policies via UI + +. Navigate to Alerts & AI > Alert Policies +. Click "New alert policy" +. Name: "Redis Enterprise Monitoring" +. Configure alert conditions + +=== NRQL Alert Conditions + +==== High Memory Usage Alert + +[source,sql] +---- +-- Alert when memory usage > 90% +SELECT (average(redis_enterprise_database_used_memory) / + average(redis_enterprise_database_memory_limit)) * 100 +FROM Metric +WHERE cluster = 'production' +FACET database + +-- Threshold: Above 90 for at least 5 minutes +-- Severity: Critical +---- + +==== Database Down Alert + +[source,sql] +---- +-- Alert when database is down +SELECT sum(redis_enterprise_database_up) +FROM Metric +WHERE cluster = 'production' +FACET database + +-- Threshold: Equal to 0 for at least 1 minute +-- Severity: Critical +---- + +==== High Latency Alert + +[source,sql] +---- +-- Alert when P99 latency exceeds threshold +SELECT percentile(redis_enterprise_database_latency, 99) +FROM Metric +WHERE cluster = 'production' +FACET database + +-- Threshold: Above 0.1 (100ms) for at least 5 minutes +-- Severity: Warning +---- + +=== Alert Configuration via Terraform + +[source,hcl] +---- +# Configure New Relic alerts with Terraform +resource "newrelic_alert_policy" "redis_enterprise" { + name = "Redis Enterprise Monitoring" +} + +resource "newrelic_nrql_alert_condition" "high_memory" { + account_id = var.newrelic_account_id + policy_id = newrelic_alert_policy.redis_enterprise.id + type = "static" + name = "Redis Enterprise High Memory Usage" + description = "Alert when database memory usage exceeds 90%" + enabled = true + violation_time_limit_seconds = 259200 + + nrql { + query = <<-EOT + SELECT (average(redis_enterprise_database_used_memory) / + average(redis_enterprise_database_memory_limit)) * 100 + FROM Metric + WHERE cluster = 'production' + FACET database + EOT + } + + critical { + operator = "above" + threshold = 90 + threshold_duration = 300 + threshold_occurrences = "all" + } + + warning { + operator = "above" + threshold = 80 + threshold_duration = 600 + threshold_occurrences = "all" + } +} + +resource "newrelic_nrql_alert_condition" "database_down" { + account_id = var.newrelic_account_id + policy_id = newrelic_alert_policy.redis_enterprise.id + type = "static" + name = "Redis Enterprise Database Down" + description = "Alert when database is unavailable" + enabled = true + + nrql { + query = <<-EOT + SELECT sum(redis_enterprise_database_up) + FROM Metric + WHERE cluster = 'production' + FACET database + EOT + } + + critical { + operator = "equals" + threshold = 0 + threshold_duration = 60 + threshold_occurrences = "all" + } +} + +# Notification channel +resource "newrelic_notification_channel" "slack" { + name = "Redis Alerts Slack" + type = "slack" + + config { + url = var.slack_webhook_url + channel = "#redis-alerts" + } +} + +# Link policy to channel +resource "newrelic_alert_policy_channel" "redis_slack" { + policy_id = newrelic_alert_policy.redis_enterprise.id + channel_id = newrelic_notification_channel.slack.id +} +---- + +== Next Steps + +* xref:dashboards/catalog.adoc[Dashboard catalog] +* xref:guides/alerting.adoc[Alert configuration] +* xref:reference/metrics.adoc[Metrics reference] diff --git a/docs/modules/ROOT/pages/platforms/prometheus.adoc b/docs/modules/ROOT/pages/platforms/prometheus.adoc new file mode 100644 index 0000000..bd63a83 --- /dev/null +++ b/docs/modules/ROOT/pages/platforms/prometheus.adoc @@ -0,0 +1,381 @@ += Prometheus Integration + +Collect and store Redis Enterprise metrics with Prometheus. + +== Overview + +Prometheus scrapes metrics from Redis Enterprise and stores them as time-series data for querying and visualization. + +NOTE: This guide references v2 alert rules and configurations, which are recommended for all deployments. For legacy v1 configurations, see the xref:dashboards/catalog.adoc#legacy-dashboards[Legacy Dashboards] section in the catalog. + +== Prerequisites + +* Prometheus server (v2.30 or later recommended) +* Network access to Redis Enterprise cluster +* Redis Enterprise metrics endpoint enabled + +== Configuration + +=== Basic Scrape Configuration + +Add the following to your `prometheus.yml`: + +[source,yaml] +---- +global: + scrape_interval: 30s + evaluation_interval: 30s + +scrape_configs: + - job_name: 'redis-enterprise' + static_configs: + - targets: ['redis-cluster-1.example.com:8070'] + metrics_path: '/metrics' + scrape_interval: 30s + scrape_timeout: 10s +---- + +=== Multiple Cluster Monitoring + +Monitor multiple Redis Enterprise clusters: + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise-prod' + static_configs: + - targets: + - 'redis-prod-1.example.com:8070' + - 'redis-prod-2.example.com:8070' + - 'redis-prod-3.example.com:8070' + relabel_configs: + - source_labels: [__address__] + target_label: cluster + replacement: 'production' + + - job_name: 'redis-enterprise-staging' + static_configs: + - targets: + - 'redis-staging-1.example.com:8070' + relabel_configs: + - source_labels: [__address__] + target_label: cluster + replacement: 'staging' +---- + +=== Authentication + +If your Redis Enterprise cluster requires authentication: + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise' + static_configs: + - targets: ['redis-cluster.example.com:8070'] + basic_auth: + username: 'prometheus' + password: 'secure-password' + # Or use password file for better security + # basic_auth: + # username: 'prometheus' + # password_file: /etc/prometheus/redis-password.txt +---- + +=== TLS/SSL Configuration + +For secure connections: + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise-secure' + scheme: https + static_configs: + - targets: ['redis-cluster.example.com:8070'] + tls_config: + ca_file: /etc/prometheus/certs/ca.crt + cert_file: /etc/prometheus/certs/client.crt + key_file: /etc/prometheus/certs/client.key + insecure_skip_verify: false + basic_auth: + username: 'prometheus' + password_file: /etc/prometheus/redis-password.txt +---- + +=== Service Discovery (Kubernetes) + +For Redis Enterprise on Kubernetes: + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise-k8s' + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - redis-enterprise + relabel_configs: + # Keep only Redis Enterprise pods + - source_labels: [__meta_kubernetes_pod_label_app] + action: keep + regex: redis-enterprise + # Use pod name as instance label + - source_labels: [__meta_kubernetes_pod_name] + target_label: instance + # Add namespace label + - source_labels: [__meta_kubernetes_namespace] + target_label: namespace +---- + +=== Service Discovery (Consul) + +For Consul-based discovery: + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise-consul' + consul_sd_configs: + - server: 'consul.example.com:8500' + services: ['redis-enterprise'] + relabel_configs: + - source_labels: [__meta_consul_service_metadata_cluster] + target_label: cluster +---- + +== Example Configurations + +=== Production-Ready Templates + +Complete, tested configuration files are available in the GitHub repository: + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/prometheus_v2/rules[Alert Rules^] - Production-ready alert definitions +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/prometheus_v2/rules/alerts.yml[alerts.yml^] - Comprehensive alert suite +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/prometheus_v2/rules/capacity-alerts.yml[capacity-alerts.yml^] - Capacity monitoring +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/prometheus_v2/rules/latency-alerts.yml[latency-alerts.yml^] - Latency thresholds +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/prometheus_v2/rules/connection-alerts.yml[connection-alerts.yml^] - Connection monitoring +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/prometheus_v2/rules/node-alerts.yml[node-alerts.yml^] - Node health alerts +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/prometheus_v2/rules/shard-alerts.yml[shard-alerts.yml^] - Shard monitoring + +* https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/grafana_v2/demo_v2/prometheus.yml[Complete Prometheus Configuration^] - Working example with v1 and v2 endpoints + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/prometheus_v2/tests[Alert Test Files^] - Validation tests for each alert rule + +TIP: Download and customize these files for your environment rather than starting from scratch. Each alert includes recommended thresholds and runbook URLs. + +== Available Metrics + +Redis Enterprise exposes comprehensive metrics including: + +* Cluster health and status +* Database operations and performance +* Node resource utilization +* Network traffic and connections +* Replication lag and status + +See the xref:reference/metrics.adoc[Metrics Reference] for complete documentation. + +== Verification + +=== Check Targets Status + +Verify Prometheus is scraping Redis Enterprise: + +[source,bash] +---- +# Check targets via API +curl http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.labels.job=="redis-enterprise")' + +# Or check in Prometheus UI +# Navigate to: http://localhost:9090/targets +---- + +Expected output: +[source,json] +---- +{ + "discoveredLabels": {...}, + "labels": { + "instance": "redis-cluster.example.com:8070", + "job": "redis-enterprise" + }, + "scrapePool": "redis-enterprise", + "scrapeUrl": "http://redis-cluster.example.com:8070/metrics", + "lastError": "", + "lastScrape": "2024-01-15T10:30:45.123Z", + "lastScrapeDuration": 0.045, + "health": "up" +} +---- + +=== Query Sample Metrics + +Test that metrics are being collected: + +[source,bash] +---- +# Check if Redis Enterprise is up +curl -g 'http://localhost:9090/api/v1/query?query=redis_enterprise_database_up' | jq + +# Check database operations per second +curl -g 'http://localhost:9090/api/v1/query?query=redis_enterprise_database_ops_per_sec' | jq + +# Check memory usage +curl -g 'http://localhost:9090/api/v1/query?query=redis_enterprise_database_used_memory' | jq +---- + +=== Test with PromQL + +Use Prometheus query language to verify data: + +[source,promql] +---- +# Show all Redis Enterprise databases +redis_enterprise_database_up + +# Calculate operations per second (5min average) +rate(redis_enterprise_database_total_ops[5m]) + +# Memory usage percentage +(redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) * 100 + +# Top 5 databases by ops +topk(5, rate(redis_enterprise_database_total_ops[5m])) +---- + +== Recording Rules + +Create recording rules for frequently-used queries to improve performance: + +[source,yaml] +---- +groups: + - name: redis_enterprise_recordings + interval: 30s + rules: + # Pre-calculate ops per second + - record: redis_enterprise:database:ops_per_sec:rate5m + expr: rate(redis_enterprise_database_total_ops[5m]) + labels: + job: redis-enterprise + + # Pre-calculate memory usage percentage + - record: redis_enterprise:database:memory_usage_pct + expr: | + (redis_enterprise_database_used_memory / + redis_enterprise_database_memory_limit) * 100 + + # Pre-calculate hit rate + - record: redis_enterprise:database:hit_rate:rate5m + expr: | + rate(redis_enterprise_database_keyspace_hits[5m]) / + (rate(redis_enterprise_database_keyspace_hits[5m]) + + rate(redis_enterprise_database_keyspace_misses[5m])) + + # Pre-calculate eviction rate + - record: redis_enterprise:database:evictions_per_sec:rate5m + expr: rate(redis_enterprise_database_evicted_keys[5m]) + + # Aggregate cluster-wide operations + - record: redis_enterprise:cluster:total_ops:rate5m + expr: sum(rate(redis_enterprise_database_total_ops[5m])) by (cluster) +---- + +Save this to `/etc/prometheus/rules/redis-enterprise.yml` and reference it in `prometheus.yml`: + +[source,yaml] +---- +rule_files: + - /etc/prometheus/rules/redis-enterprise.yml +---- + +== Retention and Storage + +Configure appropriate retention for Redis Enterprise metrics: + +[source,yaml] +---- +# In docker-compose.yml +services: + prometheus: + image: prom/prometheus:latest + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--storage.tsdb.retention.time=90d' + - '--storage.tsdb.retention.size=50GB' + - '--web.enable-lifecycle' + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + - prometheus-data:/prometheus +---- + +Or via command line: + +[source,bash] +---- +prometheus \ + --config.file=/etc/prometheus/prometheus.yml \ + --storage.tsdb.path=/var/lib/prometheus \ + --storage.tsdb.retention.time=90d \ + --storage.tsdb.retention.size=50GB \ + --web.enable-lifecycle +---- + +== Troubleshooting + +=== Target Down + +If targets show as "DOWN": + +[source,bash] +---- +# Test connectivity +curl http://redis-cluster.example.com:8070/metrics + +# Check Prometheus logs +docker logs prometheus | grep redis-enterprise + +# Verify authentication +curl -u prometheus:password http://redis-cluster.example.com:8070/metrics +---- + +=== Missing Metrics + +If expected metrics are missing: + +[source,bash] +---- +# List all available metrics +curl http://redis-cluster.example.com:8070/metrics | grep redis_enterprise + +# Check metric cardinality +curl http://localhost:9090/api/v1/label/__name__/values | jq '.data[] | select(startswith("redis_enterprise"))' +---- + +=== High Memory Usage + +If Prometheus uses too much memory: + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise' + # ... other config ... + metric_relabel_configs: + # Keep only essential metrics + - source_labels: [__name__] + regex: 'redis_enterprise_(database|cluster|node)_.*' + action: keep + # Drop high-cardinality labels + - regex: 'instance_id' + action: labeldrop +---- + +== Next Steps + +* xref:platforms/grafana.adoc[Set up Grafana visualization] +* xref:guides/alerting.adoc[Configure Prometheus alerts] +* xref:reference/metrics.adoc[Explore available metrics] diff --git a/docs/modules/ROOT/pages/platforms/splunk.adoc b/docs/modules/ROOT/pages/platforms/splunk.adoc new file mode 100644 index 0000000..a65b215 --- /dev/null +++ b/docs/modules/ROOT/pages/platforms/splunk.adoc @@ -0,0 +1,88 @@ += Splunk Integration + +Monitor Redis Enterprise metrics and logs with Splunk. + +== Overview + +Splunk provides enterprise-grade analytics for Redis Enterprise observability data. + +== Prerequisites + +* Splunk Enterprise or Splunk Cloud +* HTTP Event Collector (HEC) token +* Network access between Prometheus/Telegraf and Splunk + +== Installation + +=== Using Splunk Prometheus Integration + +. Install the Prometheus integration app in Splunk +. Configure Prometheus to forward metrics +. Set up index and sourcetype + +=== Using Telegraf + +Configure Telegraf to collect Redis Enterprise metrics and forward to Splunk: + +[source,toml] +---- +[[inputs.prometheus]] + urls = ["http://:8070/metrics"] + +[[outputs.http]] + url = "https://:8088/services/collector" + data_format = "splunkmetric" + splunk_token = "" +---- + +== Example Configurations + +=== Production-Ready Templates + +Complete configuration files are available in the GitHub repository: + +* https://github.com/redis-field-engineering/redis-enterprise-observability/tree/main/splunk[Splunk Configurations^] +** https://github.com/redis-field-engineering/redis-enterprise-observability/blob/main/splunk/config/agent_config.yml[agent_config.yml^] - Complete OpenTelemetry Collector configuration (300+ lines) +*** Receivers: Prometheus, OTLP, Jaeger, Zipkin +*** Processors: Memory limiter, resource detection, batch processing +*** Exporters: Splunk HEC, SignalFx +*** Pre-configured pipelines for metrics, traces, and logs +** Dashboard XML templates for Splunk UI + +TIP: The agent_config.yml provides a complete working configuration for the Splunk OpenTelemetry Collector. Replace placeholder values (REDIS_ENTERPRISE_HOST, SPLUNK_* environment variables) with your environment specifics. + +== Dashboard Import + +. Navigate to Search & Reporting +. Import the dashboard XML from this repository +. Configure data source and time range +. Save dashboard + +== SPL Queries + +Example queries for Redis Enterprise metrics: + +[source,spl] +---- +index=metrics metric_name=redis_enterprise_database_ops_per_sec +| timechart avg(value) by database + +index=metrics metric_name=redis_enterprise_memory_usage +| where value > 80 +| stats count by cluster, node +---- + +== Alerting + +Configure alerts using Splunk's alert framework: + +* Memory usage thresholds +* Operation rate anomalies +* Cluster health checks +* Database availability + +== Next Steps + +* xref:dashboards/catalog.adoc[Dashboard catalog] +* xref:guides/alerting.adoc[Alert setup] +* xref:reference/metrics.adoc[Metrics reference] diff --git a/docs/modules/ROOT/pages/quick-start.adoc b/docs/modules/ROOT/pages/quick-start.adoc new file mode 100644 index 0000000..643aa56 --- /dev/null +++ b/docs/modules/ROOT/pages/quick-start.adoc @@ -0,0 +1,48 @@ += Quick Start Guide + +Get started with Redis Enterprise monitoring in 5 minutes. + +== Prerequisites + +* Redis Enterprise cluster (Cloud or self-hosted) +* Access to one of the supported observability platforms +* API credentials or access tokens (platform-dependent) + +== Step 1: Choose Your Platform + +Select the observability platform you want to use: + +* xref:platforms/grafana.adoc[Grafana] - Open source visualization +* xref:platforms/prometheus.adoc[Prometheus] - Time-series metrics +* xref:platforms/dynatrace.adoc[Dynatrace] - Commercial APM +* xref:platforms/newrelic.adoc[New Relic] - SaaS monitoring +* xref:platforms/splunk.adoc[Splunk] - Enterprise analytics +* xref:platforms/kibana.adoc[Kibana] - Elastic Stack + +== Step 2: Configure Metrics Collection + +=== For Prometheus/Grafana + +[source,bash] +---- +# Configure Prometheus to scrape Redis Enterprise metrics +# See Prometheus platform guide for details +---- + +=== For Commercial Platforms + +Follow the platform-specific integration guide to configure metrics forwarding. + +== Step 3: Import Dashboards + +Download and import the pre-built dashboards from the xref:dashboards/catalog.adoc[Dashboard Catalog] for your platform. + +== Step 4: Verify Monitoring + +Check that metrics are flowing and dashboards are displaying data from your Redis Enterprise cluster. + +== Next Steps + +* xref:guides/alerting.adoc[Configure alerting] +* xref:guides/monitoring-redis-cloud.adoc[Monitor Redis Cloud] +* xref:reference/metrics.adoc[Explore available metrics] diff --git a/docs/modules/ROOT/pages/reference/configuration.adoc b/docs/modules/ROOT/pages/reference/configuration.adoc new file mode 100644 index 0000000..7a5da7b --- /dev/null +++ b/docs/modules/ROOT/pages/reference/configuration.adoc @@ -0,0 +1,314 @@ += Configuration Reference + +Configuration options for Redis Enterprise observability components. + +== Overview + +This reference covers configuration options for metrics collection, export, and monitoring across different platforms. + +== Redis Enterprise Configuration + +=== Enabling Metrics Endpoint + +Metrics are enabled by default on port 8070. To verify or configure: + +[source,bash] +---- +# Check if metrics endpoint is accessible +curl http://localhost:8070/metrics + +# Configure metrics endpoint (if needed) +rladmin cluster config metrics_exporter_port 8070 +---- + +=== Authentication + +Configure authentication for metrics endpoint: + +[source,bash] +---- +# Enable authentication +rladmin cluster config metrics_exporter_auth enabled + +# Set credentials +rladmin cluster config metrics_exporter_username +rladmin cluster config metrics_exporter_password +---- + +=== Metrics Filtering + +Filter metrics to reduce cardinality: + +[source,bash] +---- +# Configure metric prefixes to include +rladmin cluster config metrics_include_list "redis_enterprise_database,redis_enterprise_cluster" + +# Configure metric prefixes to exclude +rladmin cluster config metrics_exclude_list "redis_enterprise_internal" +---- + +== Prometheus Configuration + +=== Basic Scrape Configuration + +[source,yaml] +---- +global: + scrape_interval: 30s + evaluation_interval: 30s + +scrape_configs: + - job_name: 'redis-enterprise' + static_configs: + - targets: ['redis-host-1:8070', 'redis-host-2:8070'] + scrape_interval: 30s + scrape_timeout: 10s +---- + +=== Service Discovery + +==== Kubernetes +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise-k8s' + kubernetes_sd_configs: + - role: pod + namespaces: + names: + - redis-enterprise + relabel_configs: + - source_labels: [__meta_kubernetes_pod_label_app] + action: keep + regex: redis-enterprise +---- + +==== Consul +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise-consul' + consul_sd_configs: + - server: 'consul.example.com:8500' + services: ['redis-enterprise'] +---- + +=== Authentication Configuration + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise' + static_configs: + - targets: ['redis-host:8070'] + basic_auth: + username: 'prometheus' + password: 'secure-password' + # Or use file-based auth + basic_auth: + username: 'prometheus' + password_file: /etc/prometheus/redis-password +---- + +=== TLS Configuration + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise' + scheme: https + tls_config: + ca_file: /etc/prometheus/certs/ca.crt + cert_file: /etc/prometheus/certs/client.crt + key_file: /etc/prometheus/certs/client.key + insecure_skip_verify: false +---- + +=== Metric Relabeling + +[source,yaml] +---- +scrape_configs: + - job_name: 'redis-enterprise' + static_configs: + - targets: ['redis-host:8070'] + metric_relabel_configs: + # Keep only specific metrics + - source_labels: [__name__] + regex: 'redis_enterprise_(database|cluster)_.*' + action: keep + + # Drop high cardinality labels + - source_labels: [instance_id] + action: labeldrop + + # Rename labels + - source_labels: [db_name] + target_label: database +---- + +== Grafana Configuration + +=== Data Source Configuration + +[source,yaml] +---- +apiVersion: 1 + +datasources: + - name: Prometheus-RedisEnterprise + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + jsonData: + timeInterval: 30s + queryTimeout: 60s + httpMethod: POST + secureJsonData: + basicAuthPassword: 'password' +---- + +=== Dashboard Variables + +Common dashboard variables for Redis Enterprise: + +[source,json] +---- +{ + "templating": { + "list": [ + { + "name": "cluster", + "type": "query", + "query": "label_values(redis_enterprise_cluster_health, cluster)", + "refresh": 1 + }, + { + "name": "database", + "type": "query", + "query": "label_values(redis_enterprise_database_up{cluster=\"$cluster\"}, database)", + "refresh": 1 + } + ] + } +} +---- + +== Alerting Configuration + +=== Alertmanager Configuration + +[source,yaml] +---- +global: + resolve_timeout: 5m + slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK' + +route: + group_by: ['cluster', 'alertname'] + group_wait: 30s + group_interval: 5m + repeat_interval: 12h + receiver: 'redis-team' + routes: + - match: + severity: critical + receiver: 'pagerduty' + continue: true + +receivers: + - name: 'redis-team' + slack_configs: + - channel: '#redis-alerts' + title: 'Redis Enterprise Alert' + + - name: 'pagerduty' + pagerduty_configs: + - service_key: 'YOUR_PAGERDUTY_KEY' +---- + +=== Recording Rules Configuration + +[source,yaml] +---- +groups: + - name: redis_enterprise_recordings + interval: 30s + rules: + - record: redis_enterprise:database:ops_per_sec:rate5m + expr: rate(redis_enterprise_database_total_ops[5m]) + labels: + job: redis-enterprise + + - record: redis_enterprise:database:memory_usage_pct + expr: | + (redis_enterprise_database_used_memory / + redis_enterprise_database_memory_limit) * 100 +---- + +== Storage Configuration + +=== Prometheus Storage + +[source,yaml] +---- +storage: + tsdb: + path: /prometheus/data + retention: + time: 90d + size: 100GB + wal_compression: true + min_block_duration: 2h + max_block_duration: 36h +---- + +=== Remote Write Configuration + +[source,yaml] +---- +remote_write: + - url: "https://long-term-storage.example.com/api/v1/write" + queue_config: + capacity: 10000 + max_shards: 50 + max_samples_per_send: 5000 + write_relabel_configs: + - source_labels: [__name__] + regex: 'redis_enterprise_.*' + action: keep +---- + +== Performance Tuning + +=== Prometheus Tuning + +[source,bash] +---- +# Increase memory limit +prometheus \ + --storage.tsdb.path=/data \ + --storage.tsdb.retention.time=90d \ + --query.max-samples=50000000 \ + --query.timeout=2m +---- + +=== Grafana Tuning + +[source,ini] +---- +[database] +max_open_conn = 300 +max_idle_conn = 100 + +[dataproxy] +timeout = 90 +---- + +== Next Steps + +* xref:platforms/prometheus.adoc[Set up Prometheus] +* xref:platforms/grafana.adoc[Configure Grafana] +* xref:guides/alerting.adoc[Configure alerting] diff --git a/docs/modules/ROOT/pages/reference/metrics.adoc b/docs/modules/ROOT/pages/reference/metrics.adoc new file mode 100644 index 0000000..af2e5db --- /dev/null +++ b/docs/modules/ROOT/pages/reference/metrics.adoc @@ -0,0 +1,204 @@ += Metrics Reference + +Complete reference for Redis Enterprise metrics exposed via Prometheus. + +== Overview + +Redis Enterprise exposes comprehensive metrics at the cluster, node, and database levels via a Prometheus-compatible endpoint at `:8070/metrics`. + +== Cluster Metrics + +=== redis_enterprise_cluster_health +* *Type*: Gauge +* *Description*: Overall cluster health status +* *Values*: 0 (unhealthy), 1 (healthy) + +=== redis_enterprise_cluster_nodes_total +* *Type*: Gauge +* *Description*: Total number of nodes in the cluster +* *Labels*: `cluster` + +=== redis_enterprise_cluster_databases_total +* *Type*: Gauge +* *Description*: Total number of databases in the cluster +* *Labels*: `cluster` + +== Node Metrics + +=== redis_enterprise_node_up +* *Type*: Gauge +* *Description*: Node availability status +* *Values*: 0 (down), 1 (up) +* *Labels*: `cluster`, `node` + +=== redis_enterprise_node_cpu_usage +* *Type*: Gauge +* *Description*: Node CPU utilization percentage +* *Unit*: Percent (0-100) +* *Labels*: `cluster`, `node` + +=== redis_enterprise_node_memory_usage_bytes +* *Type*: Gauge +* *Description*: Node memory usage in bytes +* *Unit*: Bytes +* *Labels*: `cluster`, `node` + +=== redis_enterprise_node_network_bytes_in +* *Type*: Counter +* *Description*: Network bytes received by node +* *Unit*: Bytes +* *Labels*: `cluster`, `node` + +=== redis_enterprise_node_network_bytes_out +* *Type*: Counter +* *Description*: Network bytes sent by node +* *Unit*: Bytes +* *Labels*: `cluster`, `node` + +== Database Metrics + +=== redis_enterprise_database_up +* *Type*: Gauge +* *Description*: Database availability status +* *Values*: 0 (down), 1 (up) +* *Labels*: `cluster`, `database`, `db_id` + +=== redis_enterprise_database_total_ops +* *Type*: Counter +* *Description*: Total operations performed on database +* *Unit*: Operations +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_ops_per_sec +* *Type*: Gauge +* *Description*: Current operations per second +* *Unit*: Operations/second +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_used_memory +* *Type*: Gauge +* *Description*: Memory used by database +* *Unit*: Bytes +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_memory_limit +* *Type*: Gauge +* *Description*: Memory limit configured for database +* *Unit*: Bytes +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_connections +* *Type*: Gauge +* *Description*: Number of active connections to database +* *Unit*: Connections +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_total_keys +* *Type*: Gauge +* *Description*: Total number of keys in database +* *Unit*: Keys +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_evicted_keys +* *Type*: Counter +* *Description*: Number of keys evicted due to memory pressure +* *Unit*: Keys +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_expired_keys +* *Type*: Counter +* *Description*: Number of keys expired (TTL reached) +* *Unit*: Keys +* *Labels*: `cluster`, `database` + +== Latency Metrics + +=== redis_enterprise_database_latency_avg +* *Type*: Gauge +* *Description*: Average latency for database operations +* *Unit*: Seconds +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_latency_p50 +* *Type*: Gauge +* *Description*: 50th percentile latency +* *Unit*: Seconds +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_latency_p95 +* *Type*: Gauge +* *Description*: 95th percentile latency +* *Unit*: Seconds +* *Labels*: `cluster`, `database` + +=== redis_enterprise_database_latency_p99 +* *Type*: Gauge +* *Description*: 99th percentile latency +* *Unit*: Seconds +* *Labels*: `cluster`, `database` + +== Replication Metrics + +=== redis_enterprise_database_replication_lag +* *Type*: Gauge +* *Description*: Replication lag between source and replica +* *Unit*: Seconds +* *Labels*: `cluster`, `database`, `source`, `replica` + +=== redis_enterprise_database_replication_status +* *Type*: Gauge +* *Description*: Replication status +* *Values*: 0 (failed), 1 (syncing), 2 (synced) +* *Labels*: `cluster`, `database` + +== Common PromQL Queries + +=== Operations Per Second +[source,promql] +---- +rate(redis_enterprise_database_total_ops[5m]) +---- + +=== Memory Usage Percentage +[source,promql] +---- +(redis_enterprise_database_used_memory / redis_enterprise_database_memory_limit) * 100 +---- + +=== Hit Rate +[source,promql] +---- +rate(redis_enterprise_database_hits[5m]) / +(rate(redis_enterprise_database_hits[5m]) + rate(redis_enterprise_database_misses[5m])) +---- + +=== Eviction Rate +[source,promql] +---- +rate(redis_enterprise_database_evicted_keys[5m]) +---- + +== Recording Rules Examples + +Recommended recording rules for common queries: + +[source,yaml] +---- +groups: +- name: redis_enterprise + interval: 30s + rules: + - record: redis_enterprise:database:ops_per_sec + expr: rate(redis_enterprise_database_total_ops[5m]) + + - record: redis_enterprise:database:memory_usage_pct + expr: | + (redis_enterprise_database_used_memory / + redis_enterprise_database_memory_limit) * 100 +---- + +== Next Steps + +* xref:guides/alerting.adoc[Configure alerts using these metrics] +* xref:platforms/prometheus.adoc[Set up Prometheus collection] +* xref:dashboards/catalog.adoc[View pre-built dashboards] diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..aa8e0cb --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2144 @@ +{ + "name": "redis-enterprise-observability", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "antora": "3.1.13" + } + }, + "node_modules/@antora/asciidoc-loader": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.13.tgz", + "integrity": "sha512-oCtdy0EsWwIEPiQmyEM3+fpgqjySb1MVtSgyp+nwEXqxFjij8scU1xQEB3LbTYCeObbWdXsqw/nzH0pZBc1rRw==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/logger": "3.1.13", + "@antora/user-require-helper": "~3.0", + "@asciidoctor/core": "~2.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/cli": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.13.tgz", + "integrity": "sha512-wZHxryIU7+aYfRxlm2yEgnSwYI2a8Zo377BPm98KCSsbOg7nA+5mycGT7N9AbV6QQutRJnMOdrlmv1d8HFZHLg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/logger": "3.1.13", + "@antora/playbook-builder": "3.1.13", + "@antora/user-require-helper": "~3.0", + "commander": "~11.1" + }, + "bin": { + "antora": "bin/antora" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/content-aggregator": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.13.tgz", + "integrity": "sha512-tO7ohlnwtK4EpEm3NbTSj6DdN1NhF3KLDcZ59v0bosxbaEibLhEGSroFbr0KcMrTEIMqJXHzVuFsIoHUpaheYA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "@antora/logger": "3.1.13", + "@antora/user-require-helper": "~3.0", + "braces": "~3.0", + "cache-directory": "~2.0", + "fast-glob": "~3.3", + "hpagent": "~1.2", + "isomorphic-git": "~1.25", + "js-yaml": "~4.1", + "multi-progress": "~4.0", + "picomatch": "~4.0", + "progress": "~2.0", + "should-proxy": "~1.0", + "simple-get": "~4.0", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/content-classifier": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.13.tgz", + "integrity": "sha512-uMEXRNz6WDEn6L1HXsxqd7HXofAU25MBnNaB6cT8ffGle4d6FFzdaTVNRrtm1RIZJcVM7OKSkpIeu69ZYzsklg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/asciidoc-loader": "3.1.13", + "@antora/logger": "3.1.13", + "mime-types": "~2.1", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/document-converter": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.13.tgz", + "integrity": "sha512-nBeKZ7mjAABnVY1sZB+2GNYpi5cSEdN5TxVan0TH+msCBDpOn50QMJM3mb6ZZ+hJ+5jCF+qT39GOMR+l9Rtoiw==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/asciidoc-loader": "3.1.13" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/expand-path-helper": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@antora/expand-path-helper/-/expand-path-helper-3.0.0.tgz", + "integrity": "sha512-7PdEIhk97v85/CSm3HynCsX14TR6oIVz1s233nNLsiWubE8tTnpPt4sNRJR+hpmIZ6Bx9c6QDp3XIoiyu/WYYA==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/file-publisher": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.13.tgz", + "integrity": "sha512-1+zBYx6d+llorR4THtej3Az+GCH25Osp4dMZS54PxiOZ5p7X/x4YqUIB6CfCn7B6xAGtEtDMSK8ZYspv2Mqqbg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "@antora/user-require-helper": "~3.0", + "vinyl": "~3.0", + "yazl": "~2.5" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/logger": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.13.tgz", + "integrity": "sha512-pxNP7OICPGureSSbrCmZbgv8XOay1966R7d0pa0KfCbEOeM9poBdi1x8Wp4uP6vEhpRg8zT/Dyv6A1kL5NKx0Q==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "pino": "~9.2", + "pino-pretty": "~11.2", + "sonic-boom": "~4.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/navigation-builder": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.13.tgz", + "integrity": "sha512-oFXfUOdf17UyE7mYUOfWcGxIE1DTDt3tA/Fda3zvpG/XlNF8s1crd+sALjtcSi28ERLKwR3AEUaJ3sBwjZIpcg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/asciidoc-loader": "3.1.13" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/page-composer": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.13.tgz", + "integrity": "sha512-PYNzONnhc2c2TZ+ZeaRvLcdrkiyOV86BK2Lc4wvO9j6/G8kMcjQBozSD0XHuCwQK+PLf1MsKYEzFhV6LttJ4NQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/logger": "3.1.13", + "handlebars": "~4.7", + "require-from-string": "~2.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/playbook-builder": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.13.tgz", + "integrity": "sha512-ya2mc38xoIvpXrW4WFUdNI9MRA0OY3r25BHLhCB8YxExcAvKx3+n+9KrOCSRwK6NfApRxXazzIAxmC3mhtepew==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@iarna/toml": "~2.2", + "convict": "~6.2", + "js-yaml": "~4.1", + "json5": "~2.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/redirect-producer": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.13.tgz", + "integrity": "sha512-OMeF4WXm0TnDRzhNVSdUFZTmDEdY3ykOBm97yO+YbOhiM1G6gxG2u4NKIY6hqImU/s8sRJHF3eLQL6GFh2+vdQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-generator": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.13.tgz", + "integrity": "sha512-BLImt7hdSfuvD2LhPnmPivqyfytz0qUc4w4xakR9s/mH7tC4Sk/DA/BYw8BgVSeBVhpAznmHvqfs6SGJFO8RFw==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/asciidoc-loader": "3.1.13", + "@antora/content-aggregator": "3.1.13", + "@antora/content-classifier": "3.1.13", + "@antora/document-converter": "3.1.13", + "@antora/file-publisher": "3.1.13", + "@antora/logger": "3.1.13", + "@antora/navigation-builder": "3.1.13", + "@antora/page-composer": "3.1.13", + "@antora/playbook-builder": "3.1.13", + "@antora/redirect-producer": "3.1.13", + "@antora/site-mapper": "3.1.13", + "@antora/site-publisher": "3.1.13", + "@antora/ui-loader": "3.1.13", + "@antora/user-require-helper": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-mapper": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.13.tgz", + "integrity": "sha512-9PLd87ZGiJrYhnYdtZvf2aoQSptTcD925SMKbB/6ws/I4qWTOiKk+68XyezR7um17yXR6o6AbwIN6U4JVk93rg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/content-classifier": "3.1.13", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-publisher": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.13.tgz", + "integrity": "sha512-jqo4rkifU9eBBir4IcUmlcNC37Ri7KtF4XWubecHl3rGGvI5FxQnfYw2dMMyuLJ+8DTavT9MOjeBqbNSb3hSjQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/file-publisher": "3.1.13" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/ui-loader": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.13.tgz", + "integrity": "sha512-oLTTuFd60mwgEw43161qBjycLnO8bxyHc6oEnMcNJy+8PHye4BDtsLrEEErY1GGvJ40SA+xvuzznUXRVAXpzRQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "braces": "~3.0", + "cache-directory": "~2.0", + "fast-glob": "~3.3", + "hpagent": "~1.2", + "js-yaml": "~4.1", + "picomatch": "~4.0", + "should-proxy": "~1.0", + "simple-get": "~4.0", + "vinyl": "~3.0", + "yauzl": "~3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/user-require-helper": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@antora/user-require-helper/-/user-require-helper-3.0.0.tgz", + "integrity": "sha512-KIXb8WYhnrnwH7Jj21l1w+et9k5GvcgcqvLOwxqWLEd0uVZOiMFdqFjqbVm3M+zcrs1JXWMeh2LLvxBbQs3q/Q==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/expand-path-helper": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@asciidoctor/core": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.8.tgz", + "integrity": "sha512-oozXk7ZO1RAd/KLFLkKOhqTcG4GO3CV44WwOFg2gMcCsqCUTarvMT7xERIoWW2WurKbB0/ce+98r01p8xPOlBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "asciidoctor-opal-runtime": "0.3.3", + "unxhr": "1.0.1" + }, + "engines": { + "node": ">=8.11", + "npm": ">=5.0.0", + "yarn": ">=1.1.0" + } + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "dev": true, + "license": "ISC" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/antora": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/antora/-/antora-3.1.13.tgz", + "integrity": "sha512-+2UQM/rPg3Edh/SuV/7PhhKBU93mpkw5n24opGc6rGk+6FhZx4JQsFbxeALGGqTuKto0wuHD1X00msc4ODT4LQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@antora/cli": "3.1.13", + "@antora/site-generator": "3.1.13" + }, + "bin": { + "antora": "bin/antora" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asciidoctor-opal-runtime": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.3.tgz", + "integrity": "sha512-/CEVNiOia8E5BMO9FLooo+Kv18K4+4JBFRJp8vUy/N5dMRAg+fRNV4HA+o6aoSC79jVU/aT5XvUpxSxSsTS8FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "7.1.3", + "unxhr": "1.0.1" + }, + "engines": { + "node": ">=8.11" + } + }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/b4a": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.7.0.tgz", + "integrity": "sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/cache-directory": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cache-directory/-/cache-directory-2.0.0.tgz", + "integrity": "sha512-7YKEapH+2Uikde8hySyfobXBqPKULDyHNl/lhKm7cKf/GJFdG/tU/WpLrOg2y9aUrQrWUilYqawFIiGJPS6gDA==", + "dev": true, + "license": "LGPL-3.0+", + "dependencies": { + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convict": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", + "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isomorphic-git": { + "version": "1.25.10", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.25.10.tgz", + "integrity": "sha512-IxGiaKBwAdcgBXwIcxJU6rHLk+NrzYaaPKXXQffcA0GW3IUrQXdUPDXDo+hkGVcYruuz/7JlGBiuaeTCgIgivQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5" + } + }, + "node_modules/multi-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multi-progress/-/multi-progress-4.0.0.tgz", + "integrity": "sha512-9zcjyOou3FFCKPXsmkbC3ethv51SFPoA4dJD6TscIp2pUmy26kBDZW6h9XofPELrzseSkuD7r0V+emGEeo39Pg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "progress": "^2.0.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pino": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", + "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", + "dev": true, + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.2.2.tgz", + "integrity": "sha512-2FnyGir8nAJAqD3srROdrF1J5BIcMT4nwj7hHSc60El6Uxlym00UbCCd8pYIterstVBFlMyF1yFV8XdGIPbj4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "license": "ISC" + }, + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/should-proxy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/should-proxy/-/should-proxy-1.0.4.tgz", + "integrity": "sha512-RPQhIndEIVUCjkfkQ6rs6sOR6pkxJWCNdxtfG5pP0RVgUYbK5911kLTF0TNcCC0G3YCGd492rMollFT2aTd9iQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sonic-boom": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", + "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unxhr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.0.1.tgz", + "integrity": "sha512-MAhukhVHyaLGDjyDYhy8gVjWJyhTECCdNsLwlMoGFoNJ3o79fpQhtQuzmAE4IxCMDwraF4cW8ZjpAV0m9CRQbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.11" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vinyl": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.1.tgz", + "integrity": "sha512-0QwqXteBNXgnLCdWdvPQBX6FXRHtIH3VhJPTd5Lwn28tJXc34YqSCWUmkOvtJHBmB3gGoPtrOKk3Ts8/kEZ9aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^2.1.2", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.3.tgz", + "integrity": "sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..70927d7 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "docs": "antora antora-playbook.yml", + "docs:serve": "npx http-server build/site -p 8080" + }, + "devDependencies": { + "antora": "3.1.13" + } +}