1. 程式人生 > 實用技巧 >在SpringBoot中用AOP統計正在執行的定時任務(@Scheduled)

在SpringBoot中用AOP統計正在執行的定時任務(@Scheduled)

快速開始

啟動服務

from aiohttp import web

# 建立應用
app  = web.Application()
# 執行應用
web.run_app(app=app)

檢視

request

ge t

async def handle_greeting(self, request):
    name = request.match_info.get('name', "Anonymous")
    txt = "Hello, {}".format(name)
    return web.Response(text=txt)

post

async def do_login(request):
    data = await request.post()
    login = data['login']
    password = data['password']

response

字串

from aiohttp import web

async def hello(request):
    return web.Response(text="Hello, world")

json

async def handler(request):
    data = {'some': 'data'}
    return web.json_response(data)

重定向

# 絕對路徑/相對路徑
raise web.HTTPFound('/redirect')

# 使用name
async def handler(request):
    location = request.app.router['login'].url_for()
    raise web.HTTPFound(location=location)

router.add_get('/handler', handler)
router.add_get('/login', login_handler, name='login')

路由

註冊

直接呼叫

async def handle_get(request):
    ...

async def handle_post(request):
    ...


app.router.add_get("/get", handle_get)
app.router.add_post("/post", handle_post)

django樣式:表單

async def handle_get(request):
    ...

async def handle_post(request):
    ...

app.router.add_routes([
    web.get('/get', handle_get),
    web.post('/post', handle_post)])

flask樣式:裝飾器

routes = web.RouteTableDef()

@routes.get('/', [name='xxx'])
async def hello(request):
    pass

app.add_routes(routes)

反轉

# 查詢
app.add_routes([web.get('/root', handler, name='root')])
# 反轉
url == request.app.router['root'].url_for().with_query({"a": "b", "c": "d"})
assert url == URL('/root?a=b&c=d')

# 有引數
app.router.add_get('/{user}/info', poll, name='user-info')
# 反轉
url = request.app.router['user-info'].url_for(user='john_doe')
url_with_qs = url.with_query("a=b")
assert url_with_qs == '/john_doe/info?a=b'

檢視

for resource in app.router.resources():
    print(resource)
# 帶name
for name, resource in app.router.named_resources().items():
    print(name, resource)

基於類的檢視路由

檢視

class MyView(web.View):
    async def get(self):
        return await get_resp(self.request)

    async def post(self):
        return await post_resp(self.request)

路由

# 方法一
web.view('/path/to', MyView)
# 方法二
@routes.view('/path/to')
class MyView(web.View):
    ...

Session

aiohttp.web沒有內建的session內容,第三方包aiohttp_sessionsession支援

import asyncio
import time
import base64
from cryptography import fernet
from aiohttp import web
from aiohttp_session import setup, get_session, session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage

async def handler(request):
    session = await get_session(request)
    last_visit = session['last_visit'] if 'last_visit' in session else None
    text = 'Last visited: {}'.format(last_visit)
    return web.Response(text=text)

async def make_app():
    app = web.Application()
    # secret_key must be 32 url-safe base64-encoded bytes
    fernet_key = fernet.Fernet.generate_key()
    secret_key = base64.urlsafe_b64decode(fernet_key)
    setup(app, EncryptedCookieStorage(secret_key))
    app.add_routes([web.get('/', handler)])
    return app

web.run_app(make_app())

webSocket

檢視

async def websocket_handler(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)

    async for msg in ws:
        if msg.type == aiohttp.WSMsgType.TEXT:
            if msg.data == 'close':
                await ws.close()
            else:
                await ws.send_str(msg.data + '/answer')
        elif msg.type == aiohttp.WSMsgType.ERROR:
            print('ws connection closed with exception %s' %
                  ws.exception())

    print('websocket connection closed')

    return ws

路由

app.add_routes([web.get('/ws', websocket_handler)])

異常

from aiohttp import web

async def handler(request): 
    raise web.HTTPNotFound(text=str(e))  # 404

所有HTTP異常有同樣的建構函式

HTTPNotFound(*, headers=None, reason=None,
             body=None, text=None, content_type=None)

HTTPMultipleChoices, HTTPMovedPermanently, HTTPFound, HTTPSeeOther, HTTPUseProxy, HTTPTemporaryRedirect

HTTPFound(location, *, headers=None, reason=None,
          body=None, text=None, content_type=None)

HTTPMethodNotAllowed

HTTPMethodNotAllowed(method, allowed_methods, *,
                     headers=None, reason=None,
                     body=None, text=None, content_type=None)

異常類速覽

