diff --git a/README.md b/README.md index 718a9531..b3b64bee 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,14 @@ A reverse proxy like nginx, built on [pingora](https://github.com/cloudflare/pin ## Feature - Filter location by host and path +- Path rewrite with regexp - HTTP 1/2 end to end proxy - TOML base configuration, file or etcd storage - Graceful reload and auto restart after the configuration is changed - Template for http access log - Admin Web UI configuration - Genrate TLS certificates from let's encrypt +- Notification events: `lets_encrypt`, `backend_unhealthy`, `diff_config`, `restart`, etc. - Http proxy plugins: `compression`, `static serve`, `limit`, `stats`, `mock`, etc. ## Start diff --git a/SUMMARY.md b/SUMMARY.md index 5a1610f9..57d507bf 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,6 +1,7 @@ # Summary - [介绍](./docs/introduction_zh.md) +- [命令行参数](./docs/args_zh.md) - [处理流程](./docs/phase_chart_zh.md) - [配置说明](./docs/config_zh.md) - [Location说明](./docs/location_zh.md) diff --git a/docs/args_zh.md b/docs/args_zh.md new file mode 100644 index 00000000..066d2dee --- /dev/null +++ b/docs/args_zh.md @@ -0,0 +1,14 @@ +--- +description: Pingap 配置说明 +--- + +Pingap的大部分参数均是配置toml配置文件来指定,而有一些参数则是需要在启动程序时指定的,具体如下: + +- `conf`或者`c`: 默认为当前目录,指定配置文件或配置文件目录,建议使用目录的形式,便于配置按类型管理 +- `daemon`或者`d`: 可选,是否指定以后台服务的形式启用,若需要使用upgrade的形式无中断式加载新配置,则需要使用此模式 +- `upgrade`或`u`: 可选,以更新程序模式启用,此模式下新的程序会通过unix socket接收原有的程序的请求,避免请求中断 +- `test`: 可选,仅测试配置是否正确 +- `log`: 可选,指定日志输入目录 +- `admin`: 可选,配置admin的监听地址,形式为`base64(user:pass)@ip:port`,其中认证部分是basic auth,若不配置则不校验,建议配置 +- `adminnode`: 可选,是否管理节点,对于使用etcd存储配置的部署使用,设置后此节点只用于配置参数,避免配置有误导致节点无法启动,其它节点则加载对应配置运行。 +- `autorestart`: 可选,是否在配置有更新时自动重启,建议使用此方式达到准实时更新配置的效果 diff --git a/docs/log_zh.md b/docs/log_zh.md index 7439c4d1..c1889987 100644 --- a/docs/log_zh.md +++ b/docs/log_zh.md @@ -11,7 +11,7 @@ Pingap格式化可以使用以下几种默认形式`combined`,`common`,`shor - `{query}`: 请求的querystring - `{remote}`: 请求的源ip - `{client-ip}`: 客户ip,根据`x-forwarded-for`中获取 -- `{scheme}`: TODO +- `{scheme}`: 协议类型,https或http - `{uri}`: 请求的完整地址 - `{referer}`: 请求头中的referer - `{user-agent}`: 请求的user-agent diff --git a/src/http_extra/http_response.rs b/src/http_extra/http_response.rs index 1fbc1199..a649095f 100644 --- a/src/http_extra/http_response.rs +++ b/src/http_extra/http_response.rs @@ -45,6 +45,14 @@ pub fn get_super_ts() -> u32 { } } +pub fn get_hour_duration() -> u32 { + if let Ok(value) = SystemTime::now().duration_since(UNIX_EPOCH) { + (value.as_millis() % (3600 * 1000)) as u32 + } else { + 0 + } +} + fn get_cache_control(max_age: Option, cache_private: Option) -> HttpHeader { if let Some(max_age) = max_age { let category = if cache_private.unwrap_or_default() { diff --git a/src/main.rs b/src/main.rs index f8f8c40e..34c637cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -296,7 +296,6 @@ fn run() -> Result<(), Box> { let _ = perf::start_pyroscope(url)?; } - // TODO load from config let mut proxy_plugin_confs: Vec<(String, ProxyPluginConf)> = conf .proxy_plugins .iter() diff --git a/src/proxy/logger.rs b/src/proxy/logger.rs index b9da40df..257cea45 100644 --- a/src/proxy/logger.rs +++ b/src/proxy/logger.rs @@ -385,6 +385,14 @@ impl Parser { "reused" => buf.extend(ctx.reused.to_string().as_bytes()), "upstream-address" => buf.extend(ctx.upstream_address.as_bytes()), "processing" => buf.extend(ctx.processing.to_string().as_bytes()), + "upstream-connect-time" => { + if let Some(value) = ctx.upstream_connect_time { + buf.extend( + format!("{:?}", Duration::from_millis(value as u64)) + .as_bytes(), + ); + } + } _ => {} } } diff --git a/src/proxy/server.rs b/src/proxy/server.rs index bc14f1e2..4fb15497 100644 --- a/src/proxy/server.rs +++ b/src/proxy/server.rs @@ -16,7 +16,7 @@ use super::logger::Parser; use super::{Location, Upstream}; use crate::acme::{get_lets_encrypt_cert, handle_lets_encrypt}; use crate::config::{LocationConf, PingapConf, ProxyPluginStep, UpstreamConf}; -use crate::http_extra::HTTP_HEADER_NAME_X_REQUEST_ID; +use crate::http_extra::{get_hour_duration, HTTP_HEADER_NAME_X_REQUEST_ID}; use crate::plugin::get_proxy_plugin; use crate::state::State; use crate::util; @@ -478,6 +478,7 @@ impl ProxyHttp for Server { let peer = lo.upstream.new_http_peer(ctx, session).ok_or_else(|| { util::new_internal_error(503, format!("No available upstream({})", lo.upstream_name)) })?; + ctx.upstream_connect_time = Some(get_hour_duration()); Ok(Box::new(peer)) } @@ -495,6 +496,16 @@ impl ProxyHttp for Server { { ctx.reused = reused; ctx.upstream_address = peer.address().to_string(); + if let Some(value) = ctx.upstream_connect_time { + let d = get_hour_duration(); + let value = if d >= value { + d - value + } else { + d + (3600 * 1000) - value + }; + ctx.upstream_connect_time = Some(value); + } + Ok(()) } async fn upstream_request_filter( diff --git a/src/state/ctx.rs b/src/state/ctx.rs index 57e3cf91..bed15e1c 100644 --- a/src/state/ctx.rs +++ b/src/state/ctx.rs @@ -31,6 +31,7 @@ pub struct State { pub request_id: Option, pub cache_prefix: Option, pub cache_lock_duration: Option, + pub upstream_connect_time: Option, } impl Default for State { @@ -50,6 +51,7 @@ impl Default for State { request_id: None, cache_prefix: None, cache_lock_duration: None, + upstream_connect_time: None, } } }