mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-18 13:29:03 +08:00
feat: Add log cleanup support for scheduled tasks (#10871)
Refs https://github.com/1Panel-dev/1Panel/issues/5639
This commit is contained in:
parent
3be0dab8a3
commit
9d84120181
33 changed files with 176 additions and 40 deletions
|
|
@ -53,6 +53,12 @@ type CronjobOperate struct {
|
|||
AlertCount uint `json:"alertCount"`
|
||||
AlertTitle string `json:"alertTitle"`
|
||||
AlertMethod string `json:"alertMethod"`
|
||||
|
||||
CleanLogConfig
|
||||
}
|
||||
|
||||
type CleanLogConfig struct {
|
||||
Scopes []string `json:"scopes"`
|
||||
}
|
||||
|
||||
type SnapshotRule struct {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ type Cronjob struct {
|
|||
EntryIDs string `json:"entryIDs"`
|
||||
Records []JobRecords `json:"records"`
|
||||
Secret string `json:"secret"`
|
||||
|
||||
Config string `json:"config"`
|
||||
}
|
||||
|
||||
type JobRecords struct {
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@ func (u *CronjobService) LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, err
|
|||
if cronjob.Type == "snapshot" && len(cronjob.SnapshotRule) != 0 {
|
||||
_ = json.Unmarshal([]byte(cronjob.SnapshotRule), &item.SnapshotRule)
|
||||
}
|
||||
if cronjob.Type == "cleanLog" {
|
||||
_ = json.Unmarshal([]byte(cronjob.Config), &item.CleanLogConfig)
|
||||
}
|
||||
return &item, err
|
||||
}
|
||||
|
||||
|
|
@ -577,6 +580,10 @@ func (u *CronjobService) Create(req dto.CronjobOperate) error {
|
|||
}
|
||||
cronjob.Spec = spec
|
||||
cronjob.EntryIDs = entryIDs
|
||||
if req.Type == "cleanLog" {
|
||||
config, _ := json.Marshal(req.CleanLogConfig)
|
||||
cronjob.Config = string(config)
|
||||
}
|
||||
if err := cronjobRepo.Create(&cronjob); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package service
|
|||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -133,6 +134,8 @@ func (u *CronjobService) loadTask(cronjob *model.Cronjob, record *model.JobRecor
|
|||
err = u.handleSystemLog(*cronjob, record.StartTime, taskItem)
|
||||
case "syncIpGroup":
|
||||
u.handleSyncIpGroup(*cronjob, taskItem)
|
||||
case "cleanLog":
|
||||
u.handleCleanLog(*cronjob, taskItem)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
@ -216,6 +219,48 @@ func (u *CronjobService) handleNtpSync(cronjob model.Cronjob, taskItem *task.Tas
|
|||
}, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleCleanLog(cronjob model.Cronjob, taskItem *task.Task) {
|
||||
taskItem.AddSubTaskWithOps(i18n.GetWithName("CleanLog", cronjob.Name), func(t *task.Task) error {
|
||||
config := GetCleanLogConfig(cronjob)
|
||||
for _, scope := range config.Scopes {
|
||||
switch scope {
|
||||
case "website":
|
||||
websites, _ := websiteRepo.List()
|
||||
for _, website := range websites {
|
||||
curStr := i18n.GetWithName("CleanLogByName", website.PrimaryDomain)
|
||||
t.LogStart(curStr)
|
||||
accessLogPath := GetSitePath(website, SiteAccessLog)
|
||||
if err := os.Truncate(accessLogPath, 0); err != nil {
|
||||
t.LogFailedWithErr(curStr, err)
|
||||
continue
|
||||
}
|
||||
errLogPath := GetSitePath(website, SiteErrorLog)
|
||||
if err := os.Truncate(errLogPath, 0); err != nil {
|
||||
t.LogFailedWithErr(curStr, err)
|
||||
continue
|
||||
}
|
||||
t.LogSuccess(curStr)
|
||||
}
|
||||
appInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
||||
if appInstall.ID > 0 {
|
||||
curStr := i18n.GetWithName("CleanLogByName", "Openresty")
|
||||
t.LogStart(curStr)
|
||||
accessLogPath := path.Join(appInstall.GetPath(), "log", "access.log")
|
||||
if err := os.Truncate(accessLogPath, 0); err != nil {
|
||||
t.LogFailedWithErr(curStr, err)
|
||||
}
|
||||
errLogPath := path.Join(appInstall.GetPath(), "log", "error.log")
|
||||
if err := os.Truncate(errLogPath, 0); err != nil {
|
||||
t.LogFailedWithErr(curStr, err)
|
||||
}
|
||||
t.LogSuccess(curStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
|
||||
}
|
||||
|
||||
func (u *CronjobService) handleSyncIpGroup(cronjob model.Cronjob, taskItem *task.Task) {
|
||||
taskItem.AddSubTaskWithOps(i18n.GetWithName("SyncIpGroup", cronjob.Name), func(t *task.Task) error {
|
||||
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
|
|
@ -417,7 +462,7 @@ func (u *CronjobService) removeExpiredLog(cronjob model.Cronjob) {
|
|||
_ = os.Remove(file)
|
||||
}
|
||||
}
|
||||
_ = cronjobRepo.DeleteRecord(repo.WithByID(uint(records[i].ID)))
|
||||
_ = cronjobRepo.DeleteRecord(repo.WithByID(records[i].ID))
|
||||
_ = taskRepo.Delete(taskRepo.WithByID(records[i].TaskID))
|
||||
_ = os.Remove(path.Join(global.CONF.Base.InstallDir, "1panel/log/task/Cronjob", records[i].TaskID+".log"))
|
||||
}
|
||||
|
|
@ -436,3 +481,9 @@ func handleCronJobAlert(cronjob *model.Cronjob) {
|
|||
}
|
||||
_ = alert_push.PushAlert(pushAlert)
|
||||
}
|
||||
|
||||
func GetCleanLogConfig(cronJob model.Cronjob) dto.CleanLogConfig {
|
||||
config := &dto.CleanLogConfig{}
|
||||
_ = json.Unmarshal([]byte(cronJob.Config), config)
|
||||
return *config
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ IgnoreUploadErr: "Upload failed, error: {{ .detail }}, ignoring this error..."
|
|||
LoadBackupFailed: "Failed to get backup account connection, error: {{ .detail }}"
|
||||
InExecuting: "The current task is being executed, please do not repeat the execution!"
|
||||
NoSuchResource: "No backup content found in the database, skipping..."
|
||||
CleanLog: "Clean Log",
|
||||
CleanLogByName: "Clean {{.name}} Log"
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: 'The current user does not exist, please modify and try again!'
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ Upload: "Subir"
|
|||
LoadBackupFailed: "Error al obtener la conexión de la cuenta de respaldo, error: {{ .detail }}"
|
||||
InExecuting: "La tarea actual se está ejecutando, por favor no la repita"
|
||||
NoSuchResource: "No se encontraron contenidos de respaldo en la base de datos, omitiendo..."
|
||||
CleanLog: "Limpiar registro"
|
||||
CleanLogByName: "Limpiar registro de {{.name}}"
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: 'El usuario actual no existe, modifíquelo e intente de nuevo'
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ IgnoreUploadErr: "アップロード失敗、エラー: {{ .detail }}、この
|
|||
LoadBackupFailed: "バックアップアカウントの接続取得に失敗、エラー: {{ .detail }}"
|
||||
InExecuting: "現在のタスクは実行中です。重複して実行しないでください!"
|
||||
NoSuchResource: "データベースにバックアップ内容が見つかりませんでした。スキップします..."
|
||||
CleanLog: "ログをクリーン"
|
||||
CleanLogByName: "{{.name}} のログをクリーン"
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: '現在のユーザーは存在しません。変更してもう一度お試しください。'
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ IgnoreUploadErr: "업로드 실패, 오류: {{ .detail }}, 이 오류를 무시
|
|||
LoadBackupFailed: "백업 계정 연결 획득 실패, 오류: {{ .detail }}"
|
||||
InExecuting: "현재 작업이 실행 중입니다. 중복 실행하지 마세요!"
|
||||
NoSuchResource: "데이터베이스에서 백업 내용을 찾을 수 없어 건너뜁니다..."
|
||||
CleanLog: "로그 정리"
|
||||
CleanLogByName: "{{.name}} 로그 정리"
|
||||
|
||||
#도구상자
|
||||
ErrNotExistUser: '현재 사용자가 존재하지 않습니다. 수정한 후 다시 시도하세요!'
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ IgnoreUploadErr: "Muat naik gagal, ralat: {{ .detail }}, abaikan ralat ini..."
|
|||
LoadBackupFailed: "Gagal mendapatkan sambungan akaun sandaran, ralat: {{ .detail }}"
|
||||
InExecuting: "Tugas semasa sedang dilaksanakan, jangan ulangi pelaksanaan!"
|
||||
NoSuchResource: "Tiada kandungan sandaran ditemui dalam pangkalan data, dilangkau..."
|
||||
CleanLog: "Bersihkan log"
|
||||
CleanLogByName: "Bersihkan log {{.name}}"
|
||||
|
||||
#kotak alat
|
||||
ErrNotExistUser: 'Pengguna semasa tidak wujud, sila ubah suai dan cuba lagi!'
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ IgnoreUploadErr: "Upload falhou, erro: {{ .detail }}, ignorando este erro..."
|
|||
LoadBackupFailed: "Falha ao obter conexão da conta de backup, erro: {{ .detail }}"
|
||||
InExecuting: "A tarefa atual está sendo executada, não repita a execução!"
|
||||
NoSuchResource: "Nenhum conteúdo de backup encontrado no banco de dados, ignorando..."
|
||||
CleanLog: "Limpar log"
|
||||
CleanLogByName: "Limpar log de {{.name}}"
|
||||
|
||||
#caixa de ferramentas
|
||||
ErrNotExistUser: 'O usuário atual não existe, modifique e tente novamente!'
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ IgnoreUploadErr: "Ошибка загрузки: {{ .detail }}, игнориру
|
|||
LoadBackupFailed: "Не удалось получить подключение к учетной записи резервной копии, ошибка: {{ .detail }}"
|
||||
InExecuting: "Текущая задача выполняется, не повторяйте выполнение!"
|
||||
NoSuchResource: "В базе данных не найдено содержимое резервной копии, пропускаем..."
|
||||
CleanLog: "Очистить журнал"
|
||||
CleanLogByName: "Очистить журнал {{.name}}"
|
||||
|
||||
#ящик для инструментов
|
||||
ErrNotExistUser: 'Текущий пользователь не существует, измените его и повторите попытку!'
|
||||
|
|
|
|||
|
|
@ -250,6 +250,8 @@ IgnoreUploadErr: "Yükleme başarısız, hata: {{ .detail }}, bu hata yoksayıl
|
|||
LoadBackupFailed: "Yedek hesap bağlantısı alınamadı, hata: {{ .detail }}"
|
||||
InExecuting: "Mevcut görev yürütülüyor, lütfen tekrar yürütmeyin!"
|
||||
NoSuchResource: "Veritabanında yedek içeriği bulunamadı, atlanıyor..."
|
||||
CleanLog: "Günlüğü temizle"
|
||||
CleanLogByName: "{{.name}} günlüğünü temizle"
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: 'Mevcut kullanıcı mevcut değil, lütfen değiştirin ve tekrar deneyin!'
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ IgnoreUploadErr: "上傳失敗,錯誤:{{ .detail }},忽略本次錯誤..."
|
|||
LoadBackupFailed: "取得備份帳號連線失敗,錯誤:{{ .detail }}"
|
||||
InExecuting: "目前任務正在執行中,請勿重複執行!"
|
||||
NoSuchResource: "資料庫中未能查詢到備份內容,跳過..."
|
||||
CleanLog: "清理日誌"
|
||||
CleanLogByName: "清理 {{.name}} 日誌"
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: '目前使用者不存在,請修改後重試!'
|
||||
|
|
|
|||
|
|
@ -249,6 +249,8 @@ IgnoreUploadErr: "上传失败,错误:{{ .detail }},忽略本次错误..."
|
|||
LoadBackupFailed: "获取备份账号连接失败,错误:{{ .detail }}"
|
||||
InExecuting: "当前任务正在执行中,请勿重复执行!"
|
||||
NoSuchResource: "数据库中未能查询到备份内容,跳过..."
|
||||
CleanLog: "清理日志"
|
||||
CleanLogByName: "清理 {{.name}} 日志"
|
||||
|
||||
#toolbox
|
||||
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ func InitAgentDB() {
|
|||
migrations.AddTensorRTLLMModel,
|
||||
migrations.UpdateMonitorInterval,
|
||||
migrations.AddMonitorProcess,
|
||||
migrations.UpdateCronJob,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
|
|
|||
|
|
@ -666,3 +666,10 @@ var AddMonitorProcess = &gormigrate.Migration{
|
|||
return global.MonitorDB.AutoMigrate(&model.MonitorBase{})
|
||||
},
|
||||
}
|
||||
|
||||
var UpdateCronJob = &gormigrate.Migration{
|
||||
ID: "20251105-update-cronjob",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.Cronjob{})
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ export namespace Cronjob {
|
|||
alertTitle: string;
|
||||
alertMethod: string;
|
||||
alertMethodItems: Array<string>;
|
||||
|
||||
scopes?: string[];
|
||||
}
|
||||
export interface Item {
|
||||
val: string;
|
||||
|
|
|
|||
|
|
@ -2422,7 +2422,6 @@ const message = {
|
|||
qiteSite: 'Enterprise',
|
||||
videoSite: 'Video',
|
||||
errLog: 'Error log',
|
||||
accessLog: 'Website log',
|
||||
stopHelper:
|
||||
'After stopping the site, it will not be able to access normally, and the user will display the stop page of the current site when visiting. Do you want to continue? ',
|
||||
startHelper:
|
||||
|
|
@ -2433,7 +2432,6 @@ const message = {
|
|||
folderTitle: 'The website mainly contains the following folders',
|
||||
wafFolder: 'Firewall rules',
|
||||
indexFolder: 'Website root directory',
|
||||
logFolder: 'Website log',
|
||||
sslFolder: 'Website Certificate',
|
||||
enableOrNot: 'Enable',
|
||||
oldSSL: 'Existing certificate',
|
||||
|
|
|
|||
|
|
@ -2420,7 +2420,6 @@ const message = {
|
|||
qiteSite: 'Empresa',
|
||||
videoSite: 'Video',
|
||||
errLog: 'Log de errores',
|
||||
accessLog: 'Log de accesos',
|
||||
stopHelper: 'Al detener el sitio, no será accesible y mostrará una página de parada. ¿Deseas continuar?',
|
||||
startHelper: 'Al habilitar el sitio, los usuarios podrán acceder normalmente. ¿Deseas continuar?',
|
||||
sitePath: 'Directorio',
|
||||
|
|
@ -2429,7 +2428,6 @@ const message = {
|
|||
folderTitle: 'El sitio contiene principalmente las siguientes carpetas',
|
||||
wafFolder: 'Reglas del firewall',
|
||||
indexFolder: 'Directorio raíz del sitio',
|
||||
logFolder: 'Logs del sitio',
|
||||
sslFolder: 'Certificados del sitio',
|
||||
enableOrNot: 'Habilitar',
|
||||
oldSSL: 'Certificado existente',
|
||||
|
|
|
|||
|
|
@ -2342,7 +2342,6 @@ const message = {
|
|||
qiteSite: '企業',
|
||||
videoSite: 'ビデオ',
|
||||
errLog: 'エラーログ',
|
||||
accessLog: 'ウェブサイトログ',
|
||||
stopHelper:
|
||||
'サイトを停止した後、正常にアクセスできなくなり、ユーザーは訪問時に現在のサイトの停止ページを表示します。続けたいですか?',
|
||||
startHelper: 'サイトを有効にした後、ユーザーは通常、サイトのコンテンツにアクセスできますが、続行しますか?',
|
||||
|
|
@ -2352,7 +2351,6 @@ const message = {
|
|||
folderTitle: 'ウェブサイトには主に次のフォルダーが含まれています',
|
||||
wafFolder: 'ファイアウォールルール',
|
||||
indexFolder: 'ウェブサイトルートディレクトリ',
|
||||
logFolder: 'ウェブサイトログ',
|
||||
sslFolder: 'ウェブサイト証明書',
|
||||
enableOrNot: '有効にする',
|
||||
oldSSL: '既存の証明書',
|
||||
|
|
|
|||
|
|
@ -2303,7 +2303,6 @@ const message = {
|
|||
qiteSite: '기업',
|
||||
videoSite: '비디오',
|
||||
errLog: '오류 로그',
|
||||
accessLog: '웹사이트 로그',
|
||||
stopHelper:
|
||||
'사이트를 중지하면 정상적으로 액세스할 수 없으며, 사용자가 해당 사이트의 중지 페이지를 보게 됩니다. 계속하시겠습니까?',
|
||||
startHelper: '사이트를 활성화하면 사용자가 정상적으로 사이트 내용을 액세스할 수 있습니다. 계속하시겠습니까?',
|
||||
|
|
@ -2313,7 +2312,6 @@ const message = {
|
|||
folderTitle: '웹사이트는 다음과 같은 폴더를 포함합니다.',
|
||||
wafFolder: '방화벽 규칙',
|
||||
indexFolder: '웹사이트 루트 디렉터리',
|
||||
logFolder: '웹사이트 로그',
|
||||
sslFolder: '웹사이트 인증서',
|
||||
enableOrNot: '활성화 여부',
|
||||
oldSSL: '기존 인증서',
|
||||
|
|
|
|||
|
|
@ -2399,7 +2399,6 @@ const message = {
|
|||
qiteSite: 'Syarikat',
|
||||
videoSite: 'Video',
|
||||
errLog: 'Log Ralat',
|
||||
accessLog: 'Log Laman Web',
|
||||
stopHelper:
|
||||
'Selepas menghentikan laman web, ia tidak akan dapat diakses dengan normal, dan pengguna akan melihat halaman berhenti laman web semasa apabila mengunjunginya. Adakah anda mahu meneruskan?',
|
||||
startHelper:
|
||||
|
|
@ -2410,7 +2409,6 @@ const message = {
|
|||
folderTitle: 'Laman web ini terutamanya mengandungi folder berikut',
|
||||
wafFolder: 'Peraturan firewall',
|
||||
indexFolder: 'Direktori akar laman web',
|
||||
logFolder: 'Log laman web',
|
||||
sslFolder: 'Sijil laman web',
|
||||
enableOrNot: 'Aktifkan',
|
||||
oldSSL: 'Sijil sedia ada',
|
||||
|
|
|
|||
|
|
@ -2401,7 +2401,6 @@ const message = {
|
|||
qiteSite: 'Empresarial',
|
||||
videoSite: 'Site de Vídeo',
|
||||
errLog: 'Erro de log',
|
||||
accessLog: 'Log do site',
|
||||
stopHelper:
|
||||
'Após parar o site, ele não poderá ser acessado normalmente, e o usuário verá a página de parada do site atual ao visitar. Deseja continuar?',
|
||||
startHelper: 'Após ativar o site, os usuários podem acessar o conteúdo do site normalmente, deseja continuar?',
|
||||
|
|
@ -2411,7 +2410,6 @@ const message = {
|
|||
folderTitle: 'O site contém principalmente as seguintes pastas',
|
||||
wafFolder: 'Regras de firewall',
|
||||
indexFolder: 'Diretório raiz do site',
|
||||
logFolder: 'Log do site',
|
||||
sslFolder: 'Certificado do site',
|
||||
enableOrNot: 'Habilitar',
|
||||
oldSSL: 'Certificado existente',
|
||||
|
|
|
|||
|
|
@ -2398,7 +2398,6 @@ const message = {
|
|||
qiteSite: 'Корпоративный',
|
||||
videoSite: 'Видео',
|
||||
errLog: 'Лог ошибок',
|
||||
accessLog: 'Лог веб-сайта',
|
||||
stopHelper:
|
||||
'После остановки сайта он не будет доступен для нормального доступа, и пользователи будут видеть страницу остановки при посещении. Хотите продолжить?',
|
||||
startHelper:
|
||||
|
|
@ -2409,7 +2408,6 @@ const message = {
|
|||
folderTitle: 'Веб-сайт в основном содержит следующие папки',
|
||||
wafFolder: 'Правила межсетевого экрана',
|
||||
indexFolder: 'Корневая директория веб-сайта',
|
||||
logFolder: 'Лог веб-сайта',
|
||||
sslFolder: 'Сертификат веб-сайта',
|
||||
enableOrNot: 'Включить',
|
||||
oldSSL: 'Существующий сертификат',
|
||||
|
|
|
|||
|
|
@ -2456,7 +2456,6 @@ const message = {
|
|||
qiteSite: 'Kurumsal',
|
||||
videoSite: 'Video',
|
||||
errLog: 'Hata günlüğü',
|
||||
accessLog: 'Web sitesi günlüğü',
|
||||
stopHelper:
|
||||
'Site durdurulduktan sonra normal şekilde erişilemeyecek ve kullanıcı siteyi ziyaret ettiğinde mevcut sitenin durdurma sayfası görüntülenecektir. Devam etmek istiyor musunuz? ',
|
||||
startHelper:
|
||||
|
|
@ -2467,7 +2466,6 @@ const message = {
|
|||
folderTitle: 'Web sitesi esas olarak aşağıdaki klasörleri içerir',
|
||||
wafFolder: 'Güvenlik duvarı kuralları',
|
||||
indexFolder: 'Web sitesi kök dizini',
|
||||
logFolder: 'Web sitesi günlüğü',
|
||||
sslFolder: 'Web Sitesi Sertifikası',
|
||||
enableOrNot: 'Etkinleştir',
|
||||
oldSSL: 'Mevcut sertifika',
|
||||
|
|
|
|||
|
|
@ -2253,7 +2253,6 @@ const message = {
|
|||
qiteSite: '企業',
|
||||
videoSite: '影片',
|
||||
errLog: '錯誤日誌',
|
||||
accessLog: '網站日誌',
|
||||
stopHelper: '停止站點後將無法正常訪問,使用者瀏覽會顯示目前站點停止頁面,是否繼續操作?',
|
||||
startHelper: '啟用站點後,使用者可以正常瀏覽網站內容,是否繼續操作?',
|
||||
sitePath: '網站目錄',
|
||||
|
|
@ -2262,7 +2261,6 @@ const message = {
|
|||
folderTitle: '網站主要包含以下資料夾',
|
||||
wafFolder: '防火牆規則',
|
||||
indexFolder: '網站root目錄',
|
||||
logFolder: '網站日誌',
|
||||
sslFolder: '網站證書',
|
||||
enableOrNot: '是否啟用',
|
||||
oldSSL: '選擇已有證書',
|
||||
|
|
|
|||
|
|
@ -1129,6 +1129,9 @@ const message = {
|
|||
noSuchApp: '未检测到 {0} 服务,请前往脚本库页面手动安装!',
|
||||
syncHelper: '即将同步系统脚本库,该操作仅针对系统脚本,是否继续?',
|
||||
},
|
||||
|
||||
cleanLog: '清理日志',
|
||||
cleanLogscope: '清理类型',
|
||||
},
|
||||
monitor: {
|
||||
globalFilter: '全局过滤',
|
||||
|
|
@ -2245,7 +2248,6 @@ const message = {
|
|||
qiteSite: '企业',
|
||||
videoSite: '视频',
|
||||
errLog: '错误日志',
|
||||
accessLog: '网站日志',
|
||||
stopHelper: '停止站点后将无法正常访问,用户访问会显示当前站点停止页面,是否继续操作?',
|
||||
startHelper: '启用站点后,用户可以正常访问网站内容,是否继续操作?',
|
||||
sitePath: '网站目录',
|
||||
|
|
@ -2254,7 +2256,6 @@ const message = {
|
|||
folderTitle: '网站主要包含以下文件夹',
|
||||
wafFolder: '防火墙规则',
|
||||
indexFolder: '网站 root 目录(PHP 运行环境 静态网站代码存放目录)',
|
||||
logFolder: '网站日志',
|
||||
sslFolder: '网站证书',
|
||||
enableOrNot: '是否启用',
|
||||
oldSSL: '选择已有证书',
|
||||
|
|
|
|||
31
frontend/src/views/cronjob/cronjob/config/clean-log.vue
Normal file
31
frontend/src/views/cronjob/cronjob/config/clean-log.vue
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<el-card>
|
||||
<el-form-item :label="$t('cronjob.cleanLogscope')" prop="scopes">
|
||||
<el-select :model-value="modelValue" multiple @change="handleChange" clearable>
|
||||
<el-option v-for="item in scopes" :key="item.value" :value="item.value" :label="item.label" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import i18n from '@/lang';
|
||||
|
||||
interface Props {
|
||||
modelValue?: string[];
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
modelValue: () => [],
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string[]): void;
|
||||
}>();
|
||||
|
||||
const handleChange = (value: string[]) => {
|
||||
emit('update:modelValue', value);
|
||||
};
|
||||
|
||||
const scopes = [{ value: 'website', label: i18n.global.t('logs.websiteLog') }];
|
||||
</script>
|
||||
|
|
@ -201,3 +201,19 @@ export function hasBackup(type: string) {
|
|||
type === 'cutWebsiteLog'
|
||||
);
|
||||
}
|
||||
|
||||
export const cronjobTypes = [
|
||||
{ value: 'shell', label: i18n.global.t('cronjob.shell') },
|
||||
{ value: 'app', label: i18n.global.t('cronjob.app') },
|
||||
{ value: 'website', label: i18n.global.t('cronjob.website') },
|
||||
{ value: 'database', label: i18n.global.t('cronjob.database') },
|
||||
{ value: 'directory', label: i18n.global.t('cronjob.directory') },
|
||||
{ value: 'log', label: i18n.global.t('cronjob.log') },
|
||||
{ value: 'curl', label: i18n.global.t('cronjob.curl') },
|
||||
{ value: 'cutWebsiteLog', label: i18n.global.t('cronjob.cutWebsiteLog') },
|
||||
{ value: 'clean', label: i18n.global.t('setting.diskClean') },
|
||||
{ value: 'snapshot', label: i18n.global.t('cronjob.snapshot') },
|
||||
{ value: 'ntp', label: i18n.global.t('cronjob.ntp') },
|
||||
{ value: 'syncIpGroup', label: i18n.global.t('cronjob.syncIpGroup') },
|
||||
{ value: 'cleanLog', label: i18n.global.t('cronjob.cleanLog') },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -15,18 +15,12 @@
|
|||
@change="changeType"
|
||||
v-model="form.type"
|
||||
>
|
||||
<el-option value="shell" :label="$t('cronjob.shell')" />
|
||||
<el-option value="app" :label="$t('cronjob.app')" />
|
||||
<el-option value="website" :label="$t('cronjob.website')" />
|
||||
<el-option value="database" :label="$t('cronjob.database')" />
|
||||
<el-option value="directory" :label="$t('cronjob.directory')" />
|
||||
<el-option value="log" :label="$t('cronjob.log')" />
|
||||
<el-option value="curl" :label="$t('cronjob.curl')" />
|
||||
<el-option value="cutWebsiteLog" :label="$t('cronjob.cutWebsiteLog')" />
|
||||
<el-option value="clean" :label="$t('setting.diskClean')" />
|
||||
<el-option value="snapshot" :label="$t('cronjob.snapshot')" />
|
||||
<el-option value="ntp" :label="$t('cronjob.ntp')" />
|
||||
<el-option value="syncIpGroup" :label="$t('cronjob.syncIpGroup')" />
|
||||
<el-option
|
||||
v-for="item in cronjobTypes"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<div v-else class="w-full">
|
||||
<el-tag>{{ $t('cronjob.' + form.type) }}</el-tag>
|
||||
|
|
@ -94,6 +88,12 @@
|
|||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<CleanLogConfig
|
||||
v-if="form.type == 'cleanLog'"
|
||||
class="mt-5"
|
||||
v-model="form.scopes"
|
||||
></CleanLogConfig>
|
||||
|
||||
<el-card class="mt-5">
|
||||
<el-form-item :label="$t('cronjob.cronSpec')" prop="specCustom">
|
||||
<el-checkbox :label="$t('container.custom')" v-model="form.specCustom" />
|
||||
|
|
@ -756,17 +756,19 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import FileList from '@/components/file-list/index.vue';
|
||||
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
|
||||
import InputTag from '@/components/input-tag/index.vue';
|
||||
import LayoutCol from '@/components/layout-col/form.vue';
|
||||
import CleanLogConfig from '@/views/cronjob/cronjob/config/clean-log.vue';
|
||||
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import FileList from '@/components/file-list/index.vue';
|
||||
import { listBackupOptions } from '@/api/modules/backup';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Cronjob } from '@/api/interface/cronjob';
|
||||
import { addCronjob, editCronjob, loadCronjobInfo, loadNextHandle, loadScriptOptions } from '@/api/modules/cronjob';
|
||||
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
|
||||
import InputTag from '@/components/input-tag/index.vue';
|
||||
import LayoutCol from '@/components/layout-col/form.vue';
|
||||
import { listDbItems } from '@/api/modules/database';
|
||||
import { getWebsiteOptions } from '@/api/modules/website';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
|
|
@ -781,6 +783,7 @@ import {
|
|||
transObjToSpec,
|
||||
transSpecToObj,
|
||||
weekOptions,
|
||||
cronjobTypes,
|
||||
} from '../helper';
|
||||
import { loadUsers } from '@/api/modules/toolbox';
|
||||
import { loadContainerUsers } from '@/api/modules/container';
|
||||
|
|
@ -864,6 +867,8 @@ const form = reactive<Cronjob.CronjobInfo>({
|
|||
alertTitle: '',
|
||||
alertMethod: '',
|
||||
alertMethodItems: [],
|
||||
|
||||
scopes: [],
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
|
|
@ -961,6 +966,7 @@ const search = async () => {
|
|||
} else {
|
||||
form.alertMethodItems = [];
|
||||
}
|
||||
form.scopes = res.data.scopes;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
|
|
@ -1156,6 +1162,7 @@ const rules = reactive({
|
|||
timeoutUnit: [Rules.requiredSelect],
|
||||
alertCount: [Rules.integerNumber, { validator: checkSendCount, trigger: 'blur' }],
|
||||
alertMethodItems: [Rules.requiredSelect],
|
||||
scopes: [Rules.requiredSelect],
|
||||
});
|
||||
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
|
|
@ -1257,6 +1264,9 @@ const loadDatabases = async (dbType: string) => {
|
|||
const changeType = () => {
|
||||
form.specObjs = [loadDefaultSpec(form.type)];
|
||||
form.specs = [loadDefaultSpecCustom(form.type)];
|
||||
if (form.type === 'cleanLog') {
|
||||
form.name = i18n.global.t('cronjob.cleanLog');
|
||||
}
|
||||
};
|
||||
|
||||
const changeSpecType = (index: number) => {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
<br />
|
||||
<el-descriptions :title="$t('website.folderTitle')" :column="1" border>
|
||||
<el-descriptions-item label="ssl">{{ $t('website.sslFolder') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="log">{{ $t('website.logFolder') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="log">{{ $t('logs.websiteLog') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="index">{{ $t('website.indexFolder') }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<el-tabs tab-position="left" v-model="index">
|
||||
<el-tab-pane :label="$t('website.accessLog')" name="0">
|
||||
<el-tab-pane :label="$t('logs.websiteLog')" name="0">
|
||||
<LogFile :id="id" :log-type="'access.log'" v-if="index == '0'"></LogFile>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('website.errLog')" name="1">
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ const clearLog = () => {
|
|||
};
|
||||
|
||||
const cleanLog = async () => {
|
||||
let log = props.logType === 'access.log' ? i18n.global.t('website.accessLog') : i18n.global.t('website.errLog');
|
||||
let log = props.logType === 'access.log' ? i18n.global.t('logs.websiteLog') : i18n.global.t('website.errLog');
|
||||
opRef.value.acceptParams({
|
||||
title: i18n.global.t('commons.button.clean'),
|
||||
names: [],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue