728x90
반응형

라즈베리파이에서 lazyvim을 설치하려니 neovim 0.11.2 버전 이상이 필요

  • Neovim >= 0.11.2 (needs to be built with LuaJIT)

라즈비안에서 공식 설치 이미지는 0.7버전이 마지막이 었다.

그래서 neovim git 공식저장소에서 소스 받은 후 직접 빌드 후 설치

빌드시간은 3시간 이상 걸린듯하다. (라즈베리파이 B+ 사양 한계)

sudo apt update
sudo apt install -y ninja-build gettext cmake unzip curl build-essential git
git clone https://github.com/neovim/neovim.git
cd neovim
git checkout stable
make CMAKE_BUILD_TYPE=Release
sudo make install

 

728x90
반응형

'Server > Raspbian' 카테고리의 다른 글

라즈베리파이 B+ CCTV 녹화 (RTSP)  (0) 2025.10.01
라즈베리파이 고정아이피  (0) 2023.04.01
728x90
반응형

PowerToys

🧰 PowerToys란?

PowerToys는 마이크로소프트에서 공식 제공하는 윈도우용 오픈소스 유틸리티 세트입니다.
Windows 95 시절부터 존재했으며, 현재는 Windows 10과 11에서 무료로 사용할 수 있습니다.

👉 설치 방법:

설치 후 작업 표시줄에 파란색 “PT” 아이콘이 생기며, 각 기능을 켜거나 끌 수 있습니다.


🚀 주요 기능 소개

1️⃣ FancyZones — 윈도우 창 레이아웃 관리

멀티모니터 사용자나 창을 여러 개 띄워두는 사람에게 필수 기능입니다.
드래그 한 번으로 창을 원하는 구역에 자동 배치할 수 있습니다.

  • 사용 예시: 화면을 3분할로 나눠 개발툴, 브라우저, 터미널을 깔끔히 정렬
  • 단축키: Shift 키를 누른 채 창을 드래그하면 자동 정렬 가능

💡 비슷한 프로그램으로 AquaSnap, Divvy 등이 있지만, PowerToys는 무료 + 윈도우 통합이라는 장점이 있습니다.


2️⃣ PowerToys Run — 빠른 실행 런처

Alt + Space를 누르면 등장하는 빠른 검색창입니다.
앱 실행, 파일 검색, 계산기, 명령어 실행 등 무엇이든 입력만 하면 됩니다.

  • 예: calc → 계산기 실행
  • 예: cmd → 명령 프롬프트 실행
  • 예: =45*3 → 바로 계산 결과 표시

Mac의 Spotlight 같은 기능이라 작업 흐름이 훨씬 빨라집니다.


3️⃣ Color Picker — 화면의 색상 추출기

디자인 작업이나 블로그 이미지 편집할 때 유용합니다.
Win + Shift + C를 누르면 마우스 커서 아래의 **색상 코드(HEX, RGB)**를 바로 복사할 수 있습니다.

🎨 예: 웹사이트의 버튼 색상이나 배경색을 똑같이 맞출 때 편리


4️⃣ Text Extractor — 이미지 속 텍스트 복사

스크린샷에 있는 글자를 **OCR(문자 인식)**으로 추출해줍니다.
Win + Shift + T로 영역을 지정하면, 텍스트가 자동 복사됩니다.

예: 캡처 이미지 속 오류 메시지, 영수증 텍스트를 그대로 복사 가능


5️⃣ File Locksmith — 어떤 프로세스가 파일을 점유 중인지 확인

“이 파일이 사용 중이라 삭제할 수 없습니다”라는 메시지, 누구나 한 번쯤 봤죠.
이 기능을 쓰면 어떤 프로그램이 파일을 잡고 있는지 바로 확인할 수 있습니다.

  • 탐색기에서 파일 우클릭 → “File Locksmith” 선택
  • 점유 프로세스 확인 및 바로 종료 가능

6️⃣ Image Resizer — 이미지 일괄 리사이즈

여러 이미지를 한 번에 줄이거나 확대하고 싶을 때 간편합니다.

  • 파일 탐색기에서 이미지 여러 개 선택
  • 우클릭 → “Resize pictures”

미리 설정한 크기(예: 800px, 1080p 등)로 자동 변환되며, 블로그용 이미지 편집에 특히 유용합니다.


7️⃣ Keyboard Manager — 키 리매핑

잘 안 쓰는 키를 다른 기능으로 바꾸거나, 특정 단축키를 새로 지정할 수 있습니다.
예를 들어,

  • Caps Lock → Ctrl
  • Alt + S → Snipping Tool 실행
    같은 식으로 완전한 커스터마이징 키맵을 만들 수 있습니다.

8️⃣ Mouse Utilities — 마우스 강조 도구

Ctrl 키를 두 번 누르면 마우스 위치를 하이라이트해줍니다.
프레젠테이션, 화면 녹화, 튜토리얼 영상 제작 시 시선 유도에 탁월합니다.


9️⃣ Quick Accent — 특수문자 입력 보조

영문 자판에서도 é, ñ, ü 같은 발음기호 문자를 쉽게 입력할 수 있습니다.
단축키로 활성화 후 해당 알파벳을 길게 누르면 자동으로 옵션이 뜹니다.


🔟 Hosts File Editor — hosts 파일 GUI 편집기

C:\Windows\System32\drivers\etc\hosts 파일을 쉽게 관리할 수 있게 해줍니다.
도메인 테스트나 서버 전환 시 매우 유용하며, GUI로 직관적으로 수정 가능합니다.


