Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bleep
Original file line number Diff line number Diff line change
@@ -1 +1 @@
67cc768b717d3865a73bcd917c905d7d9aeb4c62
e2089546a5962c0f65c081211d604dadd9330195
3 changes: 3 additions & 0 deletions .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[advisories]
# Temp before internal sync applies dependency bumps
ignore = ["RUSTSEC-2026-0097", "RUSTSEC-2026-0098", "RUSTSEC-2026-0099"]
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ members = [
"pingora-ketama",
"pingora-load-balancing",
"pingora-memory-cache",
"pingora-prometheus",
"tinyufo",
]

Expand Down
3 changes: 3 additions & 0 deletions docs/user_guide/conf.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ group: webusers
| s2n_config_cache_size | The maximum number of unique s2n configs to cache. A value of 0 disables the cache. Default: 10 (s2n-tls only) | number |
| work_stealing | Enable work stealing runtime (default true). See Pingora runtime (WIP) section for more info | bool |
| upstream_keepalive_pool_size | The number of total connections to keep in the connection pool | number |
| daemon_wait_for_ready | When `true` and `daemon` is `true`, the parent process waits for the daemon to signal readiness (via `SIGUSR1`) before exiting. This causes systemd to delay sending `SIGQUIT` to the old process until the new instance is fully bootstrapped. Default: `false` | bool |
| daemon_ready_timeout_seconds | How long (in seconds) the parent waits for the daemon to signal readiness when `daemon_wait_for_ready` is `true`. If the daemon does not signal in time the parent exits with a non-zero code, causing systemd to abort the reload. Default: `600` | number |
| daemon_notify_timeout_seconds | How long (in seconds) the daemon retries sending `SIGUSR1` to the parent when the attempt fails with a permission error. This covers the brief window after the fork where the parent has not yet dropped its UID to match the daemon. Default: `60` | number |

