from pymilvus import connections, Collection, utility
from config import settings
import json
def connect():
connections.connect(
host=settings.MILVUS_HOST,
port=settings.MILVUS_PORT,
)
print(f"✓ 연결: {settings.MILVUS_HOST}:{settings.MILVUS_PORT}\n")
def show_collections():
"""전체 컬렉션 목록 및 기본 정보"""
print("=" * 55)
print("📦 컬렉션 목록")
print("=" * 55)
cols = utility.list_collections()
if not cols:
print(" 컬렉션 없음")
return
for name in cols:
col = Collection(name)
col.load()
count = col.num_entities
schema_fields = [f.name for f in col.schema.fields]
print(f"\n 이름 : {name}")
print(f" 데이터 수 : {count}건")
print(f" 필드 : {schema_fields}")
col.release()
def show_incident_history(limit: int = 5):
"""인시던트 히스토리 조회"""
print("\n" + "=" * 55)
print("🚨 인시던트 히스토리")
print("=" * 55)
col = Collection(settings.MILVUS_INCIDENT_COLLECTION)
col.load()
if col.num_entities == 0:
print(" 저장된 인시던트 없음")
col.release()
return
results = col.query(
expr="id >= 0",
output_fields=[
"id", "title", "severity", "service",
"namespace", "occurred_at", "root_cause",
"resolution", "tags",
],
limit=limit,
)
for r in results:
print(f"\n [{r.get('severity', '').upper()}] {r.get('title')}")
print(f" ID : {r.get('id')}")
print(f" 서비스 : {r.get('service')} / {r.get('namespace')}")
print(f" 발생일시 : {r.get('occurred_at')}")
print(f" 근본원인 : {r.get('root_cause', '')[:100]}")
print(f" 해결방법 : {r.get('resolution', '')[:100]}")
print(f" 태그 : {r.get('tags')}")
print(f" {'─' * 50}")
col.release()
def show_runbook_knowledge(limit: int = 5):
"""Runbook 지식베이스 조회"""
print("\n" + "=" * 55)
print("📖 Runbook 지식베이스")
print("=" * 55)
col = Collection(settings.MILVUS_RUNBOOK_COLLECTION)
col.load()
if col.num_entities == 0:
print(" 저장된 Runbook 없음")
col.release()
return
results = col.query(
expr="id >= 0",
output_fields=["id", "title", "category", "source_file", "chunk_index", "content"],
limit=limit,
)
for r in results:
print(f"\n [{r.get('category')}] {r.get('title')} (chunk #{r.get('chunk_index')})")
print(f" 소스 : {r.get('source_file')}")
print(f" 내용 : {r.get('content', '')[:150]}...")
print(f" {'─' * 50}")
col.release()
def show_normal_log_baseline(limit: int = 5):
"""정상 로그 베이스라인 조회"""
print("\n" + "=" * 55)
print("📊 정상 로그 베이스라인")
print("=" * 55)
col = Collection(settings.MILVUS_NORMAL_LOG_COLLECTION)
col.load()
if col.num_entities == 0:
print(" 저장된 베이스라인 없음")
col.release()
return
results = col.query(
expr="id >= 0",
output_fields=["id", "log_message", "container", "namespace", "sampled_at"],
limit=limit,
)
for r in results:
print(f"\n 컨테이너 : {r.get('container')} / {r.get('namespace')}")
print(f" 수집일시 : {r.get('sampled_at')}")
print(f" 로그 : {r.get('log_message', '')[:150]}")
print(f" {'─' * 50}")
col.release()
def search_incident_by_keyword(keyword: str, limit: int = 5):
"""인시던트를 키워드로 필터링 조회 (scalar 검색)"""
print(f"\n🔍 인시던트 키워드 검색: '{keyword}'")
print("=" * 55)
col = Collection(settings.MILVUS_INCIDENT_COLLECTION)
col.load()
results = col.query(
expr=f'service == "{keyword}" or tags like "%{keyword}%"',
output_fields=["id", "title", "severity", "service", "occurred_at", "root_cause"],
limit=limit,
)
if not results:
print(f" '{keyword}' 관련 인시던트 없음")
else:
for r in results:
print(f"\n [{r.get('severity')}] {r.get('title')}")
print(f" 서비스 : {r.get('service')}")
print(f" 발생일시 : {r.get('occurred_at')}")
print(f" 원인 : {r.get('root_cause', '')[:100]}")
col.release()
def delete_incident_by_id(incident_id: int):
"""인시던트 ID로 삭제"""
col = Collection(settings.MILVUS_INCIDENT_COLLECTION)
col.delete(f"id == {incident_id}")
col.flush()
print(f"✓ 인시던트 ID {incident_id} 삭제 완료")
def show_stats():
"""전체 통계 요약"""
print("\n" + "=" * 55)
print("📈 전체 통계")
print("=" * 55)
for col_name in [
settings.MILVUS_INCIDENT_COLLECTION,
settings.MILVUS_RUNBOOK_COLLECTION,
settings.MILVUS_NORMAL_LOG_COLLECTION,
]:
if utility.has_collection(col_name):
col = Collection(col_name)
col.load()
print(f" {col_name:35s}: {col.num_entities:>6}건")
col.release()
else:
print(f" {col_name:35s}: 컬렉션 없음")
if __name__ == "__main__":
import sys
connect()
show_stats()
if len(sys.argv) == 1:
show_collections()
show_incident_history(limit=5)
show_runbook_knowledge(limit=5)
show_normal_log_baseline(limit=5)
elif sys.argv[1] == "search" and len(sys.argv) > 2:
keyword = sys.argv[2]
search_incident_by_keyword(keyword)
elif sys.argv[1] == "delete" and len(sys.argv) > 2:
delete_incident_by_id(int(sys.argv[2]))