mirror of https://github.com/jumpserver/jumpserver
Eric
7 months ago
committed by
Bryan
15 changed files with 179 additions and 6 deletions
@ -1,5 +1,6 @@
|
||||
from .connect_methods import * |
||||
from .endpoint import * |
||||
from .loki_log import * |
||||
from .status import * |
||||
from .storage import * |
||||
from .terminal import * |
||||
|
@ -0,0 +1,35 @@
|
||||
from rest_framework.response import Response |
||||
from rest_framework.views import APIView |
||||
|
||||
from common.permissions import OnlySuperUser |
||||
from common.utils import get_logger |
||||
from terminal import serializers |
||||
from terminal.mixin import LokiMixin |
||||
|
||||
__all__ = ['LokiLogAPI', ] |
||||
|
||||
logger = get_logger(__name__) |
||||
|
||||
|
||||
class LokiLogAPI(APIView, LokiMixin): |
||||
http_method_names = ['get', ] |
||||
permission_classes = [OnlySuperUser] |
||||
|
||||
def get(self, request, *args, **kwargs): |
||||
serializer = serializers.LokiLogSerializer(data=request.query_params) |
||||
serializer.is_valid(raise_exception=True) |
||||
components = serializer.validated_data.get('components') |
||||
search = serializer.validated_data.get('search', '') |
||||
start = serializer.validated_data.get('start', ) |
||||
end = serializer.validated_data.get('end', ) |
||||
loki_logs = self.query_components_log(components, search, start, end) |
||||
return Response(data=loki_logs) |
||||
|
||||
def query_components_log(self, components, search, start, end): |
||||
# 秒转纳秒 |
||||
start_ns = int(start * 1e9) |
||||
end_ns = int(end * 1e9) |
||||
query = self.create_loki_query(components, search) |
||||
loki_client = self.get_loki_client() |
||||
loki_response = loki_client.query_range(query, start_ns, end_ns, limit=100) |
||||
return loki_response['data']['result'] |
@ -0,0 +1,15 @@
|
||||
from terminal.utils.loki_client import get_loki_client |
||||
|
||||
__all__ = ['LokiMixin', ] |
||||
|
||||
class LokiMixin: |
||||
|
||||
def get_loki_client(self): |
||||
return get_loki_client() |
||||
|
||||
def create_loki_query(self, components, search): |
||||
stream_selector = '{component!=""}' |
||||
if components: |
||||
stream_selector = '{component=~"%s"}' % components |
||||
query = f'{stream_selector} |="{search}"' |
||||
return query |
@ -0,0 +1,14 @@
|
||||
import time |
||||
|
||||
from rest_framework import serializers |
||||
|
||||
__all__ = [ |
||||
'LokiLogSerializer', |
||||
] |
||||
|
||||
|
||||
class LokiLogSerializer(serializers.Serializer): |
||||
components = serializers.CharField(required=False, ) |
||||
start = serializers.IntegerField() |
||||
end = serializers.IntegerField(default=time.time) |
||||
search = serializers.CharField(required=False, default='') |
@ -0,0 +1,57 @@
|
||||
import urllib.parse |
||||
|
||||
import requests |
||||
from django.conf import settings |
||||
from websockets.sync.client import connect as ws_connect |
||||
|
||||
|
||||
def get_loki_client(): |
||||
# TODO: 补充 auth 认证相关 |
||||
return LokiClient(base_url=settings.LOKI_BASE_URL) |
||||
|
||||
|
||||
# https://grafana.com/docs/loki/latest/reference/loki-http-api/ |
||||
|
||||
class LokiClient(object): |
||||
query_range_url = '/loki/api/v1/query_range' |
||||
tail_url = '/loki/api/v1/tail' |
||||
|
||||
def __init__(self, base_url: str): |
||||
self.base_url = base_url.rstrip('/') |
||||
|
||||
def query_range(self, query, start, end, limit=100): |
||||
params = { |
||||
'query': query, |
||||
'start': start, |
||||
'end': end, |
||||
'limit': limit, |
||||
} |
||||
url = f"{self.base_url}{self.query_range_url}" |
||||
response = requests.get(url, params=params) |
||||
if response.status_code != 200: |
||||
raise Exception(response.text) |
||||
return response.json() |
||||
|
||||
def create_tail_ws(self, query, limit=100): |
||||
data = {'query': query, 'limit': limit} |
||||
params = urllib.parse.urlencode(data) |
||||
ws_url = f"ws://{self.base_url[7:]}" |
||||
if self.base_url.startswith('https://'): |
||||
ws_url = f"wss://{self.base_url[8:]}" |
||||
url = f"{ws_url}{self.tail_url}?{params}" |
||||
ws = ws_connect(url) |
||||
return LokiTailWs(ws) |
||||
|
||||
|
||||
class LokiTailWs(object): |
||||
|
||||
def __init__(self, ws): |
||||
self._ws = ws |
||||
|
||||
def messages(self): |
||||
for message in self._ws: |
||||
yield message |
||||
|
||||
def close(self): |
||||
if self._ws: |
||||
self._ws.close() |
Loading…
Reference in new issue