mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-08-30 12:45:32 +08:00
feat(nginx-log): 新增 6 张表 phinx migration + Scheme + model
This commit is contained in:
34
app/admin/model/NginxAccessLog.php
Normal file
34
app/admin/model/NginxAccessLog.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
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 入库时间戳
|
||||
*/
|
||||
class NginxAccessLog extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_access_log';
|
||||
|
||||
protected $deleteTime = false;
|
||||
}
|
||||
24
app/admin/model/NginxLogPosition.php
Normal file
24
app/admin/model/NginxLogPosition.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
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 更新时间戳
|
||||
*/
|
||||
class NginxLogPosition extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_log_position';
|
||||
|
||||
protected $deleteTime = false;
|
||||
}
|
||||
26
app/admin/model/NginxStatHour.php
Normal file
26
app/admin/model/NginxStatHour.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use app\common\model\TimeModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $stat_date 统计日期(YYYYMMDD)
|
||||
* @property int $stat_hour 小时(0-23)
|
||||
* @property int $pv 页面浏览量
|
||||
* @property int $uv 独立访客数
|
||||
* @property int $total_bytes 总流量(字节)
|
||||
* @property int $status_2xx 2xx 响应数
|
||||
* @property int $status_3xx 3xx 响应数
|
||||
* @property int $status_4xx 4xx 响应数
|
||||
* @property int $status_5xx 5xx 响应数
|
||||
* @property int $status_other 其他状态码响应数
|
||||
* @property float $avg_request_time 平均请求耗时(秒)
|
||||
*/
|
||||
class NginxStatHour extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_stat_hour';
|
||||
|
||||
protected $deleteTime = false;
|
||||
}
|
||||
19
app/admin/model/NginxStatReferer.php
Normal file
19
app/admin/model/NginxStatReferer.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use app\common\model\TimeModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $stat_date 统计日期(YYYYMMDD)
|
||||
* @property string $referer_domain Referer 来源域名
|
||||
* @property int $pv 页面浏览量
|
||||
* @property int $uv 独立访客数
|
||||
*/
|
||||
class NginxStatReferer extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_stat_referer';
|
||||
|
||||
protected $deleteTime = false;
|
||||
}
|
||||
20
app/admin/model/NginxStatUa.php
Normal file
20
app/admin/model/NginxStatUa.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use app\common\model\TimeModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $stat_date 统计日期(YYYYMMDD)
|
||||
* @property string $ua_type UA 类型(browser/spider/unknown)
|
||||
* @property string $ua_name UA 名称
|
||||
* @property int $pv 页面浏览量
|
||||
* @property int $uv 独立访客数
|
||||
*/
|
||||
class NginxStatUa extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_stat_ua';
|
||||
|
||||
protected $deleteTime = false;
|
||||
}
|
||||
21
app/admin/model/NginxStatUrl.php
Normal file
21
app/admin/model/NginxStatUrl.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use app\common\model\TimeModel;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $stat_date 统计日期(YYYYMMDD)
|
||||
* @property string $uri 请求 URI
|
||||
* @property int $pv 页面浏览量
|
||||
* @property int $uv 独立访客数
|
||||
* @property int $total_bytes 总流量(字节)
|
||||
* @property float $avg_request_time 平均请求耗时(秒)
|
||||
*/
|
||||
class NginxStatUrl extends TimeModel
|
||||
{
|
||||
protected $name = 'nginx_stat_url';
|
||||
|
||||
protected $deleteTime = false;
|
||||
}
|
||||
77
app/admin/scheme/NginxAccessLog.php
Normal file
77
app/admin/scheme/NginxAccessLog.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
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\Index;
|
||||
|
||||
#[Table(name: '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')]
|
||||
#[Index(columns: ['uri'], name: 'idx_uri', type: 'NORMAL')]
|
||||
#[Index(columns: ['file_path'], name: 'idx_file_path', type: 'NORMAL')]
|
||||
class NginxAccessLog extends BaseScheme
|
||||
{
|
||||
#[Field(type: 'bigint', nullable: false, unsigned: true, autoIncrement: true, primary: true, comment: '主键ID')]
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, comment: '来源日志文件路径')]
|
||||
public $file_path;
|
||||
|
||||
#[Field(type: 'varchar', length: 45, nullable: false, comment: '客户端 IP(含 IPv6)')]
|
||||
public $remote_addr;
|
||||
|
||||
#[Field(type: 'varchar', length: 100, nullable: true, comment: 'HTTP 认证用户名')]
|
||||
public $remote_user;
|
||||
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, comment: '请求时间戳(业务时区)')]
|
||||
public $time_local;
|
||||
|
||||
#[Field(type: 'varchar', length: 10, nullable: true, comment: 'HTTP 方法')]
|
||||
public $method;
|
||||
|
||||
#[Field(type: 'varchar', length: 255, nullable: false, comment: '请求 URI(超 255 截断)')]
|
||||
public $uri;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, default: '', comment: '查询字符串')]
|
||||
public $query_string;
|
||||
|
||||
#[Field(type: 'varchar', length: 10, nullable: true, comment: 'HTTP 协议版本')]
|
||||
public $http_version;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: 'HTTP 状态码')]
|
||||
public $status;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', comment: '响应体字节数')]
|
||||
public $body_bytes_sent;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, default: '', comment: 'Referer')]
|
||||
public $http_referer;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, default: '', comment: 'User-Agent(超 500 截断)')]
|
||||
public $http_user_agent;
|
||||
|
||||
#[Field(type: 'decimal', precision: 10, scale: 3, default: '0.000', comment: 'nginx 请求总耗时(秒)')]
|
||||
public $request_time;
|
||||
|
||||
#[Field(type: 'decimal', precision: 10, scale: 3, default: '0.000', comment: 'upstream 响应时间(秒)')]
|
||||
public $upstream_response_time;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', comment: '总发送字节数(含 header)')]
|
||||
public $bytes_sent;
|
||||
|
||||
#[Field(type: 'varchar', length: 50, nullable: true, comment: '国家(GeoIP 预留)')]
|
||||
public $country;
|
||||
|
||||
#[Field(type: 'varchar', length: 50, nullable: true, comment: '省份(GeoIP 预留)')]
|
||||
public $province;
|
||||
|
||||
#[Field(type: 'varchar', length: 50, nullable: true, comment: '城市(GeoIP 预留)')]
|
||||
public $city;
|
||||
|
||||
#[Field(type: 'int', length: 11, unsigned: true, comment: '入库时间戳')]
|
||||
public $create_time;
|
||||
}
|
||||
43
app/admin/scheme/NginxLogPosition.php
Normal file
43
app/admin/scheme/NginxLogPosition.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
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\Index;
|
||||
|
||||
#[Table(name: 'nginx_log_position', comment: 'nginx 日志文件读取位置(增量读取状态)')]
|
||||
#[Index(columns: ['file_path'], name: 'uniq_file_path', type: 'UNIQUE')]
|
||||
class NginxLogPosition extends BaseScheme
|
||||
{
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, autoIncrement: true, primary: true)]
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'varchar', length: 500, nullable: false, comment: '日志文件绝对路径')]
|
||||
public $file_path;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', unsigned: true, comment: '文件 inode,用于检测日志轮转')]
|
||||
public $inode;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', unsigned: true, comment: '上次读取到的字节偏移')]
|
||||
public $offset;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', unsigned: true, comment: '上次读取时间戳')]
|
||||
public $last_read_time;
|
||||
|
||||
#[Field(type: 'varchar', length: 32, default: '', comment: '上次最后一行的 md5 哈希(容错校验)')]
|
||||
public $last_line_hash;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', unsigned: true, comment: '解析失败累计次数')]
|
||||
public $parse_fail_count;
|
||||
|
||||
#[Field(type: 'text', nullable: true, comment: '解析失败样本行(最多保留若干条)')]
|
||||
public $parse_fail_samples;
|
||||
|
||||
#[Field(type: 'int', length: 11, unsigned: true, comment: '创建时间戳')]
|
||||
public $create_time;
|
||||
|
||||
#[Field(type: 'int', length: 11, unsigned: true, comment: '更新时间戳')]
|
||||
public $update_time;
|
||||
}
|
||||
50
app/admin/scheme/NginxStatHour.php
Normal file
50
app/admin/scheme/NginxStatHour.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
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\Index;
|
||||
|
||||
#[Table(name: 'nginx_stat_hour', comment: 'nginx 按小时聚合统计')]
|
||||
#[Index(columns: ['stat_date', 'stat_hour'], name: 'uniq_date_hour', type: 'UNIQUE')]
|
||||
#[Index(columns: ['stat_date'], name: 'idx_stat_date', type: 'NORMAL')]
|
||||
class NginxStatHour extends BaseScheme
|
||||
{
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, autoIncrement: true, primary: true)]
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, comment: '统计日期(YYYYMMDD)')]
|
||||
public $stat_date;
|
||||
|
||||
#[Field(type: 'tinyint', length: 2, default: '0', unsigned: true, comment: '小时(0-23)')]
|
||||
public $stat_hour;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '页面浏览量')]
|
||||
public $pv;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '独立访客数')]
|
||||
public $uv;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', comment: '总流量(字节)')]
|
||||
public $total_bytes;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '2xx 响应数')]
|
||||
public $status_2xx;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '3xx 响应数')]
|
||||
public $status_3xx;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '4xx 响应数')]
|
||||
public $status_4xx;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '5xx 响应数')]
|
||||
public $status_5xx;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '其他状态码响应数')]
|
||||
public $status_other;
|
||||
|
||||
#[Field(type: 'decimal', precision: 10, scale: 3, default: '0.000', comment: '平均请求耗时(秒)')]
|
||||
public $avg_request_time;
|
||||
}
|
||||
29
app/admin/scheme/NginxStatReferer.php
Normal file
29
app/admin/scheme/NginxStatReferer.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
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\Index;
|
||||
|
||||
#[Table(name: 'nginx_stat_referer', comment: 'nginx 按 Referer 来源域名聚合统计')]
|
||||
#[Index(columns: ['stat_date', 'referer_domain'], name: 'uniq_date_referer', type: 'UNIQUE')]
|
||||
#[Index(columns: ['stat_date'], name: 'idx_stat_date', type: 'NORMAL')]
|
||||
class NginxStatReferer extends BaseScheme
|
||||
{
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, autoIncrement: true, primary: true)]
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, comment: '统计日期(YYYYMMDD)')]
|
||||
public $stat_date;
|
||||
|
||||
#[Field(type: 'varchar', length: 255, nullable: false, comment: 'Referer 来源域名(direct/unknown)')]
|
||||
public $referer_domain;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '页面浏览量')]
|
||||
public $pv;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '独立访客数')]
|
||||
public $uv;
|
||||
}
|
||||
32
app/admin/scheme/NginxStatUa.php
Normal file
32
app/admin/scheme/NginxStatUa.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
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\Index;
|
||||
|
||||
#[Table(name: 'nginx_stat_ua', comment: 'nginx 按 User-Agent 聚合统计')]
|
||||
#[Index(columns: ['stat_date', 'ua_type', 'ua_name'], name: 'uniq_date_type_name', type: 'UNIQUE')]
|
||||
#[Index(columns: ['stat_date'], name: 'idx_stat_date', type: 'NORMAL')]
|
||||
class NginxStatUa extends BaseScheme
|
||||
{
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, autoIncrement: true, primary: true)]
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, comment: '统计日期(YYYYMMDD)')]
|
||||
public $stat_date;
|
||||
|
||||
#[Field(type: 'varchar', length: 20, default: 'unknown', comment: 'UA 类型(browser/spider/unknown)')]
|
||||
public $ua_type;
|
||||
|
||||
#[Field(type: 'varchar', length: 255, nullable: false, comment: 'UA 名称(具体型号)')]
|
||||
public $ua_name;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '页面浏览量')]
|
||||
public $pv;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '独立访客数')]
|
||||
public $uv;
|
||||
}
|
||||
35
app/admin/scheme/NginxStatUrl.php
Normal file
35
app/admin/scheme/NginxStatUrl.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
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\Index;
|
||||
|
||||
#[Table(name: 'nginx_stat_url', comment: 'nginx 按 URL 聚合统计')]
|
||||
#[Index(columns: ['stat_date', 'uri'], name: 'uniq_date_uri', type: 'UNIQUE')]
|
||||
#[Index(columns: ['stat_date'], name: 'idx_stat_date', type: 'NORMAL')]
|
||||
class NginxStatUrl extends BaseScheme
|
||||
{
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, autoIncrement: true, primary: true)]
|
||||
public $id;
|
||||
|
||||
#[Field(type: 'int', length: 11, nullable: false, unsigned: true, comment: '统计日期(YYYYMMDD)')]
|
||||
public $stat_date;
|
||||
|
||||
#[Field(type: 'varchar', length: 255, nullable: false, comment: '请求 URI')]
|
||||
public $uri;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '页面浏览量')]
|
||||
public $pv;
|
||||
|
||||
#[Field(type: 'int', length: 11, default: '0', comment: '独立访客数')]
|
||||
public $uv;
|
||||
|
||||
#[Field(type: 'bigint', default: '0', comment: '总流量(字节)')]
|
||||
public $total_bytes;
|
||||
|
||||
#[Field(type: 'decimal', precision: 10, scale: 3, default: '0.000', comment: '平均请求耗时(秒)')]
|
||||
public $avg_request_time;
|
||||
}
|
||||
28
database/migrations/20260726100001_nginx_log_position.php
Normal file
28
database/migrations/20260726100001_nginx_log_position.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
|
||||
/**
|
||||
* nginx 日志分析 - 文件读取位置表
|
||||
*
|
||||
* 记录每个被解析日志文件的 inode/offset/最近读取时间/失败计数等增量读取状态。
|
||||
*/
|
||||
class NginxLogPosition extends Migrator
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('nginx_log_position')
|
||||
->setComment('nginx 日志文件读取位置(增量读取状态)')
|
||||
->addColumn('file_path', 'string', ['limit' => 500, 'null' => false, 'comment' => '日志文件绝对路径'])
|
||||
->addColumn('inode', 'biginteger', ['default' => 0, 'comment' => '文件 inode,用于检测日志轮转', 'signed' => false])
|
||||
->addColumn('offset', 'biginteger', ['default' => 0, 'comment' => '上次读取到的字节偏移', 'signed' => false])
|
||||
->addColumn('last_read_time', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '上次读取时间戳', 'signed' => false])
|
||||
->addColumn('last_line_hash', 'string', ['limit' => 32, 'default' => '', 'comment' => '上次最后一行的 md5 哈希(容错校验)'])
|
||||
->addColumn('parse_fail_count', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '解析失败累计次数', 'signed' => false])
|
||||
->addColumn('parse_fail_samples', 'text', ['null' => true, 'comment' => '解析失败样本行(最多保留若干条)'])
|
||||
->addColumn('create_time', 'integer', ['limit' => 11, 'comment' => '创建时间戳', 'signed' => false])
|
||||
->addColumn('update_time', 'integer', ['limit' => 11, 'comment' => '更新时间戳', 'signed' => false])
|
||||
->addIndex(['file_path'], ['unique' => true, 'name' => 'uniq_file_path'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
44
database/migrations/20260726100002_nginx_access_log.php
Normal file
44
database/migrations/20260726100002_nginx_access_log.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
|
||||
/**
|
||||
* nginx 日志分析 - 原始访问日志表
|
||||
*
|
||||
* 解析 nginx access.log 后入库的明细数据,按行一条记录。
|
||||
* country/province/city 留作 GeoIP 扩展字段,默认 NULL。
|
||||
*/
|
||||
class NginxAccessLog extends Migrator
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('nginx_access_log', ['id' => false, 'primary_key' => ['id']])
|
||||
->setComment('nginx 访问日志明细(解析入库)')
|
||||
->addColumn('id', 'biginteger', ['null' => false, 'signed' => false, 'identity' => true, 'comment' => '主键ID'])
|
||||
->addColumn('file_path', 'string', ['limit' => 500, 'null' => false, 'comment' => '来源日志文件路径'])
|
||||
->addColumn('remote_addr', 'string', ['limit' => 45, 'null' => false, 'comment' => '客户端 IP(含 IPv6)'])
|
||||
->addColumn('remote_user', 'string', ['limit' => 100, 'null' => true, 'comment' => 'HTTP 认证用户名'])
|
||||
->addColumn('time_local', 'integer', ['limit' => 11, 'null' => false, 'comment' => '请求时间戳(业务时区)', 'signed' => false])
|
||||
->addColumn('method', 'string', ['limit' => 10, 'null' => true, 'comment' => 'HTTP 方法'])
|
||||
->addColumn('uri', 'string', ['limit' => 255, 'null' => false, 'comment' => '请求 URI(超 255 截断)'])
|
||||
->addColumn('query_string', 'string', ['limit' => 500, 'null' => false, 'default' => '', 'comment' => '查询字符串'])
|
||||
->addColumn('http_version', 'string', ['limit' => 10, 'null' => true, 'comment' => 'HTTP 协议版本'])
|
||||
->addColumn('status', 'integer', ['limit' => 11, 'default' => 0, 'comment' => 'HTTP 状态码'])
|
||||
->addColumn('body_bytes_sent', 'biginteger', ['default' => 0, 'comment' => '响应体字节数'])
|
||||
->addColumn('http_referer', 'string', ['limit' => 500, 'null' => false, 'default' => '', 'comment' => 'Referer'])
|
||||
->addColumn('http_user_agent', 'string', ['limit' => 500, 'null' => false, 'default' => '', 'comment' => 'User-Agent(超 500 截断)'])
|
||||
->addColumn('request_time', 'decimal', ['precision' => 10, 'scale' => 3, 'default' => 0, 'comment' => 'nginx 请求总耗时(秒)'])
|
||||
->addColumn('upstream_response_time', 'decimal', ['precision' => 10, 'scale' => 3, 'default' => 0, 'comment' => 'upstream 响应时间(秒)'])
|
||||
->addColumn('bytes_sent', 'biginteger', ['default' => 0, 'comment' => '总发送字节数(含 header)'])
|
||||
->addColumn('country', 'string', ['limit' => 50, 'null' => true, 'comment' => '国家(GeoIP 预留)'])
|
||||
->addColumn('province', 'string', ['limit' => 50, 'null' => true, 'comment' => '省份(GeoIP 预留)'])
|
||||
->addColumn('city', 'string', ['limit' => 50, 'null' => true, 'comment' => '城市(GeoIP 预留)'])
|
||||
->addColumn('create_time', 'integer', ['limit' => 11, 'comment' => '入库时间戳', 'signed' => false])
|
||||
->addIndex(['time_local'], ['name' => 'idx_time_local'])
|
||||
->addIndex(['remote_addr'], ['name' => 'idx_remote_addr'])
|
||||
->addIndex(['status'], ['name' => 'idx_status'])
|
||||
->addIndex(['uri'], ['name' => 'idx_uri'])
|
||||
->addIndex(['file_path'], ['name' => 'idx_file_path'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
32
database/migrations/20260726100003_nginx_stat_hour.php
Normal file
32
database/migrations/20260726100003_nginx_stat_hour.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
|
||||
/**
|
||||
* nginx 日志分析 - 按小时聚合统计表
|
||||
*
|
||||
* 每个统计日 + 小时一行,记录 PV/UV/状态码分组/平均耗时。
|
||||
* UNIQUE(stat_date, stat_hour) 保证幂等聚合。
|
||||
*/
|
||||
class NginxStatHour extends Migrator
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('nginx_stat_hour')
|
||||
->setComment('nginx 按小时聚合统计')
|
||||
->addColumn('stat_date', 'integer', ['limit' => 11, 'null' => false, 'comment' => '统计日期(YYYYMMDD)', 'signed' => false])
|
||||
->addColumn('stat_hour', 'tinyinteger', ['default' => 0, 'comment' => '小时(0-23)', 'signed' => false])
|
||||
->addColumn('pv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '页面浏览量'])
|
||||
->addColumn('uv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '独立访客数'])
|
||||
->addColumn('total_bytes', 'biginteger', ['default' => 0, 'comment' => '总流量(字节)'])
|
||||
->addColumn('status_2xx', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '2xx 响应数'])
|
||||
->addColumn('status_3xx', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '3xx 响应数'])
|
||||
->addColumn('status_4xx', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '4xx 响应数'])
|
||||
->addColumn('status_5xx', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '5xx 响应数'])
|
||||
->addColumn('status_other', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '其他状态码响应数'])
|
||||
->addColumn('avg_request_time', 'decimal', ['precision' => 10, 'scale' => 3, 'default' => 0, 'comment' => '平均请求耗时(秒)'])
|
||||
->addIndex(['stat_date', 'stat_hour'], ['unique' => true, 'name' => 'uniq_date_hour'])
|
||||
->addIndex(['stat_date'], ['name' => 'idx_stat_date'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
26
database/migrations/20260726100004_nginx_stat_url.php
Normal file
26
database/migrations/20260726100004_nginx_stat_url.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
|
||||
/**
|
||||
* nginx 日志分析 - 按 URL 聚合统计表
|
||||
*
|
||||
* 每个统计日 + URI 一行,记录 PV/UV/流量/平均耗时,用于热门 URL 排行。
|
||||
*/
|
||||
class NginxStatUrl extends Migrator
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('nginx_stat_url')
|
||||
->setComment('nginx 按 URL 聚合统计')
|
||||
->addColumn('stat_date', 'integer', ['limit' => 11, 'null' => false, 'comment' => '统计日期(YYYYMMDD)', 'signed' => false])
|
||||
->addColumn('uri', 'string', ['limit' => 255, 'null' => false, 'comment' => '请求 URI'])
|
||||
->addColumn('pv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '页面浏览量'])
|
||||
->addColumn('uv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '独立访客数'])
|
||||
->addColumn('total_bytes', 'biginteger', ['default' => 0, 'comment' => '总流量(字节)'])
|
||||
->addColumn('avg_request_time', 'decimal', ['precision' => 10, 'scale' => 3, 'default' => 0, 'comment' => '平均请求耗时(秒)'])
|
||||
->addIndex(['stat_date', 'uri'], ['unique' => true, 'name' => 'uniq_date_uri'])
|
||||
->addIndex(['stat_date'], ['name' => 'idx_stat_date'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
24
database/migrations/20260726100005_nginx_stat_referer.php
Normal file
24
database/migrations/20260726100005_nginx_stat_referer.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
|
||||
/**
|
||||
* nginx 日志分析 - 按 Referer 来源域名聚合统计表
|
||||
*
|
||||
* 每个统计日 + 来源域名一行,记录 PV/UV,用于外链来源排行。
|
||||
*/
|
||||
class NginxStatReferer extends Migrator
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('nginx_stat_referer')
|
||||
->setComment('nginx 按 Referer 来源域名聚合统计')
|
||||
->addColumn('stat_date', 'integer', ['limit' => 11, 'null' => false, 'comment' => '统计日期(YYYYMMDD)', 'signed' => false])
|
||||
->addColumn('referer_domain', 'string', ['limit' => 255, 'null' => false, 'comment' => 'Referer 来源域名(direct/unknown)'])
|
||||
->addColumn('pv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '页面浏览量'])
|
||||
->addColumn('uv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '独立访客数'])
|
||||
->addIndex(['stat_date', 'referer_domain'], ['unique' => true, 'name' => 'uniq_date_referer'])
|
||||
->addIndex(['stat_date'], ['name' => 'idx_stat_date'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
26
database/migrations/20260726100006_nginx_stat_ua.php
Normal file
26
database/migrations/20260726100006_nginx_stat_ua.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use think\migration\Migrator;
|
||||
|
||||
/**
|
||||
* nginx 日志分析 - 按 User-Agent 聚合统计表
|
||||
*
|
||||
* 每个统计日 + UA 类型 + UA 名称一行,记录 PV/UV。
|
||||
* ua_type: browser/spider/unknown/手机浏览器等;ua_name: 具体名称(Chrome 120 等)。
|
||||
*/
|
||||
class NginxStatUa extends Migrator
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('nginx_stat_ua')
|
||||
->setComment('nginx 按 User-Agent 聚合统计')
|
||||
->addColumn('stat_date', 'integer', ['limit' => 11, 'null' => false, 'comment' => '统计日期(YYYYMMDD)', 'signed' => false])
|
||||
->addColumn('ua_type', 'string', ['limit' => 20, 'default' => 'unknown', 'comment' => 'UA 类型(browser/spider/unknown)'])
|
||||
->addColumn('ua_name', 'string', ['limit' => 255, 'null' => false, 'comment' => 'UA 名称(具体型号)'])
|
||||
->addColumn('pv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '页面浏览量'])
|
||||
->addColumn('uv', 'integer', ['limit' => 11, 'default' => 0, 'comment' => '独立访客数'])
|
||||
->addIndex(['stat_date', 'ua_type', 'ua_name'], ['unique' => true, 'name' => 'uniq_date_type_name'])
|
||||
->addIndex(['stat_date'], ['name' => 'idx_stat_date'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user