華為云計(jì)算 云知識(shí) 教你如何將華為云CDN日志轉(zhuǎn)存到OBS
教你如何將華為云CDN日志轉(zhuǎn)存到OBS

 【最新活動(dòng)】

CDN記錄了所有域名(包括已刪除域名,如果您開通了企業(yè)項(xiàng)目,則已刪除域名不支持此功能)被網(wǎng)絡(luò)用戶訪問(wèn)的詳細(xì)日志,您可以通過(guò)CDN控制臺(tái)查看和下載最近30天的日志,對(duì)您的業(yè)務(wù)資源被訪問(wèn)情況進(jìn)行詳細(xì)分析。

日志轉(zhuǎn)存儲(chǔ)服務(wù)是華為云CDN配合 函數(shù)工作流 ,將CDN日志存儲(chǔ)到OBS桶,可以幫助您將日志存儲(chǔ)更長(zhǎng)的時(shí)間,便于您基于長(zhǎng)時(shí)間的日志做出自定義的數(shù)據(jù)分析,有助于您更好地了解您CDN的服務(wù)質(zhì)量,以及您的終端客戶的訪問(wèn)詳情,提高您的業(yè)務(wù)決策能力。

本文以Python3.6為例,為您介紹通過(guò)API創(chuàng)建FunctionGraph函數(shù)和Timer觸發(fā)器,實(shí)現(xiàn)定時(shí)將CDN日志轉(zhuǎn)存到OBS。

 

CDN日志轉(zhuǎn)存到OBS需具備的前提條件

暫時(shí)僅支持日志轉(zhuǎn)存到北京四的OBS桶,請(qǐng)您提前準(zhǔn)備好位于北京四的OBS桶。

詳細(xì)操作步驟如下:

創(chuàng)建委托

登錄華為云控制臺(tái),在左側(cè)導(dǎo)航欄,選擇管理與監(jiān)管> 統(tǒng)一身份認(rèn)證 服務(wù)

在左側(cè)導(dǎo)航欄,選擇“委托”頁(yè)簽,單擊右上方的“+ 創(chuàng)建委托”。

在創(chuàng)建委托頁(yè)面,按照如下參數(shù)設(shè)置委托。

委托名稱:FG_TO_CDN。

委托類型:云服務(wù)。

云服務(wù):函數(shù)工作流FunctionGraph。

持續(xù)時(shí)間:永久。

單擊“下一步”,進(jìn)入為“FG_TO_CDN”委托配置權(quán)限界面。

權(quán)限選擇:OBS OperateAccess 、CDN LogsReadOnlyAccess。

單擊“下一步”,配置作用范圍。

作用范圍:全局服務(wù)。

單擊“確認(rèn)”,完成委托配置。

 

準(zhǔn)備函數(shù)工作流環(huán)境

登錄華為云控制臺(tái),在左側(cè)導(dǎo)航欄,選擇計(jì)算>函數(shù)工作流,region選擇“北京四”。

單擊右上方“創(chuàng)建函數(shù)”,進(jìn)入創(chuàng)建函數(shù)界面

選擇模板:創(chuàng)建空白函數(shù)。

輸入函數(shù)名稱:cdn_to_obs(可自定義)。

所屬應(yīng)用:選擇默認(rèn)的“default”。

委托名稱:選擇已創(chuàng)建好的委托“FG_TO_CDN” 。

企業(yè)項(xiàng)目:選擇“default”。

運(yùn)行時(shí)語(yǔ)言:選擇“Python 3.6”。

代碼上傳方式:選擇“默認(rèn)代碼”。

單擊“創(chuàng)建函數(shù)”,進(jìn)入代碼編輯界面,將代碼示例的代碼內(nèi)容貼入在線IDE。

說(shuō)明:如果有多個(gè)域名的日志需要轉(zhuǎn)存,您需要分別為每個(gè)域名創(chuàng)建一個(gè)函數(shù)工作流。

