| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- import { Injectable, OnDestroy } from '@angular/core';
- import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';
- import { LogEntry } from '../models/log.model';
- import { AuthService } from './auth.service';
-
- @Injectable({
- providedIn: 'root'
- })
- export class LogService implements OnDestroy {
- private logStreamSubject = new Subject<LogEntry>();
- logStream$ = this.logStreamSubject.asObservable();
-
- private logs: LogEntry[] = [];
- private logsSubject = new BehaviorSubject<LogEntry[]>([]);
- logs$ = this.logsSubject.asObservable();
-
- private eventSource: EventSource | null = null;
- private isConnected = false;
-
- private subscriptions: Subscription = new Subscription();
- private currentSessionId?: string;
-
- constructor(private authService: AuthService) {
- this.initializeAuthSubscription();
- }
-
- // 初始化认证状态订阅
- private initializeAuthSubscription() {
- this.subscriptions.add(
- this.authService.authState$.subscribe(authState => {
- console.log('LogService: 认证状态变化', authState.isAuthenticated);
-
- if (authState.isAuthenticated) {
- // 用户已登录,连接日志流
- this.connectToLogStream();
- } else {
- // 用户登出,断开日志流
- this.disconnect();
-
- // 添加日志通知
- this.addLog({
- id: Date.now().toString(),
- timestamp: new Date(),
- level: 'info',
- message: '用户未登录,日志流未连接',
- source: 'log-service'
- });
- }
- })
- );
- }
-
- // 连接到日志流
- connectToLogStream(sessionId?: string) {
- if (this.eventSource) {
- this.eventSource.close();
- }
-
- // 检查是否已登录
- if (!this.authService.isAuthenticated()) {
- console.warn('未登录状态,不连接日志流');
- return;
- }
-
- // 获取认证token
- const token = this.authService.getToken();
- if (!token) {
- console.error('无法获取认证token');
- return;
- }
-
- // 构建带认证参数的URL
- let url = `/api/logs/stream?token=${encodeURIComponent(token)}`;
- if (sessionId) {
- url += `&sessionId=${sessionId}`;
- }
-
- console.log('连接日志流URL:', url);
- this.eventSource = new EventSource(url);
-
- this.eventSource.onopen = () => {
- console.log('日志流连接已建立');
- this.isConnected = true;
- this.addLog({
- id: Date.now().toString(),
- timestamp: new Date(),
- level: 'info',
- message: '已连接到日志流',
- source: 'log-service'
- });
- };
-
- this.eventSource.onmessage = (event) => {
- const logData = event.data;
- if (logData && logData !== ': heartbeat') {
- const logEntry: LogEntry = {
- id: Date.now().toString(),
- timestamp: new Date(),
- level: 'info', // 默认级别,实际可能从日志中解析
- message: logData,
- source: 'opencode'
- };
-
- // 尝试解析日志级别
- if (logData.toLowerCase().includes('error')) {
- logEntry.level = 'error';
- } else if (logData.toLowerCase().includes('warn')) {
- logEntry.level = 'warn';
- } else if (logData.toLowerCase().includes('debug')) {
- logEntry.level = 'debug';
- }
-
- // 尝试提取会话ID
- const sessionMatch = logData.match(/session[:\s-]*([a-zA-Z0-9_-]+)/i);
- if (sessionMatch) {
- logEntry.sessionID = sessionMatch[1];
- }
-
- this.addLog(logEntry);
- }
- };
-
- this.eventSource.onerror = (error) => {
- console.error('日志流连接错误:', error);
- this.isConnected = false;
-
- // 检查是否仍然登录
- if (this.authService.isAuthenticated()) {
- this.addLog({
- id: Date.now().toString(),
- timestamp: new Date(),
- level: 'error',
- message: '日志流连接断开,正在重连...',
- source: 'log-service'
- });
-
- // 5秒后重连(仅在登录状态下)
- setTimeout(() => {
- if (this.authService.isAuthenticated()) {
- this.connectToLogStream(sessionId);
- }
- }, 5000);
- } else {
- this.addLog({
- id: Date.now().toString(),
- timestamp: new Date(),
- level: 'warn',
- message: '日志流连接断开(用户未登录)',
- source: 'log-service'
- });
- }
- };
- }
-
- // 断开日志流连接
- disconnect() {
- if (this.eventSource) {
- this.eventSource.close();
- this.eventSource = null;
- this.isConnected = false;
-
- this.addLog({
- id: Date.now().toString(),
- timestamp: new Date(),
- level: 'info',
- message: '已断开日志流连接',
- source: 'log-service'
- });
- }
- }
-
- // 添加日志
- private addLog(log: LogEntry) {
- this.logs.unshift(log); // 新的在前面
- if (this.logs.length > 1000) { // 限制日志数量
- this.logs.pop();
- }
-
- this.logsSubject.next([...this.logs]);
- this.logStreamSubject.next(log);
- }
-
- // 手动添加日志
- log(level: 'info' | 'warn' | 'error' | 'debug', message: string, source?: string, sessionId?: string) {
- const logEntry: LogEntry = {
- id: Date.now().toString(),
- timestamp: new Date(),
- level,
- message,
- source: source || 'app',
- sessionID: sessionId
- };
-
- this.addLog(logEntry);
- }
-
- // 获取所有日志
- getLogs(): LogEntry[] {
- return [...this.logs];
- }
-
- // 根据条件过滤日志
- getFilteredLogs(filter: { sessionId?: string; level?: string; limit?: number }): LogEntry[] {
- let filtered = [...this.logs];
-
- if (filter.sessionId) {
- filtered = filtered.filter(log => log.sessionID === filter.sessionId);
- }
-
- if (filter.level && filter.level !== 'all') {
- filtered = filtered.filter(log => log.level === filter.level);
- }
-
- if (filter.limit) {
- filtered = filtered.slice(0, filter.limit);
- }
-
- return filtered;
- }
-
- // 清空日志
- clearLogs() {
- this.logs = [];
- this.logsSubject.next([]);
- }
-
- // 检查连接状态
- isStreamConnected(): boolean {
- return this.isConnected;
- }
-
- // 切换会话过滤
- switchSession(sessionId?: string) {
- if (this.authService.isAuthenticated()) {
- this.connectToLogStream(sessionId);
- } else {
- console.warn('未登录状态,无法切换会话过滤');
- }
- }
-
- ngOnDestroy() {
- this.subscriptions.unsubscribe();
- this.disconnect();
- }
- }
|