2020-08-30 14:09:34 +08:00
|
|
|
import logging
|
|
|
|
|
|
|
|
import mimetypes
|
|
|
|
|
|
|
|
import aiohttp.web
|
|
|
|
import ray.new_dashboard.utils as dashboard_utils
|
|
|
|
from ray.new_dashboard.datacenter import DataSource, GlobalSignals
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
routes = dashboard_utils.ClassMethodRouteTable
|
|
|
|
|
|
|
|
|
|
|
|
class LogHead(dashboard_utils.DashboardHeadModule):
|
|
|
|
LOG_URL_TEMPLATE = "http://{ip}:{port}/logs"
|
|
|
|
|
|
|
|
def __init__(self, dashboard_head):
|
|
|
|
super().__init__(dashboard_head)
|
|
|
|
mimetypes.add_type("text/plain", ".err")
|
|
|
|
mimetypes.add_type("text/plain", ".out")
|
|
|
|
routes.static("/logs", self._dashboard_head.log_dir, show_index=True)
|
|
|
|
GlobalSignals.node_info_fetched.append(
|
|
|
|
self.insert_log_url_to_node_info)
|
|
|
|
|
|
|
|
async def insert_log_url_to_node_info(self, node_info):
|
2020-09-17 01:17:29 +08:00
|
|
|
node_id = node_info.get("raylet", {}).get("nodeId")
|
|
|
|
if node_id is None:
|
2020-08-30 14:09:34 +08:00
|
|
|
return
|
2020-09-17 01:17:29 +08:00
|
|
|
agent_port = DataSource.agents.get(node_id)
|
2020-08-30 14:09:34 +08:00
|
|
|
if agent_port is None:
|
|
|
|
return
|
|
|
|
agent_http_port, _ = agent_port
|
2020-09-17 01:17:29 +08:00
|
|
|
log_url = self.LOG_URL_TEMPLATE.format(
|
|
|
|
ip=node_info.get("ip"), port=agent_http_port)
|
2020-08-30 14:09:34 +08:00
|
|
|
node_info["logUrl"] = log_url
|
|
|
|
|
|
|
|
@routes.get("/log_index")
|
|
|
|
async def get_log_index(self, req) -> aiohttp.web.Response:
|
|
|
|
url_list = []
|
2020-09-17 01:17:29 +08:00
|
|
|
agent_ips = []
|
|
|
|
for node_id, ports in DataSource.agents.items():
|
|
|
|
ip = DataSource.node_id_to_ip[node_id]
|
|
|
|
agent_ips.append(ip)
|
2020-08-30 14:09:34 +08:00
|
|
|
url_list.append(
|
|
|
|
self.LOG_URL_TEMPLATE.format(ip=ip, port=str(ports[0])))
|
2020-09-17 01:17:29 +08:00
|
|
|
if self._dashboard_head.ip not in agent_ips:
|
2020-08-30 14:09:34 +08:00
|
|
|
url_list.append(
|
|
|
|
self.LOG_URL_TEMPLATE.format(
|
|
|
|
ip=self._dashboard_head.ip,
|
|
|
|
port=self._dashboard_head.http_port))
|
|
|
|
return aiohttp.web.Response(
|
|
|
|
text=self._directory_as_html(url_list), content_type="text/html")
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _directory_as_html(url_list) -> str:
|
|
|
|
# returns directory's index as html
|
|
|
|
|
|
|
|
index_of = "Index of logs"
|
|
|
|
h1 = f"<h1>{index_of}</h1>"
|
|
|
|
|
|
|
|
index_list = []
|
|
|
|
for url in sorted(url_list):
|
|
|
|
index_list.append(f'<li><a href="{url}">{url}</a></li>')
|
|
|
|
index_list = "\n".join(index_list)
|
|
|
|
ul = f"<ul>\n{index_list}\n</ul>"
|
|
|
|
body = f"<body>\n{h1}\n{ul}\n</body>"
|
|
|
|
|
|
|
|
head_str = f"<head>\n<title>{index_of}</title>\n</head>"
|
|
|
|
html = f"<html>\n{head_str}\n{body}\n</html>"
|
|
|
|
|
|
|
|
return html
|
|
|
|
|
|
|
|
async def run(self, server):
|
|
|
|
pass
|