單擊“配置”,進(jìn)入函數(shù)配置界面。

執(zhí)行超時(shí)時(shí)間:函數(shù)運(yùn)行的超時(shí)時(shí)間,超時(shí)的函數(shù)將被強(qiáng)行停止,建議設(shè)置為900。

說(shuō)明:如果您發(fā)現(xiàn)轉(zhuǎn)存的日志數(shù)量不對(duì),請(qǐng)向“函數(shù)工作流”服務(wù)提工單,增大執(zhí)行超時(shí)時(shí)間。

url :https://cdn.myhuaweicloud.com/v1.0/cdn/logs(CDN日志下載的url)。

domain_name :com(需要轉(zhuǎn)存日志的 CDN加速 域名)。

obsAddress :com(用于存日志的OBS桶域名)。

destBucket :******(用于存日志的OBS桶名稱)。

單擊右上方“保存”,完成設(shè)置。

創(chuàng)建“觸發(fā)器。在函數(shù)配置界面選擇“觸發(fā)器”,單擊右側(cè)“創(chuàng)建觸發(fā)器”。

觸發(fā)器類型:定時(shí)觸發(fā)器 (TIMER)。

定時(shí)器名稱:自定義的定時(shí)器名稱,例如:Timer-0001。

觸發(fā)規(guī)則:Cron表達(dá)式。

Cron表達(dá)式:0 0 8 * * ?(每天早上8點(diǎn)執(zhí)行一次日志轉(zhuǎn)存儲(chǔ))。

是否開啟:開啟。

單擊“確定”,完成定時(shí)觸發(fā)器設(shè)置。

創(chuàng)建測(cè)試事件。在函數(shù)配置界面,單擊右上角“請(qǐng)選擇測(cè)試事件”下拉框,選擇“配置測(cè)試事件”。

配置測(cè)試事件:創(chuàng)建新的測(cè)試事件。

事件模板:空白模板。

事件名稱:test。

測(cè)試事件:{"message":"CDNLog-OBS"}。

單擊“保存”,完成測(cè)試事件創(chuàng)建。

測(cè)試函數(shù)。在函數(shù)詳情頁(yè)面,單擊右上角“請(qǐng)選擇測(cè)試事件”下拉框,選擇“test”,單擊“測(cè)試”。

 

查看配置是否成功

登錄華為云控制臺(tái),在左側(cè)導(dǎo)航欄,選擇存儲(chǔ)> 對(duì)象存儲(chǔ)服務(wù) OBS。

單擊您存儲(chǔ)日志的桶,在左側(cè)導(dǎo)航欄選擇“對(duì)象”。

訪問(wèn)路徑:文件夾(桶名稱)>文件夾(加速域名)>文件夾(日志日期)>日志內(nèi)容。

說(shuō)明:當(dāng)前代碼示例僅支持轉(zhuǎn)存當(dāng)前時(shí)間前一日的日志,如果您需要轉(zhuǎn)存日志的加速域名前一日沒有日志產(chǎn)生,則OBS桶側(cè)不會(huì)產(chǎn)生相關(guān)文件。

OBS桶將對(duì)轉(zhuǎn)存到桶里的日志收費(fèi),具體收費(fèi)規(guī)則請(qǐng)參考計(jì)費(fèi)說(shuō)明。

 

停止日志轉(zhuǎn)存服務(wù)

. 登錄華為云控制臺(tái),在左側(cè)導(dǎo)航欄,選擇“計(jì)算>函數(shù)工作流”,region選擇“北京四”。

在左側(cè)導(dǎo)航欄選擇“函數(shù)”>“函數(shù)列表”,選中2中創(chuàng)建的函數(shù)名。

在函數(shù)詳情頁(yè)選擇“觸發(fā)器”。

單擊“停用”,完成配置。

 

代碼示例

代碼如下所示:

# -*- coding:utf-8 -*-

import requests

import datetime

