blob: 6b72f0235c719133761b87c2c0f679b44e9a2285 [file] [log] [blame]
// 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::skywalking_proto::v3::{InstanceProperties, KeyStringValuePair};
use once_cell::sync::Lazy;
use std::{collections::HashMap, process};
use systemstat::{IpAddr, Platform, System};
static IPS: Lazy<Vec<String>> = Lazy::new(|| {
System::new()
.networks()
.ok()
.map(|networks| {
networks
.values()
.filter(|network| {
network.name != "lo"
&& !network.name.starts_with("docker")
&& !network.name.starts_with("br-")
})
.flat_map(|network| {
network.addrs.iter().filter_map(|addr| match addr.addr {
IpAddr::V4(addr) => Some(addr.to_string()),
_ => None,
})
})
.collect()
})
.unwrap_or_default()
});
static HOST_NAME: Lazy<Option<String>> = Lazy::new(|| {
hostname::get()
.ok()
.and_then(|hostname| hostname.into_string().ok())
});
const OS_NAME: Option<&str> = if cfg!(target_os = "linux") {
Some("Linux")
} else if cfg!(target_os = "windows") {
Some("Windows")
} else if cfg!(target_os = "macos") {
Some("Mac OS X")
} else {
None
};
#[derive(Debug, Default)]
pub struct Properties {
inner: HashMap<String, Vec<String>>,
}
impl Properties {
pub const KEY_HOST_NAME: &'static str = "hostname";
pub const KEY_IPV4: &'static str = "ipv4";
pub const KEY_LANGUAGE: &'static str = "language";
pub const KEY_OS_NAME: &'static str = "OS Name";
pub const KEY_PROCESS_NO: &'static str = "Process No.";
}
impl Properties {
#[inline]
pub fn new() -> Self {
Default::default()
}
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<String>) {
self.inner.entry(key.into()).or_default().push(value.into());
}
pub fn update(&mut self, key: &str, value: impl Into<String>) {
if let Some(values) = self.inner.get_mut(key) {
*values = vec![value.into()];
}
}
pub fn remove(&mut self, key: &str) {
self.inner.remove(key);
}
pub fn insert_os_info(&mut self) {
for (key, value) in build_os_info() {
self.insert(key, value);
}
}
pub(crate) fn convert_to_instance_properties(
self,
service_name: String,
instance_name: String,
) -> InstanceProperties {
let mut properties = Vec::new();
for (key, values) in self.inner {
for value in values {
properties.push(KeyStringValuePair {
key: key.clone(),
value,
});
}
}
InstanceProperties {
service: service_name,
service_instance: instance_name,
properties,
layer: Default::default(),
}
}
}
fn build_os_info() -> Vec<(String, String)> {
let mut items = Vec::new();
if let Some(os_name) = OS_NAME.as_ref() {
items.push((Properties::KEY_OS_NAME.to_string(), os_name.to_string()));
}
if let Some(host_name) = HOST_NAME.as_ref() {
items.push((Properties::KEY_HOST_NAME.to_string(), host_name.clone()));
}
for ip in IPS.iter() {
items.push((Properties::KEY_IPV4.to_string(), ip.to_string()));
}
items.push((
Properties::KEY_PROCESS_NO.to_string(),
process::id().to_string(),
));
items.push((Properties::KEY_LANGUAGE.to_string(), "rust".to_string()));
items
}