🖥️ 그 외 유용한 기능들

  • Peek: 파일을 선택하고 Ctrl + Space로 미리보기
  • Paste as Plain Text: 복사한 텍스트를 서식 없이 붙여넣기
  • Crop and Lock: 앱 창의 특정 영역만 따서 띄우기
  • Registry Preview: .reg 파일을 미리 보고 안전하게 병합

⚙️ 정리: PowerToys는 이런 분께 추천합니다

대상이유
🧑‍💻 개발자 창 관리, 단축키 커스터마이징, 빠른 실행
🎨 디자이너 Color Picker, Image Resizer, Quick Accent
✍️ 블로거 Text Extractor, Paste as Plain Text, FancyZones
📊 일반 사용자 파일 점유 확인, 마우스 강조, hosts 편집
728x90
반응형

'Server > Windows' 카테고리의 다른 글

window tail -f log.txt  (0) 2024.04.25
bitvise - windows 터널링  (0) 2023.03.29
bitvise - windows 터널링  (0) 2023.03.29
windows 포트 포워딩 프로그램  (0) 2023.03.29
728x90
반응형

🧭 1. VisualVM 소개

VisualVM은 JDK에 포함된 jvisualvm 또는 독립 실행형 형태로 제공되는 JVM 모니터링 및 분석 도구입니다.
다음과 같은 기능을 제공합니다.

🔹 주요 기능

기능설명
CPU / 메모리 모니터링 힙(Heap) / PermGen(Metaspace) 사용량, GC(Garbage Collection) 횟수 확인
스레드 상태 추적 실행 중 스레드, 데드락, Runnable/Waiting 상태 추적
프로파일링(Profiling) CPU, 메서드 호출 빈도, 메모리 할당 추적
Heap Dump 분석 힙 덤프를 시각적으로 분석하여 메모리 누수 탐지
원격 모니터링(Remote Monitoring) 원격 서버의 톰캣 프로세스 모니터링 가능 (JMX 또는 jstatd 사용)

⚙️ 2. Tomcat 연동 방법

(1) 로컬 톰캣

  • 같은 PC에서 톰캣 실행 시 자동으로 VisualVM이 JVM 프로세스를 탐지합니다.
  • 그냥 jvisualvm 실행 → “Local” 탭에서 org.apache.catalina.startup.Bootstrap 프로세스 선택하면 됩니다.

(2) 원격 톰캣

  1. 톰캣 실행 옵션에 JMX 포트 설정
  2.  
    CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
  3. 톰캣 재시작 후 VisualVM에서 원격 호스트 추가
    • VisualVM → Add Remote Host
    • “JMX Connection”으로 hostname:9090 입력
  4. 원격 연결 시 방화벽 9090 포트 허용 필요합니다.

⚠️ 3. 운영 시 주의점

구분주의사항설명
성능 부하 ⚠️ 실시간 프로파일링(Profiling) 시 CPU 점유율 상승 운영 서버에서는 “모니터링”만, 프로파일링은 테스트 환경에서만 수행
보안 ⚠️ JMX 인증 미설정 시 누구나 접근 가능 운영 환경에서는 jmxremote.access / jmxremote.password 파일로 인증 필수
메모리 사용량 증가 VisualVM 연결 시 JVM의 Metaspace와 Heap 사용량 소폭 증가 일시적인 영향이므로 큰 문제는 없으나, 여유 메모리 확보 권장
방화벽 설정 ⚠️ JMX 포트 외부 노출 금지 내부망에서만 접근하거나 SSH 터널링을 사용
Heap Dump 크기 대형 서비스는 Heap Dump 시 수백 MB~수 GB 발생 가능 운영 중에는 Heap Dump 남발 금지 — 스냅샷은 트래픽 저하 유발 가능

🧩 4. 권장 운영 방식

목적방법
개발·테스트 환경 VisualVM을 이용해 GC 튜닝, 스레드 분석, 메모리 누수 점검
운영 환경 기본 JMX 연결만 유지하고, 필요할 때만 접속
장기 모니터링 VisualVM 대신 Prometheus + Grafana 또는 JMX Exporter를 통해 안정적 시각화 추천

💡 팁

  • 플러그인 설치로 기능 확장 가능 (Visual GC, Thread Inspector 등)
  • JDK 버전별 호환성 주의 — JDK 17 이상에서는 최신 VisualVM (2.x 이상) 사용
  • SSH 터널링을 이용하면 JMX 포트를 외부로 열지 않고도 원격 모니터링 가능:
  •  
    ssh -L 9090:localhost:9090 user@your-server

📈 5. VisualVM 실무 팁

  • Visual GC 플러그인 설치 → GC 동작 시각화
    → Tools > Plugins > Available Plugins > Visual GC
  • Heap Dump는 꼭 트래픽 낮은 시간에 수행
  • 자동 모니터링은 VisualVM 대신 Prometheus + JMX Exporter 연동 추천

728x90
반응형
728x90
반응형

ubuntu에 casaos의 docker jellyfin의 영상 폴더를 pcloud Crypto Folder에 연결하려고 시도해보았다.

docker jellyfin 빌드시에 pcloud폴더가 permission denied에러로 구동불가

ubuntu server

casaos 설치

pcloudcc 설치
    pcloud마운트하기
    pcloudcc -u user@user.com -p -s -c -m /home/user/pcloud -d

casaos 앱스토어 Jellyfin 설치

