增加数据日志开关

This commit is contained in:
Anyon 2020-09-21 11:58:10 +08:00
parent 7e9c209c65
commit c2a5e46c2a
8 changed files with 124 additions and 50 deletions

View File

@ -16,6 +16,7 @@
namespace app\admin\controller;
use think\admin\Controller;
use think\admin\service\AdminService;
/**
* 系统日志管理
@ -42,6 +43,7 @@ class Oplog extends Controller
public function index()
{
$this->title = '系统日志管理';
$this->isSupper = AdminService::instance()->isSuper();
$query = $this->_query($this->table)->like('action,node,content,username,geoip');
$query->dateBetween('create_at')->order('id desc')->page();
}

View File

@ -78,6 +78,27 @@ class Plugs extends Controller
}
}
/**
* 数据变更日志
* @login true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function oplog()
{
if (AdminService::instance()->isSuper()) {
$data = $this->_vali([
'state.in:0,1' => '状态值范围错误!',
'state.require' => '状态值不能为空!',
]);
sysconf('base.oplog_state', $data['state']);
$this->success('数据变更日志切换成功!');
} else {
$this->error('只有超级管理员才能操作!');
}
}
/**
* 当前运行模式
* @login true

View File

@ -17,44 +17,55 @@ use think\admin\service\AdminService;
use think\admin\service\SystemService;
use think\helper\Str;
/*! 全局操作日志数据 */
try {
/*! 全局数据变更数据 */
$GLOBALS['oplogs'] = [];
/*! 操作日志批量写入 */
/*! 数据变更日志开关状态 */
if (intval(sysconf('base.oplog_state'))) {
/*! 数据变更批量写入 */
app()->event->listen('HttpEnd', function () {
if (is_array($GLOBALS['oplogs']) && count($GLOBALS['oplogs']) > 0) {
foreach (array_chunk($GLOBALS['oplogs'], 100) as $items) {
app()->db->name('SystemOplog')->insertAll($items);
}
$GLOBALS['oplogs'] = [];
if (rand(1, 100) <= 10) {
if (rand(1, 100) <= 10) { /*! 清理一周前的日志记录 */
$lastdate = date('Y-m-d H:i:s', strtotime('-7days'));
app()->db->name('SystemOplog')->where('create_at', '<', $lastdate)->delete();
}
}
});
/*! 数据操作监听分析 */
/*! 数据操作SQL语句监听分析 */
app()->db->listen(function ($sqlstr) {
[$type,] = explode(' ', $sqlstr);
if (in_array($type, ['INSERT', 'UPDATE', 'DELETE']) && AdminService::instance()->isLogin()) {
[$sqlstr] = explode('GROUP BY', explode('ORDER BY', $sqlstr)[0]);
if (preg_match('/^INSERT\s+INTO\s+`(.*?)`\s+SET\s+(.*?)\s*$/i', $sqlstr, $matches)) {
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 200);
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("添加 {$matches[1]} 数据", "添加数据:{$matches[2]}");
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 800);
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("添加 {$matches[1]} 数据", $matches[2]);
}
} elseif (preg_match('/^INSERT\s*INTO\s*`(.*?)`\s*\((.*?)\)\s*VALUES\s+\((.*?)\)\s*$/i', $sqlstr, $matches)) {
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 150);
$matches[3] = substr(str_replace(['`', '\''], '', $matches[3]), 800);
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("添加 {$matches[1]} 数据", "{$matches[2]} VALUES {$matches[3]}");
}
} elseif (preg_match('/^UPDATE\s+`(.*?)`\s+SET\s+(.*?)\s+WHERE\s+(.*?)\s*$/i', $sqlstr, $matches)) {
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
$matches[3] = substr(str_replace(['`', '\''], '', $matches[3]), 0, 200);
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 200);
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("更新 {$matches[1]} 数据 {$matches[3]}", "更新内容 {$matches[2]}");
$matches[3] = substr(str_replace(['`', '\''], '', $matches[3]), 0, 150);
$matches[2] = substr(str_replace(['`', '\''], '', $matches[2]), 0, 800);
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("更新 {$matches[1]} 数据 {$matches[3]}", $matches[2]);
}
} elseif (preg_match('/^DELETE\s*FROM\s*`(.*?)`\s*WHERE\s*(.*?)\s*$/i', $sqlstr, $matches)) {
if (stripos($matches[1] = Str::studly($matches[1]), 'SystemOplog') === false) {
$matches[2] = str_replace(['`', '\''], '', $matches[2]);
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("删除 {$matches[1]} 数据", "删除条件 {$matches[2]}");
$GLOBALS['oplogs'][] = SystemService::instance()->getOplog("删除 {$matches[1]} 数据 {$matches[2]}", "");
}
}
}
});
}
} catch (\Exception $exception) {
app()->log->error($exception->getMessage());
}

View File

