blob: 91d85bb2074e37226cc2afeb094f9ce6e759b5bb [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::{Pipeline, PipelineEntry, Status, VsrAction, VsrConsensus};
use iggy_binary_protocol::Operation;
use message_bus::MessageBus;
use server_common::sharding::IggyNamespace;
use std::borrow::Cow;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlaneKind {
Metadata,
Partitions,
}
impl PlaneKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Metadata => "metadata",
Self::Partitions => "partitions",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReplicaRole {
Primary,
Backup,
}
impl ReplicaRole {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Primary => "primary",
Self::Backup => "backup",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ViewChangeReason {
NormalHeartbeatTimeout,
ViewChangeStatusTimeout,
ReceivedStartViewChange,
ReceivedDoViewChange,
}
impl ViewChangeReason {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::NormalHeartbeatTimeout => "normal_heartbeat_timeout",
Self::ViewChangeStatusTimeout => "view_change_status_timeout",
Self::ReceivedStartViewChange => "received_start_view_change",
Self::ReceivedDoViewChange => "received_do_view_change",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IgnoreReason {
NotPrimary,
NotNormal,
Syncing,
NewerView,
OlderView,
OldPrepare,
UnknownPrepare,
DuplicateAck,
ChecksumMismatch,
InvalidOperation,
ApplyFailed,
PersistFailed,
}
impl IgnoreReason {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::NotPrimary => "not_primary",
Self::NotNormal => "not_normal",
Self::Syncing => "syncing",
Self::NewerView => "newer_view",
Self::OlderView => "older_view",
Self::OldPrepare => "old_prepare",
Self::UnknownPrepare => "unknown_prepare",
Self::DuplicateAck => "duplicate_ack",
Self::ChecksumMismatch => "checksum_mismatch",
Self::InvalidOperation => "invalid_operation",
Self::ApplyFailed => "apply_failed",
Self::PersistFailed => "persist_failed",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlActionKind {
SendStartViewChange,
SendDoViewChange,
SendStartView,
SendPrepareOk,
SendPrepare,
RebuildPipeline,
CommitJournal,
SendCommit,
}
impl ControlActionKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::SendStartViewChange => "send_start_view_change",
Self::SendDoViewChange => "send_do_view_change",
Self::SendStartView => "send_start_view",
Self::SendPrepareOk => "send_prepare_ok",
Self::SendPrepare => "send_prepare",
Self::RebuildPipeline => "rebuild_pipeline",
Self::CommitJournal => "commit_journal",
Self::SendCommit => "send_commit",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SimEventKind {
ClientRequestReceived,
PrepareQueued,
PrepareAcked,
OperationCommitted,
ClientReplyEmitted,
ViewChangeStarted,
PrimaryElected,
ReplicaStateChanged,
NamespaceProgressUpdated,
ControlMessageScheduled,
}
impl SimEventKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::ClientRequestReceived => "ClientRequestReceived",
Self::PrepareQueued => "PrepareQueued",
Self::PrepareAcked => "PrepareAcked",
Self::OperationCommitted => "OperationCommitted",
Self::ClientReplyEmitted => "ClientReplyEmitted",
Self::ViewChangeStarted => "ViewChangeStarted",
Self::PrimaryElected => "PrimaryElected",
Self::ReplicaStateChanged => "ReplicaStateChanged",
Self::NamespaceProgressUpdated => "NamespaceProgressUpdated",
Self::ControlMessageScheduled => "ControlMessageScheduled",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NamespaceLogContext {
pub raw: u64,
pub stream_id: Option<u32>,
pub topic_id: Option<u32>,
pub partition_id: Option<u32>,
}
impl NamespaceLogContext {
#[must_use]
pub fn from_raw(plane: PlaneKind, raw: u64) -> Self {
if matches!(plane, PlaneKind::Metadata) {
return Self {
raw,
stream_id: None,
topic_id: None,
partition_id: None,
};
}
let namespace = IggyNamespace::from_raw(raw);
#[allow(clippy::cast_possible_truncation)]
let stream_id = namespace.stream_id() as u32;
#[allow(clippy::cast_possible_truncation)]
let topic_id = namespace.topic_id() as u32;
#[allow(clippy::cast_possible_truncation)]
let partition_id = namespace.partition_id() as u32;
Self {
raw,
stream_id: Some(stream_id),
topic_id: Some(topic_id),
partition_id: Some(partition_id),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ReplicaLogContext {
pub plane: PlaneKind,
pub cluster_id: u128,
pub replica_id: u8,
pub namespace: NamespaceLogContext,
pub view: u32,
pub log_view: u32,
pub commit: u64,
pub status: Status,
pub role: ReplicaRole,
}
impl ReplicaLogContext {
#[must_use]
pub fn from_consensus<B, P>(consensus: &VsrConsensus<B, P>, plane: PlaneKind) -> Self
where
B: MessageBus,
P: Pipeline<Entry = PipelineEntry>,
{
let role = if consensus.is_primary() {
ReplicaRole::Primary
} else {
ReplicaRole::Backup
};
Self {
plane,
cluster_id: consensus.cluster(),
replica_id: consensus.replica(),
namespace: NamespaceLogContext::from_raw(plane, consensus.namespace()),
view: consensus.view(),
log_view: consensus.log_view(),
commit: consensus.commit_max(),
status: consensus.status(),
role,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RequestLogEvent {
pub replica: ReplicaLogContext,
pub client_id: u128,
pub request_id: u64,
pub operation: Operation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PrepareLogEvent {
pub replica: ReplicaLogContext,
pub op: u64,
pub parent_checksum: u128,
pub prepare_checksum: u128,
pub client_id: u128,
pub request_id: u64,
pub operation: Operation,
pub pipeline_depth: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AckLogEvent {
pub replica: ReplicaLogContext,
pub op: u64,
pub prepare_checksum: u128,
pub ack_from_replica: u8,
pub ack_count: usize,
pub quorum: usize,
pub quorum_reached: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CommitLogEvent {
pub replica: ReplicaLogContext,
pub op: u64,
pub client_id: u128,
pub request_id: u64,
pub operation: Operation,
pub pipeline_depth: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ViewChangeLogEvent {
pub replica: ReplicaLogContext,
pub old_view: u32,
pub new_view: u32,
pub reason: ViewChangeReason,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ControlActionLogEvent {
pub replica: ReplicaLogContext,
pub action: ControlActionKind,
pub target_replica: Option<u8>,
pub op: Option<u64>,
pub commit: Option<u64>,
}
impl ControlActionLogEvent {
#[must_use]
pub const fn from_vsr_action(replica: ReplicaLogContext, action: &VsrAction) -> Self {
match *action {
VsrAction::SendStartViewChange { .. } => Self {
replica,
action: ControlActionKind::SendStartViewChange,
target_replica: None,
op: None,
commit: None,
},
VsrAction::SendDoViewChange {
target, op, commit, ..
} => Self {
replica,
action: ControlActionKind::SendDoViewChange,
target_replica: Some(target),
op: Some(op),
commit: Some(commit),
},
VsrAction::SendStartView { op, commit, .. } => Self {
replica,
action: ControlActionKind::SendStartView,
target_replica: None,
op: Some(op),
commit: Some(commit),
},
VsrAction::SendPrepareOk {
target, from_op, ..
} => Self {
replica,
action: ControlActionKind::SendPrepareOk,
target_replica: Some(target),
op: Some(from_op),
commit: None,
},
VsrAction::RetransmitPrepares { .. } => Self {
replica,
action: ControlActionKind::SendPrepare,
target_replica: None,
op: None,
commit: None,
},
VsrAction::RebuildPipeline { from_op, to_op, .. } => Self {
replica,
action: ControlActionKind::RebuildPipeline,
target_replica: None,
op: Some(from_op),
commit: Some(to_op),
},
VsrAction::CommitJournal => Self {
replica,
action: ControlActionKind::CommitJournal,
target_replica: None,
op: None,
commit: None,
},
VsrAction::SendCommit { commit, .. } => Self {
replica,
action: ControlActionKind::SendCommit,
target_replica: None,
op: None,
commit: Some(commit),
},
}
}
}
pub trait StructuredSimEvent {
fn emit(&self, sim_event: SimEventKind);
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PartitionDiagEvent<'a> {
pub replica: ReplicaLogContext,
pub message: &'static str,
pub operation: Option<Operation>,
pub op: Option<u64>,
pub prepare_checksum: Option<u128>,
pub reason: Option<&'a str>,
pub error: Option<Cow<'a, str>>,
}
impl<'a> PartitionDiagEvent<'a> {
#[must_use]
pub const fn new(replica: ReplicaLogContext, message: &'static str) -> Self {
Self {
replica,
message,
operation: None,
op: None,
prepare_checksum: None,
reason: None,
error: None,
}
}
#[must_use]
pub const fn with_operation(mut self, operation: Operation) -> Self {
self.operation = Some(operation);
self
}
#[must_use]
pub const fn with_op(mut self, op: u64) -> Self {
self.op = Some(op);
self
}
#[must_use]
pub const fn with_prepare_checksum(mut self, prepare_checksum: u128) -> Self {
self.prepare_checksum = Some(prepare_checksum);
self
}
#[must_use]
pub const fn with_reason(mut self, reason: &'a str) -> Self {
self.reason = Some(reason);
self
}
#[must_use]
pub fn with_error<E>(mut self, error: E) -> Self
where
E: Into<Cow<'a, str>>,
{
self.error = Some(error.into());
self
}
}
pub fn emit_partition_diag(level: tracing::Level, event: &PartitionDiagEvent<'_>) {
match level {
tracing::Level::ERROR => emit_partition_diag_error(event),
tracing::Level::WARN => emit_partition_diag_warn(event),
tracing::Level::INFO => emit_partition_diag_info(event),
tracing::Level::DEBUG => emit_partition_diag_debug(event),
tracing::Level::TRACE => emit_partition_diag_trace(event),
}
}
fn emit_partition_diag_error(event: &PartitionDiagEvent<'_>) {
let ctx = event.replica;
let operation = event.operation.map_or("", operation_as_str);
let op = event.op.unwrap_or_default();
let prepare_checksum = event.prepare_checksum.unwrap_or_default();
let reason = event.reason.unwrap_or("");
let error = event.error.as_deref().unwrap_or("");
tracing::event!(
target: "iggy.partitions.diag",
tracing::Level::ERROR,
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
operation,
op,
prepare_checksum,
reason,
error,
message = event.message,
);
}
fn emit_partition_diag_warn(event: &PartitionDiagEvent<'_>) {
let ctx = event.replica;
let operation = event.operation.map_or("", operation_as_str);
let op = event.op.unwrap_or_default();
let prepare_checksum = event.prepare_checksum.unwrap_or_default();
let reason = event.reason.unwrap_or("");
let error = event.error.as_deref().unwrap_or("");
tracing::event!(
target: "iggy.partitions.diag",
tracing::Level::WARN,
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
operation,
op,
prepare_checksum,
reason,
error,
message = event.message,
);
}
fn emit_partition_diag_info(event: &PartitionDiagEvent<'_>) {
let ctx = event.replica;
let operation = event.operation.map_or("", operation_as_str);
let op = event.op.unwrap_or_default();
let prepare_checksum = event.prepare_checksum.unwrap_or_default();
let reason = event.reason.unwrap_or("");
let error = event.error.as_deref().unwrap_or("");
tracing::event!(
target: "iggy.partitions.diag",
tracing::Level::INFO,
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
operation,
op,
prepare_checksum,
reason,
error,
message = event.message,
);
}
fn emit_partition_diag_debug(event: &PartitionDiagEvent<'_>) {
let ctx = event.replica;
let operation = event.operation.map_or("", operation_as_str);
let op = event.op.unwrap_or_default();
let prepare_checksum = event.prepare_checksum.unwrap_or_default();
let reason = event.reason.unwrap_or("");
let error = event.error.as_deref().unwrap_or("");
tracing::event!(
target: "iggy.partitions.diag",
tracing::Level::DEBUG,
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
operation,
op,
prepare_checksum,
reason,
error,
message = event.message,
);
}
fn emit_partition_diag_trace(event: &PartitionDiagEvent<'_>) {
let ctx = event.replica;
let operation = event.operation.map_or("", operation_as_str);
let op = event.op.unwrap_or_default();
let prepare_checksum = event.prepare_checksum.unwrap_or_default();
let reason = event.reason.unwrap_or("");
let error = event.error.as_deref().unwrap_or("");
tracing::event!(
target: "iggy.partitions.diag",
tracing::Level::TRACE,
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
operation,
op,
prepare_checksum,
reason,
error,
message = event.message,
);
}
#[must_use]
pub const fn status_as_str(status: Status) -> &'static str {
match status {
Status::Normal => "normal",
Status::ViewChange => "view_change",
Status::Recovering => "recovering",
}
}
#[must_use]
pub const fn operation_as_str(operation: Operation) -> &'static str {
match operation {
Operation::Reserved => "reserved",
Operation::CreateTopicWithAssignments => "create_topic_with_assignments",
Operation::CreatePartitionsWithAssignments => "create_partitions_with_assignments",
Operation::RemoveConsumerGroupMember => "remove_consumer_group_member",
Operation::CompleteConsumerGroupRevocation => "complete_consumer_group_revocation",
Operation::TruncatePartition => "truncate_partition",
Operation::CreateStream => "create_stream",
Operation::UpdateStream => "update_stream",
Operation::DeleteStream => "delete_stream",
Operation::PurgeStream => "purge_stream",
Operation::CreateTopic => "create_topic",
Operation::UpdateTopic => "update_topic",
Operation::DeleteTopic => "delete_topic",
Operation::PurgeTopic => "purge_topic",
Operation::CreatePartitions => "create_partitions",
Operation::DeletePartitions => "delete_partitions",
Operation::DeleteSegments => "delete_segments",
Operation::CreateConsumerGroup => "create_consumer_group",
Operation::DeleteConsumerGroup => "delete_consumer_group",
Operation::JoinConsumerGroup => "join_consumer_group",
Operation::LeaveConsumerGroup => "leave_consumer_group",
Operation::CreateUser => "create_user",
Operation::UpdateUser => "update_user",
Operation::DeleteUser => "delete_user",
Operation::ChangePassword => "change_password",
Operation::UpdatePermissions => "update_permissions",
Operation::CreatePersonalAccessToken => "create_personal_access_token",
Operation::DeletePersonalAccessToken => "delete_personal_access_token",
Operation::Register => "register",
Operation::Logout => "logout",
Operation::NonReplicated => "non_replicated",
Operation::SendMessages => "send_messages",
Operation::StoreConsumerOffset => "store_consumer_offset",
Operation::DeleteConsumerOffset => "delete_consumer_offset",
Operation::StoreConsumerOffset2 => "store_consumer_offset_2",
Operation::DeleteConsumerOffset2 => "delete_consumer_offset_2",
}
}
#[must_use]
pub const fn namespace_component(component: Option<u32>) -> u32 {
match component {
Some(value) => value,
None => 0,
}
}
pub fn emit_sim_event<T>(sim_event: SimEventKind, event: &T)
where
T: StructuredSimEvent,
{
event.emit(sim_event);
}
// INFO, not DEBUG: only view-change completion flows through here
// (PrimaryElected / ReplicaStateChanged) - rare fault-path transitions and
// the primary diagnostic for stalled clusters. Default test/prod filters
// drop DEBUG, which made wedged view changes invisible in logs.
pub fn emit_replica_event(sim_event: SimEventKind, ctx: &ReplicaLogContext) {
tracing::event!(
target: "iggy.sim",
tracing::Level::INFO,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
);
}
pub fn emit_namespace_progress_event(
sim_event: SimEventKind,
ctx: &ReplicaLogContext,
op: u64,
pipeline_depth: usize,
) {
tracing::event!(
target: "iggy.sim",
tracing::Level::DEBUG,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
op,
pipeline_depth,
);
}
impl StructuredSimEvent for RequestLogEvent {
fn emit(&self, sim_event: SimEventKind) {
let ctx = self.replica;
tracing::event!(
target: "iggy.sim",
tracing::Level::DEBUG,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
client_id = self.client_id,
request_id = self.request_id,
operation = operation_as_str(self.operation),
);
}
}
impl StructuredSimEvent for PrepareLogEvent {
fn emit(&self, sim_event: SimEventKind) {
let ctx = self.replica;
tracing::event!(
target: "iggy.sim",
tracing::Level::DEBUG,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
op = self.op,
parent_checksum = self.parent_checksum,
prepare_checksum = self.prepare_checksum,
client_id = self.client_id,
request_id = self.request_id,
operation = operation_as_str(self.operation),
pipeline_depth = self.pipeline_depth,
);
}
}
impl StructuredSimEvent for AckLogEvent {
fn emit(&self, sim_event: SimEventKind) {
let ctx = self.replica;
tracing::event!(
target: "iggy.sim",
tracing::Level::DEBUG,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
op = self.op,
prepare_checksum = self.prepare_checksum,
ack_from_replica = self.ack_from_replica,
ack_count = self.ack_count,
quorum = self.quorum,
quorum_reached = self.quorum_reached,
);
}
}
impl StructuredSimEvent for CommitLogEvent {
fn emit(&self, sim_event: SimEventKind) {
let ctx = self.replica;
tracing::event!(
target: "iggy.sim",
tracing::Level::DEBUG,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
op = self.op,
client_id = self.client_id,
request_id = self.request_id,
operation = operation_as_str(self.operation),
pipeline_depth = self.pipeline_depth,
);
}
}
impl StructuredSimEvent for ViewChangeLogEvent {
fn emit(&self, sim_event: SimEventKind) {
let ctx = self.replica;
// INFO for the same reason as emit_replica_event: view-change starts
// must be visible under default log filters.
tracing::event!(
target: "iggy.sim",
tracing::Level::INFO,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
old_view = self.old_view,
new_view = self.new_view,
reason = self.reason.as_str(),
);
}
}
impl StructuredSimEvent for ControlActionLogEvent {
fn emit(&self, sim_event: SimEventKind) {
let ctx = self.replica;
tracing::event!(
target: "iggy.sim",
tracing::Level::DEBUG,
sim_event = sim_event.as_str(),
plane = ctx.plane.as_str(),
cluster_id = ctx.cluster_id,
replica_id = ctx.replica_id,
namespace_raw = ctx.namespace.raw,
stream_id = namespace_component(ctx.namespace.stream_id),
topic_id = namespace_component(ctx.namespace.topic_id),
partition_id = namespace_component(ctx.namespace.partition_id),
view = ctx.view,
log_view = ctx.log_view,
commit = ctx.commit,
status = status_as_str(ctx.status),
role = ctx.role.as_str(),
action = self.action.as_str(),
target_replica = self.target_replica.unwrap_or_default(),
op = self.op.unwrap_or_default(),
action_commit = self.commit.unwrap_or_default(),
);
}
}