version: '3.8'
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    environment:
      - PUID=1000 # Replace with your user ID
      - PGID=1000 # Replace with your group ID
      - TZ=Europe/London # Replace with your timezone
    volumes:
      - /path/to/jellyfin/config:/config # Host path for Jellyfin configuration
      - /path/to/jellyfin/cache:/cache # Host path for Jellyfin cache
      - /home/user/pcloud:/media # Host path for your media files
    ports:
      - 8096:8096 # HTTP access
      - 8920:8920 # HTTPS access (optional)
      - 7359:7359/udp # For server discovery
    restart: unless-stopped

 

위의 - /home/user/pcloud:/media 를 마운트할때 permission denied 발생

 

GPT에게 물어보니 아래 답변

 

FUSE 마운트 권한 문제

  • pcloudcc는 FUSE(Filesystem in Userspace)로 동작합니다.
  • 기본적으로 FUSE 마운트는 마운트한 사용자만 접근 가능하고, 다른 사용자/프로세스(특히 root, docker)가 접근하면 Permission denied가 나올 수 있어요.

/home/user/pcloud의 권한 변경을 해보았으나 permission denied 해결안됨

 

/home/user 폴더자체를 연결함. 그 후에 permission denied 없이 정상 구동

유저 home폴더를 연결 후 permission denied없이 연결됨

/home/user:/media

그 후 jellyfin에서 /home/user/pcloud 폴더의 영상폴더로 설정
728x90
반응형

'Server > Linux' 카테고리의 다른 글

ubuntu 고정아이피  (0) 2023.04.01
ubuntu 고정아이피  (0) 2023.04.01
iptable  (0) 2023.03.29
저용량, 저사양 리눅스  (0) 2023.03.29
apache <-> tomcat 연동  (0) 2023.03.29
728x90
반응형

집에 TP-LINK TC60 홈캠이 있다.

택배 및 출입을 보기위해 현관 앞에 설치하였는데 문제는 SD카드가 CCTV채로 노출되어 있다는 것이다.

 

TP-LINK링크 CLOUD를 이용하자니 비용이 들어서 나의 장비로 따로 녹화하기로 하였다.

 

처음에는 서버에 MOTION-EYE를 DOCKER에 올린 듯 RTSP로 연결 후 녹화를 하였다.

하지만 집의 서버를 24시간 켜두기에는 전기료가 부담스러웠다.

 

그래서 찾은 방법은 현재 집에 24시간 돌아가는 라즈베리파이 B+가 있다.

라즈베리파이는 caddy proxy 서버로 잘 사용중이다. (ngnix proxy manager은 라즈베리파이에 구동불가)

전기료도 적게먹고 최적의 기기로 판단해서 해당기기로 녹화하기를 구상했다.

 

Claude.ai를 사용해서 질의 후 최종 VNC로 녹화 후 CLOUD 서버에 업로드 스크립트를 만들었다.

 

1. CCTV -> RTSP -> 서버 -> MOTION-EYE (전기료 부담)

2. CCTV -> RTSP -> 라즈베리파이 B+ -> ffmpeg (녹화시 CPU가 90%까지 올라가고 발열까지 있다.)

3. CCTV -> RTSP -> 라즈베리파이 B+ -> VNC (CPU사용이 6~10% 안전적이 었다.)

 

3번 테스트

# VLC 설치
sudo apt install vlc

# VLC로 녹화 테스트
cvlc rtsp://아이디:암호@URL:554/stream2 \
  --sout '#std{access=file,mux=mp4,dst=test_vlc.mp4}' \
  --run-time=10 \
  vlc://quit

 

3번으로 스크립트작성 자동 녹화 및 백업, 파일 정리

 

 CCTV -> RTSP -> 라즈베리파이 B+ -> VNC -> RCLONE -> PCLOUD 업로드 (또는 GOOGLE DRIVE, CLOUD)

#!/bin/bash

# ===========================================
# VLC 기반 CCTV 녹화 및 pcloud 백업 스크립트
# Raspberry Pi Model B Plus 최적화 (검증완료)
# CPU 사용률: 6-10%
# ===========================================

RTSP_URL="rtsp://아이디:암호@URL:554/stream2"
STORAGE_PATH="/home/pi/cctv"
PCLOUD_REMOTE="pcloud:Backups/cctv"
MAX_STORAGE_GB=20
SEGMENT_DURATION=600        # 10분 세그먼트
#BACKUP_INTERVAL=1800       # 30분마다 백업
BACKUP_INTERVAL=3600        # 60분마다 백업
KEEP_LOCAL_HOURS=12         # 로컬 파일 12시간 보관
MAX_LOCAL_FILES=200         # 최대 200개 파일
PCLOUD_KEEP_DAYS=7          # pcloud 7일 보관

LOG_FILE="/home/pi/script/cctv/log/cctv_backup.log"
LOCK_FILE="/h/cctv_upload.lock"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

mkdir -p "$STORAGE_PATH"
mkdir -p "$STORAGE_PATH/uploading"
mkdir -p "$STORAGE_PATH/uploaded"
mkdir -p "$STORAGE_PATH/temp"

