mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-08-30 12:45:32 +08:00
feat(nginx-log): curd 生成 raw/position 后台并改只读
- NginxAccessLog + NginxLogPosition Scheme 加 #[Component] 注解 - Scheme Table name 补 ul_ 前缀(curd 严格校验要求) - curd 生成 nginx 模块完整后台(controller/model/view/js) - Base/App 双层只读控制器(参照 TimerLogBase 范式) - AccessLogBase: add/edit/delete/modify 全部 error - LogPositionBase: 同上 - 视图改造: - access_log 裁剪到 8 列核心字段(time_local/method/uri/status/remote_addr/request_time/body_bytes_sent/http_user_agent) - status/request_time 自定义 badge 渲染 - toolbar 清空 + operat 仅保留详情(B 类只读页面) - log_position 全字段 + 只读化 - HTTP 验证:index 200 OK + add/edit/delete/modify 全部返回错误
This commit is contained in:
13
app/admin/controller/nginx/AccessLog.php
Normal file
13
app/admin/controller/nginx/AccessLog.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\nginx;
|
||||
|
||||
use base\admin\controller\nginx\AccessLogBase;
|
||||
|
||||
/**
|
||||
* nginx 访问日志明细(解析入库)
|
||||
* 日志表为只读,由系统定时任务自动写入,后台不支持手动增删改。
|
||||
*/
|
||||
class AccessLog extends AccessLogBase
|
||||
{
|
||||
}
|
||||
13
app/admin/controller/nginx/LogPosition.php
Normal file
13
app/admin/controller/nginx/LogPosition.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller\nginx;
|
||||
|
||||
use base\admin\controller\nginx\LogPositionBase;
|
||||
|
||||
/**
|
||||
* nginx 日志文件读取位置(增量读取状态)
|
||||
* 日志表为只读,由系统定时任务自动维护,后台不支持手动增删改。
|
||||
*/
|
||||
class LogPosition extends LogPositionBase
|
||||
{
|
||||
}
|
||||
@@ -5,30 +5,36 @@ namespace app\admin\model;
|
||||
use app\common\model\TimeModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $file_path 来源日志文件路径
|
||||
* @property string $remote_addr 客户端 IP
|
||||
* @property string $remote_user HTTP 认证用户名
|
||||
* @property int $time_local 请求时间戳
|
||||
* @property string $method HTTP 方法
|
||||
* @property string $uri 请求 URI
|
||||
* @property string $query_string 查询字符串
|
||||
* @property string $http_version HTTP 协议版本
|
||||
* @property int $status HTTP 状态码
|
||||
* @property int $body_bytes_sent 响应体字节数
|
||||
* @property string $http_referer Referer
|
||||
* @property string $http_user_agent User-Agent
|
||||
* @property float $request_time 请求总耗时(秒)
|
||||
* @property float $upstream_response_time upstream 响应时间(秒)
|
||||
* @property int $bytes_sent 总发送字节数
|
||||
* @property string $country 国家
|
||||
* @property string $province 省份
|
||||
* @property string $city 城市
|
||||
* @property int $create_time 入库时间戳
|
||||
* @property int $id 主键ID
|
||||
* @property string $file_path 来源日志文件路径
|
||||
* @property string $remote_addr 客户端 IP(含 IPv6)
|
||||
* @property string $remote_user HTTP 认证用户名
|
||||
* @property int $time_local 请求时间戳(业务时区)
|
||||
* @property string $method HTTP 方法
|
||||
* @property string $uri 请求 URI(超 255 截断)
|
||||
* @property string $query_string 查询字符串
|
||||
* @property string $http_version HTTP 协议版本
|
||||
* @property int $status HTTP 状态码
|
||||
* @property int $body_bytes_sent 响应体字节数
|
||||
* @property string $http_referer Referer
|
||||
* @property string $http_user_agent User-Agent(超 500 截断)
|
||||
* @property float|double $request_time nginx 请求总耗时
|
||||
* @property float|double $upstream_response_time upstream 响应时间
|
||||
* @property int $bytes_sent 总发送字节数(含 header)
|
||||
* @property string $country 国家(GeoIP 预留)
|
||||
* @property string $province 省份(GeoIP 预留)
|
||||
* @property string $city 城市(GeoIP 预留)
|
||||
* @property int $create_time 入库时间戳
|
||||
*/
|
||||
class NginxAccessLog extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_access_log';
|
||||
|
||||
protected $name = "nginx_access_log";
|
||||
|
||||
protected $deleteTime = false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,20 +5,26 @@ namespace app\admin\model;
|
||||
use app\common\model\TimeModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $file_path 日志文件绝对路径
|
||||
* @property int $inode 文件 inode
|
||||
* @property int $offset 字节偏移
|
||||
* @property int $last_read_time 上次读取时间戳
|
||||
* @property string $last_line_hash 上次最后一行 md5
|
||||
* @property int $parse_fail_count 解析失败累计次数
|
||||
* @property string $parse_fail_samples 解析失败样本
|
||||
* @property int $create_time 创建时间戳
|
||||
* @property int $update_time 更新时间戳
|
||||
* @property int $id
|
||||
* @property string $file_path 日志文件绝对路径
|
||||
* @property int $inode 文件 inode,用于检测日志轮转
|
||||
* @property int $offset 上次读取到的字节偏移
|
||||
* @property int $last_read_time 上次读取时间戳
|
||||
* @property string $last_line_hash 上次最后一行的 md5 哈希(容错校验)
|
||||
* @property int $parse_fail_count 解析失败累计次数
|
||||
* @property string $parse_fail_samples 解析失败样本行(最多保留若干条)
|
||||
* @property int $create_time 创建时间戳
|
||||
* @property int $update_time 更新时间戳
|
||||
*/
|
||||
class NginxLogPosition extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_log_position';
|
||||
|
||||
protected $name = "nginx_log_position";
|
||||
|
||||
protected $deleteTime = false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ namespace app\admin\scheme;
|
||||
use app\common\scheme\BaseScheme;
|
||||
use app\common\scheme\attribute\Table;
|
||||
use app\common\scheme\attribute\Field;
|
||||
use app\common\scheme\attribute\Component;
|
||||
use app\common\scheme\attribute\Index;
|
||||
|
||||
#[Table(name: 'nginx_access_log', comment: 'nginx 访问日志明细(解析入库)')]
|
||||
#[Table(name: 'ul_nginx_access_log', comment: 'nginx 访问日志明细(解析入库)')]
|
||||
#[Index(columns: ['time_local'], name: 'idx_time_local', type: 'NORMAL')]
|
||||
#[Index(columns: ['remote_addr'], name: 'idx_remote_addr', type: 'NORMAL')]
|
||||
#[Index(columns: ['status'], name: 'idx_status', type: 'NORMAL')]
|
||||
@@ -19,59 +20,78 @@ class NginxAccessLog extends BaseScheme
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, comment: '来源日志文件路径')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $file_path;
|
||||
|
||||
#[Field(type: 'varchar', length: 45, nullable: false, comment: '客户端 IP(含 IPv6)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $remote_addr;
|
||||
|
||||
#[Field(type: 'varchar', length: 100, nullable: true, comment: 'HTTP 认证用户名')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $remote_user;
|
||||
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, comment: '请求时间戳(业务时区)')]
|
||||
#[Component(type: 'date', options: [])]
|
||||
public $time_local;
|
||||
|
||||
#[Field(type: 'varchar', length: 10, nullable: true, comment: 'HTTP 方法')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $method;
|
||||
|
||||
#[Field(type: 'varchar', length: 255, nullable: false, comment: '请求 URI(超 255 截断)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $uri;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, default: '', comment: '查询字符串')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $query_string;
|
||||
|
||||
#[Field(type: 'varchar', length: 10, nullable: true, comment: 'HTTP 协议版本')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $http_version;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: 'HTTP 状态码')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $status;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', comment: '响应体字节数')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $body_bytes_sent;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, default: '', comment: 'Referer')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $http_referer;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, default: '', comment: 'User-Agent(超 500 截断)')]
|
||||
#[Component(type: 'textarea', options: [])]
|
||||
public $http_user_agent;
|
||||
|
||||
#[Field(type: 'decimal', precision: 10, scale: 3, default: '0.000', comment: 'nginx 请求总耗时(秒)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $request_time;
|
||||
|
||||
#[Field(type: 'decimal', precision: 10, scale: 3, default: '0.000', comment: 'upstream 响应时间(秒)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $upstream_response_time;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', comment: '总发送字节数(含 header)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $bytes_sent;
|
||||
|
||||
#[Field(type: 'varchar', length: 50, nullable: true, comment: '国家(GeoIP 预留)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $country;
|
||||
|
||||
#[Field(type: 'varchar', length: 50, nullable: true, comment: '省份(GeoIP 预留)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $province;
|
||||
|
||||
#[Field(type: 'varchar', length: 50, nullable: true, comment: '城市(GeoIP 预留)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $city;
|
||||
|
||||
#[Field(type: 'int', length: 11, unsigned: true, comment: '入库时间戳')]
|
||||
#[Component(type: 'date', options: [])]
|
||||
public $create_time;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ namespace app\admin\scheme;
|
||||
use app\common\scheme\BaseScheme;
|
||||
use app\common\scheme\attribute\Table;
|
||||
use app\common\scheme\attribute\Field;
|
||||
use app\common\scheme\attribute\Component;
|
||||
use app\common\scheme\attribute\Index;
|
||||
|
||||
#[Table(name: 'nginx_log_position', comment: 'nginx 日志文件读取位置(增量读取状态)')]
|
||||
#[Table(name: 'ul_nginx_log_position', comment: 'nginx 日志文件读取位置(增量读取状态)')]
|
||||
#[Index(columns: ['file_path'], name: 'uniq_file_path', type: 'UNIQUE')]
|
||||
class NginxLogPosition extends BaseScheme
|
||||
{
|
||||
@@ -15,29 +16,38 @@ class NginxLogPosition extends BaseScheme
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, comment: '日志文件绝对路径')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $file_path;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', unsigned: true, comment: '文件 inode,用于检测日志轮转')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $inode;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', unsigned: true, comment: '上次读取到的字节偏移')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $offset;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', unsigned: true, comment: '上次读取时间戳')]
|
||||
#[Component(type: 'date', options: [])]
|
||||
public $last_read_time;
|
||||
|
||||
#[Field(type: 'varchar', length: 32, default: '', comment: '上次最后一行的 md5 哈希(容错校验)')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $last_line_hash;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', unsigned: true, comment: '解析失败累计次数')]
|
||||
#[Component(type: 'text', options: [])]
|
||||
public $parse_fail_count;
|
||||
|
||||
#[Field(type: 'text', nullable: true, comment: '解析失败样本行(最多保留若干条)')]
|
||||
#[Component(type: 'textarea', options: [])]
|
||||
public $parse_fail_samples;
|
||||
|
||||
#[Field(type: 'int', length: 11, unsigned: true, comment: '创建时间戳')]
|
||||
#[Component(type: 'date', options: [])]
|
||||
public $create_time;
|
||||
|
||||
#[Field(type: 'int', length: 11, unsigned: true, comment: '更新时间戳')]
|
||||
#[Component(type: 'date', options: [])]
|
||||
public $update_time;
|
||||
}
|
||||
|
||||
11
app/admin/view/nginx/access_log/_common.js
Normal file
11
app/admin/view/nginx/access_log/_common.js
Normal file
@@ -0,0 +1,11 @@
|
||||
var init = {
|
||||
tableElem: '#currentTable',
|
||||
tableRenderId: 'currentTableRenderId',
|
||||
indexUrl: 'nginx.access_log/index',
|
||||
addUrl: '',
|
||||
editUrl: '',
|
||||
readUrl: 'nginx.access_log/read',
|
||||
deleteUrl: '',
|
||||
exportUrl: '',
|
||||
modifyUrl: '',
|
||||
};
|
||||
122
app/admin/view/nginx/access_log/add.html
Normal file
122
app/admin/view/nginx/access_log/add.html
Normal file
@@ -0,0 +1,122 @@
|
||||
<div class="layuimini-container">
|
||||
<form id="app-form" class="layui-form layuimini-form">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">来源日志文件路径</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="file_path" class="layui-input" lay-verify="required" placeholder="请输入来源日志文件路径" value="{$Request.param.file_path|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">客户端 IP(含 IPv6)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remote_addr" class="layui-input" lay-verify="required" placeholder="请输入客户端 IP(含 IPv6)" value="{$Request.param.remote_addr|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 认证用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remote_user" class="layui-input" placeholder="请输入HTTP 认证用户名" value="{$Request.param.remote_user|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">请求时间戳(业务时区)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="time_local" data-date="" data-date-type="datetime" class="layui-input" lay-verify="required" placeholder="请输入请求时间戳(业务时区)" value="{$Request.param.time_local|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 方法</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="method" class="layui-input" placeholder="请输入HTTP 方法" value="{$Request.param.method|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">请求 URI(超 255 截断)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="uri" class="layui-input" lay-verify="required" placeholder="请输入请求 URI(超 255 截断)" value="{$Request.param.uri|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">查询字符串</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="query_string" class="layui-input" lay-verify="required" placeholder="请输入查询字符串" value="{$Request.param.query_string|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 协议版本</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="http_version" class="layui-input" placeholder="请输入HTTP 协议版本" value="{$Request.param.http_version|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 状态码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="status" class="layui-input" placeholder="请输入HTTP 状态码" value="{$Request.param.status|default='0'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">响应体字节数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="body_bytes_sent" class="layui-input" placeholder="请输入响应体字节数" value="{$Request.param.body_bytes_sent|default='0'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Referer</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="http_referer" class="layui-input" lay-verify="required" placeholder="请输入Referer" value="{$Request.param.http_referer|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">User-Agent(超 500 截断)</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="http_user_agent" class="layui-textarea" lay-verify="required" placeholder="请输入User-Agent(超 500 截断)">{$Request.param.http_user_agent|default=''}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">nginx 请求总耗时</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="request_time" class="layui-input" placeholder="请输入nginx 请求总耗时" value="{$Request.param.request_time|default='0.000'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">upstream 响应时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="upstream_response_time" class="layui-input" placeholder="请输入upstream 响应时间" value="{$Request.param.upstream_response_time|default='0.000'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">总发送字节数(含 header)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="bytes_sent" class="layui-input" placeholder="请输入总发送字节数(含 header)" value="{$Request.param.bytes_sent|default='0'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">国家(GeoIP 预留)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="country" class="layui-input" placeholder="请输入国家(GeoIP 预留)" value="{$Request.param.country|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">省份(GeoIP 预留)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="province" class="layui-input" placeholder="请输入省份(GeoIP 预留)" value="{$Request.param.province|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">城市(GeoIP 预留)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="city" class="layui-input" placeholder="请输入城市(GeoIP 预留)" value="{$Request.param.city|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line"></div>
|
||||
<div class="layui-form-item text-center">
|
||||
{notempty name='$Request.param.backTagId'}
|
||||
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
|
||||
{/notempty}
|
||||
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
3
app/admin/view/nginx/access_log/add.js
Normal file
3
app/admin/view/nginx/access_log/add.js
Normal file
@@ -0,0 +1,3 @@
|
||||
$(function(){
|
||||
ua.listen();
|
||||
})
|
||||
122
app/admin/view/nginx/access_log/edit.html
Normal file
122
app/admin/view/nginx/access_log/edit.html
Normal file
@@ -0,0 +1,122 @@
|
||||
<div class="layuimini-container">
|
||||
<form id="app-form" class="layui-form layuimini-form">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">来源日志文件路径</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="file_path" class="layui-input" lay-verify="required" placeholder="请输入来源日志文件路径" value="{$row.file_path|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">客户端 IP(含 IPv6)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remote_addr" class="layui-input" lay-verify="required" placeholder="请输入客户端 IP(含 IPv6)" value="{$row.remote_addr|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 认证用户名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="remote_user" class="layui-input" placeholder="请输入HTTP 认证用户名" value="{$row.remote_user|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">请求时间戳(业务时区)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="time_local" data-date="" data-date-type="datetime" class="layui-input" lay-verify="required" placeholder="请输入请求时间戳(业务时区)" value="{$row.time_local|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 方法</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="method" class="layui-input" placeholder="请输入HTTP 方法" value="{$row.method|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">请求 URI(超 255 截断)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="uri" class="layui-input" lay-verify="required" placeholder="请输入请求 URI(超 255 截断)" value="{$row.uri|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">查询字符串</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="query_string" class="layui-input" lay-verify="required" placeholder="请输入查询字符串" value="{$row.query_string|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 协议版本</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="http_version" class="layui-input" placeholder="请输入HTTP 协议版本" value="{$row.http_version|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">HTTP 状态码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="status" class="layui-input" placeholder="请输入HTTP 状态码" value="{$row.status|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">响应体字节数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="body_bytes_sent" class="layui-input" placeholder="请输入响应体字节数" value="{$row.body_bytes_sent|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Referer</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="http_referer" class="layui-input" lay-verify="required" placeholder="请输入Referer" value="{$row.http_referer|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">User-Agent(超 500 截断)</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="http_user_agent" class="layui-textarea" lay-verify="required" placeholder="请输入User-Agent(超 500 截断)">{$row.http_user_agent|raw|default=''}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">nginx 请求总耗时</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="request_time" class="layui-input" placeholder="请输入nginx 请求总耗时" value="{$row.request_time|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">upstream 响应时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="upstream_response_time" class="layui-input" placeholder="请输入upstream 响应时间" value="{$row.upstream_response_time|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">总发送字节数(含 header)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="bytes_sent" class="layui-input" placeholder="请输入总发送字节数(含 header)" value="{$row.bytes_sent|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">国家(GeoIP 预留)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="country" class="layui-input" placeholder="请输入国家(GeoIP 预留)" value="{$row.country|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">省份(GeoIP 预留)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="province" class="layui-input" placeholder="请输入省份(GeoIP 预留)" value="{$row.province|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">城市(GeoIP 预留)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="city" class="layui-input" placeholder="请输入城市(GeoIP 预留)" value="{$row.city|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line"></div>
|
||||
<div class="layui-form-item text-center">
|
||||
{notempty name='$Request.param.backTagId'}
|
||||
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
|
||||
{/notempty}
|
||||
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
3
app/admin/view/nginx/access_log/edit.js
Normal file
3
app/admin/view/nginx/access_log/edit.js
Normal file
@@ -0,0 +1,3 @@
|
||||
$(function(){
|
||||
ua.listen();
|
||||
})
|
||||
9
app/admin/view/nginx/access_log/index.html
Normal file
9
app/admin/view/nginx/access_log/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="layuimini-container">
|
||||
<div class="layuimini-main">
|
||||
<table id="currentTable" class="layui-table layui-hide"
|
||||
data-auth-index="{:auth('nginx.access_log/index')}"
|
||||
data-auth-read="{:auth('nginx.access_log/read')}"
|
||||
lay-filter="currentTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
48
app/admin/view/nginx/access_log/index.js
Normal file
48
app/admin/view/nginx/access_log/index.js
Normal file
@@ -0,0 +1,48 @@
|
||||
$(function(){
|
||||
ua.table.render({
|
||||
init: init,
|
||||
toolbar: [],
|
||||
defaultToolbar: ['filter'],
|
||||
cols: [[
|
||||
{type: 'checkbox'},
|
||||
{field: 'time_local', title: '时间', width: 170, search: 'range', templet: ua.table.date},
|
||||
{field: 'method', title: '方法', width: 80, search: 'select', selectList: {GET: 'GET', POST: 'POST', PUT: 'PUT', DELETE: 'DELETE', HEAD: 'HEAD', OPTIONS: 'OPTIONS', PATCH: 'PATCH'}},
|
||||
{field: 'uri', title: 'URI', minWidth: 200, searchOp: '%*%'},
|
||||
{field: 'status', title: '状态码', width: 90, search: 'select', selectList: {200: '200', 301: '301', 302: '302', 304: '304', 400: '400', 401: '401', 403: '403', 404: '404', 499: '499', 500: '500', 502: '502', 503: '503', 504: '504'}, templet: function(d) {
|
||||
var s = parseInt(d.status);
|
||||
var cls = 'layui-badge';
|
||||
if (s >= 200 && s < 300) cls = 'layui-badge layui-bg-green';
|
||||
else if (s >= 300 && s < 400) cls = 'layui-badge layui-bg-blue';
|
||||
else if (s >= 400 && s < 500) cls = 'layui-badge layui-bg-orange';
|
||||
else if (s >= 500) cls = 'layui-badge layui-bg-red';
|
||||
return '<span class="' + cls + '">' + d.status + '</span>';
|
||||
}},
|
||||
{field: 'remote_addr', title: '客户端IP', width: 140, searchOp: '%*%'},
|
||||
{field: 'request_time', title: '耗时(秒)', width: 100, search: 'number_limit', templet: function(d) {
|
||||
var t = parseFloat(d.request_time);
|
||||
if (t >= 1) return '<span class="layui-badge layui-bg-red">' + t + 's</span>';
|
||||
if (t >= 0.3) return '<span class="layui-badge layui-bg-orange">' + t + 's</span>';
|
||||
return t + 's';
|
||||
}},
|
||||
{field: 'body_bytes_sent', title: '响应字节', width: 100, search: 'number_limit'},
|
||||
{field: 'http_user_agent', title: 'User-Agent', minWidth: 200, search: false},
|
||||
{
|
||||
width: 100, title: '操作', templet: ua.table.tool, fixed: 'right', operat: [
|
||||
[{
|
||||
class: 'layui-btn layui-btn-primary layui-btn-xs',
|
||||
method: 'tab',
|
||||
field: 'id',
|
||||
text: '详情',
|
||||
title: '查看详情',
|
||||
auth: 'read',
|
||||
url: init.readUrl,
|
||||
icon: ''
|
||||
}]
|
||||
]
|
||||
},
|
||||
|
||||
]],
|
||||
});
|
||||
|
||||
ua.listen();
|
||||
})
|
||||
229
app/admin/view/nginx/access_log/read.html
Normal file
229
app/admin/view/nginx/access_log/read.html
Normal file
@@ -0,0 +1,229 @@
|
||||
<div class="layuimini-container detail-container">
|
||||
<div class="layuimini-main">
|
||||
<div class="layui-card detail-card">
|
||||
<div class="layui-card-header detail-header">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md9">
|
||||
<h2 class="detail-title">#{$row.id} {$title}</h2>
|
||||
<div class="detail-id">ID: {$row.id}</div>
|
||||
</div>
|
||||
<div class="layui-col-md3 text-right detail-actions">
|
||||
<button class="layui-btn layui-btn-primary" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</button>
|
||||
<button class="layui-btn" onclick="location.href='{:url("edit", ["id" => $row.id])}'">编辑</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body detail-content">
|
||||
<div class="layui-row layui-col-space12">
|
||||
<!-- 左侧主体内容 -->
|
||||
<div class="layui-col-md8 detail-main">
|
||||
<div class="detail-field-group">
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">来源日志文件路径</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.file_path"}
|
||||
{$row.file_path}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">客户端 IP(含 IPv6)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.remote_addr"}
|
||||
{$row.remote_addr}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">HTTP 认证用户名</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.remote_user"}
|
||||
{$row.remote_user}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">请求时间戳(业务时区)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.time_local"}
|
||||
{$row.time_local|date="Y-m-d H:i:s"}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">HTTP 方法</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.method"}
|
||||
{$row.method}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">请求 URI(超 255 截断)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.uri"}
|
||||
{$row.uri}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">查询字符串</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.query_string"}
|
||||
{$row.query_string}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">HTTP 协议版本</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.http_version"}
|
||||
{$row.http_version}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">响应体字节数</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.body_bytes_sent"}
|
||||
{$row.body_bytes_sent}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">Referer</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.http_referer"}
|
||||
{$row.http_referer}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">User-Agent(超 500 截断)</div>
|
||||
<div class="detail-field-value" style="white-space: pre-wrap;">
|
||||
{notempty name="row.http_user_agent"}
|
||||
{$row.http_user_agent|raw}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无内容</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">nginx 请求总耗时</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.request_time"}
|
||||
{$row.request_time}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">upstream 响应时间</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.upstream_response_time"}
|
||||
{$row.upstream_response_time}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">总发送字节数(含 header)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.bytes_sent"}
|
||||
{$row.bytes_sent}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">国家(GeoIP 预留)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.country"}
|
||||
{$row.country}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">省份(GeoIP 预留)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.province"}
|
||||
{$row.province}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">城市(GeoIP 预留)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.city"}
|
||||
{$row.city}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧基础信息 -->
|
||||
<div class="layui-col-md4 detail-side">
|
||||
<h3 class="detail-side-title">基础信息</h3>
|
||||
<div class="detail-field-group">
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">ID</div>
|
||||
<div class="detail-field-value">{$row.id}</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">HTTP 状态码</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.status"}
|
||||
{$row.status}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">入库时间戳</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.create_time"}
|
||||
{$row.create_time|date="Y-m-d H:i:s"}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
22
app/admin/view/nginx/access_log/read.js
Normal file
22
app/admin/view/nginx/access_log/read.js
Normal file
@@ -0,0 +1,22 @@
|
||||
$(function(){
|
||||
// 删除数据
|
||||
window.deleteData = function(id) {
|
||||
layer.confirm('确定要删除这条数据吗?', {
|
||||
icon: 3,
|
||||
title: '提示'
|
||||
}, function(index) {
|
||||
$.post('{{:url("delete")}}', {id: id}, function(res) {
|
||||
if (res.code == 0) {
|
||||
layer.msg('删除成功', {icon: 1}, function() {
|
||||
location.href = '{{:url("index")}}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
layer.close(index);
|
||||
});
|
||||
};
|
||||
|
||||
ua.listen();
|
||||
})
|
||||
11
app/admin/view/nginx/log_position/_common.js
Normal file
11
app/admin/view/nginx/log_position/_common.js
Normal file
@@ -0,0 +1,11 @@
|
||||
var init = {
|
||||
tableElem: '#currentTable',
|
||||
tableRenderId: 'currentTableRenderId',
|
||||
indexUrl: 'nginx.log_position/index',
|
||||
addUrl: '',
|
||||
editUrl: '',
|
||||
readUrl: 'nginx.log_position/read',
|
||||
deleteUrl: '',
|
||||
exportUrl: '',
|
||||
modifyUrl: '',
|
||||
};
|
||||
56
app/admin/view/nginx/log_position/add.html
Normal file
56
app/admin/view/nginx/log_position/add.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="layuimini-container">
|
||||
<form id="app-form" class="layui-form layuimini-form">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">日志文件绝对路径</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="file_path" class="layui-input" lay-verify="required" placeholder="请输入日志文件绝对路径" value="{$Request.param.file_path|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文件 inode,用于检测日志轮转</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="inode" class="layui-input" placeholder="请输入文件 inode,用于检测日志轮转" value="{$Request.param.inode|default='0'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上次读取到的字节偏移</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="offset" class="layui-input" placeholder="请输入上次读取到的字节偏移" value="{$Request.param.offset|default='0'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上次读取时间戳</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="last_read_time" data-date="" data-date-type="datetime" class="layui-input" placeholder="请输入上次读取时间戳" value="{$Request.param.last_read_time|default='0'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上次最后一行的 md5 哈希(容错校验)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="last_line_hash" class="layui-input" placeholder="请输入上次最后一行的 md5 哈希(容错校验)" value="{$Request.param.last_line_hash|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">解析失败累计次数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="parse_fail_count" class="layui-input" placeholder="请输入解析失败累计次数" value="{$Request.param.parse_fail_count|default='0'}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">解析失败样本行(最多保留若干条)</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="parse_fail_samples" class="layui-textarea" placeholder="请输入解析失败样本行(最多保留若干条)">{$Request.param.parse_fail_samples|default=''}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line"></div>
|
||||
<div class="layui-form-item text-center">
|
||||
{notempty name='$Request.param.backTagId'}
|
||||
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
|
||||
{/notempty}
|
||||
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
3
app/admin/view/nginx/log_position/add.js
Normal file
3
app/admin/view/nginx/log_position/add.js
Normal file
@@ -0,0 +1,3 @@
|
||||
$(function(){
|
||||
ua.listen();
|
||||
})
|
||||
56
app/admin/view/nginx/log_position/edit.html
Normal file
56
app/admin/view/nginx/log_position/edit.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="layuimini-container">
|
||||
<form id="app-form" class="layui-form layuimini-form">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">日志文件绝对路径</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="file_path" class="layui-input" lay-verify="required" placeholder="请输入日志文件绝对路径" value="{$row.file_path|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文件 inode,用于检测日志轮转</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="inode" class="layui-input" placeholder="请输入文件 inode,用于检测日志轮转" value="{$row.inode|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上次读取到的字节偏移</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="offset" class="layui-input" placeholder="请输入上次读取到的字节偏移" value="{$row.offset|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上次读取时间戳</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="last_read_time" data-date="" data-date-type="datetime" class="layui-input" placeholder="请输入上次读取时间戳" value="{$row.last_read_time|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">上次最后一行的 md5 哈希(容错校验)</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="last_line_hash" class="layui-input" placeholder="请输入上次最后一行的 md5 哈希(容错校验)" value="{$row.last_line_hash|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">解析失败累计次数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="parse_fail_count" class="layui-input" placeholder="请输入解析失败累计次数" value="{$row.parse_fail_count|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">解析失败样本行(最多保留若干条)</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="parse_fail_samples" class="layui-textarea" placeholder="请输入解析失败样本行(最多保留若干条)">{$row.parse_fail_samples|raw|default=''}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line"></div>
|
||||
<div class="layui-form-item text-center">
|
||||
{notempty name='$Request.param.backTagId'}
|
||||
<div class="layui-btn layui-btn-sm page-back-button" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</div>
|
||||
{/notempty}
|
||||
<button type="submit" class="layui-btn layui-btn-normal layui-btn-sm" lay-submit>确认</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary layui-btn-sm">重置</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
3
app/admin/view/nginx/log_position/edit.js
Normal file
3
app/admin/view/nginx/log_position/edit.js
Normal file
@@ -0,0 +1,3 @@
|
||||
$(function(){
|
||||
ua.listen();
|
||||
})
|
||||
9
app/admin/view/nginx/log_position/index.html
Normal file
9
app/admin/view/nginx/log_position/index.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="layuimini-container">
|
||||
<div class="layuimini-main">
|
||||
<table id="currentTable" class="layui-table layui-hide"
|
||||
data-auth-index="{:auth('nginx.log_position/index')}"
|
||||
data-auth-read="{:auth('nginx.log_position/read')}"
|
||||
lay-filter="currentTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
41
app/admin/view/nginx/log_position/index.js
Normal file
41
app/admin/view/nginx/log_position/index.js
Normal file
@@ -0,0 +1,41 @@
|
||||
$(function(){
|
||||
ua.table.render({
|
||||
init: init,
|
||||
toolbar: [],
|
||||
defaultToolbar: ['filter'],
|
||||
cols: [[
|
||||
{type: 'checkbox'},
|
||||
{field: 'id', title: 'ID', width: 80},
|
||||
{field: 'file_path', title: '文件路径', minWidth: 250},
|
||||
{field: 'inode', title: 'inode', width: 120},
|
||||
{field: 'offset', title: '偏移量', width: 120},
|
||||
{field: 'last_read_time', title: '最后读取时间', width: 170, search: 'range', templet: ua.table.date},
|
||||
{field: 'last_line_hash', title: '最后行哈希', width: 160, search: false},
|
||||
{field: 'parse_fail_count', title: '失败次数', width: 100, search: 'number_limit', templet: function(d) {
|
||||
var c = parseInt(d.parse_fail_count);
|
||||
if (c > 0) return '<span class="layui-badge layui-bg-red">' + c + '</span>';
|
||||
return '<span class="layui-badge layui-bg-green">0</span>';
|
||||
}},
|
||||
{field: 'parse_fail_samples', title: '失败样本', minWidth: 200, search: false},
|
||||
{field: 'create_time', title: '创建时间', width: 170, search: 'range', templet: ua.table.date},
|
||||
{field: 'update_time', title: '更新时间', width: 170, search: false, templet: ua.table.date},
|
||||
{
|
||||
width: 100, title: '操作', templet: ua.table.tool, fixed: 'right', operat: [
|
||||
[{
|
||||
class: 'layui-btn layui-btn-primary layui-btn-xs',
|
||||
method: 'tab',
|
||||
field: 'id',
|
||||
text: '详情',
|
||||
title: '查看详情',
|
||||
auth: 'read',
|
||||
url: init.readUrl,
|
||||
icon: ''
|
||||
}]
|
||||
]
|
||||
},
|
||||
|
||||
]],
|
||||
});
|
||||
|
||||
ua.listen();
|
||||
})
|
||||
119
app/admin/view/nginx/log_position/read.html
Normal file
119
app/admin/view/nginx/log_position/read.html
Normal file
@@ -0,0 +1,119 @@
|
||||
<div class="layuimini-container detail-container">
|
||||
<div class="layuimini-main">
|
||||
<div class="layui-card detail-card">
|
||||
<div class="layui-card-header detail-header">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md9">
|
||||
<h2 class="detail-title">#{$row.id} {$title}</h2>
|
||||
<div class="detail-id">ID: {$row.id}</div>
|
||||
</div>
|
||||
<div class="layui-col-md3 text-right detail-actions">
|
||||
<button class="layui-btn layui-btn-primary" layuimini-content-href="{$Request.param.backTagId}" data-back="1">返回</button>
|
||||
<button class="layui-btn" onclick="location.href='{:url("edit", ["id" => $row.id])}'">编辑</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body detail-content">
|
||||
<div class="layui-row layui-col-space12">
|
||||
<!-- 左侧主体内容 -->
|
||||
<div class="layui-col-md8 detail-main">
|
||||
<div class="detail-field-group">
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">日志文件绝对路径</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.file_path"}
|
||||
{$row.file_path}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">文件 inode,用于检测日志轮转</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.inode"}
|
||||
{$row.inode}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">上次读取到的字节偏移</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.offset"}
|
||||
{$row.offset}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">上次读取时间戳</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.last_read_time"}
|
||||
{$row.last_read_time|date="Y-m-d H:i:s"}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">上次最后一行的 md5 哈希(容错校验)</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.last_line_hash"}
|
||||
{$row.last_line_hash}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">解析失败累计次数</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.parse_fail_count"}
|
||||
{$row.parse_fail_count}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">解析失败样本行(最多保留若干条)</div>
|
||||
<div class="detail-field-value" style="white-space: pre-wrap;">
|
||||
{notempty name="row.parse_fail_samples"}
|
||||
{$row.parse_fail_samples|raw}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无内容</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧基础信息 -->
|
||||
<div class="layui-col-md4 detail-side">
|
||||
<h3 class="detail-side-title">基础信息</h3>
|
||||
<div class="detail-field-group">
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">ID</div>
|
||||
<div class="detail-field-value">{$row.id}</div>
|
||||
</div>
|
||||
<div class="detail-field-item">
|
||||
<div class="detail-field-label">创建时间戳</div>
|
||||
<div class="detail-field-value">
|
||||
{notempty name="row.create_time"}
|
||||
{$row.create_time|date="Y-m-d H:i:s"}
|
||||
{else/}
|
||||
<span class="layui-text-em">暂无数据</span>
|
||||
{/notempty}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
22
app/admin/view/nginx/log_position/read.js
Normal file
22
app/admin/view/nginx/log_position/read.js
Normal file
@@ -0,0 +1,22 @@
|
||||
$(function(){
|
||||
// 删除数据
|
||||
window.deleteData = function(id) {
|
||||
layer.confirm('确定要删除这条数据吗?', {
|
||||
icon: 3,
|
||||
title: '提示'
|
||||
}, function(index) {
|
||||
$.post('{{:url("delete")}}', {id: id}, function(res) {
|
||||
if (res.code == 0) {
|
||||
layer.msg('删除成功', {icon: 1}, function() {
|
||||
location.href = '{{:url("index")}}';
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
layer.close(index);
|
||||
});
|
||||
};
|
||||
|
||||
ua.listen();
|
||||
})
|
||||
106
extend/base/admin/controller/nginx/AccessLogBase.php
Normal file
106
extend/base/admin/controller/nginx/AccessLogBase.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace base\admin\controller\nginx;
|
||||
|
||||
use app\common\controller\AdminController;
|
||||
use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnotation;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="nginx 访问日志明细(解析入库)")
|
||||
*/
|
||||
class AccessLogBase extends AdminController
|
||||
{
|
||||
|
||||
use \app\admin\traits\Curd;
|
||||
|
||||
protected $sort = [
|
||||
'time_local' => 'desc',
|
||||
];
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
|
||||
$this->model = new \app\admin\model\NginxAccessLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="列表")
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
if (input('selectFields')) {
|
||||
return $this->selectList();
|
||||
}
|
||||
list($page, $limit, $where, $excludes, $request_options, $group) = $this->buildTableParames();
|
||||
$count = $this->model
|
||||
->where($where)
|
||||
->group($group)
|
||||
->count();
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->page($page, $limit)
|
||||
->order($this->sort)
|
||||
->group($group)
|
||||
->select();
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '',
|
||||
'count' => $count,
|
||||
'data' => $list,
|
||||
];
|
||||
|
||||
return json($data);
|
||||
}
|
||||
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="详情")
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
|
||||
$this->assign('row', $row);
|
||||
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="添加")
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
$this->error('日志表不允许手动添加');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="编辑")
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$this->error('日志表不允许编辑');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="删除")
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$this->error('日志表不允许删除');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="属性修改")
|
||||
*/
|
||||
public function modify()
|
||||
{
|
||||
$this->error('日志表不允许修改');
|
||||
}
|
||||
}
|
||||
106
extend/base/admin/controller/nginx/LogPositionBase.php
Normal file
106
extend/base/admin/controller/nginx/LogPositionBase.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace base\admin\controller\nginx;
|
||||
|
||||
use app\common\controller\AdminController;
|
||||
use app\admin\service\annotation\ControllerAnnotation;
|
||||
use app\admin\service\annotation\NodeAnotation;
|
||||
use think\App;
|
||||
|
||||
/**
|
||||
* @ControllerAnnotation(title="nginx 日志文件读取位置(增量读取状态)")
|
||||
*/
|
||||
class LogPositionBase extends AdminController
|
||||
{
|
||||
|
||||
use \app\admin\traits\Curd;
|
||||
|
||||
protected $sort = [
|
||||
'id' => 'desc',
|
||||
];
|
||||
|
||||
public function __construct(App $app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
|
||||
$this->model = new \app\admin\model\NginxLogPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="列表")
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if ($this->request->isAjax()) {
|
||||
if (input('selectFields')) {
|
||||
return $this->selectList();
|
||||
}
|
||||
list($page, $limit, $where, $excludes, $request_options, $group) = $this->buildTableParames();
|
||||
$count = $this->model
|
||||
->where($where)
|
||||
->group($group)
|
||||
->count();
|
||||
$list = $this->model
|
||||
->where($where)
|
||||
->page($page, $limit)
|
||||
->order($this->sort)
|
||||
->group($group)
|
||||
->select();
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '',
|
||||
'count' => $count,
|
||||
'data' => $list,
|
||||
];
|
||||
|
||||
return json($data);
|
||||
}
|
||||
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="详情")
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
$row = $this->model->find($id);
|
||||
empty($row) && $this->error('数据不存在');
|
||||
|
||||
$this->assign('row', $row);
|
||||
|
||||
return $this->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="添加")
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
$this->error('日志表不允许手动添加');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="编辑")
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$this->error('日志表不允许编辑');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="删除")
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$this->error('日志表不允许删除');
|
||||
}
|
||||
|
||||
/**
|
||||
* @NodeAnotation(title="属性修改")
|
||||
*/
|
||||
public function modify()
|
||||
{
|
||||
$this->error('日志表不允许修改');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user