Exception
  HTTPException
    HTTPSuccessful
      * 200 - HTTPOk
      * 201 - HTTPCreated
      * 202 - HTTPAccepted
      * 203 - HTTPNonAuthoritativeInformation
      * 204 - HTTPNoContent
      * 205 - HTTPResetContent
      * 206 - HTTPPartialContent
    HTTPRedirection
      * 300 - HTTPMultipleChoices
      * 301 - HTTPMovedPermanently
      * 302 - HTTPFound
      * 303 - HTTPSeeOther
      * 304 - HTTPNotModified
      * 305 - HTTPUseProxy
      * 307 - HTTPTemporaryRedirect
      * 308 - HTTPPermanentRedirect
    HTTPError
      HTTPClientError
        * 400 - HTTPBadRequest
        * 401 - HTTPUnauthorized
        * 402 - HTTPPaymentRequired
        * 403 - HTTPForbidden
        * 404 - HTTPNotFound
        * 405 - HTTPMethodNotAllowed
        * 406 - HTTPNotAcceptable
        * 407 - HTTPProxyAuthenticationRequired
        * 408 - HTTPRequestTimeout
        * 409 - HTTPConflict
        * 410 - HTTPGone
        * 411 - HTTPLengthRequired
        * 412 - HTTPPreconditionFailed
        * 413 - HTTPRequestEntityTooLarge
        * 414 - HTTPRequestURITooLong
        * 415 - HTTPUnsupportedMediaType
        * 416 - HTTPRequestRangeNotSatisfiable
        * 417 - HTTPExpectationFailed
        * 421 - HTTPMisdirectedRequest
        * 422 - HTTPUnprocessableEntity
        * 424 - HTTPFailedDependency
        * 426 - HTTPUpgradeRequired
        * 428 - HTTPPreconditionRequired
        * 429 - HTTPTooManyRequests
        * 431 - HTTPRequestHeaderFieldsTooLarge
        * 451 - HTTPUnavailableForLegalReasons
      HTTPServerError
        * 500 - HTTPInternalServerError
        * 501 - HTTPNotImplemented
        * 502 - HTTPBadGateway
        * 503 - HTTPServiceUnavailable
        * 504 - HTTPGatewayTimeout
        * 505 - HTTPVersionNotSupported
        * 506 - HTTPVariantAlsoNegotiates
        * 507 - HTTPInsufficientStorage
        * 510 - HTTPNotExtended
        * 511 - HTTPNetworkAuthenticationRequired

日誌

aiohttp使用標準日誌記錄來跟蹤庫活動

'aiohttp.access'
'aiohttp.client'
'aiohttp.internal'
'aiohttp.server'
'aiohttp.web'
'aiohttp.websocket'

使用日誌時的配置

import logging
from aiohttp import web

app = web.Application()
logging.basicConfig(level=logging.DEBUG)
web.run_app(app, port=5000)
  • 訪問日誌

訪問日誌預設情況下處於啟用狀態。如果設定了debug標誌,並且使用了預設的記錄器aiohttp.access,則如果未附加任何處理程式,則訪問日誌將輸出到stderr。此外,如果預設記錄器未設定日誌級別,則日誌級別將設定為logging.DEBUG

此日誌記錄可以由aiohttp.web.AppRunner()aiohttp.web.run_app()控制。

要覆蓋預設記錄器,請傳遞一個logging.Logger例項以覆蓋預設記錄器。

禁用訪問日誌

web.run_app(app, access_log=None)
  • 錯誤日誌

aiohttp.web使用名為aiohttp.server的記錄器來儲存在Web請求處理中給出的錯誤。

預設情況下啟用此日誌。

要使用其他記錄器名稱,請將logger=logging.Logger()傳遞給aiohttp.web.AppRunner()建構函式。

  • 日誌格式

預設格式

'%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"'

預設訪問記錄器的直接替換示例

from aiohttp.abc import AbstractAccessLogger

class AccessLogger(AbstractAccessLogger):

    def log(self, request, response, time):
        self.logger.info(f'{request.remote} '
                         f'"{request.method} {request.path} '
                         f'done in {time}s: {response.status}')

格式速覽

Option Meaning
%% The percent sign
%a Remote IP-address (IP-address of proxy if using reverse proxy)
%t Time when the request was started to process
%P The process ID of the child that serviced the request
%r First line of request
%s Response status code
%b Size of response in bytes, including HTTP headers
%T The time taken to serve the request, in seconds
%Tf The time taken to serve the request, in seconds with fraction in %.06f format
%D The time taken to serve the request, in microseconds
%{FOO}i request.headers['FOO']
%{FOO}o response.headers['FOO']