# 디스크 공간 체크 (적극적 정리)
check_disk_space() {
    local USED_MB=$(du -sm "$STORAGE_PATH" 2>/dev/null | awk '{print $1}')
    local USED_GB=$((USED_MB / 1024))
    
    if [ -z "$USED_GB" ]; then
        USED_GB=0
    fi
    
    # 15GB 넘으면 긴급 정리
    if [ "$USED_GB" -gt 15 ]; then
        log "⚠️  디스크 공간 위험 ($USED_GB GB / $MAX_STORAGE_GB GB)"
        log "   긴급 정리 시작..."
        
        local count=0
        while IFS= read -r file; do
            if [ -f "$file" ]; then
                rm -f "$file"
                log "   긴급 삭제: $(basename "$file")"
                count=$((count + 1))
                [ $count -ge 10 ] && break
            fi
        done < <(find "$STORAGE_PATH" -name "*.mp4" -type f -printf '%T+ %p\n' 2>/dev/null | sort | cut -d' ' -f2-)
    fi
    
    # 파일 개수로도 체크
    local FILE_COUNT=$(find "$STORAGE_PATH" -name "*.mp4" -type f 2>/dev/null | wc -l)
    if [ "$FILE_COUNT" -gt "$MAX_LOCAL_FILES" ]; then
        log "⚠️  파일 개수 초과 ($FILE_COUNT / $MAX_LOCAL_FILES)"
        local OVER_COUNT=$((FILE_COUNT - MAX_LOCAL_FILES + 10))
        
        local count=0
        while IFS= read -r file; do
            if [ -f "$file" ]; then
                rm -f "$file"
                log "   개수 초과 삭제: $(basename "$file")"
                count=$((count + 1))
                [ $count -ge $OVER_COUNT ] && break
            fi
        done < <(find "$STORAGE_PATH" -name "*.mp4" -type f -printf '%T+ %p\n' 2>/dev/null | sort | cut -d' ' -f2-)
    fi
}

# 네트워크 연결 확인
check_network() {
    local host=$(echo "$RTSP_URL" | sed -n 's|.*@\([^:]*\):.*|\1|p')
    if [ -z "$host" ]; then
        host=$(echo "$RTSP_URL" | sed -n 's|rtsp://\([^:/]*\).*|\1|p')
    fi
    
    if ping -c 1 -W 3 "$host" > /dev/null 2>&1; then
        return 0
    else
        return 1
    fi
}

# VLC 녹화 (안정화)
start_recording() {
    log "🎥 VLC 녹화 시작 (CPU 최적화 모드)"
    log "   RTSP: $RTSP_URL"
    log "   세그먼트: ${SEGMENT_DURATION}초"
    
    local consecutive_failures=0
    local MAX_FAILURES=5
    
    while true; do
        # 네트워크 체크
        if ! check_network; then
            log "❌ 네트워크 연결 없음, 60초 후 재시도..."
            consecutive_failures=$((consecutive_failures + 1))
            
            if [ $consecutive_failures -ge $MAX_FAILURES ]; then
                log "⚠️  연속 실패 ${consecutive_failures}회, 5분 대기..."
                sleep 300
                consecutive_failures=0
            else
                sleep 60
            fi
            continue
        fi
        
        local TIMESTAMP=$(date +%Y%m%d_%H%M%S)
        local TEMP_FILE="$STORAGE_PATH/temp/cctv_${TIMESTAMP}.mp4"
        local OUTPUT_FILE="$STORAGE_PATH/cctv_${TIMESTAMP}.mp4"
        
        log "📹 녹화 시작: $(basename "$OUTPUT_FILE")"
        
        # VLC 실행 (에러 출력을 파일로 저장)
        local VLC_LOG="/tmp/vlc_${TIMESTAMP}.log"
        
        timeout $((SEGMENT_DURATION + 30)) cvlc \
            "rtsp://아이디:암호@URL:554/stream2" \
            --quiet \
            --no-audio \
            --no-sout-audio \
            --rtsp-tcp \
            --network-caching=2000 \
            --sout-mux-caching=2000 \
            --sout "#std{access=file,mux=mp4,dst=$TEMP_FILE}" \
            --run-time="$SEGMENT_DURATION" \
            vlc://quit \
            > "$VLC_LOG" 2>&1
        
        local VLC_EXIT=$?
        
        # 에러 로그에서 심각한 문제만 기록
        if [ -f "$VLC_LOG" ]; then
            grep -E "error:|failed|cannot" "$VLC_LOG" | grep -v "PulseAudio\|interface\|globalhotkeys\|dummy" >> "$LOG_FILE"
            rm -f "$VLC_LOG"
        fi
        
        # 녹화 결과 확인
        if [ -f "$TEMP_FILE" ] && [ -s "$TEMP_FILE" ]; then
            local FILE_SIZE=$(du -h "$TEMP_FILE" | cut -f1)
            
            # 최소 크기 확인 (1MB 이상)
            local FILE_SIZE_BYTES=$(stat -c%s "$TEMP_FILE" 2>/dev/null || echo 0)
            if [ "$FILE_SIZE_BYTES" -lt 1048576 ]; then
                log "⚠️  파일 크기 너무 작음: $FILE_SIZE_BYTES bytes"
                rm -f "$TEMP_FILE"
                consecutive_failures=$((consecutive_failures + 1))
                sleep 10
                continue
            fi
            
            # 정상 파일 이동
            mv "$TEMP_FILE" "$STORAGE_PATH/uploading/"
            log "✅ 녹화 완료: $(basename "$OUTPUT_FILE") ($FILE_SIZE)"
            
            consecutive_failures=0
            
            # 시스템 상태 (5회마다 출력)
            if [ $((RANDOM % 5)) -eq 0 ]; then
                if command -v vcgencmd &> /dev/null; then
                    local CPU_TEMP=$(vcgencmd measure_temp 2>/dev/null | grep -oP '\d+\.\d+' || echo "N/A")
                    log "   CPU 온도: ${CPU_TEMP}°C"
                fi
                
                local MEM_FREE=$(free -m | awk 'NR==2{printf "%.0f", $7}')
                log "   여유 메모리: ${MEM_FREE}MB"
            fi
            
        else
            log "❌ 녹화 실패: $(basename "$OUTPUT_FILE") (exit: $VLC_EXIT)"
            rm -f "$TEMP_FILE"
            
            consecutive_failures=$((consecutive_failures + 1))
            
            # 연속 실패 시 긴 대기
            if [ $consecutive_failures -ge $MAX_FAILURES ]; then
                log "⚠️  연속 실패 ${consecutive_failures}회, RTSP 연결 문제 가능성"
                log "   5분 후 재시도..."
                sleep 300
                consecutive_failures=0
            else
                sleep 30
            fi
        fi
        
        check_disk_space
        sleep 5
    done
}

