Package: thinknet-observer
thinknet-observer-pythonเป็น library ที่รวบรวมเครื่องมือการทำ observaibility ตาม format ของบริษัท ด้วยภาษา python โดยมีเครื่องมือดังนี้metricslogtracingInstallationpip install thinknet-observerMetricsการเรียกใช้ metrics เพื่อให้prometheusมาเก็บ (pull) โดยมีวิธีการใช้งานดังนี้:PrometheusMiddleware()เป็น Class ที่ return middleware สำหรับเก็บ default metricsExamplefromthinknet_observerimportPrometheusMiddleware# Flaskapp=Flask(__name__)# FastAPIapp=FastAPI()''' use middleware to collect default metrics '''# singleprocess modemiddleware=PrometheusMiddleware(app)# multiprocess modemiddleware=PrometheusMiddleware(app,is_multiprocessing=True)# add exclude (optional)list_exclude=[{"route":"/healthz"}]middleware.add_exclude(list_exclude)extensionModule สำหรับสร้าง custom metrics โดยมีการเรียกใช้งานดังนี้fromthinknet_observerimportMetricCollectorโดย custom metrics มีฟังก์ชั่นการทำงาน 4 ประเภทดังนี้MetricCollector.counter(name, description, label)เป็น class method สำหรับสร้าง metrics ประเภท counter ซึ่งสามารถเพิ่มค่าได้อย่างเดียวParameternametypedescriptionnameStringชื่อของ metricsdescriptionStringdescription ของ metricslabelsArrayarray of string labels ของ metrics [optional]Example# no labelcustom_counter=MetricCollector.counter("CUSTOM_COUNTER","desc of CUSTOM_COUNTER")custom_counter.inc(1)#เพิ่มค่า 1# labelcustom_counter_label=MetricCollector.counter("CUSTOM_COUNTER","desc of CUSTOM_COUNTER",["key1","key2"])custom_counter_label.labels('value1','value2').inc(1)MetricCollector.gauge(name, description, label)เป็น class method สำหรับสร้าง metric ประเภท gauge ซึ่งสามารถเพิ่ม/ลดค่าได้ParameternametypedescriptionnameStringชื่อของ metricsdescriptionStringdescription ของ metricslabelsArrayarray of string labels ของ metrics [optional]Example# no labelscustom_gauge=MetricCollector.gauge("CUSTOM_GAUGE","desc of CUSTOM_GAUGE",)custom_gauge.inc(1)#เพิ่มค่า 1custom_gauge.dec(5)#ลดค่าลง 5#labelscustom_gauge_label=MetricCollector.gauge("CUSTOM_GAUGE","desc of CUSTOM_GAUGE",["key1","key2"])custom_gauge_label.labels('value1','value2').inc(1)custom_gauge_label.labels('value1','value2').dec(5)MetricCollector.histogram(name, description,label, bucket)เป็น class method สำหรับสร้าง metric ประเภท histogramParameternametypedescriptionnameStringชื่อของ metricsdescriptionStringdescription ของ metricslabelsArrayarray of string labels ของ metrics [optional]bucketArrayarray of bucket for histogram [optional]Example# no labelscustom_histogram=MetricCollector.histogram("CUSTOM_HISTOGRAM","desc of CUSTOM_HISTOGRAM",)custom_histogram.observe(20)# labelscustom_histogram=MetricCollector.histogram("CUSTOM_HISTOGRAM","desc of CUSTOM_HISTOGRAM",["key1","key2"])custom_histogram.labels('value1','value2').observe(20)MetricCollector.summary(name, description, label)เป็น class method สำหรับสร้าง metric ประเภท summaryParameternametypedescriptionnameStringชื่อของ metricsdescriptionStringdescription ของ metricslabelsArrayarray of string labels ของ metrics [optional]Example# no labelscustom_summary=MetricCollector.summary("CUSTOM_SUMMARY","desc of CUSTOM_SUMMARY")custom_summary.observe(10)# labelscustom_summary_label=MetricCollector.summary("CUSTOM_SUMMARY","desc of CUSTOM_SUMMARY",["key1","key2"])custom_summary_label.labels('value1','value2').observe(10)multiprocess modeกรณีรันเป็น multiprocess mode ให้เพิ่ม environment: PROMETHEUS_MULTIPROC_DIR ด้วยPROMETHEUS_MULTIPROC_DIR=./prometheus_multiproc/ (folder for multiprocess metrics)using gunicorn (Flask)กรณีรันด้วย gunicorn แบบ multiprocess mode  ให้เพิ่ม file: gunicorn.config.py ที่ root path ด้วยimportosfrompathlibimportPathfrommultiprocessingimportcpu_countfromosimportenvironfromprometheus_clientimportmultiprocessfromthinknet_observerimportclear_multiproc_dirdefchild_exit(server,worker):multiprocess.mark_process_dead(worker.pid)defmax_workers():returncpu_count()clear_multiproc_dir()ref:https://github.com/prometheus/client_pythonLoglog ของ thinknet_observer มีทั้งหมดสามแบบ logging, analyzer และ cronlogger โดยใช้แตกต่างกันดังต่อไปนี้logging()เป็น class method สำหรับใช้ logging เราจะใช้เมื่อต้องการ log เพื่อแสดงข้อความเกี่ยวกับการทำงานของระบบ (มักใช้กับ project ที่เป็น Service) และข้อความนั้น ๆ เป็น String โดย Log ที่ได้จะแสดงข้อมูลดังต่อไปนี้Field NameDescriptiontimestampเวลาที่ทำการสร้าง log โดยจะอยู่ใน Format %Y-%m-%dT%H:%M:%Slevelระดับของ Log (สามารถอ่านเพิ่มเติมlog level)messageข้อความที่ต้องการจะแสดงlog.sourceที่มาต้นทางของ log นั้น ๆlog.versionเวอร์ชั่นของ logวิธีการเรียกใช้งานfromthinknet_observerimportLogger# Create instancelog=Logger.logging()# Generate Loglog.error(message="Error Message")# {'timestamp':'2022-03-30T13:28:22Z','level':'ERROR','message':'Error Message','log.source':'application','log.version':1}analyzer()log ประเภทนี้เหมือนกับประเภทก่อนหน้าแต่ในการรับ message จะสามารถรับ message ที่เป็น Json ได้ (มักใช้กับ project ที่เป็น Service)โดย Log ที่ได้จะแสดงข้อมูลดังต่อไปนี้Field NameDescriptiontimestampเวลาที่ทำการสร้าง log โดยจะอยู่ใน Format %Y-%m-%dT%H:%M:%Slevelระดับของ Log (สามารถอ่านเพิ่มเติมlog level)messageข้อความที่ต้องการจะแสดงlog.sourceที่มาต้นทางของ log นั้น ๆlog.versionเวอร์ชั่นของ logลักษณะของ message ที่ต้องการ log{"httpStatus":4xx,5xx(int)[optional]"serviceCode":keyที่สามารถสื่อความหมายชัดเจน(string"description":messageจริงๆของระบบ(ถ้าไม่มีค่อยกำหนดเอง)(string)"traceID":ได้จากheaders(string)"payload":Stringify({})[optional]}วิธีการเรียกใช้งานfromthinknet_observerimportLogger# Create instanceanalyzelog=Logger.analyzer()# Generate Loganalyzelog.error(message={"index":0,"data":[]})# {'timestamp':'2022-03-30T13:28:22Z','level':'ERROR','message':'{"serviceCode": 0, "description": "error message"}','log.source':'analyzer','log.version':1}cronlogger(version, repo_name, project_name, tags, service)เป็น class method ที่ log ที่ไว้สำหรับการให้ข้อมูลเพื่อแจ้งขั้นตอนของการทำงานของระบบ ณ ปัจจุบัน โดยใช้กับ script ที่รันในลักษณะ cron job เช่นการ ETL ข้อมูล โดยข้อมูลที่ log สร้างขึ้นจะมีรายละเอียดดังต่อไปนี้Parameternametypedescriptionversionstringเลข version ของ script หรือ repo ซึ่งดึงมาจาก package.jsonrepo_namestringชื่อของ repo นั้นๆproject_namestringชื่อของ script ที่รัน ซึ่งดึงมาจาก package.jsontagsstringค่า tagging [optional]servicestring or dictscript นี้เกี่ยวข้องกับ service ไหน [optional]Output:Field NameDescription@timestampเวลาที่ทำการสร้าง log โดยจะอยู่ใน Format %Y-%m-%dT%H:%M:%Snameชื่อของ repository ที่ใช้งานอยู่ ณ ปัจจุบันprojectชื่อของ project ที่ repository ที่ใช้งานอยู่ ณ ปัจจุบันstatusสถานะ หรือขั้นตอนการทำงาน ณ ปัจจุบัน ได้แก่ start, running, error และ successtypeประเภทของ log โดยในที่นี้จะเป็น log ประเภท cronmessageข้อความที่ต้องการจะแสดงtagsTag ที่มีความเกี่ยวข้องกับ project โดยรับค่าเป็น string เช่น 'etl,testing' (optional)serviceservice ที่มีความเกี่ยวข้องกับโปรเจค (optional)_versionเวอร์ชั่นของ repositoryวิธีการเรียกใช้งานfromthinknet_observerimportLogger# Create instancecronlog=Logger.cronlogger(version="1",repo_name="test",project_name="testest")# Generate Logcronlog.error(message="test message",extra={"status":"error"})# {'name': 'test','project': 'testest','status': 'error','type': cron,'tags': ,'service': {},'@timestamp':'2022-03-30T13:28:22Z','message': 'test message','_version':1}Accesslogaccesslog เป็น log ที่ใช้กับ service เมื่อมีการส่ง request จะส่ง log กลับมา
อ่านวิธีการ configuration เพิ่มเติมhttps://pgjones.gitlab.io/hypercorn/how_to_guides/configuring.htmlตัวอย่างการใช้งานfromsrc.thinknet_observerimport_create_logger,AccessLogAtomsfromsrc.thinknet_observerimportclear_multiproc_dirhypercorn.logging._create_logger=_create_loggerhypercorn.logging.AccessLogAtoms=AccessLogAtomsclear_multiproc_dir()bind=environ.get("APP_HOST","0.0.0.0")+":"+environ.get("APP_PORT","8080")loglevel="info"accesslog="-"access_log_format='{"remote-addr":"%(h)s","method" : "%(m)s" ,"url" : "%(U)s", "status" :%(s)s, "trace-id" : "%({trace-id}o)s", "res": "%({content-length}o)s" ,"user-agent" : "%(a)s" ,"timestamp" : "%(t)s" ,"response-time" : "%(M)s" , "referrer" : "%(f)s" , "log.source": "http","log.version": "1"}'workers=int(environ.get("NUM_WORKER",max_workers()))root_path="/face-recognition-service"