import time

import os

import sys

import json

 

from com.obs.client.obs_client import ObsClient

 

from urllib.parse import urlparse

 

if sys.version_info.major == 2 or not sys.version > '3':

    import httplib

else:

    import http.client as httplib

 

current_file_path = os.path.dirname(os.path.realpath(__file__))

# Adds the current path to search paths to import third-party libraries.

sys.path.append(current_file_path)

 

TEMP_ROOT_PATH = "/tmp/"  # Downloads a file from OBS to this directory.

region = 'china'  # This parameter does not need to be changed and will be used when FunctionGraph accesses OBS.

secure = True  # This parameter does not need to be changed and will be used when FunctionGraph accesses OBS.

signature = 'v4'  # This parameter does not need to be changed and will be used when FunctionGraph accesses OBS.

port = 443  # This parameter does not need to be changed and will be used when FunctionGraph accesses OBS.

path_style = True  # This parameter does not need to be changed and will be used when FunctionGraph accesses OBS.

 

 

def handler(event, context):

    logger = context.getLogger()

    queryDate = context.getUserData('queryDate')

    if queryDate is None:

        yesterday = datetime.date.today() + datetime.timedelta(-1)

        queryDate = yesterday.strftime("%Y-%m-%d")

        timeStamp = int(time.mktime(yesterday.timetuple()) * 1000)

    else:

        date = datetime.datetime.strptime(queryDate, "%Y-%m-%d")

        timeStamp = int(time.mktime(date.timetuple()) * 1000)

 

    pageSize = 20

    pageNumber = 1

 

    requests.packages.urllib3.disable_warnings()

    start(context, queryDate, timeStamp, pageSize, pageNumber)

 

 

def start(context, queryDate, timeStamp, pageSize, pageNumber):

    logger = context.getLogger()

    logUrl = context.getUserData('url')

    domainName = context.getUserData('domain_name')

 

    params = {'query_date': timeStamp, 'domain_name': domainName, 'page_size': pageSize, 'page_number': pageNumber, 'enterprise_project_id':'ALL'}

    headers = {'Content-Type': 'application/json;charset=UTF-8', 'X-Auth-Token': context.getToken()}

    res = requests.get(logUrl, params=params, headers=headers, verify=False)

    if res.status_code != 200:

        logger.info("query log urls: " + res.url + ", error: " + res.text)

        return ("query log urls: " + res.url + ", error: " + res.text)

 

    resJson = json.loads(res.text)

    logger.info(res.text)

    total = resJson['total']

    i = 0

    for val in resJson['logs']:

        i += 1

        logger.info(val["link"])

 

        url = urlparse(val["link"])

        netlocs = url.netloc.split(":")

        conn = httplib.HTTPConnection(netlocs[0], int(netlocs[1]))

        conn.request('GET', url.path + "?" + url.query)

        objName = os.path.join(val["domain_name"], queryDate, val["name"])

        put_content_to_obs(context, objName, conn.getresponse())

 

    if pageSize * pageNumber < total:

        start(context, queryDate, timeStamp, pageSize, pageNumber + 1)

 

 

def put_content_to_obs(context, objName, content):

    ak = context.getAccessKey()

    sk = context.getSecretKey()

    obsAddress = context.getUserData('obsAddress')

    destBucket = context.getUserData('destBucket')

    TestObs = ObsClient(access_key_id=ak, secret_access_key=sk,

                        is_secure=secure, server=obsAddress, signature=signature, path_style=path_style, region=region,

                        ssl_verify=False, port=port,

                        max_retry_count=5, timeout=20)

    resp = TestObs.putContent(destBucket, objName, content=content)

    if resp.status < 300:

        print('requestId:', resp.requestId)

    else:

        print('errorCode:', resp.errorCode)

        print('errorMessage:', resp.errorMessage)

 

希望以上內(nèi)容對(duì)你的業(yè)務(wù)有所幫助,感謝~