# pcloud 업로드 (중복 실행 방지 + 개선)
upload_to_pcloud() {
    log "☁️  pcloud 백업 프로세스 시작"
    
    while true; do
        sleep "$BACKUP_INTERVAL"
        
        # 업로드 중인지 확인 (lock 파일)
        if [ -f "$LOCK_FILE" ]; then
            local LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null)
            if ps -p "$LOCK_PID" > /dev/null 2>&1; then
                log "⏳ 이전 업로드 진행 중 (PID: $LOCK_PID), 대기..."
                continue
            else
                log "⚠️  오래된 lock 파일 제거"
                rm -f "$LOCK_FILE"
            fi
        fi
        
        # rclone 연결 확인
        if ! rclone about "$PCLOUD_REMOTE" > /dev/null 2>&1; then
            log "❌ pcloud 연결 실패, 다음 사이클에 재시도"
            continue
        fi
        
        # lock 생성
        echo $$ > "$LOCK_FILE"
        
        # 2분 이상 된 파일만 업로드
        local UPLOAD_COUNT=0
        local SKIP_COUNT=0
        local FAIL_COUNT=0
        
        while IFS= read -r file; do
            if [ ! -f "$file" ]; then
                continue
            fi
            
            local FILENAME=$(basename "$file")
            local DATE_STR=$(echo "$FILENAME" | grep -oE '[0-9]{8}' | head -1)
            
            local REMOTE_PATH="$PCLOUD_REMOTE"
            if [ -n "$DATE_STR" ]; then
                local YEAR=${DATE_STR:0:4}
                local MONTH=${DATE_STR:4:2}
                REMOTE_PATH="$PCLOUD_REMOTE/$YEAR/$MONTH"
            fi
            
            # pcloud에 이미 존재하는지 확인
            if rclone ls "$REMOTE_PATH/$FILENAME" > /dev/null 2>&1; then
                log "⏭️  건너뜀: $FILENAME (이미 존재)"
                mv "$file" "$STORAGE_PATH/uploaded/"
                SKIP_COUNT=$((SKIP_COUNT + 1))
                continue
            fi
            
            local FILE_SIZE=$(du -h "$file" | cut -f1)
            log "⬆️  업로드: $FILENAME ($FILE_SIZE)"
            
            if rclone copy "$file" "$REMOTE_PATH" \
                --transfers 1 \
                --checkers 1 \
                --buffer-size 8M \
                --bwlimit 2M \
                --retries 3 \
                --low-level-retries 3 \
                --timeout 300s \
                --contimeout 60s \
                --stats 0 \
                -q >> "$LOG_FILE" 2>&1; then
                
                # 업로드 검증
                if rclone ls "$REMOTE_PATH/$FILENAME" > /dev/null 2>&1; then
                    log "✅ 업로드 성공: $FILENAME"
                    mv "$file" "$STORAGE_PATH/uploaded/"
                    UPLOAD_COUNT=$((UPLOAD_COUNT + 1))
                else
                    log "❌ 업로드 검증 실패: $FILENAME"
                    FAIL_COUNT=$((FAIL_COUNT + 1))
                fi
            else
                log "❌ 업로드 실패: $FILENAME (재시도 예정)"
                FAIL_COUNT=$((FAIL_COUNT + 1))
            fi
            
        done < <(find "$STORAGE_PATH/uploading" -name "*.mp4" -type f -mmin +2 2>/dev/null)
        
        if [ $UPLOAD_COUNT -gt 0 ] || [ $SKIP_COUNT -gt 0 ] || [ $FAIL_COUNT -gt 0 ]; then
            log "📊 업로드 결과 - 성공: ${UPLOAD_COUNT}, 건너뜀: ${SKIP_COUNT}, 실패: ${FAIL_COUNT}"
        else
            log "📭 업로드할 파일 없음"
        fi
        
        # lock 해제
        rm -f "$LOCK_FILE"
    done
}

