feat(frpLogger): add real-time instance log streaming functionality

Implement cross-platform log streaming for frpc instances with support for Windows, systemd, and init.d systems. Includes WebSocket API endpoint for real-time log streaming, token validation, and instance ownership checks. Update README and API documentation to reflect new functionality.

The implementation handles:
- Platform-specific log collection (Windows Event Log, journalctl, log files)
- WebSocket-based real-time streaming
- Token validation and instance access control
- Log level parsing and formatting
- Historical log retrieval since service start
This commit is contained in:
2026-03-26 17:46:50 +08:00
parent 61e4ad6ecc
commit 839bad3c94
11 changed files with 1658 additions and 7 deletions

65
frpLogger/os.go Normal file
View File

@@ -0,0 +1,65 @@
package frpLogger
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
)
func GetInitSystem() string {
if runtime.GOOS == "windows" {
return "windows"
}
if runtime.GOOS == "linux" {
if _, err := os.Stat("/run/systemd/system"); err == nil {
return "systemd"
}
if _, err := os.Stat("/etc/init.d"); err == nil {
return "init.d"
}
}
return "unknown"
}
func IsInstanceRunning(instanceID int) bool {
initType := GetInitSystem()
serviceName, err := GetServiceNameByInstanceID(instanceID)
if err != nil {
return false
}
switch initType {
case "windows":
cmd := exec.Command("sc", "query", serviceName)
output, err := cmd.CombinedOutput()
if err != nil {
return false
}
return strings.Contains(string(output), "RUNNING")
case "systemd":
cmd := exec.Command("systemctl", "is-active", serviceName)
output, err := cmd.CombinedOutput()
if err != nil {
return false
}
return strings.TrimSpace(string(output)) == "active"
case "init.d":
servicePath := fmt.Sprintf("/etc/init.d/%s", serviceName)
if _, err := os.Stat(servicePath); err != nil {
return false
}
cmd := exec.Command(servicePath, "status")
output, err := cmd.CombinedOutput()
if err != nil {
return false
}
return strings.Contains(string(output), "is running")
default:
return false
}
}