最近在支持python stack,需要提供open telemetry 的能力。有的同学提供了一个open telemetry auto instrument 的方式lib,这样就不需要每个应用程序自己写open telementry function 了。但是有个同学用了,始终不工作。我们就分析一下为什么。
他们提供的类库使用的方式是 auto_instrument, 这个方式 是让所有的 instrumentor 去改掉app 的生成类- 也就是monkey patch的方式,比如用 flask.Flask = _InstrumentedFlask,_InstrumentedFlask增加了middleware 的方式来建立,这个就要所有的app 都是直接这个类的instance 比如
from opentelemetry.instrumentation import auto_instrumentation
from threading import Thread
import uvicorn
from flask import Flask
from fastapi import FastAPI
# Initialize auto-instrumentation
auto_instrumentation.initialize()
# Flask application
flask_app = Flask(__name__)
@flask_app.route("/")
def flask_hello():
return "Hello, Flask!"
但是如果我有个一个类是Flask的继承类,这样改动就不work 了
The line flask.Flask = _InstrumentedFlask means that the original flask.Flask class is being replaced globally with _InstrumentedFlask. This ensures that any new instance of Flask created after this replacement will actually be an instance of _InstrumentedFlask, which includes additional functionality (e.g., telemetry instrumentation). If you have another class that extends from Flask, it will not automatically become an instance of _InstrumentedFlask. This is because the replacement only affects direct instantiations of flask.Flask, not subclasses of Flask.
这个case 就是
from flask_openapi3 import OpenAPI
from opentelemetry.instrumentation.flask import FlaskInstrumentor
# Create your OpenAPI app
app = OpenAPI(__name__)
from flask_openapi3 import OpenAPI
from opentelemetry.instrumentation.flask import FlaskInstrumentor
# Create your OpenAPI app
app = OpenAPI(__name__)
源码 是用app = OpenAPI(name) 生成的app , 而OpenAPI 是Flask的子类,所以即使改成 flask.Flask = _InstrumentedFlask 也没用。所以他们的auto_instrument 就不work
需要改成这样
from flask_openapi3 import OpenAPI
from opentelemetry.instrumentation.flask import FlaskInstrumentor
# Create your OpenAPI app
app = OpenAPI(__name__)
# Explicitly instrument the OpenAPI app
FlaskInstrumentor().instrument_app(app)
@app.get("/")
def hello_world():
return "Hello, OpenAPI with Flask!"
因此,auto instrument不是万能的, 他的注入是依赖entrypoint 机制,进行monkey patch,类似装饰器的概念。但是如果app 是继承的字类,这个方式就不能工作了。