Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api/logging): enhance the logging while api 500 #357

Merged
merged 9 commits into from
Apr 13, 2022
3 changes: 3 additions & 0 deletions src/api/bkuser_core/audit/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ def create_general_log(
}
if request:
extra_value["client_ip"] = get_client_ip(request)
# from esb/apigateway, will got a valid bk_app_code
if hasattr(request, "bk_app_code"):
extra_value["bk_app_code"] = request.bk_app_code

extra_value.update(audit_info.to_dict())
extra_value.update(extra_info or {})
Expand Down
44 changes: 38 additions & 6 deletions src/api/bkuser_core/common/exception_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
specific language governing permissions and limitations under the License.
"""
import logging
import traceback

from bkuser_core.bkiam.exceptions import IAMPermissionDenied
from django.core.exceptions import PermissionDenied
from django.db import ProgrammingError
from django.http import Http404
from rest_framework.exceptions import AuthenticationFailed, ValidationError
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from rest_framework.views import exception_handler
from sentry_sdk import capture_exception

Expand All @@ -43,13 +44,30 @@ def custom_exception_handler(exc, context):
# # Only presents in ValidationError
# "fields_detail": {"field1": ["error message"]}
# }
# extra details
detail = {
"error": "unknown",
}
if context:
try:
req = context.get("request")
detail["path"] = req.path
detail["method"] = req.method
detail["query_params"] = req.query_params
detail["request_id"] = req.headers.get("X-Request-Id")
if hasattr(req, "bk_app_code"):
detail["bk_app_code"] = req.bk_app_code
except Exception: # pylint: disable=broad-except
# do nothing if get extra details fail
pass

if exist_force_raw_header(context["request"]):
return get_raw_exception_response(exc, context)
return get_raw_exception_response(exc, context, detail)
else:
return get_ee_exception_response(exc, context)
return get_ee_exception_response(exc, context, detail)


def get_ee_exception_response(exc, context):
def get_ee_exception_response(exc, context, detail):
"""针对企业版异常返回封装"""
data = {"result": False, "data": None, "code": -1}

Expand All @@ -70,7 +88,7 @@ def get_ee_exception_response(exc, context):
data["message"] = "403, authentication failed"
else:
# log
logger.exception("unknown exception while handling the request")
logger.exception("unknown exception while handling the request, detail=%s", detail)
# report to sentry
capture_exception(exc)
# build response
Expand Down Expand Up @@ -104,7 +122,7 @@ def one_line_error(detail):
return "参数格式错误"


def get_raw_exception_response(exc, context):
def get_raw_exception_response(exc, context, detail):
if isinstance(exc, ValidationError):
data = {
"code": "VALIDATION_ERROR",
Expand All @@ -126,11 +144,25 @@ def get_raw_exception_response(exc, context):
data = {"code": "PROGRAMMING_ERROR", "detail": UNKNOWN_ERROR_HINT}
return Response(data, status=HTTP_400_BAD_REQUEST, headers={})

# log
logger.exception("unknown exception while handling the request, detail=%s", detail)
# report to sentry
capture_exception(exc)

# Call REST framework's default exception handler to get the standard error response.
response = exception_handler(exc, context)
# Use a default error code
if response is not None:
response.data.update(code="ERROR")
setattr(response, "from_exception", True)
return response

# NOTE: 不暴露给前端, 只打日志, 所以不放入data.detail
# error detail
if exc is not None:
detail["error"] = traceback.format_exc()

data = {"result": False, "data": detail, "code": -1, "message": UNKNOWN_ERROR_HINT}
response = Response(data=data, status=HTTP_500_INTERNAL_SERVER_ERROR)
setattr(response, "from_exception", True)
return response
8 changes: 7 additions & 1 deletion src/bkuser_global/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,16 @@ def get_loggers(package_name: str, log_level: str) -> dict:
"level": log_level,
"propagate": True,
},
"": {
# NOTE: if use "" instead of "root", should change all propagate to False! and test it
# currently, use the same settings as blueapps, even it's wrong root config
"root": {
"handlers": ["root"],
"level": log_level,
},
# "": {
wklken marked this conversation as resolved.
Show resolved Hide resolved
# "handlers": ["root"],
# "level": log_level,
# },
"requests": {
"handlers": ["root"],
"level": log_level,
Expand Down
2 changes: 2 additions & 0 deletions src/saas/bkuser_shell/apis/viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import json
import logging
import math
import uuid
from collections import OrderedDict
from typing import Callable, Optional

Expand Down Expand Up @@ -176,4 +177,5 @@ def make_default_headers(operator: str) -> dict:
settings.API_APP_CODE_HEADER_NAME: settings.APP_ID,
settings.API_APP_SECRET_HEADER_NAME: settings.APP_TOKEN,
"Accept-Language": get_language(),
"X-Request-ID": uuid.uuid4().hex,
wklken marked this conversation as resolved.
Show resolved Hide resolved
}