Solutions:如何为Python Flask应用进行APM
如果大家之前看过我写的文章“应用程序性能监控/管理(APM)实践”,那么你就会对Elastic APM有个比较清楚的认识。在今天的蚊帐中,我就再累述了。在那篇文章中,我着重介绍了APM到底是什么东东。在今天的练习中,我来展示如何对Python Flask来进行监控。
测试应用
我们的Flash测试应用非常简单,就是一个简单的查询天气的微服务。这个API的接口如下:
http://api.openweathermap.org/data/2.5/weather?q=beijing&units=imperial&appid=271d1234d3f497eed5b1d80a07b3fcd1
使用上面的接口,我们可以得到北京的天气如下:
{"coord":{"lon":116.4,"lat":39.91},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"base":"stations","main":{"temp":79.68,"feels_like":72.21,"temp_min":73.99,"temp_max":84.99,"pressure":1016,"humidity":11},"visibility":10000,"wind":{"speed":4.47,"deg":250},"clouds":{"all":0},"dt":1586754618,"sys":{"type":1,"id":9609,"country":"CN","sunrise":1586727568,"sunset":1586774994},"timezone":28800,"id":1816670,"name":"Beijing","cod":200}
这是一个非常简单的应用。整个应用的代码如下:
app.py
import requests
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///weather.db'
db = SQLAlchemy(app)
class City(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
@app.route('/beijing', methods=['GET'])
def getBeijing():
url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=271d1234d3f497eed5b1d80a07b3fcd1'
city = "beijing"
weather_data = []
r = requests.get(url.format(city)).json()
weather = {
'city' : city,
'temperature' : r['main']['temp'],
'description' : r['weather'][0]['description'],
'icon' : r['weather'][0]['icon'],
}
weather_data.append(weather)
return render_template('weather.html', weather_data=weather_data)
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
new_city = request.form.get('city')
if new_city:
new_city_obj = City(name=new_city)
db.session.add(new_city_obj)
db.session.commit()
cities = City.query.all()
url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=271d1234d3f497eed5b1d80a07b3fcd1'
weather_data = []
for city in cities:
r = requests.get(url.format(city.name)).json()
weather = {
'city' : city.name,
'temperature' : r['main']['temp'],
'description' : r['weather'][0]['description'],
'icon' : r['weather'][0]['icon'],
}
weather_data.append(weather)
return render_template('weather.html', weather_data=weather_data)
为了能够运行这个应用,我们必须安装相应的python库:
pip3 install requests
pip3 install flask
pip3 install flask_sqlalchemy
在命令行中,我们打入如下的命令:
export FLASK_APP=app.py
然后,我们运行这个应用:
flask run
如果你上面都运行正确的话,我们可以在浏览器中输入localhost:5000,并可以看到如下的内容:
$ flask run
* Serving Flask-SocketIO app "app"
/usr/local/lib/python3.7/site-packages/flask_sqlalchemy/__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.
'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '
* Serving Flask app "app"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
我们可以添加一个城市来得到它的天气。在这个应用中它除了得到天气之外,它也同时访问sqlite数据库。
安装
安装Elastic Stack,有两种方法。最简单的一种方法是运用docker来一键部署Elasticsearch, Kibana和APM服务器。详细安装步骤请参阅链接liu-xiao-guo/apm-contrib。下面我们采用一种手动的方法来部署Elastic Stack。
我们可以按照我们的文章“Elastic:菜鸟上手指南”来安装及运行我们的Elasticsearch及Kibana。
我们也必须安装和Elasticsearch一样版本的APM服务器。我们打开我们的Kibana界面,并点击左上角的部分:
然后,我们按照上面的步骤一步一步地进行安装:
我们按照上面的要求配置好Elasticsearch的地址及用户名和密码(如果你已经启动了安全的设置):
如果我们能看到上面的信息则表示我们的APM服务器的安装是成功的。由于我们针对的是Flask应用框架,所以我们点击Flask来进行安装。
按照上面的要求,我们需要进行安装如下的python 模块:
pip3 install elastic-apm[flask]
pip3 install psutil
同时按照要求,我们需要对我们的python应用进行修改。整个修改后的应用如下:
app.py
import requests
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
# initialize using environment variables
from elasticapm.contrib.flask import ElasticAPM
app = Flask(__name__)
apm = ElasticAPM(app)
# or configure to use ELASTIC_APM in your application's settings
from elasticapm.contrib.flask import ElasticAPM
app.config['ELASTIC_APM'] = {
# Set required service name. Allowed characters:
# a-z, A-Z, 0-9, -, _, and space
'SERVICE_NAME': 'python-flask',
# Use if APM Server requires a token
'SECRET_TOKEN': '',
# Set custom APM Server URL (default: http://localhost:8200)
'SERVER_URL': 'http://localhost:8200',
}
apm = ElasticAPM(app)
#app = Flask(__name__)
#app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///weather.db'
db = SQLAlchemy(app)
...
在上面,我们把从Kibana中拷贝过来的代码粘贴过来。同时我们需要把DEBUG功能关掉。这个可以在官方文档中可以看到。如果是在DEBUG模式下,transaction及error是不会发到我们的APM服务器中的。我们在上面填入SERVICE_NAME及SERVER_URL。
一旦完成我们上面的配置后,我们重新运行一下我们的Python Flash应用,并打开我们的 Kibana:
点击上面的python_flask:
点击上面的GET /,我们可以看到:
我们可以看到在页面启动的时候的一个transaction的时间是花在哪里。这对我们的在调试微服务及数据库的访问性能调试会有很大的帮助。
我们在浏览器中打入http://localhost:5000/beijing,这样:
点击上面的Traces:
在上面,它显示了目前在APM应用中的所有的接口的列表。我们点击上面的GET /beijing:
在上面,我们可以看到这个接口调用的情况。
整个Python flask的应用可以在地址https://github.com/liu-xiao-guo/weather_app_flask 下载
更多阅读
参考:
【1】https://www.elastic.co/guide/en/apm/agent/python/current/flask-support.html