# 파일 정리 (로컬 + pcloud)
cleanup_old_files() {
    log "🗑️  파일 정리 프로세스 시작"
    
    while true; do
        sleep 1800  # 30분마다
        
        # 로컬 정리 - 12시간 이상
        local DELETED=$(find "$STORAGE_PATH/uploaded" -name "*.mp4" -type f -mmin +$((KEEP_LOCAL_HOURS * 60)) -delete -print 2>/dev/null | wc -l)
        
        if [ "$DELETED" -gt 0 ]; then
            log "🗑️  로컬 정리: ${DELETED}개 파일 삭제 (${KEEP_LOCAL_HOURS}시간 이상)"
        fi
        
        # uploading 폴더 - 1일 이상
        local OLD_UPLOADING=$(find "$STORAGE_PATH/uploading" -name "*.mp4" -type f -mmin +1440 -delete -print 2>/dev/null | wc -l)
        
        if [ "$OLD_UPLOADING" -gt 0 ]; then
            log "🗑️  오래된 업로딩 파일 삭제: ${OLD_UPLOADING}개"
        fi
        
        # temp 폴더 정리
        find "$STORAGE_PATH/temp" -name "*.mp4" -type f -mmin +60 -delete 2>/dev/null
        
        # 통계
        local USED_MB=$(du -sm "$STORAGE_PATH" 2>/dev/null | awk '{print $1}')
        local USED_GB=$((USED_MB / 1024))
        local FILE_COUNT=$(find "$STORAGE_PATH" -name "*.mp4" -type f 2>/dev/null | wc -l)
        log "💾 저장 공간: ${USED_GB}GB / ${MAX_STORAGE_GB}GB, 파일: ${FILE_COUNT}개"
        
        # 6시간마다 pcloud 정리
        local CLEANUP_MARKER="/tmp/pcloud_cleanup_last"
        local CURRENT_TIME=$(date +%s)
        local LAST_CLEANUP=0
        
        if [ -f "$CLEANUP_MARKER" ]; then
            LAST_CLEANUP=$(stat -c %Y "$CLEANUP_MARKER" 2>/dev/null || echo 0)
        fi
        
        if [ $((CURRENT_TIME - LAST_CLEANUP)) -gt 21600 ]; then
            cleanup_pcloud
            touch "$CLEANUP_MARKER"
        fi
    done
}

# pcloud 정리
cleanup_pcloud() {
    log "☁️  pcloud 정리 시작 (${PCLOUD_KEEP_DAYS}일 이상)"
    
    if ! rclone listremotes 2>/dev/null | grep -q "pcloud:"; then
        log "   rclone 미설정, 건너뜀"
        return
    fi
    
    # 연결 확인
    if ! rclone about "$PCLOUD_REMOTE" > /dev/null 2>&1; then
        log "❌ pcloud 연결 실패"
        return
    fi
    
    log "   ${PCLOUD_KEEP_DAYS}일 이전 파일 삭제 중..."
    
    # 삭제 실행
    if rclone delete "$PCLOUD_REMOTE" \
        --min-age "${PCLOUD_KEEP_DAYS}d" \
        --verbose \
        >> "$LOG_FILE" 2>&1; then
        
        log "✅ pcloud 정리 완료"
        
        # 용량 확인
        local PCLOUD_SIZE=$(rclone size "$PCLOUD_REMOTE" 2>/dev/null | grep "Total size:" | awk '{print $3, $4}')
        if [ -n "$PCLOUD_SIZE" ]; then
            log "☁️  pcloud 사용량: $PCLOUD_SIZE"
        fi
    else
        log "⚠️  pcloud 정리 중 오류 발생"
    fi
}

# 시스템 모니터링
monitor_system() {
    while true; do
        sleep 300  # 5분마다
        
        # VLC 프로세스 체크
        if ! pgrep -f "cvlc" > /dev/null 2>&1; then
            log "⚠️  VLC 프로세스 미실행"
        fi
        
        # 시스템 리소스
        local CPU_TEMP="N/A"
        if command -v vcgencmd &> /dev/null; then
            CPU_TEMP=$(vcgencmd measure_temp 2>/dev/null | grep -oP '\d+\.\d+' || echo "N/A")
        fi
        
        local MEM_USAGE=$(free -m | awk 'NR==2{printf "%.1f%%", $3*100/$2}')
        local DISK_USAGE=$(df -h "$STORAGE_PATH" | awk 'NR==2{print $5}')
        local CPU_LOAD=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
        
        log "📊 시스템 - CPU: ${CPU_TEMP}°C, 부하: ${CPU_LOAD}, 메모리: ${MEM_USAGE}, 디스크: ${DISK_USAGE}"
    done
}

# 종료 핸들러
cleanup_and_exit() {
    log "🛑 종료 신호 수신"
    rm -f "$LOCK_FILE"
    pkill -P $$
    pkill vlc 2>/dev/null
    log "✅ 스크립트 종료"
    exit 0
}

trap cleanup_and_exit SIGINT SIGTERM

# 메인 실행
log "=========================================="
log "🎬 VLC 기반 CCTV 녹화 시스템 시작 (v2.0)"
log "=========================================="
log "📍 RTSP URL: $RTSP_URL"
log "💾 저장 경로: $STORAGE_PATH"
log "☁️  pcloud 경로: $PCLOUD_REMOTE"
log "📦 최대 저장 용량: ${MAX_STORAGE_GB}GB"
log "⏱️  세그먼트 길이: ${SEGMENT_DURATION}초"
log "🔄 백업 주기: ${BACKUP_INTERVAL}초"
log "🗓️  로컬 보관: ${KEEP_LOCAL_HOURS}시간"
log "☁️  pcloud 보관: ${PCLOUD_KEEP_DAYS}일"
log "📁 최대 파일: ${MAX_LOCAL_FILES}개"
log "=========================================="

# VLC 확인
if ! command -v cvlc &> /dev/null; then
    log "❌ VLC 미설치: sudo apt install vlc"
    exit 1
fi

# rclone 확인
UPLOAD_DISABLED=0
if ! rclone listremotes 2>/dev/null | grep -q "pcloud:"; then
    log "⚠️  rclone pcloud 미설정 (업로드 비활성화)"
    UPLOAD_DISABLED=1
fi

