summaryrefslogtreecommitdiff
path: root/debian/.local/bin/ylog
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-12-24 13:54:03 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-12-24 13:54:03 +0900
commit28e8bdf7f8286bd431b7f3b709e79f3827b31469 (patch)
tree85b44eff6da4d8443198fb6e04dfb6ee55244588 /debian/.local/bin/ylog
parent8470ff001befcfd0f626dea69a9e76d43aee0511 (diff)
updates
Diffstat (limited to 'debian/.local/bin/ylog')
-rwxr-xr-xdebian/.local/bin/ylog359
1 files changed, 359 insertions, 0 deletions
diff --git a/debian/.local/bin/ylog b/debian/.local/bin/ylog
new file mode 100755
index 0000000..254803b
--- /dev/null
+++ b/debian/.local/bin/ylog
@@ -0,0 +1,359 @@
+#!/bin/sh
+
+HOST="root@thesiah.xyz"
+LOG_DIR="/var/log/nginx"
+
+TARGET="all" # "all" means no target filter (show all lines)
+COUNTRY="all" # all|kr|us
+SCOPE="all" # all|access|recordings
+EXCL_FIREFOX=0 # 1 = exclude Firefox lines by default
+EXCLUDES="59.19.56.8" # default exclude pattern
+ADD_EXCLUDES=""
+LINE_LIMIT=500 # default number of lines when TARGET=all
+DATE_FILTER="" # date filter: "2" = 2 days ago, "~2" = last 2 days to today
+
+usage() {
+ cat <<'EOF'
+Usage: ylog [options]
+
+Options:
+ -t TARGET Search IP or string (default: all → no filter, show all lines)
+ e.g. -t 207.96.105.230
+ e.g. -t si
+ e.g. -t all
+
+ -c COUNTRY Select country logs (default: all)
+ all : all logs
+ kr : recordings.kr.log + recordings.access.log
+ us : recordings.us.log + recordings.access.log
+
+ -s SCOPE Select log scope (default: all)
+ all : recordings + access
+ recordings : recordings.* logs only
+ access : access.* logs only
+
+ -n Disable Firefox exclusion (by default, Firefox lines are excluded)
+
+ -x PATTERN Add extra exclude pattern (can be repeated)
+ e.g. -x bot -x '192\.0\.2\.1'
+
+ -l N Limit number of lines (default: 10)
+ Only applies when TARGET=all
+ e.g. -l 50 → show last 50 lines per file
+
+ -d DATE Filter by date
+ e.g. -d 2 → logs from 2 days ago only
+ e.g. -d 1 → logs from 1 day ago only
+ e.g. -d ~2 → logs from 2 days ago to today
+
+ -h Show this help
+
+Examples:
+ ylog # All logs, last 10 lines each
+ ylog -s recordings # Recordings logs only, last 10 lines each
+ ylog -c kr -t 1.2.3.4 # Search specific IP in Korean logs
+ ylog -t all -l 50 # All logs, last 50 lines each
+ ylog -d 1 # Logs from 1 day ago only
+ ylog -d ~2 # Logs from 2 days ago to today
+EOF
+ exit 0
+}
+
+while getopts "t:c:s:nx:l:d:h" opt; do
+ case "$opt" in
+ t) TARGET="$OPTARG" ;;
+ c) COUNTRY="$OPTARG" ;;
+ s) SCOPE="$OPTARG" ;;
+ n) EXCL_FIREFOX=1 ;;
+ x) ADD_EXCLUDES="${ADD_EXCLUDES}
+$OPTARG" ;;
+ l) LINE_LIMIT="$OPTARG" ;;
+ d) DATE_FILTER="$OPTARG" ;;
+ h) usage ;;
+ *) usage ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+# escape for grep -E
+esc_target=$(printf '%s' "$TARGET" | sed -E 's/[][^$.*/+?(){}|\\]/\\&/g')
+
+remote_sh='
+set -eu
+LOG_DIR="'"$LOG_DIR"'"
+COUNTRY="'"$COUNTRY"'"
+SCOPE="'"$SCOPE"'"
+TARGET="'"$TARGET"'"
+ESC_TARGET="'"$esc_target"'"
+EXCL_FIREFOX='"$EXCL_FIREFOX"'
+LINE_LIMIT='"$LINE_LIMIT"'
+DATE_FILTER="'"$DATE_FILTER"'"
+
+# collect files
+pick_files() {
+ # recordings: include recordings.access.log only if COUNTRY=all
+ if [ "$SCOPE" = "recordings" ] || [ "$SCOPE" = "all" ]; then
+ if [ "$COUNTRY" = "all" ]; then
+ for q in "$LOG_DIR/recordings.access.log" "$LOG_DIR/recordings.access.log".*; do
+ [ -e "$q" ] && printf "%s\n" "$q"
+ done
+ fi
+ case "$COUNTRY" in
+ kr) for q in "$LOG_DIR/recordings.kr.log" "$LOG_DIR/recordings.kr.log".*; do [ -e "$q" ] && printf "%s\n" "$q"; done ;;
+ us) for q in "$LOG_DIR/recordings.us.log" "$LOG_DIR/recordings.us.log".*; do [ -e "$q" ] && printf "%s\n" "$q"; done ;;
+ all)
+ for p in recordings.kr.log recordings.us.log; do
+ for q in "$LOG_DIR/$p" "$LOG_DIR/$p".*; do [ -e "$q" ] && printf "%s\n" "$q"; done
+ done
+ ;;
+ esac
+ fi
+ # access logs
+ if [ "$SCOPE" = "access" ] || [ "$SCOPE" = "all" ]; then
+ for q in "$LOG_DIR/access.log" "$LOG_DIR/access.log".*; do
+ [ -e "$q" ] && printf "%s\n" "$q"
+ done
+ fi
+ if [ "$SCOPE" = "hidden" ] || [ "$SCOPE" = "all" ]; then
+ for q in "$LOG_DIR/hidden.access.log" "$LOG_DIR/hidden.access.log".*; do
+ [ -e "$q" ] && printf "%s\n" "$q"
+ done
+ fi
+}
+
+# build exclude regex
+build_exre() {
+ EXRE=""
+ TEMP_FILE="/tmp/.ylog_exre_$$"
+ rm -f "$TEMP_FILE"
+
+ { printf "%s\n" "${EXCLUDES:-}"; printf "%s\n" "${ADD_EXCLUDES:-}"; } | sed "/^$/d" | while IFS= read -r pat
+ do
+ esc=$(printf "%s" "$pat" | sed -E "s/[][^$.*/+?(){}|\\]/\\\\&/g")
+ if [ -s "$TEMP_FILE" ]; then
+ EXRE="$(cat "$TEMP_FILE")|$esc"
+ else
+ EXRE="$esc"
+ fi
+ printf "%s" "$EXRE" > "$TEMP_FILE"
+ done
+
+ if [ -f "$TEMP_FILE" ]; then
+ cat "$TEMP_FILE"
+ rm -f "$TEMP_FILE"
+ fi
+}
+
+FILES_TMP="/tmp/.ylog_files_$$"
+pick_files | sed "/^$/d" | sort -u > "$FILES_TMP"
+
+if [ ! -s "$FILES_TMP" ]; then
+ echo "[WARN] No log files found for COUNTRY=$COUNTRY SCOPE=$SCOPE." >&2
+ exit 0
+fi
+
+if [ -n "$DATE_FILTER" ]; then
+ echo "[SCAN] Target: \"$TARGET\" Country: $COUNTRY Scope: $SCOPE Date: $DATE_FILTER"
+else
+ echo "[SCAN] Target: \"$TARGET\" Country: $COUNTRY Scope: $SCOPE"
+fi
+echo "[FILES]"
+cat "$FILES_TMP"
+
+EXRE="$(build_exre || true)"
+
+RESULTS_TMP="/tmp/.ylog_results_$$"
+rm -f "$RESULTS_TMP"
+
+found=0
+for f in $(cat "$FILES_TMP"); do
+ [ -e "$f" ] || continue
+ case "$f" in *.gz) reader="zcat -f -- \"$f\"" ;; *) reader="cat -- \"$f\"" ;; esac
+
+ if [ "$TARGET" = "all" ]; then
+ cmd="$reader"
+ else
+ cmd="$reader | grep -E -- \"${ESC_TARGET}\""
+ fi
+
+ if [ -n "${EXRE:-}" ]; then
+ cmd="$cmd | grep -v -E -- \"$EXRE\""
+ fi
+ [ "$EXCL_FIREFOX" -eq 1 ] && cmd="$cmd | grep -vi firefox"
+
+ if [ "$TARGET" = "all" ]; then
+ sh -c "$cmd | tail -n $LINE_LIMIT" >> "$RESULTS_TMP" 2>/dev/null && found=1
+ else
+ sh -c "$cmd" >> "$RESULTS_TMP" 2>/dev/null && found=1
+ fi
+done
+
+# Deduplicate: keep only the latest log for same IP+URI within same minute
+# Format: IP - user [datetime] "METHOD URI PROTOCOL" status bytes ...
+if [ -f "$RESULTS_TMP" ] && [ -s "$RESULTS_TMP" ]; then
+ # Date filtering: calculate target dates
+ TARGET_DATE=""
+ START_DATE=""
+ if [ -n "$DATE_FILTER" ]; then
+ if [ "$(printf '%s' "$DATE_FILTER" | cut -c1)" = "~" ]; then
+ # Range mode: ~N means last N days to today
+ DAYS=$(printf '%s' "$DATE_FILTER" | sed 's/^~//')
+ if [ -n "$DAYS" ] && [ "$DAYS" -gt 0 ] 2>/dev/null; then
+ START_DATE=$(date -d "$DAYS days ago" +%d/%b/%Y 2>/dev/null || date -v-${DAYS}d +%d/%b/%Y 2>/dev/null || echo "")
+ [ -z "$START_DATE" ] && START_DATE=""
+ fi
+ else
+ # Single date mode: N means N days ago only
+ DAYS="$DATE_FILTER"
+ if [ -n "$DAYS" ] && [ "$DAYS" -ge 0 ] 2>/dev/null; then
+ TARGET_DATE=$(date -d "$DAYS days ago" +%d/%b/%Y 2>/dev/null || date -v-${DAYS}d +%d/%b/%Y 2>/dev/null || echo "")
+ [ -z "$TARGET_DATE" ] && TARGET_DATE=""
+ fi
+ fi
+ fi
+
+ awk -v date_filter="${DATE_FILTER:-}" -v target_date="${TARGET_DATE:-}" -v start_date="${START_DATE:-}" "
+ function parse_date(date_str, parts, month_num) {
+ # date_str format: \"DD/MMM/YYYY\"
+ split(date_str, parts, \"/\")
+ month_names = \"JanFebMarAprMayJunJulAugSepOctNovDec\"
+ month_num = index(month_names, parts[2])
+ month_num = (month_num + 2) / 3 # Convert to 1-12
+ # Return YYYYMMDD for easy comparison
+ return sprintf(\"%04d%02d%02d\", parts[3], month_num, parts[1])
+ }
+
+ BEGIN {
+ today = strftime(\"%Y%m%d\")
+ filter_target = \"\"
+ date_range_start = \"\"
+ date_range_end = \"\"
+
+ if (date_filter != \"\" && date_filter ~ /^~/) {
+ # Range mode: extract days
+ if (start_date != \"\" && split(start_date, sd_parts, \"/\") == 3) {
+ month_names = \"JanFebMarAprMayJunJulAugSepOctNovDec\"
+ month_num = index(month_names, sd_parts[2])
+ if (month_num > 0) {
+ month_num = (month_num + 2) / 3
+ start_date_num = sprintf(\"%04d%02d%02d\", sd_parts[3], month_num, sd_parts[1])
+ date_range_start = start_date_num
+ date_range_end = today
+ }
+ }
+ } else if (date_filter != \"\" && target_date != \"\") {
+ # Single date mode
+ if (split(target_date, td_parts, \"/\") == 3) {
+ month_names = \"JanFebMarAprMayJunJulAugSepOctNovDec\"
+ month_num = index(month_names, td_parts[2])
+ if (month_num > 0) {
+ month_num = (month_num + 2) / 3
+ target_date_num = sprintf(\"%04d%02d%02d\", td_parts[3], month_num, td_parts[1])
+ filter_target = target_date_num
+ }
+ }
+ }
+ }
+ {
+ line = \$0
+
+ # Extract datetime [DD/MMM/YYYY:HH:MM:SS
+ datetime = \"\"
+ minute_part = \"\"
+ pos = match(line, /\\[[0-9]{2}\\/[A-Z][a-z]{2}\\/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}/)
+ if (pos > 0) {
+ datetime = substr(line, pos + 1, 20)
+ date_part = substr(datetime, 1, 11) # DD/MMM/YYYY
+ minute_part = substr(datetime, 1, 17) # DD/MMM/YYYY:HH:MM
+
+ # Date filtering
+ if (filter_target != \"\" || date_range_start != \"\") {
+ line_date_num = parse_date(date_part)
+ if (filter_target != \"\" && line_date_num != filter_target) {
+ next # Skip if not matching target date
+ }
+ if (date_range_start != \"\" && (line_date_num < date_range_start || line_date_num > date_range_end)) {
+ next # Skip if outside date range
+ }
+ }
+ }
+
+ # Extract IP (first field before \" - \")
+ ip = \"\"
+ pos = match(line, /^[0-9a-fA-F:.]+/)
+ if (pos > 0) {
+ ip = substr(line, pos, RLENGTH)
+ }
+
+ # Extract URI (between quotes after method)
+ uri = \"\"
+ # Find the quoted request part: \"METHOD URI PROTOCOL\"
+ # Use split on quotes to find the request section
+ split(line, parts, \"\\\"\")
+ if (length(parts) >= 2) {
+ # parts[2] should be \"METHOD URI PROTOCOL\"
+ n = split(parts[2], req_parts, \" \")
+ if (n >= 2) {
+ uri = req_parts[2]
+ }
+ }
+
+ # Create key: IP + minute + URI
+ key = ip \"|\" minute_part \"|\" uri
+
+ # Store latest line for each key (compare by full line for latest)
+ if (!(key in latest) || line > latest[key]) {
+ latest[key] = line
+ timestamp[key] = datetime
+ }
+ }
+ END {
+ empty_str = \"\"
+ idx = 0
+ for (key in latest) {
+ line = latest[key]
+ pos = match(line, /\\[[0-9]{2}\\/[A-Z][a-z]{2}\\/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}/)
+ if (pos > 0) {
+ datetime = substr(line, pos + 1, 20)
+ date_part = substr(datetime, 1, 11)
+ time_part = substr(datetime, 13, 8)
+ gsub(/:/, empty_str, time_part)
+ time_num = time_part + 0
+ split(date_part, d_parts, \"/\")
+ month_names = \"JanFebMarAprMayJunJulAugSepOctNovDec\"
+ month_num = index(month_names, d_parts[2])
+ if (month_num > 0) {
+ month_num = (month_num + 2) / 3
+ sort_key = sprintf(\"%04d%02d%02d%06d%08d\", d_parts[3], month_num, d_parts[1], time_num, idx)
+ sorted_lines[sort_key] = line
+ } else {
+ sorted_lines[sprintf(\"99999999999999999999%08d\", idx)] = line
+ }
+ } else {
+ sorted_lines[sprintf(\"99999999999999999999%08d\", idx)] = line
+ }
+ idx++
+ }
+ n = asorti(sorted_lines, sorted_keys)
+ for (i = 1; i <= n; i++) {
+ print sorted_lines[sorted_keys[i]]
+ }
+ }
+ " "$RESULTS_TMP"
+ found=1
+fi
+
+rm -f "$FILES_TMP" "$RESULTS_TMP"
+
+if [ "$TARGET" != "all" ] && [ "$found" -eq 0 ]; then
+ echo "[INFO] No matches found (or filtered out)." >&2
+fi
+'
+
+# remote execution
+ssh "$HOST" \
+ EXCLUDES="$(printf '%s' "$EXCLUDES")" \
+ ADD_EXCLUDES="$(printf '%s' "$ADD_EXCLUDES")" \
+ /bin/sh <<REMOTE_EOF
+$remote_sh
+REMOTE_EOF