sys stats

master
veypi 12 months ago
parent 73e56ca8c5
commit 1560ec9ad2

@ -21,7 +21,7 @@ dropTag:
@git push origin :refs/tags/$(version) @git push origin :refs/tags/$(version)
run: run:
go run *.go -d @cd oab && cargo run -- -c ./cfg-demo.yml
syncDB: syncDB:

78
oab/Cargo.lock generated

@ -884,6 +884,30 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.3.8" version = "0.3.8"
@ -1935,6 +1959,15 @@ version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@ -2022,6 +2055,15 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.46.0"
@ -2158,6 +2200,7 @@ dependencies = [
"serde_yaml", "serde_yaml",
"service-manager", "service-manager",
"sqlx 0.5.13", "sqlx 0.5.13",
"sysinfo",
"thiserror", "thiserror",
"tokio", "tokio",
"tracing", "tracing",
@ -2596,6 +2639,26 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "rayon"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.16" version = "0.2.16"
@ -3753,6 +3816,21 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sysinfo"
version = "0.29.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a18d114d420ada3a891e6bc8e96a2023402203296a47cdd65083377dad18ba5"
dependencies = [
"cfg-if",
"core-foundation-sys",
"libc",
"ntapi",
"once_cell",
"rayon",
"winapi",
]
[[package]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.5.1" version = "0.5.1"

@ -61,4 +61,5 @@ bytes = "1.5.0"
nkeys = "0.3.2" nkeys = "0.3.2"
tracing-appender = "0.2.2" tracing-appender = "0.2.2"
reqwest = "0.11.22" reqwest = "0.11.22"
sysinfo = "0.29.10"

@ -1,3 +1,3 @@
<!DOCTYPE html><html><head><title>OA</title><meta charset=utf-8><meta name=description content=oneauth><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/ico href="/favicon.ico"> <script type="module" crossorigin src="/assets/index.559d1c65.js"></script> <!DOCTYPE html><html><head><title>OA</title><meta charset=utf-8><meta name=description content=oneauth><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/ico href="/favicon.ico"> <script type="module" crossorigin src="/assets/index.43a53367.js"></script>
<link rel="stylesheet" href="/assets/index.4abc03f5.css"> <link rel="stylesheet" href="/assets/index.4abc03f5.css">
</head><body><div id=v-msg></div><div id=q-app></div></body></html> </head><body><div id=v-msg></div><div id=q-app></div></body></html>

@ -9,7 +9,9 @@ use std::time::{Duration, Instant};
use futures_util::StreamExt; use futures_util::StreamExt;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::process;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use sysinfo::{Pid, ProcessExt, System, SystemExt};
use tracing::{info, warn}; use tracing::{info, warn};
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
@ -25,6 +27,38 @@ struct ClientInfo {
name: String, name: String,
host: String, host: String,
} }
pub fn start_stats_info(url: String) {
tokio::spawn(async move {
let pid = process::id();
info!("star on pid {}", pid);
let mut s = System::new_all();
let pid = Pid::from(pid as usize);
let props = sysinfo::ProcessRefreshKind::everything();
let url = format!("http://{}/api/v1/import/prometheus", url);
let client = reqwest::Client::new();
let start = Instant::now();
loop {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
s.refresh_process_specifics(pid, props);
if let Some(process) = s.process(pid) {
let stat_str = format!(
"oa_stats_cpu {}\noa_stats_mem {}\noa_stats_start {}",
process.cpu_usage(),
process.memory(),
start.elapsed().as_secs(),
);
match client.post(&url).body(stat_str).send().await {
Ok(_) => {}
Err(e) => {
warn!("{}", e);
}
}
}
}
});
}
pub fn start_nats_online(client: async_nats::client::Client) { pub fn start_nats_online(client: async_nats::client::Client) {
let db: Arc<Mutex<HashMap<i64, ClientInfo>>> = Arc::new(Mutex::new(HashMap::new())); let db: Arc<Mutex<HashMap<i64, ClientInfo>>> = Arc::new(Mutex::new(HashMap::new()));
{ {

@ -49,8 +49,10 @@ async fn main() -> Result<()> {
web(data).await?; web(data).await?;
Ok(()) Ok(())
} }
async fn web(data: AppState) -> Result<()> { async fn web(data: AppState) -> Result<()> {
// libs::task::start_nats_online(client.clone()); // libs::task::start_nats_online(client.clone());
libs::task::start_stats_info(data.info.ts_url.clone());
let url = data.server_url.clone(); let url = data.server_url.clone();
let dav = libs::fs::core(); let dav = libs::fs::core();
let serv = HttpServer::new(move || { let serv = HttpServer::new(move || {

@ -17,7 +17,7 @@
"@toast-ui/editor": "^3.2.2", "@toast-ui/editor": "^3.2.2",
"@types/validator": "^13.11.2", "@types/validator": "^13.11.2",
"@veypi/msg": "^0.1.1", "@veypi/msg": "^0.1.1",
"@veypi/oaer": "^0.0.6", "@veypi/oaer": "^0.0.9",
"@veypi/one-icon": "2", "@veypi/one-icon": "2",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^1.2.1", "axios": "^1.2.1",

@ -7,7 +7,7 @@
const cfg = { const cfg = {
host: 'http://' + window.location.host, host: window.location.protocol + '//' + window.location.host,
id: 'FR9P5t8debxc11aFF', id: 'FR9P5t8debxc11aFF',
} }

@ -7,6 +7,7 @@
import { ref } from 'vue' import { ref } from 'vue'
const use_params = () => {
let mode = ref(0) let mode = ref(0)
let mode_label = ['近5分钟', '近1小时', '近24小时', '近7天', '近30天'] let mode_label = ['近5分钟', '近1小时', '近24小时', '近7天', '近30天']
let change_mode = (m: number) => { let change_mode = (m: number) => {
@ -67,5 +68,8 @@ const set_delta = (start?: Date, end?: Date) => {
params.value.start.getTime() params.value.start.getTime()
console.log(delta) console.log(delta)
} }
return { params, change_mode, mode, mode_label }
}
export { params, change_mode, mode, mode_label } export default use_params

@ -6,7 +6,7 @@
--> -->
<template> <template>
<div class="w-full h-full"> <div class="w-full h-full">
<div class="h-16 flex justify-start items-center"> <div v-if="enable_mode" class="h-16 flex justify-start items-center">
<q-chip clickable :color="enable_sync ? 'primary' : ''" @click="enable_sync = !enable_sync">{{ enable_sync ? '关闭同步' <q-chip clickable :color="enable_sync ? 'primary' : ''" @click="enable_sync = !enable_sync">{{ enable_sync ? '关闭同步'
: :
'开启同步' }}</q-chip> '开启同步' }}</q-chip>
@ -14,26 +14,33 @@
@click="change_mode(k)">{{ @click="change_mode(k)">{{
v }}</q-chip> v }}</q-chip>
</div> </div>
<div class="v-chart w-full" style="height: calc(100% - 4rem);" ref="chartdom"></div> <div class="v-chart w-full" :style="{
height:
enable_mode ? 'calc(100% - 4rem)' : '100%'
}" ref="chartdom"></div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import * as echart from 'echarts' import * as echart from 'echarts'
import api from 'src/boot/api'; import api from 'src/boot/api';
import { params, mode, change_mode, mode_label } from './params' // import { params, mode, change_mode, mode_label } from './params'
import use_params from './params'
import { onMounted, onUnmounted, computed, ref, watch, markRaw } from 'vue'; import { onMounted, onUnmounted, computed, ref, watch, markRaw } from 'vue';
let { params, mode, change_mode, mode_label } = use_params()
interface Item { interface Item {
name: string name: string
query: string | string[] query: string | string[]
ext?: string
valueFormatter?: (s: number) => string valueFormatter?: (s: number) => string
label?: string | string[] | ((s: any) => string) label?: string | string[] | ((s: any) => string)
} }
let props = withDefaults(defineProps<{ let props = withDefaults(defineProps<{
item: Item, item: Item,
sync?: boolean, sync?: boolean,
enable_zoom?: boolean,
time_mode?: number,
enable_mode?: boolean,
}>(), }>(),
{ {
} }
@ -63,6 +70,7 @@ const init_chart = () => {
clearInterval(e) clearInterval(e)
}) })
options.value = { options.value = {
title: { text: props.item.name, x: 'center' },
animationThreshold: 200, animationThreshold: 200,
tooltip: Object.assign({}, tooltip), tooltip: Object.assign({}, tooltip),
axisPointer: { axisPointer: {
@ -74,15 +82,17 @@ const init_chart = () => {
xAxis: { xAxis: {
type: 'time', type: 'time',
}, },
dataZoom: [ yAxis: {},
series: []
}
if (props.enable_zoom) {
options.value.dataZoom = [
{ {
type: 'slider', type: 'slider',
xAxisIndex: [0], xAxisIndex: [0],
filterMode: 'filter' filterMode: 'filter'
}, },
], ]
yAxis: {},
series: []
} }
if (props.item.valueFormatter) { if (props.item.valueFormatter) {
options.value.tooltip.valueFormatter = props.item.valueFormatter options.value.tooltip.valueFormatter = props.item.valueFormatter
@ -182,6 +192,9 @@ watch(mode, q => {
onMounted(() => { onMounted(() => {
enable_sync.value = props.sync enable_sync.value = props.sync
if (props.time_mode) {
change_mode(props.time_mode)
}
chart = markRaw(echart.init(chartdom.value, null, { renderer: 'svg' })) chart = markRaw(echart.init(chartdom.value, null, { renderer: 'svg' }))
init_chart() init_chart()
}) })
@ -193,7 +206,10 @@ onUnmounted(() => {
</script> </script>
<style> <style>
.v-chart {} .v-chart {
min-width: 20rem;
min-height: 15rem;
}
.v-echarts-tooltip { .v-echarts-tooltip {
/* height: 5rem; */ /* height: 5rem; */

@ -61,7 +61,6 @@ const sync_app = () => {
}) })
} }
watch(id, (e) => { watch(id, (e) => {
console.log(e)
if (e) { if (e) {
sync_app() sync_app()
} }

@ -16,7 +16,6 @@
<q-icon class="mx-2" size="2rem" @click="$q.dark.toggle" :name="$q.dark.mode ? 'v-light' : 'v-dark'"></q-icon> <q-icon class="mx-2" size="2rem" @click="$q.dark.toggle" :name="$q.dark.mode ? 'v-light' : 'v-dark'"></q-icon>
<OAer v-if="user.ready" @logout="user.logout" :is-dark="$q.dark.mode as boolean"> <OAer v-if="user.ready" @logout="user.logout" :is-dark="$q.dark.mode as boolean">
123
</OAer> </OAer>
</q-toolbar> </q-toolbar>
<q-toolbar class=""> <q-toolbar class="">

@ -6,185 +6,82 @@
--> -->
<template> <template>
<div> <div>
<div v-if="id"> <div class="page-h1">
<div class="text-2xl mb-4"> 服务
消息服务
<div class="float-right text-sm">{{ new Date(data.now).toLocaleString() }}</div>
</div> </div>
<div class=""> <q-card class="w-40 text-center py-4 start_card">
<div class="w-full">ID: {{ id }}</div> <div class="text-3xl"> 已运行 </div>
<div class="flex gap-8"> <div class="text-2xl mt-2">
<div>CPU占用: {{ data.cpu }}%</div> {{ start_time }}
<div>内存占用: {{ (data.mem / 1024 / 1024).toFixed(2) }}M</div>
<div>连接数: {{ data.connections }}</div>
</div> </div>
<div>发送: {{ (send_received[0] / 1024).toFixed(2) }} KB/s</div> </q-card>
<div>收到: {{ (send_received[1] / 1024).toFixed(2) }} KB/s</div> <div class="flex flex-nowrap" style="">
<div class="w-1/2">
<tschart :item="querys[0]" :time_mode="1"></tschart>
</div> </div>
<div class="grid grid-cols-4 gap-4 mt-10" v-if="conns.length"> <div class="w-1/2">
<div>ID</div> <tschart :item="querys[1]" :time_mode="1"></tschart>
<div>Name</div>
<div>运行时间</div>
<div>订阅主题</div>
<template v-for="c of conns" :key="c.cid">
<div>{{ c.cid }}</div>
<div>{{ c.name || '无' }}</div>
<div>{{ new Date(c.start).toLocaleString() }}</div>
<div>{{ c.subscriptions_list ?
c.subscriptions_list.sort().join(' ') : '' }}</div>
</template>
</div>
</div>
<div class="flex flex-nowrap">
<div class="grow" style="min-height: 50vh;">
<tschart :item="querys[idx]"></tschart>
</div>
<div class="flex flex-col gap-5">
<q-chip :color="idx === i ? 'primary' : ''" class="select-none" v-for="(q, i) in querys" :key="i" @click="idx = i"
clickable>{{
q.name }} </q-chip>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref, watch, onUnmounted } from 'vue'; import { ref, onUnmounted, onMounted } from 'vue';
import { nats } from '@veypi/oaer'
import api from 'src/boot/api'
const data = ref({} as any)
const conns = ref<any[]>([])
const id = computed(() => data.value.server_id)
const subs: any[] = []
const timer = ref()
let old_data = [0, 0]
const send_received = computed(() => {
if (!id.value) {
return [0, 0]
}
let os = data.value.out_bytes
let or = data.value.in_bytes
let res = [os - old_data[0], or - old_data[1]]
old_data = [os, or]
return res
})
watch(id, (_) => {
timer.value = setInterval(() => {
api.nats.general().then(e => {
data.value = e
})
api.nats.conns().then(e => {
conns.value = e.connections
})
// nats.request('$SYS.REQ.SERVER.PING').then((m) => {
// data.value = JSON.parse(m)
// })
}, 1000)
})
watch(computed(() => nats.ready.value), e => {
if (e) {
api.nats.general().then(e => {
old_data = [e.out_bytes, e.in_bytes]
data.value = e
})
}
}, { immediate: true })
onUnmounted(() => {
if (timer.value) {
clearInterval(timer.value)
}
for (let i of subs) {
i.unsubscribe()
}
})
import tschart from 'src/components/tschart'; import tschart from 'src/components/tschart';
import api from 'src/boot/api';
const idx = ref(0) const start_time = ref('')
const timer = ref()
const querys = ref<{ const querys = ref<{
name: string, query: string[] | string, label?: any, name: string, query: string[] | string, label?: any,
valueFormatter?: any valueFormatter?: any
}[]>([ }[]>([
{ {
name: 'cpu占用', name: 'cpu',
// query: `100 - avg (irate(node_cpu_seconds_total{mode="idle"}[3s])) query: `oa_stats_cpu`,
// by(id) * 100`, label: 'cpu',
query: `avg by
(id)(irate(node_cpu_seconds_total{mode=~"sytem|user|iowait|irq|softirq|nice|steal|guest"}[3s]))
* 100`,
label: (d: any) => d.id as string,
valueFormatter: (value: number) => value.toFixed(2) + "%", valueFormatter: (value: number) => value.toFixed(2) + "%",
}, },
{
name: 'linux内存使用率',
query: [
`((node_memory_Buffers_bytes + node_memory_Cached_bytes +
node_memory_MemFree_bytes) / node_memory_MemTotal_bytes) * 100`,
],
label: (d: any) => d.id as string,
valueFormatter: (value: number) => value.toFixed(2) + "%",
},
{
name: '磁盘',
query: `(1 - avg(node_filesystem_avail_bytes /
node_filesystem_size_bytes[3s]) by (device, id)) * 100 `,
label: (d: any) => `${d.id}: ${d.device}` as string,
valueFormatter: (value: number) => value.toFixed(2) + "%",
},
{
name: '磁盘IOPS',
query: [
`sum by (id) (rate(node_disk_reads_completed_total[3s]))`,
`sum by (id) (rate(node_disk_writes_completed_total[3s]))`,
],
label: [
(d: any) => `${d.id}`,
(d: any) => `${d.id}`,
],
},
{
name: '网络带宽',
query: [
`sum by(id)(irate(node_network_receive_bytes_total{device!~"bond.*?|lo"}[3s])) / 1048576`,
`sum by(id)(irate(node_network_transmit_bytes_total{device!~"bond.*?|lo"}[3s])) / 1048576`
],
label: [
(d: any) => `${d.id} 下行`,
(d: any) => `${d.id} 上行`,
],
valueFormatter: (value: number) => value.toFixed(2) + "MB/s",
},
{ {
name: '内存', name: '内存',
query: [ query: `oa_stats_mem / 1048576`,
`(node_memory_Buffers_bytes + node_memory_Cached_bytes + label: '内存',
node_memory_MemFree_bytes) / 1024 / 1024 / 1024`, valueFormatter: (value: number) => value.toFixed(2) + "MB",
`node_memory_MemTotal_bytes / 1024 /1024 / 1024`
],
label: [(d: any) => `${d.id}使用内`, (d: any) => `${d.id}总内存`],
valueFormatter: (value: number) => value.toFixed(2) + "GB",
}, },
// {
// name: 'Mac cpu',
// query: 'node_cpu_seconds_total',
// label: (d: any) => `cpu: ${d.cpu} mode: ${d.mode}` as string
// },
// {
// name: 'mem',
// query: 'node_memory_free_bytes / 1024 / 1024 / 1024'
// },
// {
// name: 'Mac swap',
// query: 'node_memory_swap_used_bytes / 1024 / 1024 '
// },
]) ])
onMounted(() => {
api.tsdb.query('oa_stats_start').then(e => {
if (e.data.result.length) {
let s = Number(e.data.result[0].value[1])
if (s < 60) {
start_time.value = s + ' 秒'
} else if (s < 3600) {
start_time.value = (s / 60).toFixed(1) + ' 分钟'
} else if (s < 3600 * 24) {
start_time.value = (s / 60 / 60).toFixed(1) + ' 小时'
} else {
start_time.value = (s / 60 / 60 / 24).toFixed(1) + ' 天'
}
}
})
})
onUnmounted(() => {
if (timer.value) {
clearInterval(timer.value)
}
})
</script> </script>
<style scoped></style> <style lang="scss" scoped>
.start_card {
:first-child {
color: $primary
}
:nth-child(2) {}
}
</style>

@ -530,18 +530,20 @@
resolved "https://registry.yarnpkg.com/@veypi/msg/-/msg-0.1.1.tgz#94864ae2c0a81991b8a30d87f12d2245fdebbead" resolved "https://registry.yarnpkg.com/@veypi/msg/-/msg-0.1.1.tgz#94864ae2c0a81991b8a30d87f12d2245fdebbead"
integrity sha512-UiAF/Y0EGT/37tGApptzHBNUpo78LbnrEkCqGAGMkJp86wrUyOgTAvuvQ197Ifqw9PIbjZM9dAgMv4DfMJQEYA== integrity sha512-UiAF/Y0EGT/37tGApptzHBNUpo78LbnrEkCqGAGMkJp86wrUyOgTAvuvQ197Ifqw9PIbjZM9dAgMv4DfMJQEYA==
"@veypi/oaer@^0.0.6": "@veypi/oaer@^0.0.9":
version "0.0.6" version "0.0.9"
resolved "https://registry.yarnpkg.com/@veypi/oaer/-/oaer-0.0.6.tgz#02a1f9c54ec4e43805123a9f16ddfeda152e6758" resolved "https://registry.yarnpkg.com/@veypi/oaer/-/oaer-0.0.9.tgz#b47d9bd635dfaa3df1d756e6c132f717969f60e2"
integrity sha512-B1czF/GGWPCVRdtXvqVjTE9m/Tli8fmhy9K6lPnbt89QzkdYVmQ6DMs1rugMlPw+Lflc3pqeQuCUmlKjKgMqPQ== integrity sha512-YmyykQW6Kw4XeQ47/ogObSx3JotfX08Kali3GoN4eOGl2Sa++q+kqkDq+2IFmdw0P9naZ+pzu7OChjo7TjZuHg==
dependencies: dependencies:
"@veypi/msg" "^0.1.0" "@veypi/msg" "^0.1.0"
"@veypi/one-icon" "2" "@veypi/one-icon" "2"
animate.css "^4.1.1" animate.css "^4.1.1"
autoprefixer "^10.4.16" autoprefixer "^10.4.16"
axios "^1.5.1"
js-base64 "^3.7.5" js-base64 "^3.7.5"
mitt "^3.0.1" mitt "^3.0.1"
postcss "^8.4.31" postcss "^8.4.31"
tailwindcss "^3.3.3"
webdav "^5.3.0" webdav "^5.3.0"
"@veypi/one-icon@2": "@veypi/one-icon@2":
@ -869,6 +871,15 @@ axios@^1.2.1:
form-data "^4.0.0" form-data "^4.0.0"
proxy-from-env "^1.1.0" proxy-from-env "^1.1.0"
axios@^1.5.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102"
integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
balanced-match@^1.0.0: balanced-match@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"

Loading…
Cancel
Save