diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/how-to/migrate-to-ngit-grasp.md | 69 | ||||
| -rwxr-xr-x | docs/how-to/migration-scripts/30-extract-parse-failures.sh | 34 | ||||
| -rwxr-xr-x | docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh | 34 | ||||
| -rwxr-xr-x | docs/how-to/migration-scripts/run-migration-analysis.sh | 28 | ||||
| -rwxr-xr-x | docs/how-to/migration-scripts/validate-service.sh | 150 |
5 files changed, 304 insertions, 11 deletions
diff --git a/docs/how-to/migrate-to-ngit-grasp.md b/docs/how-to/migrate-to-ngit-grasp.md index 9b812a5..00af6c8 100644 --- a/docs/how-to/migrate-to-ngit-grasp.md +++ b/docs/how-to/migrate-to-ngit-grasp.md | |||
| @@ -122,19 +122,36 @@ ls /path/to/git/npub1*/ # Should show *.git directories | |||
| 122 | 122 | ||
| 123 | ### Phase 4 Needs the Correct Service Name | 123 | ### Phase 4 Needs the Correct Service Name |
| 124 | 124 | ||
| 125 | Phase 4 extracts structured logs (`[PARSE_FAIL]`, `[PURGATORY_EXPIRED]`) from journald. You must specify the service that has these logs - typically the **archive** service (ngit-grasp), not the production service (ngit-relay). | 125 | > **CRITICAL:** Phase 4 extracts structured logs (`[PARSE_FAIL]`, `[PURGATORY_EXPIRED]`) from journald. These logs **ONLY exist in ngit-grasp services**, NOT in ngit-relay services. |
| 126 | |||
| 127 | If you specify an ngit-relay service (like `ngit-relay.service`), Phase 4 will find **zero logs** and produce empty results. This is a common mistake that wastes time and produces misleading analysis. | ||
| 128 | |||
| 129 | **Correct service names (ngit-grasp):** | ||
| 130 | - `ngit-grasp.service` | ||
| 131 | - `ngit-grasp-relay-ngit-dev.service` (NixOS multi-instance) | ||
| 132 | - `ngit-grasp-archive.service` | ||
| 133 | |||
| 134 | **Incorrect service names (ngit-relay - NO structured logging):** | ||
| 135 | - `ngit-relay.service` | ||
| 136 | - `relay-ngit-dev.service` | ||
| 126 | 137 | ||
| 127 | ```bash | 138 | ```bash |
| 128 | # Find all ngit-related services | 139 | # Find all ngit-related services |
| 129 | systemctl list-units 'ngit-*' --all | 140 | systemctl list-units 'ngit-*' --all |
| 130 | 141 | ||
| 131 | # Check which service has structured logging | 142 | # Check which service has structured logging (should be ngit-grasp) |
| 132 | journalctl -u ngit-grasp-*.service | grep -E '\[PARSE_FAIL\]|\[PURGATORY_EXPIRED\]' | head -5 | 143 | journalctl -u ngit-grasp-*.service | grep -E '\[PARSE_FAIL\]|\[PURGATORY_EXPIRED\]' | head -5 |
| 133 | 144 | ||
| 145 | # Verify ngit-relay does NOT have structured logging | ||
| 146 | journalctl -u ngit-relay.service | grep -E '\[PARSE_FAIL\]|\[PURGATORY_EXPIRED\]' | head -5 | ||
| 147 | # ^ This should return nothing | ||
| 148 | |||
| 134 | # Use the archive service name for Phase 4 | 149 | # Use the archive service name for Phase 4 |
| 135 | ./run-migration-analysis.sh ... --service ngit-grasp-relay-ngit-dev.service | 150 | ./run-migration-analysis.sh ... --service ngit-grasp-relay-ngit-dev.service |
| 136 | ``` | 151 | ``` |
| 137 | 152 | ||
| 153 | The migration scripts now validate the service name and will **error** if you specify an ngit-relay service, preventing this common mistake. | ||
| 154 | |||
| 138 | ### Permission Issues with Service-Owned Directories | 155 | ### Permission Issues with Service-Owned Directories |
| 139 | 156 | ||
| 140 | Git data directories are typically owned by the service user and may require elevated permissions to read. | 157 | Git data directories are typically owned by the service user and may require elevated permissions to read. |
| @@ -273,7 +290,7 @@ Skip or run specific phases: | |||
| 273 | | `--archive-relay <url>` | Target relay WebSocket URL (required) | | 290 | | `--archive-relay <url>` | Target relay WebSocket URL (required) | |
| 274 | | `--prod-git <path>` | Git base directory for prod (enables Phase 2) | | 291 | | `--prod-git <path>` | Git base directory for prod (enables Phase 2) | |
| 275 | | `--archive-git <path>` | Git base directory for archive (enables Phase 2) | | 292 | | `--archive-git <path>` | Git base directory for archive (enables Phase 2) | |
| 276 | | `--service <name>` | Systemd service name (enables Phase 4) | | 293 | | `--service <name>` | Systemd service name for Phase 4 log extraction. **MUST be an ngit-grasp service** (not ngit-relay). Structured logging only exists in ngit-grasp. | |
| 277 | | `--output <dir>` | Output directory (default: auto-generated) | | 294 | | `--output <dir>` | Output directory (default: auto-generated) | |
| 278 | | `--skip-phase-N` | Skip phase N (1-5) | | 295 | | `--skip-phase-N` | Skip phase N (1-5) | |
| 279 | | `--only-phase-N` | Run only phase N | | 296 | | `--only-phase-N` | Run only phase N | |
| @@ -427,16 +444,50 @@ The analysis will continue without log data. | |||
| 427 | 444 | ||
| 428 | ### Phase 4 finds no structured logs | 445 | ### Phase 4 finds no structured logs |
| 429 | 446 | ||
| 430 | Structured logging (`[PARSE_FAIL]`, `[PURGATORY_EXPIRED]`) is only available in ngit-grasp. If checking an ngit-relay service, no structured logs will be found. | 447 | **Symptom:** Phase 4 completes but `parse-failures.txt` and `purgatory-expired.txt` are empty or contain only header comments. |
| 448 | |||
| 449 | **Most common cause:** You're querying the wrong service (ngit-relay instead of ngit-grasp). | ||
| 450 | |||
| 451 | Structured logging (`[PARSE_FAIL]`, `[PURGATORY_EXPIRED]`) **only exists in ngit-grasp services**. If you specify an ngit-relay service, Phase 4 will find zero logs. | ||
| 452 | |||
| 453 | **How to diagnose:** | ||
| 431 | 454 | ||
| 432 | ```bash | 455 | ```bash |
| 433 | # Verify you're checking the right service (should be ngit-grasp) | 456 | # 1. Check what service you configured |
| 434 | journalctl -u ngit-grasp-*.service | grep -E '\[PARSE_FAIL\]|\[PURGATORY_EXPIRED\]' | head -5 | 457 | cat /path/to/output/config.txt | grep SERVICE_NAME |
| 435 | 458 | ||
| 436 | # If checking ngit-relay, structured logs won't exist | 459 | # 2. If it contains "ngit-relay", that's the problem! |
| 437 | # Use --service with the ngit-grasp archive service name instead | 460 | # ngit-relay does NOT have structured logging |
| 461 | |||
| 462 | # 3. Find the correct ngit-grasp service | ||
| 463 | systemctl list-units 'ngit-grasp*' --all | ||
| 464 | |||
| 465 | # 4. Verify the ngit-grasp service has structured logs | ||
| 466 | journalctl -u ngit-grasp-relay-ngit-dev.service --since "7 days ago" | \ | ||
| 467 | grep -E '\[PARSE_FAIL\]|\[PURGATORY_EXPIRED\]' | head -5 | ||
| 438 | ``` | 468 | ``` |
| 439 | 469 | ||
| 470 | **How to fix:** | ||
| 471 | |||
| 472 | ```bash | ||
| 473 | # Update SERVICE_NAME to the ngit-grasp archive service and re-run | ||
| 474 | ./run-migration-analysis.sh \ | ||
| 475 | --prod-relay wss://relay.ngit.dev \ | ||
| 476 | --archive-relay ws://localhost:7443 \ | ||
| 477 | --service ngit-grasp-relay-ngit-dev.service \ | ||
| 478 | --from-phase-4 # Skip phases 1-3, just re-run phase 4 | ||
| 479 | ``` | ||
| 480 | |||
| 481 | **Other possible causes:** | ||
| 482 | |||
| 483 | 1. **Structured logging not deployed:** If the ngit-grasp instance doesn't have the logging improvements deployed, no structured logs will exist. Check the ngit-grasp version. | ||
| 484 | |||
| 485 | 2. **No events in time window:** If there genuinely were no parse failures or purgatory expiry events, the files will be empty. This is valid - it means everything parsed successfully. | ||
| 486 | |||
| 487 | 3. **Wrong time range:** The default is 30 days. If your archive has been running longer, you may need `--since` to extend the range. | ||
| 488 | |||
| 489 | **Prevention:** The migration scripts now validate the service name and will error if you specify an ngit-relay service. | ||
| 490 | |||
| 440 | ### Event counts are multiples of 250 | 491 | ### Event counts are multiples of 250 |
| 441 | 492 | ||
| 442 | This suggests pagination may have failed. The scripts use `--paginate` by default, but if you see exactly 250, 500, 750 events, verify the relay is responding correctly. | 493 | This suggests pagination may have failed. The scripts use `--paginate` by default, but if you see exactly 250, 500, 750 events, verify the relay is responding correctly. |
| @@ -645,7 +696,7 @@ This section documents the specific configuration and lessons learned from migra | |||
| 645 | 696 | ||
| 646 | 2. **Check archive accessibility**: We initially tried to run analysis remotely, but the archive relay was localhost-only. Had to SSH to VPS. | 697 | 2. **Check archive accessibility**: We initially tried to run analysis remotely, but the archive relay was localhost-only. Had to SSH to VPS. |
| 647 | 698 | ||
| 648 | 3. **Use archive service for Phase 4**: Structured logging (`[PARSE_FAIL]`, `[PURGATORY_EXPIRED]`) is in the ngit-grasp archive service, not the ngit-relay production service. | 699 | 3. **Use archive service for Phase 4 (CRITICAL)**: Structured logging (`[PARSE_FAIL]`, `[PURGATORY_EXPIRED]`) is **ONLY** in the ngit-grasp archive service, NOT the ngit-relay production service. Running Phase 4 against `ngit-relay.service` produces zero results because ngit-relay doesn't emit structured logs. The scripts now validate this and error if you specify an ngit-relay service. |
| 649 | 700 | ||
| 650 | 4. **Install git on VPS**: Git wasn't installed on the minimal VPS. The scripts now check for this in prerequisites. | 701 | 4. **Install git on VPS**: Git wasn't installed on the minimal VPS. The scripts now check for this in prerequisites. |
| 651 | 702 | ||
diff --git a/docs/how-to/migration-scripts/30-extract-parse-failures.sh b/docs/how-to/migration-scripts/30-extract-parse-failures.sh index bc2049a..410fcbc 100755 --- a/docs/how-to/migration-scripts/30-extract-parse-failures.sh +++ b/docs/how-to/migration-scripts/30-extract-parse-failures.sh | |||
| @@ -65,6 +65,14 @@ | |||
| 65 | 65 | ||
| 66 | set -euo pipefail | 66 | set -euo pipefail |
| 67 | 67 | ||
| 68 | # Get script directory for sourcing helpers | ||
| 69 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 70 | |||
| 71 | # Source the service validation helper | ||
| 72 | if [[ -f "$SCRIPT_DIR/validate-service.sh" ]]; then | ||
| 73 | source "$SCRIPT_DIR/validate-service.sh" | ||
| 74 | fi | ||
| 75 | |||
| 68 | # Colors for output (disabled if not a terminal) | 76 | # Colors for output (disabled if not a terminal) |
| 69 | if [[ -t 1 ]]; then | 77 | if [[ -t 1 ]]; then |
| 70 | RED='\033[0;31m' | 78 | RED='\033[0;31m' |
| @@ -188,11 +196,35 @@ main() { | |||
| 188 | esac | 196 | esac |
| 189 | done | 197 | done |
| 190 | 198 | ||
| 191 | # Validate service name | 199 | # Validate service name format |
| 192 | if [[ ! "$service" =~ \.service$ ]]; then | 200 | if [[ ! "$service" =~ \.service$ ]]; then |
| 193 | service="${service}.service" | 201 | service="${service}.service" |
| 194 | fi | 202 | fi |
| 195 | 203 | ||
| 204 | # Validate service is appropriate for structured logging | ||
| 205 | # This prevents the common mistake of using ngit-relay instead of ngit-grasp | ||
| 206 | if type validate_service_for_structured_logging &>/dev/null; then | ||
| 207 | # Use non-interactive mode if not a terminal, skip log check (we'll do our own) | ||
| 208 | local interactive="true" | ||
| 209 | [[ ! -t 0 ]] && interactive="false" | ||
| 210 | |||
| 211 | if ! validate_service_for_structured_logging "$service" "false" "$interactive"; then | ||
| 212 | log_error "Service validation failed. Use an ngit-grasp service for structured logging." | ||
| 213 | exit 1 | ||
| 214 | fi | ||
| 215 | else | ||
| 216 | # Fallback validation if helper not available | ||
| 217 | if [[ "$service" == *"ngit-relay"* ]]; then | ||
| 218 | log_error "Service name appears to be ngit-relay: $service" | ||
| 219 | log_error "Structured logging ([PARSE_FAIL]) only exists in ngit-grasp services." | ||
| 220 | log_error "Please use the ngit-grasp archive service instead." | ||
| 221 | log_error "" | ||
| 222 | log_error "To find the correct service:" | ||
| 223 | log_error " systemctl list-units 'ngit-grasp*' --all" | ||
| 224 | exit 1 | ||
| 225 | fi | ||
| 226 | fi | ||
| 227 | |||
| 196 | log_info "Extracting parse failures from systemd logs" | 228 | log_info "Extracting parse failures from systemd logs" |
| 197 | log_info "Service: $service" | 229 | log_info "Service: $service" |
| 198 | log_info "Output: $output_dir" | 230 | log_info "Output: $output_dir" |
diff --git a/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh b/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh index 8cadad9..a20780e 100755 --- a/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh +++ b/docs/how-to/migration-scripts/31-extract-purgatory-expiry.sh | |||
| @@ -76,6 +76,14 @@ | |||
| 76 | 76 | ||
| 77 | set -euo pipefail | 77 | set -euo pipefail |
| 78 | 78 | ||
| 79 | # Get script directory for sourcing helpers | ||
| 80 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 81 | |||
| 82 | # Source the service validation helper | ||
| 83 | if [[ -f "$SCRIPT_DIR/validate-service.sh" ]]; then | ||
| 84 | source "$SCRIPT_DIR/validate-service.sh" | ||
| 85 | fi | ||
| 86 | |||
| 79 | # Colors for output (disabled if not a terminal) | 87 | # Colors for output (disabled if not a terminal) |
| 80 | if [[ -t 1 ]]; then | 88 | if [[ -t 1 ]]; then |
| 81 | RED='\033[0;31m' | 89 | RED='\033[0;31m' |
| @@ -195,11 +203,35 @@ main() { | |||
| 195 | esac | 203 | esac |
| 196 | done | 204 | done |
| 197 | 205 | ||
| 198 | # Validate service name | 206 | # Validate service name format |
| 199 | if [[ ! "$service" =~ \.service$ ]]; then | 207 | if [[ ! "$service" =~ \.service$ ]]; then |
| 200 | service="${service}.service" | 208 | service="${service}.service" |
| 201 | fi | 209 | fi |
| 202 | 210 | ||
| 211 | # Validate service is appropriate for structured logging | ||
| 212 | # This prevents the common mistake of using ngit-relay instead of ngit-grasp | ||
| 213 | if type validate_service_for_structured_logging &>/dev/null; then | ||
| 214 | # Use non-interactive mode if not a terminal, skip log check (we'll do our own) | ||
| 215 | local interactive="true" | ||
| 216 | [[ ! -t 0 ]] && interactive="false" | ||
| 217 | |||
| 218 | if ! validate_service_for_structured_logging "$service" "false" "$interactive"; then | ||
| 219 | log_error "Service validation failed. Use an ngit-grasp service for structured logging." | ||
| 220 | exit 1 | ||
| 221 | fi | ||
| 222 | else | ||
| 223 | # Fallback validation if helper not available | ||
| 224 | if [[ "$service" == *"ngit-relay"* ]]; then | ||
| 225 | log_error "Service name appears to be ngit-relay: $service" | ||
| 226 | log_error "Structured logging ([PURGATORY_EXPIRED]) only exists in ngit-grasp services." | ||
| 227 | log_error "Please use the ngit-grasp archive service instead." | ||
| 228 | log_error "" | ||
| 229 | log_error "To find the correct service:" | ||
| 230 | log_error " systemctl list-units 'ngit-grasp*' --all" | ||
| 231 | exit 1 | ||
| 232 | fi | ||
| 233 | fi | ||
| 234 | |||
| 203 | log_info "Extracting purgatory expiry events from systemd logs" | 235 | log_info "Extracting purgatory expiry events from systemd logs" |
| 204 | log_info "Service: $service" | 236 | log_info "Service: $service" |
| 205 | log_info "Output: $output_dir" | 237 | log_info "Output: $output_dir" |
diff --git a/docs/how-to/migration-scripts/run-migration-analysis.sh b/docs/how-to/migration-scripts/run-migration-analysis.sh index 65d9d17..b2ca142 100755 --- a/docs/how-to/migration-scripts/run-migration-analysis.sh +++ b/docs/how-to/migration-scripts/run-migration-analysis.sh | |||
| @@ -548,6 +548,34 @@ run_phase_4() { | |||
| 548 | return 0 | 548 | return 0 |
| 549 | fi | 549 | fi |
| 550 | 550 | ||
| 551 | # Validate service name before running Phase 4 | ||
| 552 | # Structured logging only exists in ngit-grasp, not ngit-relay | ||
| 553 | if [[ "$SERVICE_NAME" == *"ngit-relay"* ]]; then | ||
| 554 | log_error "SERVICE_NAME appears to be ngit-relay: $SERVICE_NAME" | ||
| 555 | log_error "" | ||
| 556 | log_error "Phase 4 requires an ngit-grasp service with structured logging." | ||
| 557 | log_error "Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) only exists" | ||
| 558 | log_error "in ngit-grasp services, NOT in ngit-relay services." | ||
| 559 | log_error "" | ||
| 560 | log_error "Please update --service to use the ngit-grasp archive service." | ||
| 561 | log_error "" | ||
| 562 | log_error "To find the correct service name:" | ||
| 563 | log_error " systemctl list-units 'ngit-grasp*' --all" | ||
| 564 | log_error "" | ||
| 565 | log_error "Common ngit-grasp service names:" | ||
| 566 | log_error " - ngit-grasp.service" | ||
| 567 | log_error " - ngit-grasp-relay-ngit-dev.service (NixOS multi-instance)" | ||
| 568 | log_error " - ngit-grasp-archive.service" | ||
| 569 | return 1 | ||
| 570 | fi | ||
| 571 | |||
| 572 | # Warn if service name doesn't look like ngit-grasp | ||
| 573 | if [[ "$SERVICE_NAME" != *"ngit-grasp"* && "$SERVICE_NAME" != *"grasp"* ]]; then | ||
| 574 | log_warn "SERVICE_NAME doesn't contain 'ngit-grasp': $SERVICE_NAME" | ||
| 575 | log_warn "Structured logging only exists in ngit-grasp services." | ||
| 576 | log_warn "If this is not an ngit-grasp service, Phase 4 will find no logs." | ||
| 577 | fi | ||
| 578 | |||
| 551 | local cmds=() | 579 | local cmds=() |
| 552 | 580 | ||
| 553 | cmds+=("'$SCRIPT_DIR/30-extract-parse-failures.sh' '$SERVICE_NAME' '$OUTPUT_DIR/logs'") | 581 | cmds+=("'$SCRIPT_DIR/30-extract-parse-failures.sh' '$SERVICE_NAME' '$OUTPUT_DIR/logs'") |
diff --git a/docs/how-to/migration-scripts/validate-service.sh b/docs/how-to/migration-scripts/validate-service.sh new file mode 100755 index 0000000..2525a3f --- /dev/null +++ b/docs/how-to/migration-scripts/validate-service.sh | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # | ||
| 3 | # validate-service.sh - Validate service name for structured logging | ||
| 4 | # | ||
| 5 | # This helper script validates that a service name is appropriate for | ||
| 6 | # Phase 4 log extraction. Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) | ||
| 7 | # only exists in ngit-grasp services, NOT in ngit-relay services. | ||
| 8 | # | ||
| 9 | # USAGE: | ||
| 10 | # Source this script and call the validation function: | ||
| 11 | # | ||
| 12 | # source validate-service.sh | ||
| 13 | # validate_service_for_structured_logging "$SERVICE_NAME" || exit 1 | ||
| 14 | # | ||
| 15 | # BACKGROUND: | ||
| 16 | # Phase 4 of the migration analysis extracts structured log entries from | ||
| 17 | # journald. These log entries only exist in ngit-grasp services. If you | ||
| 18 | # accidentally specify an ngit-relay service, Phase 4 will find no logs | ||
| 19 | # and produce empty results. | ||
| 20 | # | ||
| 21 | # This validation prevents that common mistake by: | ||
| 22 | # 1. Checking if the service name contains "ngit-relay" (error) | ||
| 23 | # 2. Warning if the service name doesn't contain "ngit-grasp" | ||
| 24 | # 3. Optionally checking if structured logs actually exist | ||
| 25 | # | ||
| 26 | # SEE ALSO: | ||
| 27 | # docs/how-to/migrate-to-ngit-grasp.md - Full migration guide | ||
| 28 | # 30-extract-parse-failures.sh - Uses this validation | ||
| 29 | # 31-extract-purgatory-expiry.sh - Uses this validation | ||
| 30 | # | ||
| 31 | |||
| 32 | # Colors for output (disabled if not a terminal) | ||
| 33 | if [[ -t 1 ]]; then | ||
| 34 | _VS_RED='\033[0;31m' | ||
| 35 | _VS_YELLOW='\033[0;33m' | ||
| 36 | _VS_NC='\033[0m' | ||
| 37 | else | ||
| 38 | _VS_RED='' | ||
| 39 | _VS_YELLOW='' | ||
| 40 | _VS_NC='' | ||
| 41 | fi | ||
| 42 | |||
| 43 | # Validates that the service name is appropriate for structured logging | ||
| 44 | # | ||
| 45 | # Arguments: | ||
| 46 | # $1 - service_name: The systemd service name to validate | ||
| 47 | # $2 - check_logs: Whether to check if logs actually exist (default: "true") | ||
| 48 | # $3 - interactive: Whether to prompt for confirmation (default: "true") | ||
| 49 | # | ||
| 50 | # Returns: | ||
| 51 | # 0 - Service is valid for structured logging | ||
| 52 | # 1 - Service is invalid or user declined to continue | ||
| 53 | # | ||
| 54 | # Example: | ||
| 55 | # validate_service_for_structured_logging "ngit-grasp.service" || exit 1 | ||
| 56 | # validate_service_for_structured_logging "ngit-grasp.service" "false" # Skip log check | ||
| 57 | # validate_service_for_structured_logging "ngit-grasp.service" "true" "false" # Non-interactive | ||
| 58 | # | ||
| 59 | validate_service_for_structured_logging() { | ||
| 60 | local service_name="$1" | ||
| 61 | local check_logs="${2:-true}" | ||
| 62 | local interactive="${3:-true}" | ||
| 63 | |||
| 64 | # Check if service name looks like ngit-relay (ERROR - wrong service type) | ||
| 65 | if [[ "$service_name" == *"ngit-relay"* ]]; then | ||
| 66 | echo -e "${_VS_RED}ERROR: Service name appears to be ngit-relay: $service_name${_VS_NC}" >&2 | ||
| 67 | echo "" >&2 | ||
| 68 | echo "Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) only exists in" >&2 | ||
| 69 | echo "ngit-grasp services, NOT in ngit-relay services." >&2 | ||
| 70 | echo "" >&2 | ||
| 71 | echo "Please use the ngit-grasp archive service instead." >&2 | ||
| 72 | echo "" >&2 | ||
| 73 | echo "To find the correct service name:" >&2 | ||
| 74 | echo " systemctl list-units 'ngit-grasp*' --all" >&2 | ||
| 75 | echo "" >&2 | ||
| 76 | echo "Common ngit-grasp service names:" >&2 | ||
| 77 | echo " - ngit-grasp.service" >&2 | ||
| 78 | echo " - ngit-grasp-relay-ngit-dev.service (NixOS multi-instance)" >&2 | ||
| 79 | echo " - ngit-grasp-archive.service" >&2 | ||
| 80 | return 1 | ||
| 81 | fi | ||
| 82 | |||
| 83 | # Check if service name looks like ngit-grasp (WARNING if not) | ||
| 84 | if [[ "$service_name" != *"ngit-grasp"* && "$service_name" != *"grasp"* ]]; then | ||
| 85 | echo -e "${_VS_YELLOW}WARNING: Service name doesn't contain 'ngit-grasp': $service_name${_VS_NC}" >&2 | ||
| 86 | echo "" >&2 | ||
| 87 | echo "Structured logging ([PARSE_FAIL], [PURGATORY_EXPIRED]) only exists in" >&2 | ||
| 88 | echo "ngit-grasp services." >&2 | ||
| 89 | echo "" >&2 | ||
| 90 | |||
| 91 | if [[ "$interactive" == "true" ]]; then | ||
| 92 | read -p "Continue anyway? (y/N) " -n 1 -r | ||
| 93 | echo | ||
| 94 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then | ||
| 95 | return 1 | ||
| 96 | fi | ||
| 97 | else | ||
| 98 | echo "Non-interactive mode: proceeding despite warning" >&2 | ||
| 99 | fi | ||
| 100 | fi | ||
| 101 | |||
| 102 | # Optionally check if structured logs actually exist | ||
| 103 | if [[ "$check_logs" == "true" ]]; then | ||
| 104 | # Check if journalctl is available | ||
| 105 | if ! command -v journalctl &> /dev/null; then | ||
| 106 | echo -e "${_VS_YELLOW}WARNING: journalctl not available, cannot verify logs exist${_VS_NC}" >&2 | ||
| 107 | return 0 | ||
| 108 | fi | ||
| 109 | |||
| 110 | # Check for structured log entries | ||
| 111 | local has_parse_fail has_purgatory | ||
| 112 | has_parse_fail=$(journalctl -u "$service_name" --since "7 days ago" 2>/dev/null | grep -c '\[PARSE_FAIL\]' || echo "0") | ||
| 113 | has_purgatory=$(journalctl -u "$service_name" --since "7 days ago" 2>/dev/null | grep -c '\[PURGATORY_EXPIRED\]' || echo "0") | ||
| 114 | |||
| 115 | # Strip any non-numeric characters (grep -c can have trailing whitespace) | ||
| 116 | has_parse_fail="${has_parse_fail//[^0-9]/}" | ||
| 117 | has_purgatory="${has_purgatory//[^0-9]/}" | ||
| 118 | has_parse_fail="${has_parse_fail:-0}" | ||
| 119 | has_purgatory="${has_purgatory:-0}" | ||
| 120 | |||
| 121 | if [[ "$has_parse_fail" -eq 0 && "$has_purgatory" -eq 0 ]]; then | ||
| 122 | echo -e "${_VS_YELLOW}WARNING: No structured logs found in $service_name (last 7 days)${_VS_NC}" >&2 | ||
| 123 | echo "" >&2 | ||
| 124 | echo "This may indicate:" >&2 | ||
| 125 | echo " 1. Wrong service (should be ngit-grasp archive service, not ngit-relay)" >&2 | ||
| 126 | echo " 2. Structured logging not yet deployed to this ngit-grasp instance" >&2 | ||
| 127 | echo " 3. No parse failures or purgatory expiry events in the time window" >&2 | ||
| 128 | echo "" >&2 | ||
| 129 | echo "To verify you have the right service:" >&2 | ||
| 130 | echo " systemctl list-units 'ngit-grasp*' --all" >&2 | ||
| 131 | echo " journalctl -u <service> | grep -E '\\[PARSE_FAIL\\]|\\[PURGATORY_EXPIRED\\]' | head -5" >&2 | ||
| 132 | echo "" >&2 | ||
| 133 | |||
| 134 | if [[ "$interactive" == "true" ]]; then | ||
| 135 | read -p "Continue anyway? (y/N) " -n 1 -r | ||
| 136 | echo | ||
| 137 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then | ||
| 138 | return 1 | ||
| 139 | fi | ||
| 140 | else | ||
| 141 | echo "Non-interactive mode: proceeding despite warning" >&2 | ||
| 142 | fi | ||
| 143 | fi | ||
| 144 | fi | ||
| 145 | |||
| 146 | return 0 | ||
| 147 | } | ||
| 148 | |||
| 149 | # Export the function so it can be used after sourcing | ||
| 150 | export -f validate_service_for_structured_logging | ||