Skip to content
Open
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 core/common/src/types/stats/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub struct Stats {
pub kernel_version: String,
/// The version of the Iggy server.
pub iggy_server_version: String,
/// The semantic version of the Iggy server in the numeric format e.g. 1.2.3 -> 100200300 (major * 1000000 + minor * 1000 + patch).
/// The semantic version of the Iggy server in the numeric format e.g. 1.2.3 -> 1002003 (major * 1000000 + minor * 1000 + patch).
pub iggy_server_semver: Option<u32>,
/// Cache metrics per partition
#[serde(with = "cache_metrics_serializer")]
Expand Down
215 changes: 215 additions & 0 deletions foreign/python/apache_iggy.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ __all__ = [
"AutoCommitAfter",
"AutoCommitWhen",
"AutoLogin",
"CacheMetrics",
"CacheMetricsKey",
"Consumer",
"ConsumerGroup",
"ConsumerGroupDetails",
Expand All @@ -49,6 +51,7 @@ __all__ = [
"SendMessage",
"SendMessagesConfirmation",
"SendMessagesResponse",
"Stats",
"StreamDetails",
"StreamPermissions",
"TcpConfig",
Expand Down Expand Up @@ -290,6 +293,57 @@ class AutoLogin:
"""
def __repr__(self) -> builtins.str: ...

@typing.final
class CacheMetrics:
r"""
Cache metrics for a specific partition.
"""
@property
def hits(self) -> builtins.int:
r"""
Number of cache hits.
"""
@property
def misses(self) -> builtins.int:
r"""
Number of cache misses.
"""
@property
def hit_ratio(self) -> builtins.float:
r"""
Hit ratio (hits / (hits + misses)).
"""
def __repr__(self) -> builtins.str: ...

@typing.final
class CacheMetricsKey:
r"""
Key identifying the partition a `CacheMetrics` entry belongs to.

Hashable and comparable, so it can key the `Stats.cache_metrics` dict.
"""
@property
def stream_id(self) -> builtins.int:
r"""
The unique identifier (numeric) of the stream.
"""
@property
def topic_id(self) -> builtins.int:
r"""
The unique identifier (numeric) of the topic within the stream.
"""
@property
def partition_id(self) -> builtins.int:
r"""
The unique identifier (numeric) of the partition within the topic.
"""
def __eq__(self, other: builtins.object, /) -> builtins.bool: ...
def __hash__(self) -> builtins.int: ...
def __new__(
cls, stream_id: builtins.int, topic_id: builtins.int, partition_id: builtins.int
) -> CacheMetricsKey: ...
def __repr__(self) -> builtins.str: ...

class Consumer:
r"""
The consumer polling the messages. It selects both the consumer kind and the
Expand Down Expand Up @@ -872,6 +926,16 @@ class IggyClient:
Sends a ping request to the server to check connectivity.
Raises `RuntimeError` if the connection fails.
"""
def get_stats(self) -> collections.abc.Awaitable[Stats]:
r"""
Get the statistics and details of the server and its running process.

Returns:
An awaitable that resolves to `Stats`.

Raises:
RuntimeError: If the request fails.
"""
def describe_options(
self, scope: builtins.str
) -> collections.abc.Awaitable[list[OptionSpec]]:
Expand Down Expand Up @@ -1836,6 +1900,157 @@ class SendMessagesResponse:
with an offset a client has already recorded.
"""

@typing.final
class Stats:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CacheMetrics and CacheMetricsKey both define __repr__, but Stats does not. Since get_stats is a diagnostic call, print(stats) showing an object address is not great. A short repr with a few key fields would help.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 7a28235Stats.__repr__ now prints hostname, server version and the headline counters (streams/topics/partitions/messages/clients).

r"""
The statistics and details of the server and its running process.
"""
@property
def process_id(self) -> builtins.int:
r"""
The unique identifier of the server process.
"""
@property
def cpu_usage(self) -> builtins.float:
r"""
The CPU usage of the server process, in percent.
"""
@property
def total_cpu_usage(self) -> builtins.float:
r"""
The total CPU usage of the system, in percent.
"""
@property
def memory_usage(self) -> builtins.int:
r"""
The memory usage of the server process, in bytes.
"""
@property
def total_memory(self) -> builtins.int:
r"""
The total memory of the system, in bytes.
"""
@property
def available_memory(self) -> builtins.int:
r"""
The available memory of the system, in bytes.
"""
@property
def run_time(self) -> datetime.timedelta:
r"""
The run time of the server process.
"""
@property
def start_time(self) -> builtins.int:
r"""
The start time of the server process, in microseconds since the Unix epoch.
"""
@property
def read_bytes(self) -> builtins.int:
r"""
The total number of bytes read.
"""
@property
def written_bytes(self) -> builtins.int:
r"""
The total number of bytes written.
"""
@property
def messages_size_bytes(self) -> builtins.int:
r"""
The total size of the messages, in bytes.
"""
@property
def streams_count(self) -> builtins.int:
r"""
The total number of streams.
"""
@property
def topics_count(self) -> builtins.int:
r"""
The total number of topics.
"""
@property
def partitions_count(self) -> builtins.int:
r"""
The total number of partitions.
"""
@property
def segments_count(self) -> builtins.int:
r"""
The total number of segments.
"""
@property
def messages_count(self) -> builtins.int:
r"""
The total number of messages.
"""
@property
def clients_count(self) -> builtins.int:
r"""
The total number of connected clients.
"""
@property
def consumer_groups_count(self) -> builtins.int:
r"""
The total number of consumer groups.
"""
@property
def hostname(self) -> builtins.str:
r"""
The name of the host the server runs on.
"""
@property
def os_name(self) -> builtins.str:
r"""
The name of the operating system.
"""
@property
def os_version(self) -> builtins.str:
r"""
The version of the operating system.
"""
@property
def kernel_version(self) -> builtins.str:
r"""
The version of the kernel.
"""
@property
def iggy_server_version(self) -> builtins.str:
r"""
The version of the Iggy server.
"""
@property
def iggy_server_semver(self) -> builtins.int | None:
r"""
The numeric semantic version of the Iggy server, or `None` when unknown.
E.g. 1.2.3 -> 1002003 (major * 1000000 + minor * 1000 + patch).
"""
@property
def cache_metrics(self) -> builtins.dict[CacheMetricsKey, CacheMetrics]:
r"""
Cache metrics per partition.

Built once when the stats snapshot is created; every access returns the
same dict.
"""
@property
def threads_count(self) -> builtins.int:
r"""
The number of threads in the server process.
"""
@property
def free_disk_space(self) -> builtins.int:
r"""
The available (free) disk space for the data directory, in bytes.
"""
@property
def total_disk_space(self) -> builtins.int:
r"""
The total disk space for the data directory, in bytes.
"""
def __repr__(self) -> builtins.str: ...

@typing.final
class StreamDetails:
@property
Expand Down
20 changes: 20 additions & 0 deletions foreign/python/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use crate::options::OptionSpec as PyOptionSpec;
use crate::permissions::Permissions as PyPermissions;
use crate::receive_message::{PollingStrategy, ReceiveMessage};
use crate::send_message::{SendMessage, SendMessagesResponse as PySendMessagesResponse};
use crate::stats::Stats as PyStats;
use crate::stream::StreamDetails;
use crate::topic::{IggyExpiry, MaxTopicSize, Topic, TopicDetails};
use crate::user::{
Expand Down Expand Up @@ -157,6 +158,25 @@ impl IggyClient {
})
}

/// Get the statistics and details of the server and its running process.
///
/// Returns:
/// An awaitable that resolves to `Stats`.
///
/// Raises:
/// RuntimeError: If the request fails.
Comment on lines +161 to +167

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Rust SystemClient::get_stats contract requires authentication and the read_servers permission. Document both. Test before connect/login, after disconnect, without permission, and with read_servers/manage_servers.

#[gen_stub(override_return_type(type_repr="collections.abc.Awaitable[Stats]", imports=("collections.abc")))]
fn get_stats<'a>(&self, py: Python<'a>) -> PyResult<Bound<'a, PyAny>> {
let inner = self.inner.clone();
future_into_py(py, async move {
let stats = inner
.get_stats()
.await
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
Ok(PyStats::from(stats))
})
}

