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
11 changes: 9 additions & 2 deletions src/anolisa/crates/anolisa-core/src/telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ pub struct TelemetryConfig {
pub ops_user_defined_ids: Vec<String>,
/// Ops directory for component .jsonl files
pub ops_dir: PathBuf,
/// logrotate config path for ops .jsonl files
pub logrotate_config_path: PathBuf,
/// Instance ID cache path
pub instance_id_cache_path: PathBuf,
/// Path to `/etc/machine-id` (used as instance ID fallback)
Expand Down Expand Up @@ -108,6 +110,7 @@ impl Default for TelemetryConfig {
ops_sls_account_id: default_ops_id,
ops_user_defined_ids: vec!["anolisa-livetrace".into()],
ops_dir: PathBuf::from("/var/log/anolisa/sls/ops"),
logrotate_config_path: PathBuf::from("/etc/logrotate.d/anolisa"),
instance_id_cache_path: PathBuf::from("/var/lib/anolisa/instance-id.cache"),
machine_id_path: PathBuf::from("/etc/machine-id"),
release_path: PathBuf::from("/etc/anolisa-release"),
Expand Down Expand Up @@ -213,10 +216,11 @@ impl TelemetryStarter {
installer.configure_ops_user_defined_ids(),
)?;

// 7-10. Ops telemetry setup
// 7-11. Ops telemetry setup
let ops = OpsTelemetrySetup::new(&self.config);
Self::run_step("create ops directory", ops.create_ops_dir())?;
Self::run_step("create ops jsonl files", ops.create_ops_jsonl_files())?;
Self::run_step("setup logrotate", ops.setup_logrotate())?;
Self::run_step("enable sls log marker", ops.enable_sls_log_marker())?;
let instance_info = Self::run_step(
"write instance snapshot",
Expand Down Expand Up @@ -248,9 +252,11 @@ impl TelemetryStarter {
///
/// Called after `anolisa unregister` successfully writes register.json.
/// Note: does not uninstall ilogtail itself, only revokes upload configuration.
/// Ops directory and .jsonl files are preserved (components still write locally).
/// Ops directory, .jsonl files and logrotate config are preserved
/// (components still write locally, disk size still needs to be bounded).
pub fn stop(&self) -> Result<(), TelemetryError> {
// 0. Remove agentsight SLS log marker file
// (logrotate config is preserved — components still write to .jsonl files)
let ops = OpsTelemetrySetup::new(&self.config);
ops.remove_sls_log_marker()?;

Expand Down Expand Up @@ -283,6 +289,7 @@ pub(crate) fn test_config(dir: &tempfile::TempDir) -> TelemetryConfig {
ops_sls_account_id: "987654321".into(),
ops_user_defined_ids: vec!["anolisa-livetrace".into()],
ops_dir: dir.path().join("ops"),
logrotate_config_path: dir.path().join("logrotate-anolisa"),
instance_id_cache_path: dir.path().join("instance-id.cache"),
machine_id_path: dir.path().join("machine-id"),
release_path: dir.path().join("anolisa-release"),
Expand Down
4 changes: 2 additions & 2 deletions src/anolisa/crates/anolisa-core/src/telemetry/ilogtail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,12 @@ impl<'a> IlogtailInstaller<'a> {
.map_err(|e| TelemetryError::Command(format!("chmod failed: {e}")))?;

let install = if region_info.use_internal {
Command::new("sh")
Command::new("bash")
.args([&tmp_script, "install", region_id.as_str()])
.output()
} else {
let public_region = format!("{region_id}-internet");
Command::new("sh")
Command::new("bash")
.args([tmp_script.as_str(), "install", &public_region])
.output()
};
Expand Down
82 changes: 82 additions & 0 deletions src/anolisa/crates/anolisa-core/src/telemetry/ops_telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! Responsibilities:
//! - Create `/var/log/anolisa/sls/ops/` directory
//! - Pre-create component `.jsonl` files
//! - Configure logrotate for ops `.jsonl` files
//! - Enable / remove agentsight SLS log marker
//! - Write `instance.jsonl` snapshot

Expand Down Expand Up @@ -66,6 +67,41 @@ impl<'a> OpsTelemetrySetup<'a> {
Ok(())
}

/// Write logrotate config for ops `.jsonl` files.
///
/// Creates `/etc/logrotate.d/anolisa` with a `size 30M / rotate 1` policy
/// using rename-mode rotation so ilogtail inode offsets are preserved.
pub fn setup_logrotate(&self) -> Result<(), TelemetryError> {
let config_path = &self.config.logrotate_config_path;
if let Some(parent) = config_path.parent() {
fs::create_dir_all(parent)?;
}

let glob = self.config.ops_dir.join("*.jsonl");
let content = format!(
"{glob} {{\n size 30M\n rotate 1\n missingok\n notifempty\n create 0666 root root\n}}\n",
glob = glob.display()
);
fs::write(config_path, content)?;

#[cfg(target_os = "linux")]
{
use std::os::unix::fs::PermissionsExt;
fs::set_permissions(config_path, fs::Permissions::from_mode(0o644))?;
}

Ok(())
}

/// Remove logrotate config for ops `.jsonl` files.
pub fn remove_logrotate(&self) -> Result<(), TelemetryError> {
let config_path = &self.config.logrotate_config_path;
if config_path.exists() {
fs::remove_file(config_path)?;
}
Ok(())
}

/// Enable agentsight SLS log marker file
pub fn enable_sls_log_marker(&self) -> Result<(), TelemetryError> {
let marker = &self.config.sls_log_marker;
Expand Down Expand Up @@ -164,6 +200,52 @@ mod tests {
assert!(instance_file.exists());
}

#[test]
fn test_setup_logrotate_creates_config() {
let dir = TempDir::new().unwrap();
let cfg = test_config(&dir);
let ops = OpsTelemetrySetup::new(&cfg);
ops.setup_logrotate().unwrap();

let content = fs::read_to_string(&cfg.logrotate_config_path).unwrap();
assert!(content.contains("size 30M"));
assert!(content.contains("rotate 1"));
assert!(content.contains("create 0666 root root"));
assert!(content.contains("*.jsonl"));
}

#[test]
fn test_setup_logrotate_idempotent() {
let dir = TempDir::new().unwrap();
let cfg = test_config(&dir);
let ops = OpsTelemetrySetup::new(&cfg);
ops.setup_logrotate().unwrap();
ops.setup_logrotate().unwrap();

let content = fs::read_to_string(&cfg.logrotate_config_path).unwrap();
assert_eq!(content.matches("size 30M").count(), 1);
}

#[test]
fn test_remove_logrotate_noop_when_absent() {
let dir = TempDir::new().unwrap();
let cfg = test_config(&dir);
let ops = OpsTelemetrySetup::new(&cfg);
assert!(ops.remove_logrotate().is_ok());
}

#[test]
fn test_remove_logrotate_deletes_config() {
let dir = TempDir::new().unwrap();
let cfg = test_config(&dir);
let ops = OpsTelemetrySetup::new(&cfg);
ops.setup_logrotate().unwrap();
assert!(cfg.logrotate_config_path.exists());

ops.remove_logrotate().unwrap();
assert!(!cfg.logrotate_config_path.exists());
}

#[test]
fn test_enable_and_remove_sls_log_marker() {
let dir = TempDir::new().unwrap();
Expand Down
Loading