# 초기 네트워크 확인
if ! check_network; then
    log "⚠️  RTSP 호스트에 연결할 수 없습니다"
    log "   계속 시도하지만 녹화가 실패할 수 있습니다"
fi

# 백그라운드 프로세스 시작
start_recording &
RECORDING_PID=$!

if [ $UPLOAD_DISABLED -eq 0 ]; then
    upload_to_pcloud &
    UPLOAD_PID=$!
fi

cleanup_old_files &
CLEANUP_PID=$!

monitor_system &
MONITOR_PID=$!

log "✅ 모든 프로세스 시작 완료"
log "   녹화 PID: $RECORDING_PID"
[ $UPLOAD_DISABLED -eq 0 ] && log "   업로드 PID: $UPLOAD_PID"
log "   정리 PID: $CLEANUP_PID"
log "   모니터링 PID: $MONITOR_PID"
log "=========================================="

# 메인 프로세스 대기
wait

 

ROG, CPU, RAM, NETWORK 사용률 (BTOP++, LOG)

 

PCLOUD에 정상적으로 업로드도 확인 되었다.

 

기타 테스트

# 1. 실행
./cctv_backup.sh

# 2. 로그 확인 (다른 터미널)
tail -f /var/log/cctv_backup.log

# 3. 확인할 것
# ✓ 녹화 시작 메시지
# ✓ 10분 후 파일 생성 확인
# ✓ 30분 후 업로드 시작 확인
# ✓ pcloud에 파일 업로드 확인

# 4. 파일 확인
ls -lh /home/pi/cctv/uploading/
ls -lh /home/pi/cctv/uploaded/

# 5. pcloud 확인
rclone ls pcloud:Backups/cctv
728x90
반응형

'Server > Raspbian' 카테고리의 다른 글

라즈베리파이 B+ 에서 nvim(neovim) 최신버전설치  (0) 2025.11.06
라즈베리파이 고정아이피  (0) 2023.04.01
728x90
반응형

DBever에서 세미콜론으로 쿼리 구분 실행

 

DBever에서 SQL이 엔터로 띄어져 있으면 쿼리 실행시 에러가난다.

세미콜론(;)으로 쿼리 구분자로 인식 후 쿼리 실행시 에러 없이 구분해서 잘 실행된다.

SQL 에러 구문
-------------------------------------------------------
SELECT *
FROM TEST
WHERE 
                <--여기가 엔터로 띄어져 있을때
id = '123'
-------------------------------------------------------

SQL 세미콜론(;)으로 SQL 구분 되어 실행
-------------------------------------------------------
SELECT *
FROM TEST
WHERE 
				<--엔터로 띄어져 있어도 ;으로 마지막 SQL 인식
id = '123';
-------------------------------------------------------

 

DBever 설정

DBever
윈도우(W) > 환경설정(P) > 편집기 > SQL 편집기 > SQL 실행

Delimiters
Statements delimiter : ;  <-- 세미콜론으로 입력
Blank line is statement delimiter : Never

 

 

 

 

 

728x90
반응형
728x90
반응형

VSCODE를 켜면 윈도우 탐색기, 이클립스, DBever 등등 윈도우 프로그램의 그래픽 깨짐 현상이 있어서 재대로 사용을 하지 못할 정도 였다.

 

해당 PC는 워크스테이션이고 윈도우11 그래픽카드는 NVIDIA Quadro K5000 그래픽카드를 사용중이다.

이클립스만 보면 이렇게 깨지고 있다.

 

 

 

NVIDIA 제어판 > 3D 설정 > 3D 설정 관리 > 이미지 선명화 (기본 옵션)

이렇게 설정 후 재부팅하니 그래픽 깨지는 현상이 없어졌다.

반대로 이미지 선명화가 켜기 상태이면 끄기를 선택하고 재부팅해보자.

 

이미지선명화 (끄기) 일경우 > 이미지선명화 (켜기) > 윈도우 재부팅

이미지선명화 (켜기) 일경우 > 이미지선명화 (끄기) > 윈도우 재부팅

 

 

 

728x90
반응형

'TOOL > VSCODE' 카테고리의 다른 글

vscode로 spring 또는 Apache Struts 개발하기  (0) 2025.09.17
728x90
반응형

현재 유지보수중인 사이트중에 오래전에 이클립스로 개발되어 있는 spring 프로젝트가 하나 있다.

 

Eclipse Luna(4.4.2), Java-jdk 1.6, Tomcat 7.0, Apache Struts 1.1 개발되어 있다.

 

이클립스의 버벅임 때문에 소스를 수정하기 힘이 들때가 많았다.

 

Spring boot 프로젝트이면 vscode로 실행 및 debug를 할 수 있으나

vscode의 경우 일반 Spring 또는 Apache Struts 경우 실행할때마다 Build 후 War로 구동시키는 방법 밖에 없는것 같다.

 

그래서 고민 후 이클립스로 프로젝트 구동 후 소스코드 및 로그만 vscode에서 확인하는 걸로 해보니 할결 편해졌다.

 

오랜된 소스라 Jsp에 거의 비지니스 로직이 있고 Debug는 거의할 필요없는 수정 요청 정도여서 편집기로만

vscode로 사용하면 되기에 해당 설정이 나에게는 적당한 방법이 었다.

 

구성

Eclipse에서 tomcat 프로젝트를 구동

Eclipse 메뉴 > Run > Debug Configurations > 해당 Tomcat 설정 > Common > Standard Input and Ouput > File

로그 파일 생성

 

vscode

편집 및 로그확인을 vscode에서 수행할 수 있다.

 