@ -16,8 +16,8 @@
<div class="layui-card-header notselect">
<b>运行模式</b><span class="color-desc font-s12 padding-left-5">Run Mode</span>
</div>
<div class="layui-card-body nowrap">
<div class="layui-btn-group">
<div class="layui-card-body">
<div class="layui-btn-group nowrap">
{if $app->isDebug()}
<a class="layui-btn layui-btn-sm layui-btn-active" data-tips-text="当前以开发模式运行中...">以开发模式运行</a>
<a class="layui-btn layui-btn-sm layui-btn-primary" data-tips-text="立即切换到生产模式运行" data-load="{:url('admin/api.plugs/debug')}?state=1">以生产模式运行</a>
@ -27,6 +27,10 @@
{/if}
</div>
</div>
<div class="layui-card-body">
<p><b>开发模式</b>开发人员或在功能调试时使用系统异常时会显示详细的错误信息同时还会记录操作日志及数据库SQL语句信息。</p>
<p><b>生产模式</b>:项目正式部署上线后使用,系统异常时统一显示 {:config('app.error_message')}”,只记录重要的异常日志信息,强烈推荐上线后使用此模式。</p>
</div>
</div>
{/notempty}
@ -34,8 +38,8 @@
<div class="layui-card-header notselect">
<b>存储引擎</b><span class="color-desc font-s12 padding-left-5">Storage Engine</span>
</div>
<div class="layui-card-body nowrap">
<div class="layui-btn-group">
<div class="layui-card-body">
<div class="layui-btn-group nowrap">
{foreach ['local'=>'本地服务器存储','qiniu'=>'七牛云对象存储','alioss'=>'阿里云OSS存储'] as $k => $v} {if sysconf('storage.type') eq $k}
{if auth('storage')}<a data-title="配置{$v}" data-tips-text="切换并配置以{$v}文件" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{/if}
{else}
@ -43,6 +47,11 @@
{/if}{/foreach}
</div>
</div>
<div class="layui-card-body">
<p><b>本地服务器存储</b>:文件直接上传到本地服务器的 `static/upload` 目录,不支持大文件上传,占用服务器磁盘空间,访问时消耗服务器带宽流量。</p>
<p><b>七牛云对象存储</b>:文件直接上传到七牛云存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
<p><b>阿里云OSS存储</b>文件直接上传到阿里云OSS存储空间支持大文件上传不占用服务器空间及服务器带宽流量支持 CDN 加速访问,访问量大时推荐使用。</p>
</div>
</div>
<div class="layui-card padding-20">

View File

@ -1,9 +1,25 @@
{extend name='main'}
{block name="button"}
<!--{if isset($isSupper) and $isSupper}-->
<div class="layui-form inline-block">
<!--{if intval(sysconf('base.oplog_state')) eq 1}-->
<input type="checkbox" title="数据变更日志" value="0" checked lay-filter="OplogState">
<!--{else}-->
<input type="checkbox" title="数据变更日志" value="1" lay-filter="OplogState">
<!--{/if}-->
<script>
form.render(), form.on('checkbox(OplogState)', function (elem) {
$.form.load('{:url("admin/api.plugs/oplog")}', {state: elem.value});
});
</script>
</div>
<!--{/if}-->
<!--{if auth("clear")}-->
<button data-load='{:url("clear")}' data-confirm="确定要消除所有日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>清理日志</button>
<!--{/if}-->
<!--{if auth("remove")}-->
<button data-action='{:url("remove")}' data-rule="id#{key}" data-csrf="{:systoken('remove')}" data-confirm="确定要删除日志吗?" class='layui-btn layui-btn-sm layui-btn-primary'>删除日志</button>
<!--{/if}-->
@ -36,9 +52,11 @@
操作账号:<span class="font-w7">{$vo.username|default='-'}</span><br>
操作节点:<span class="color-desc">{$vo.node|default='-'}</span>
</td>
<td class='text-left nowrap'>
<td class='text-left nowrap padding-row-0 padding-right-0'>
<div style="overflow:auto;max-height:58px;padding:5px 0">
<p class="color-text layui-elip" style="max-width:550px">{$vo.action|default='-'}</p>
<p class="color-desc layui-elip" style="max-width:550px">{$vo.content|default='-'}</p>
<div class="color-desc layui-elip" style="white-space:normal">{$vo.content|default='-'}</div>
</div>
</td>
<td class='text-left nowrap'>
<p class="color-text">{$vo.geoip|default='-'}</p>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -61,11 +61,18 @@ fieldset {
&-group {
overflow: hidden;
line-height: 28px;
border-radius: 5px;
background: #009688;
border: 1px solid #009688 !important;
+ .layui-btn {
margin-left: 8px;
}
.layui-btn {
height: 28px;
line-height: 28px;
border-width: 0 !important;
+ .layui-btn {
@ -93,6 +100,7 @@ fieldset {
}
}
/*! 搜索表单样式 */
.form-search {
.layui-btn {
@ -257,11 +265,16 @@ label.think-radio, label.think-checkbox {
line-height: 24px !important
}
/** Layui 样式调整 */
.layui-input, .layui-select {
line-height: 38px
}
.layui-form-checkbox.layui-form-checked {
i {
border-color: #5FB878;
}
}
.layui-table {
overflow: hidden;
border-width: 0;