log.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. //go:build darwin || linux || windows
  2. package libbox
  3. import (
  4. "archive/zip"
  5. "io"
  6. "io/fs"
  7. "os"
  8. "path/filepath"
  9. "runtime"
  10. "runtime/debug"
  11. "time"
  12. )
  13. type crashReportMetadata struct {
  14. reportMetadata
  15. CrashedAt string `json:"crashedAt,omitempty"`
  16. SignalName string `json:"signalName,omitempty"`
  17. SignalCode string `json:"signalCode,omitempty"`
  18. ExceptionName string `json:"exceptionName,omitempty"`
  19. ExceptionReason string `json:"exceptionReason,omitempty"`
  20. }
  21. func archiveCrashReport(path string, crashReportsDir string) {
  22. content, err := os.ReadFile(path)
  23. if err != nil || len(content) == 0 {
  24. return
  25. }
  26. info, _ := os.Stat(path)
  27. crashTime := time.Now().UTC()
  28. if info != nil {
  29. crashTime = info.ModTime().UTC()
  30. }
  31. initReportDir(crashReportsDir)
  32. destPath, err := nextAvailableReportPath(crashReportsDir, crashTime)
  33. if err != nil {
  34. return
  35. }
  36. initReportDir(destPath)
  37. writeReportFile(destPath, "go.log", content)
  38. metadata := crashReportMetadata{
  39. reportMetadata: baseReportMetadata(),
  40. CrashedAt: crashTime.Format(time.RFC3339),
  41. }
  42. writeReportMetadata(destPath, metadata)
  43. os.Remove(path)
  44. copyConfigSnapshot(destPath)
  45. }
  46. func configSnapshotPath() string {
  47. return filepath.Join(sBasePath, "configuration.json")
  48. }
  49. func saveConfigSnapshot(configContent string) {
  50. snapshotPath := configSnapshotPath()
  51. os.WriteFile(snapshotPath, []byte(configContent), 0o666)
  52. chownReport(snapshotPath)
  53. }
  54. func redirectStderr(path string) error {
  55. crashReportsDir := filepath.Join(sWorkingPath, "crash_reports")
  56. archiveCrashReport(path, crashReportsDir)
  57. archiveCrashReport(path+".old", crashReportsDir)
  58. outputFile, err := os.Create(path)
  59. if err != nil {
  60. return err
  61. }
  62. if runtime.GOOS != "android" && runtime.GOOS != "windows" {
  63. err = outputFile.Chown(sUserID, sGroupID)
  64. if err != nil {
  65. outputFile.Close()
  66. os.Remove(outputFile.Name())
  67. return err
  68. }
  69. }
  70. err = debug.SetCrashOutput(outputFile, debug.CrashOptions{})
  71. if err != nil {
  72. outputFile.Close()
  73. os.Remove(outputFile.Name())
  74. return err
  75. }
  76. _ = outputFile.Close()
  77. return nil
  78. }
  79. func CreateZipArchive(sourcePath string, destinationPath string) error {
  80. sourceInfo, err := os.Stat(sourcePath)
  81. if err != nil {
  82. return err
  83. }
  84. if !sourceInfo.IsDir() {
  85. return os.ErrInvalid
  86. }
  87. destinationFile, err := os.Create(destinationPath)
  88. if err != nil {
  89. return err
  90. }
  91. defer func() {
  92. _ = destinationFile.Close()
  93. }()
  94. zipWriter := zip.NewWriter(destinationFile)
  95. rootName := filepath.Base(sourcePath)
  96. err = filepath.WalkDir(sourcePath, func(path string, d fs.DirEntry, err error) error {
  97. if err != nil {
  98. return err
  99. }
  100. relativePath, err := filepath.Rel(sourcePath, path)
  101. if err != nil {
  102. return err
  103. }
  104. if relativePath == "." {
  105. return nil
  106. }
  107. archivePath := filepath.ToSlash(filepath.Join(rootName, relativePath))
  108. if d.IsDir() {
  109. _, err = zipWriter.Create(archivePath + "/")
  110. return err
  111. }
  112. fileInfo, err := d.Info()
  113. if err != nil {
  114. return err
  115. }
  116. header, err := zip.FileInfoHeader(fileInfo)
  117. if err != nil {
  118. return err
  119. }
  120. header.Name = archivePath
  121. header.Method = zip.Deflate
  122. writer, err := zipWriter.CreateHeader(header)
  123. if err != nil {
  124. return err
  125. }
  126. sourceFile, err := os.Open(path)
  127. if err != nil {
  128. return err
  129. }
  130. _, err = io.Copy(writer, sourceFile)
  131. closeErr := sourceFile.Close()
  132. if err != nil {
  133. return err
  134. }
  135. return closeErr
  136. })
  137. if err != nil {
  138. _ = zipWriter.Close()
  139. return err
  140. }
  141. return zipWriter.Close()
  142. }