/// Describe the option catalog for a resource scope.
///
/// This is the discovery surface for the `options` argument on
Expand Down
5 changes: 5 additions & 0 deletions foreign/python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod options;
mod permissions;
mod receive_message;
mod send_message;
mod stats;
mod stream;
mod topic;
mod user;
Expand All @@ -40,6 +41,7 @@ use permissions::{GlobalPermissions, Permissions, StreamPermissions, TopicPermis
use pyo3::prelude::*;
use receive_message::{PollingStrategy, ReceiveMessage};
use send_message::{SendMessage, SendMessagesConfirmation, SendMessagesResponse};
use stats::{CacheMetrics, CacheMetricsKey, Stats};
use stream::StreamDetails;
use topic::{IggyExpiry, MaxTopicSize, Partition, Topic, TopicDetails};
use user::{UserInfo, UserInfoDetails, UserStatus};
Expand All @@ -57,6 +59,9 @@ fn apache_iggy(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<TcpConfig>()?;
m.add_class::<TcpReconnectionConfig>()?;
m.add_class::<StreamDetails>()?;
m.add_class::<Stats>()?;
m.add_class::<CacheMetrics>()?;
m.add_class::<CacheMetricsKey>()?;
m.add_class::<Topic>()?;
m.add_class::<TopicDetails>()?;
m.add_class::<IggyExpiry>()?;
Expand Down
Loading