vscode에서 편집은 그냥 프로젝트를 열면 되고 로그는 터미널에서 이클립스 설정한 로그파일을 파워쉘

Get-Content $Path -Wait -Tail 20으로 실시간으로 확인하면 됩니다.

 

vscode에서 터미널에 파월쉘 스크립트로 확인

아래 스크립트는 개발 및 운영 로그를 한번에 확인할 수 있게 파워쉘을 작성하였다.

 

이클립스 및 vscode를 2개를 실행시켜서 하기에 이게 무슨 괴조합이냐라고 할 수 있지만 Eclipse의 멈춤 빡침보다 훨신 쾌적하다.

 

#파워쉘 스크립트 실행 log.bat
@echo off
powershell -NoLogo -ExecutionPolicy Bypass -File "%~dp0log-viewer.ps1"
#log-viewer.ps1

$devLog  = "D:\project\dev.log"
$prodLog = "D:\project\prod.log"

# --- DEV 로그 모니터링 Job ---
Start-Job -ScriptBlock {
    $Path = "D:\project\dev.log"
    #$Prefix = "[DEV]"
    $Prefix = ""
    $inSqlBlock = $false
    $inErrorBlock = $false

    Get-Content $Path -Wait -Tail 20 | ForEach-Object {
        $line = $_

        # SQL 블록 시작
        if ($line -match "^-{5,}" -or $line -match "^\s*SQL\s*$" -or $line -match "^\s*select\s" -or $line -match "^\s*insert\s" -or $line -match "^\s*update\s" -or $line -match "^\s*delete\s") {
            $inSqlBlock = $true
            Write-Host "$Prefix $line" -ForegroundColor Green; return
        }

        # SQL 블록 종료
        if ($inSqlBlock -and ($line -match "^-{5,}" -or $line -eq "")) { $inSqlBlock = $false; Write-Host "$Prefix $line" -ForegroundColor Green; return }

        # SQL 블록 내부
        if ($inSqlBlock) { Write-Host "$Prefix $line" -ForegroundColor Green; return }

        # Exception / Error 블록 시작
        if ($line -match "Exception" -or $line -match "Error") { $inErrorBlock = $true; Write-Host "$Prefix [ERR] $line" -ForegroundColor Red; return }

        # Error stack trace
        if ($inErrorBlock -and $line -match "^\s+at ") { Write-Host "$Prefix [ERR] $line" -ForegroundColor Red; return }

        # Error 블록 종료
        if ($inErrorBlock -and $line -eq "") { $inErrorBlock = $false; Write-Host "$Prefix     $line" -ForegroundColor White; return }

        # 일반 로그 레벨별 색상
        switch -Regex ($line) {
            " INFO "  { Write-Host "$Prefix [INF] $line" -ForegroundColor Cyan; break }
            " WARN "  { Write-Host "$Prefix [WRN] $line" -ForegroundColor Yellow; break }
            " ERROR " { Write-Host "$Prefix [ERR] $line" -ForegroundColor Red; break }
            " DEBUG " { Write-Host "$Prefix [DBG] $line" -ForegroundColor DarkGray; break }
            default   { Write-Host "$Prefix $line" -ForegroundColor White }
        }
    }
}

# --- PROD 로그 모니터링 Job ---
Start-Job -ScriptBlock {
    $Path = "D:\project\prod.log"
    #$Prefix = "[PROD]"
    $Prefix = ""
    $inSqlBlock = $false
    $inErrorBlock = $false

    Get-Content $Path -Wait -Tail 20 | ForEach-Object {
        $line = $_

        if ($line -match "^-{5,}" -or $line -match "^\s*SQL\s*$" -or $line -match "^\s*select\s" -or $line -match "^\s*insert\s" -or $line -match "^\s*update\s" -or $line -match "^\s*delete\s") {
            $inSqlBlock = $true
            Write-Host "$Prefix $line" -ForegroundColor Green; return
        }
        if ($inSqlBlock -and ($line -match "^-{5,}" -or $line -eq "")) { $inSqlBlock = $false; Write-Host "$Prefix $line" -ForegroundColor Green; return }
        if ($inSqlBlock) { Write-Host "$Prefix $line" -ForegroundColor Green; return }

        if ($line -match "Exception" -or $line -match "Error") { $inErrorBlock = $true; Write-Host "$Prefix [ERR] $line" -ForegroundColor Red; return }
        if ($inErrorBlock -and $line -match "^\s+at ") { Write-Host "$Prefix [ERR] $line" -ForegroundColor Red; return }
        if ($inErrorBlock -and $line -eq "") { $inErrorBlock = $false; Write-Host "$Prefix     $line" -ForegroundColor White; return }

        switch -Regex ($line) {
            " INFO "  { Write-Host "$Prefix [INF] $line" -ForegroundColor Cyan; break }
            " WARN "  { Write-Host "$Prefix [WRN] $line" -ForegroundColor Yellow; break }
            " ERROR " { Write-Host "$Prefix [ERR] $line" -ForegroundColor Red; break }
            " DEBUG " { Write-Host "$Prefix [DBG] $line" -ForegroundColor DarkGray; break }
            default   { Write-Host "$Prefix $line" -ForegroundColor White }
        }
    }
}

# --- 두 Job 출력 확인 (실시간 스트리밍)
Get-Job | Receive-Job -Wait -AutoRemoveJob
728x90
반응형

'TOOL > VSCODE' 카테고리의 다른 글

VSCODE 윈도우 화면 깨짐  (0) 2025.09.23

+ Recent posts