#!/usr/bin/env bash # ============================================================================= # logs.sh — 查看服务日志 # # 用法: # ./logs.sh # tail -f 实时跟踪日志 # ./logs.sh --last # 只显示最后 100 行(不跟踪) # ./logs.sh -n 50 # 显示最后 50 行并跟踪 # ./logs.sh scripts # 列出所有脚本执行日志 # ./logs.sh scripts --last # 查看最新一次脚本日志 # # 日志目录一览: # .local-dev/logs/ — 后端服务运行日志 # .local-dev/docker-logs/ — Docker 容器日志(每日一文件) # .local-dev/script-logs/ — 脚本执行日志(带时间戳) # # 后端服务: openim-server, chat-rpc, admin-rpc, chat-api, admin-api, # meetingmsg, livecloud, livestream, build-server # 前端服务: pc, meetingh5, h5, cms, build-cms, build-down # Docker: redis, kafka, etcd, livekit # ============================================================================= set -euo pipefail source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" # 注意:logs.sh 不调用 init_script_log,避免 tail -f 被重定向到日志文件 SVC="${1:-}" OPT="${2:-}" NLINES="${3:-100}" # ── 无参数:打印概览 ────────────────────────────────────────────────────────── if [[ -z "$SVC" ]]; then echo "" echo -e "${BOLD}用法:${NC} $0 [--last|-n ]" echo "" echo -e "${BOLD}后端服务日志${NC} ($LOG_DIR/):" for svc in "${ALL_SVCS[@]}"; do local_log="$LOG_DIR/$svc.log" if [[ -f "$local_log" ]]; then size=$(du -sh "$local_log" 2>/dev/null | awk '{print $1}') printf " %-18s %s (%s)\n" "$svc" "$local_log" "$size" else printf " %-18s (无日志)\n" "$svc" fi done echo "" echo -e "${BOLD}Docker 容器日志${NC} ($DOCKER_LOG_DIR/):" for svc in redis kafka etcd livekit; do log_dir="$DOCKER_LOG_DIR/$svc" if [[ -d "$log_dir" ]]; then latest=$(ls -t "$log_dir"/*.log 2>/dev/null | head -1 || echo "") if [[ -n "$latest" ]]; then size=$(du -sh "$latest" 2>/dev/null | awk '{print $1}') printf " %-10s %s (%s)\n" "$svc" "$latest" "$size" else printf " %-10s (目录存在,暂无日志文件)\n" "$svc" fi else printf " %-10s (未启动)\n" "$svc" fi done echo "" echo -e "${BOLD}前端服务日志${NC} ($LOG_DIR/fe-*.log):" FE_LIST=(pc meetingh5 h5 cms build-cms build-down) for fe in "${FE_LIST[@]}"; do fe_log="$LOG_DIR/fe-${fe}.log" if [[ -f "$fe_log" ]]; then size=$(du -sh "$fe_log" 2>/dev/null | awk '{print $1}') printf " %-14s %s (%s)\n" "$fe" "$fe_log" "$size" else printf " %-14s (无日志)\n" "$fe" fi done echo "" echo -e "${BOLD}脚本执行日志${NC} ($SCRIPT_LOG_DIR/):" if [[ -d "$SCRIPT_LOG_DIR" ]]; then ls -t "$SCRIPT_LOG_DIR"/*.log 2>/dev/null | head -5 | while read -r f; do size=$(du -sh "$f" 2>/dev/null | awk '{print $1}') printf " %s (%s)\n" "$(basename "$f")" "$size" done count=$(ls "$SCRIPT_LOG_DIR"/*.log 2>/dev/null | wc -l | tr -d ' ') [[ "$count" -gt 5 ]] && echo " ... 共 $count 个文件" else echo " (尚无脚本日志)" fi echo "" exit 0 fi # ── 脚本执行日志 ────────────────────────────────────────────────────────────── if [[ "$SVC" == "scripts" ]]; then if [[ ! -d "$SCRIPT_LOG_DIR" ]] || [[ -z "$(ls "$SCRIPT_LOG_DIR"/*.log 2>/dev/null)" ]]; then warn "暂无脚本执行日志 ($SCRIPT_LOG_DIR/)" exit 0 fi if [[ "$OPT" == "--last" ]]; then latest=$(ls -t "$SCRIPT_LOG_DIR"/*.log | head -1) info "最新脚本日志: $latest" echo "──────────────────────────────────────" cat "$latest" else info "所有脚本执行日志 ($SCRIPT_LOG_DIR/):" ls -lht "$SCRIPT_LOG_DIR"/*.log 2>/dev/null | awk '{printf " %-8s %s %s\n", $5, $6" "$7" "$8, $9}' echo "" echo "查看最新: $0 scripts --last" echo "查看指定: cat $SCRIPT_LOG_DIR/" fi exit 0 fi # ── Docker 容器日志 ─────────────────────────────────────────────────────────── _docker_log() { local cname="$1" local log_dir="$DOCKER_LOG_DIR/${cname#dev-}" local latest_file info "$cname 容器日志" # 展示日志文件路径 if [[ -d "$log_dir" ]]; then latest_file=$(ls -t "$log_dir"/*.log 2>/dev/null | head -1 || echo "") if [[ -n "$latest_file" ]]; then info "本地日志文件: $latest_file" fi fi echo "──────────────────────────────────────" if [[ "$OPT" == "--last" ]]; then docker logs --tail "$NLINES" "$cname" 2>&1 else docker logs -f --tail "${NLINES}" "$cname" 2>&1 fi } case "$SVC" in redis) _docker_log "dev-redis"; exit 0 ;; kafka) _docker_log "dev-kafka"; exit 0 ;; etcd) _docker_log "dev-etcd"; exit 0 ;; livekit) _docker_log "dev-livekit"; exit 0 ;; esac # ── 前端服务日志 ────────────────────────────────────────────────────────────── FE_LIST=(pc meetingh5 h5 cms build-cms build-down) for _fe in "${FE_LIST[@]}"; do if [[ "$SVC" == "$_fe" ]]; then LOGFILE="$LOG_DIR/fe-${SVC}.log" pidfile="$PID_DIR/fe-${SVC}.pid" if [[ ! -f "$LOGFILE" ]]; then error "日志文件不存在: $LOGFILE" echo " $SVC 可能尚未启动。启动命令: ./deploy-test/07-start-frontend.sh $SVC" exit 1 fi if [[ -f "$pidfile" ]] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then info "$SVC 正在运行 (PID=$(cat "$pidfile"))" else warn "$SVC 当前未运行(显示历史日志)" fi info "日志文件: $LOGFILE" size=$(du -sh "$LOGFILE" 2>/dev/null | awk '{print $1}') info "文件大小: $size" echo "──────────────────────────────────────" if [[ "$OPT" == "--last" ]]; then tail -n "${NLINES}" "$LOGFILE" elif [[ "$OPT" == "-n" ]]; then tail -f -n "${NLINES}" "$LOGFILE" else tail -f -n 100 "$LOGFILE" fi exit 0 fi done # ── 后端服务日志 ────────────────────────────────────────────────────────────── LOGFILE="$LOG_DIR/$SVC.log" if [[ ! -f "$LOGFILE" ]]; then error "日志文件不存在: $LOGFILE" echo " 服务 $SVC 可能尚未启动。启动命令: ./deploy-test/05-start.sh $SVC" exit 1 fi PIDFILE="$PID_DIR/$SVC.pid" if [[ -f "$PIDFILE" ]] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then info "$SVC 正在运行 (PID=$(cat "$PIDFILE"))" else warn "$SVC 当前未运行(显示历史日志)" fi info "日志文件: $LOGFILE" size=$(du -sh "$LOGFILE" 2>/dev/null | awk '{print $1}') info "文件大小: $size" echo "──────────────────────────────────────" if [[ "$OPT" == "--last" ]]; then tail -n "${NLINES}" "$LOGFILE" elif [[ "$OPT" == "-n" ]]; then tail -f -n "${NLINES}" "$LOGFILE" else tail -f -n 100 "$LOGFILE" fi