-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
unknown
committed
Nov 5, 2024
1 parent
4641520
commit ca046d9
Showing
11 changed files
with
1,100 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,15 @@ | ||
# asitop-exporter | ||
# asitop-exporter | ||
参考 nvitop-exporter,基于 asitop 开发的 Mac 系统上metrics监控工具 | ||
## 一、编译 | ||
pip install prometheus_client Cython pyinstaller requests | ||
### whl | ||
python setup.py bdist_wheel | ||
### 可执行文件 | ||
cd asitop_exporter | ||
pyinstaller __main__.spec | ||
## 二、使用 | ||
sudo asitop-exporter -B 10.20.30.40 -p 9999 --interval 60.0 --post_url http://xxx.xxx.xxx.xxx/ | ||
1、程序需要以 sudo 权限运行 | ||
2、程序运行 10.20.30.40 的 9999 端口, 可以通过http请求 http://10.20.30.40:9999/metrics 获取 prometheus 格式的信息 | ||
3、--interval 60.0 监控间隔,表示每60s获取一次信息,默认是5s | ||
4、--post_url http://xxx.xxx.xxx.xxx/ 监控信息回调接口,以json格式返回。不设置则不会post. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# This file is part of asitop, the interactive NVIDIA-GPU process viewer. | ||
# | ||
# Copyright 2021-2024 fangxuwei. All Rights Reserved. | ||
# | ||
# Licensed 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. | ||
# ============================================================================== | ||
"""Prometheus exporter built on top of ``asitop``.""" | ||
|
||
from asitop_exporter.exporter import PrometheusExporter | ||
from asitop_exporter.utils import get_ip_address | ||
from asitop_exporter.version import __version__ | ||
|
||
|
||
__all__ = ['PrometheusExporter', 'get_ip_address'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# This file is part of asitop, the interactive NVIDIA-GPU process viewer. | ||
# | ||
# Copyright 2021-2024 fangxuwei. All Rights Reserved. | ||
# | ||
# Licensed 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. | ||
# ============================================================================== | ||
"""Prometheus exporter built on top of ``asitop``.""" | ||
|
||
import sys | ||
|
||
from asitop_exporter.cli import main | ||
|
||
|
||
if __name__ == '__main__': | ||
sys.exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# -*- mode: python ; coding: utf-8 -*- | ||
|
||
|
||
a = Analysis( | ||
['__main__.py'], | ||
pathex=[], | ||
binaries=[], | ||
datas=[], | ||
hiddenimports=[], | ||
hookspath=[], | ||
hooksconfig={}, | ||
runtime_hooks=[], | ||
excludes=[], | ||
noarchive=False, | ||
optimize=0, | ||
) | ||
pyz = PYZ(a.pure) | ||
|
||
exe = EXE( | ||
pyz, | ||
a.scripts, | ||
a.binaries, | ||
a.datas, | ||
[], | ||
name='asitop-exporter', | ||
debug=False, | ||
bootloader_ignore_signals=False, | ||
strip=False, | ||
upx=True, | ||
upx_exclude=[], | ||
runtime_tmpdir=None, | ||
console=True, | ||
disable_windowed_traceback=False, | ||
argv_emulation=False, | ||
target_arch=None, | ||
codesign_identity=None, | ||
entitlements_file=None, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
# This file is part of asitop, the interactive NVIDIA-GPU process viewer. | ||
# | ||
# Copyright 2021-2024 fangxuwei. All Rights Reserved. | ||
# | ||
# Licensed 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. | ||
# ============================================================================== | ||
"""Prometheus exporter built on top of ``asitop``.""" | ||
|
||
from __future__ import annotations | ||
import time | ||
import argparse | ||
import sys | ||
from typing import TextIO | ||
|
||
from prometheus_client import start_wsgi_server | ||
from termcolor import colored | ||
|
||
from asitop_exporter.exporter import PrometheusExporter | ||
from asitop_exporter.utils import get_ip_address, run_powermetrics_process | ||
from asitop_exporter.version import __version__ | ||
|
||
|
||
def cprint(text: str = '', *, file: TextIO | None = None) -> None: | ||
"""Print colored text to a file.""" | ||
for prefix, color in ( | ||
('INFO: ', 'yellow'), | ||
('WARNING: ', 'yellow'), | ||
('ERROR: ', 'red'), | ||
('NVML ERROR: ', 'red'), | ||
): | ||
if text.startswith(prefix): | ||
# text = text.replace( | ||
# prefix.rstrip(), | ||
# colored(prefix.rstrip(), color=color, attrs=('bold',)), | ||
# 1, | ||
# ) | ||
text = prefix.rstrip() | ||
print(text, file=file) | ||
|
||
|
||
def parse_arguments() -> argparse.Namespace: | ||
"""Parse command-line arguments for ``asitop-exporter``.""" | ||
|
||
def posfloat(argstring: str) -> float: | ||
num = float(argstring) | ||
if num <= 0: | ||
raise ValueError | ||
return num | ||
|
||
posfloat.__name__ = 'positive float' | ||
|
||
parser = argparse.ArgumentParser( | ||
prog='asitop-exporter', | ||
description='Prometheus exporter built on top of `asitop`.', | ||
formatter_class=argparse.RawTextHelpFormatter, | ||
add_help=False, | ||
) | ||
parser.add_argument( | ||
'--help', | ||
'-h', | ||
dest='help', | ||
action='help', | ||
default=argparse.SUPPRESS, | ||
help='Show this help message and exit.', | ||
) | ||
parser.add_argument( | ||
'--version', | ||
'-V', | ||
dest='version', | ||
action='version', | ||
version=f'%(prog)s {__version__} (asitop {__version__})', | ||
help="Show %(prog)s's version number and exit.", | ||
) | ||
|
||
parser.add_argument( | ||
'--hostname', | ||
'--host', | ||
'-H', | ||
dest='hostname', | ||
type=str, | ||
default=get_ip_address(), | ||
metavar='HOSTNAME', | ||
help='Hostname to display in the exporter. (default: %(default)s)', | ||
) | ||
parser.add_argument( | ||
'--bind-address', | ||
'--bind', | ||
'-B', | ||
dest='bind_address', | ||
type=str, | ||
default='127.0.0.1', | ||
metavar='ADDRESS', | ||
help='Local address to bind to. (default: %(default)s)', | ||
) | ||
parser.add_argument( | ||
'--port', | ||
'-p', | ||
type=int, | ||
default=8000, | ||
help='Port to listen on. (default: %(default)d)', | ||
) | ||
parser.add_argument( | ||
'--interval', | ||
dest='interval', | ||
type=posfloat, | ||
default=5.0, | ||
metavar='SEC', | ||
help='Interval between updates in seconds. (default: %(default)s)', | ||
) | ||
|
||
parser.add_argument( | ||
'--post_url', | ||
dest='post_url', | ||
type=str, | ||
default=None, | ||
metavar='ADDRESS', | ||
help='post result to url', | ||
) | ||
|
||
parser.add_argument( | ||
'--alive_time', | ||
dest='alive_time', | ||
type=int, | ||
default=60, | ||
metavar='minute', | ||
help='powermetrics file alive time. asitop-exporter will delete the pre file and create a new one after alive_time', | ||
) | ||
|
||
args = parser.parse_args() | ||
if args.interval < 0.25: | ||
parser.error( | ||
f'the interval {args.interval:0.2g}s is too short, which may cause performance issues. ' | ||
f'Expected 1/4 or higher.', | ||
) | ||
|
||
return args | ||
|
||
|
||
def main() -> int: # pylint: disable=too-many-locals,too-many-statements | ||
"""Main function for ``asitop-exporter`` CLI.""" | ||
args = parse_arguments() | ||
|
||
|
||
timecode = str(int(time.time())) | ||
|
||
# powermetrics_process = run_powermetrics_process(timecode, | ||
# interval=args.interval * 1000) | ||
|
||
exporter = PrometheusExporter(hostname=args.hostname, interval=args.interval, timecode=timecode, post_url=args.post_url, alive_time=args.alive_time) | ||
exporter.start_powermetrics_process() | ||
|
||
try: | ||
start_wsgi_server(port=args.port, addr=args.bind_address) | ||
except OSError as ex: | ||
if 'address already in use' in str(ex).lower(): | ||
cprint( | ||
( | ||
'ERROR: Address {} is already in use. ' | ||
'Please specify a different port via `--port <PORT>`.' | ||
).format( | ||
colored( | ||
f'http://{args.bind_address}:{args.port}', | ||
color='blue', | ||
attrs=('bold', 'underline'), | ||
), | ||
), | ||
file=sys.stderr, | ||
) | ||
elif 'cannot assign requested address' in str(ex).lower(): | ||
cprint( | ||
( | ||
'ERROR: Cannot assign requested address at {}. ' | ||
'Please specify a different address via `--bind-address <ADDRESS>`.' | ||
).format( | ||
colored( | ||
f'http://{args.bind_address}:{args.port}', | ||
color='blue', | ||
attrs=('bold', 'underline'), | ||
), | ||
), | ||
file=sys.stderr, | ||
) | ||
else: | ||
cprint(f'ERROR: {ex}', file=sys.stderr) | ||
return 1 | ||
|
||
cprint( | ||
'INFO : Start the exporter on {} at {}.'.format( | ||
colored(args.hostname, color='magenta', attrs=('bold',)), | ||
colored( | ||
f'http://{args.bind_address}:{args.port}/metrics', | ||
color='green', | ||
attrs=('bold', 'underline'), | ||
), | ||
), | ||
file=sys.stderr, | ||
) | ||
|
||
try: | ||
exporter.collect() | ||
except KeyboardInterrupt: | ||
cprint(file=sys.stderr) | ||
cprint('INFO: Interrupted by user.', file=sys.stderr) | ||
exporter.terminate_powermetrics_process() | ||
|
||
return 0 | ||
|
||
|
||
if __name__ == '__main__': | ||
sys.exit(main()) |
Oops, something went wrong.