## Extension
Any unknown settings will be ignored. This allows extending the conf file to add and pass user defined settings. See User defined configuration section.
3 changes: 1 addition & 2 deletions docs/user_guide/modify_filter.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ impl ProxyHttp for MyGateway {

fn main() {
...
let mut prometheus_service_http =
pingora::services::listening::Service::prometheus_http_service();
let mut prometheus_service_http = pingora_prometheus::prometheus_http_service();
prometheus_service_http.add_tcp("127.0.0.1:6192");
my_server.add_service(prometheus_service_http);

Expand Down
20 changes: 6 additions & 14 deletions docs/user_guide/prom.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
# Prometheus

Pingora has a built-in prometheus HTTP metric server for scraping.
The [`pingora-prometheus`](https://docs.rs/pingora-prometheus) crate provides a
Prometheus HTTP metrics server for scraping.

## Enabling Prometheus Support
## Adding the Dependency

Prometheus support is an optional feature in Pingora. To use it, you need to enable the `prometheus` feature in your `Cargo.toml`:
Add `pingora-prometheus` to your `Cargo.toml`:

```toml
# If using the main pingora crate
pingora = { version = "0.8.0", features = ["prometheus"] }

# If using pingora-core directly
pingora-core = { version = "0.8.0", features = ["prometheus"] }

# If using pingora-proxy crate
pingora-proxy = { version = "0.8.0", features = ["prometheus"] }
pingora-prometheus = "0.8.0"
```

## Setting up a Prometheus Metrics Endpoint

Once the feature is enabled, you can set up a Prometheus metrics endpoint like this:

```rust
...
let mut prometheus_service_http = Service::prometheus_http_service();
let mut prometheus_service_http = pingora_prometheus::prometheus_http_service();
prometheus_service_http.add_tcp("0.0.0.0:1234");
my_server.add_service(prometheus_service_http);
my_server.run_forever();
Expand Down
47 changes: 47 additions & 0 deletions pingora-cache/src/eviction/lru.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ impl<const N: usize> Manager<N> {
(u64key(key) % N as u64) as usize
}

/// Peek at the least-recently-used key in the given shard without evicting it.
///
/// Returns the cache key at the LRU tail of the shard, or `None` if empty.
/// Useful for reporting the eviction frontier (the age of the next item
/// that would be evicted).
pub fn peek_lru(&self, shard: usize) -> Option<CompactCacheKey> {
self.0.peek_lru(shard).map(|(key, _weight)| key)
}

/// Serialize the given shard
pub fn serialize_shard(&self, shard: usize) -> Result<Vec<u8>> {
use rmp_serde::encode::Serializer;
Expand Down Expand Up @@ -614,4 +623,42 @@ mod test {
// Cleanup test directory
std::fs::remove_dir_all(dir_path).unwrap();
}

#[test]
fn test_peek_lru() {
let lru = Manager::<1>::with_capacity(20, 20);
let until = SystemTime::now();

// empty shard returns None
assert!(lru.peek_lru(0).is_none());

let key1 = CacheKey::new("", "a", "1").to_compact();
lru.admit(key1.clone(), 1, until);
// single item: it's both the head and the tail
assert_eq!(lru.peek_lru(0).unwrap(), key1);

// admit more keys to push key1 to the tail
let key2 = CacheKey::new("", "b", "1").to_compact();
lru.admit(key2.clone(), 1, until);
for i in 0..5 {
lru.admit(
CacheKey::new("", format!("f{i}"), "1").to_compact(),
1,
until,
);
}
// key1 is the LRU tail (admitted first)
assert_eq!(lru.peek_lru(0).unwrap(), key1);

// promote key1 — now key2 becomes the tail
lru.access(&key1, 1, until);
assert_eq!(lru.peek_lru(0).unwrap(), key2);

// peek_lru should not remove the item
assert_eq!(lru.peek_lru(0).unwrap(), key2);
assert!(lru.peek(&key2));

// out-of-bounds shard returns None
assert!(lru.peek_lru(999).is_none());
}
}
2 changes: 0 additions & 2 deletions pingora-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ strum = "0.26.2"
strum_macros = "0.26.2"
libc = "0.2.70"
chrono = { version = "~0.4.31", features = ["alloc"], default-features = false }
prometheus = { version = "0.14", optional = true }
sentry = { version = "0.36", features = [
"backtrace",
"contexts",
Expand Down Expand Up @@ -108,4 +107,3 @@ openssl_derived = ["any_tls"]
any_tls = []
sentry = ["dep:sentry"]
connection_filter = []
prometheus = ["dep:prometheus"]
2 changes: 0 additions & 2 deletions pingora-core/src/apps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
//! The abstraction and implementation interface for service application logic

pub mod http_app;
#[cfg(feature = "prometheus")]
pub mod prometheus_http_app;

use crate::server::ShutdownWatch;
use async_trait::async_trait;
Expand Down
66 changes: 0 additions & 66 deletions pingora-core/src/apps/prometheus_http_app.rs

This file was deleted.

13 changes: 13 additions & 0 deletions pingora-core/src/connectors/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use crate::protocols::http::client::HttpSession;
use crate::protocols::http::v1::client::HttpSession as Http1Session;
use crate::upstreams::peer::Peer;
use pingora_error::Result;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use std::time::Duration;

pub mod custom;
Expand Down Expand Up @@ -151,6 +153,17 @@ where
pub fn prefer_h1(&self, peer: &impl Peer) {
self.h2.prefer_h1(peer);
}

/// Return the number of times a pooled connection was found to contain
/// unexpected data from the server.
pub fn unexpected_data_connection_count(&self) -> u64 {
self.h1.unexpected_data_connection_count()
}

/// Return a shared reference to the unexpected data connection counter for periodic metric reporting.
pub fn unexpected_data_connection_counter(&self) -> Arc<AtomicU64> {
self.h1.unexpected_data_connection_counter()
}
}

#[cfg(test)]
Expand Down
13 changes: 13 additions & 0 deletions pingora-core/src/connectors/http/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use crate::protocols::http::v1::client::HttpSession;
use crate::upstreams::peer::Peer;

use pingora_error::Result;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use std::time::Duration;

pub struct Connector {
Expand Down Expand Up @@ -60,6 +62,17 @@ impl Connector {
.release_stream(stream, peer.reuse_hash(), idle_timeout);
}
}

/// Return the number of times a pooled connection was found to contain
/// unexpected data from the server.
pub fn unexpected_data_connection_count(&self) -> u64 {
self.transport.unexpected_data_connection_count()
}

/// Return a shared reference to the unexpected data connection counter for periodic metric reporting.
pub fn unexpected_data_connection_counter(&self) -> Arc<AtomicU64> {
self.transport.unexpected_data_connection_counter()
}
}

#[cfg(test)]
Expand Down
Loading
Loading