I'm use the fastapi_log library( https://pypi.org/project/fastapi-log/ ) ( https://github.com/12345k/fastapi-log ) in my FastAPI project.
It works great to log request and responses(return statements), but it does not log HTTPExceptions(which I used in some parts of the program instead of return statements).
How can I edit the source code for log_request.py ( https://github.com/12345k/fastapi-log/blob/main/fastapi_log/log_request.py ) to be able to log responses from HTTPExceptions as well ?
The log_request.py source code :
import re
import time
from starlette.requests import Request
from typing import Callable
from fastapi import HTTPException, Request, Response
import time
import os
import uuid
import json
from user_agents import parse
from urllib.parse import parse_qs
from datetime import datetime
from fastapi.routing import APIRoute
import sqlite3
path = os.path.abspath(os.path.dirname(__file__))
path = path.replace("__init__.py","")
conn = sqlite3.connect(path+'/database/test.db')
conn.execute('''CREATE TABLE IF NOT EXISTS REQUEST
(ENDPOINT TEXT NOT NULL,
TYPE INT NOT NULL,
BODY CHAR(50),
UUID REAL,
TIME TEXT NOT NULL);''')
class LoggingRoute(APIRoute):
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
try:
uuid_str = str(uuid.uuid4())
header = dict(request.headers)
if "uuid" in header.keys():
uuid_str = header["uuid"]
user_agent = parse(request.headers["user-agent"])
browser=user_agent.browser.version
if len(browser) >=2:
browser_major,browser_minor = browser[0],browser[1]
else:
browser_major,browser_minor =0,0
user_os=user_agent.os.version
if len(user_os) >=2:
os_major,os_minor = user_os[0],user_os[1]
else:
os_major,os_minor =0,0
# Request json
body = await request.body()
if len(body)!=0:
body=json.loads(body)
else:
body=""
request_json = {
"type":"request",
"uuid":uuid_str,
"env": os.environ.get("ENV"),
"region": os.environ.get("REGION"),
"name": os.environ.get("NAME"),
"method": request.method,
"useragent":
{
"family": user_agent.browser.family,
"major": browser_major,
"minor": browser_minor,
"patch": user_agent.browser.version_string,
"device": {
"family": user_agent.device.family,
"brand": user_agent.device.brand,
"model": user_agent.device.model,
"major": "0",
"minor": "0",
"patch": "0"
},
"os": {
"family": user_agent.os.family,
"major": os_major,
"minor": os_minor,
"patch": user_agent.os.version_string
},
},
"url": request.url.path,
"query": parse_qs(str(request.query_params)),
"body":body,
"length": request.get("content-length"),
'ts': f'{datetime.now():%Y-%m-%d %H:%M:%S%z}'
}
print(json.dumps(request_json,indent=4))
start_time = time.time()
response = await original_route_handler(request)
process_time = (time.time() - start_time) * 1000
formatted_process_time = '{0:.2f}'.format(process_time)
metrics_json = {
"type": "metrics",
"uuid": uuid_str,
"env": os.environ.get("ENV"),
"region": os.environ.get("REGION"),
"name": os.environ.get("NAME"),
"method": request.method,
"status_code": response.status_code,
"url": request.url.path,
"query": parse_qs(str(request.query_params)),
"length": response.headers["content-length"],
"latency": formatted_process_time,
"ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}'
}
print(json.dumps(metrics_json,indent=4))
try:
if len(request_json) !=0:
url = str(request_json["url"]).replace("/","")
method=request_json["method"]
body=str(request_json["body"])
uuid_str=request_json["uuid"]
time_value = request_json["ts"]
# print(body)
conn.execute(f"INSERT INTO REQUEST VALUES (?,?,?,?,?)",( url , method, body, uuid_str,time_value ))
# VALUES ({request_json["url"].replace("/","")}, {request_json["method"]},"str(request_json[body])", {request_json["uuid"]} )""");
conn.commit()
except Exception as exc:
print(exc)
pass
return response
except Exception as exc:
body = await request.body()
detail = {"errors": str(exc), "body": body.decode("utf-8")}
print(detail)
raise HTTPException(status_code=422, detail=detail)
return custom_route_handler
Related
im running a Redis server. and im gettig the folowwing error.
ERROR: Exception in ASGI application
what have i done wrong?
This is my code:
``
from fastapi import FastAPI
from models import Parks
import requests
import uvicorn
import json
import redis2
SERVER_URL = 'localhost'
SERVER_PORT = 8000
REDIS_SERVER = 'localhost'
REDIS_PORT = 6379
app = FastAPI()
#app.post("/api/v1/ru")
async def get_data(rub_post: Parks):
token = "**************"
url = "https://********************************/users/?filter=" + rub_post.car_number
headers = {"Content-Type": "application/json; charset=utf-8", "X-Access-Token": token}
response = requests.get(url, headers=headers)
j = response.json()
if not j['users']['count'] == 0:
note: str = j['users']['list'][0]['places'][0]['notes']
else:
return {"Answer": "car not found"}
if rub_post.parked_id in note:
return {"Answer": "found car"}
if "P" in note:
redis_cli = redis2.Redis(host=REDIS_SERVER, port=REDIS_PORT, db=0)
dict_f = {"carId": rub_post.car_number, "parkingTicketId": rub_post.parked_id,
"laneId": "cded89ec403083a31", "transactionId": "Invalid Parking",
"currency": "", "price": "", "userPn": "", "userEmail": "", "userName": "",
"companyName": "", "paymentMethod": [{"type": "", "amount": "", "id": ""}]
}
redis_cli.lpush('terminalToLprIsCarAuthorized', json.dumps(dict_f))
return {"Answer": "invalid car"}
if __name__ == '__main__':
uvicorn.run(app, host=SERVER_URL, port=SERVER_PORT)
``
still new to this and i cant find whats wrong. thanks for the helpers
I found an example from this web site,
https://blog.hanchon.live/guides/google-login-with-fastapi/
is there a similar example for microsoft AD authentication?
import os
import starlette
from starlette.config import Config
from authlib.integrations.starlette_client import OAuth
# OAuth settings
GOOGLE_CLIENT_ID = os.environ.get('GOOGLE_CLIENT_ID') or None
GOOGLE_CLIENT_SECRET = os.environ.get('GOOGLE_CLIENT_SECRET') or None
if GOOGLE_CLIENT_SECRET is None or GOOGLE_CLIENT_ID is None:
raise BaseException('Missing env variables')
# setup OAuth
config_data = {'GOOGLE_CLIENT_ID': GOOGLE_CLIENT_ID,
'GOOGLE_CLIENT_SECRET': GOOGLE_CLIENT_SECRET}
starlette_config = Config(environ=config_data)
oauth = OAuth(starlette_config)
oauth.register(
name='google',
server_metada_url='https://accounts.google.com/.well-known/openid-configuration',
client_kwargs={'scope': 'openid email profile'}
)
The output is:]On instance['id']:
'10'
Given JSON data is InValid
Traceback (most recent call last):
File "sample3.py", line 38, in
invalidjsonData = json.loads(
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/json/init.py", line 357, in loads
return _default_decoder.decode(s)
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/json/decoder.py", line 353, in raw_decode]
user_schema is:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "User",
"description": "A user request json",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a user",
"type": "integer"
},
"name": {
"description": "Name of the user",
"type": "string"
},
"contact_number": {
"type": "number"
}
},
"required": ["id", "name", "contact_number"]
}
an example from github:
import json
from fastapi import FastAPI
from starlette.config import Config
from starlette.requests import Request
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import HTMLResponse, RedirectResponse
from authlib.integrations.starlette_client import OAuth, OAuthError
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="!secret")
config = Config('.env')
oauth = OAuth(config)
CONF_URL = 'https://accounts.google.com/.well-known/openid-configuration'
oauth.register(
name='google',
server_metadata_url=CONF_URL,
client_kwargs={
'scope': 'openid email profile'
}
)
#app.get('/')
async def homepage(request: Request):
user = request.session.get('user')
if user:
data = json.dumps(user)
html = (
f'<pre>{data}</pre>'
'logout'
)
return HTMLResponse(html)
return HTMLResponse('login')
#app.get('/login')
async def login(request: Request):
redirect_uri = request.url_for('auth')
return await oauth.google.authorize_redirect(request, redirect_uri)
#app.get('/auth')
async def auth(request: Request):
try:
token = await oauth.google.authorize_access_token(request)
except OAuthError as error:
return HTMLResponse(f'<h1>{error.error}</h1>')
user = token.get('userinfo')
if user:
request.session['user'] = dict(user)
return RedirectResponse(url='/')
#app.get('/logout')
async def logout(request: Request):
request.session.pop('user', None)
return RedirectResponse(url='/')
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host='127.0.0.1', port=8000)
import requests, json, time
url = 'https://api.kucoin.com/api/v1/orders'
headers = {
"KC-API-KEY": '',
"KC-API-PASSPHRASE": '',
"clientOid": "AAA",
"side": "sell",
"symbol": "BTC-USDT",
"type": "market",
"size": "0.001",
}
response = requests.post(url, headers=headers)
print(response.status_code)
print(response.json())
I am trying to place an order but it isn't working. Am I missing some parameters?
Error:
{'code': '400001', 'msg': 'Please check the header of your request for KC-API-KEY, KC-API-SIGN, KC-API-TIMESTAMP, KC-API-PASSPHRASE'}
According to the official docs, all private request must contain the following headers:
KC-API-KEY
KC-API-SIGN
KC-API-TIMESTAMP
KC-API-PASSPHRASE
KC-API-VERSION
Here is an example of the endpoint to place a order limit:
import base64, hmac, hashlib, json
# constants
API_KEY = "YOUR_API_KEY"
API_SECRET = "YOUR_API_SECRET"
API_PASSPHRASE = "YOUR_API_PASSPHRASE"
url = "https://api.kucoin.com/api/v1/orders"
now = int(time.time() * 1000)
data = {"clientOid": "AAA", "side": "sell", "symbol": "BTC-USDT", "type": "market", "size": "0.001"}
data_json = json.dumps(data)
str_to_sign = str(now) + 'POST' + '/api/v1/orders' + data_json
signature = base64.b64encode(hmac.new(API_SECRET.encode(
'utf-8'), str_to_sign.encode('utf-8'), hashlib.sha256).digest())
passphrase = base64.b64encode(hmac.new(API_SECRET.encode(
'utf-8'), API_PASSPHRASE.encode('utf-8'), hashlib.sha256).digest())
headers = {
"KC-API-SIGN": signature,
"KC-API-TIMESTAMP": str(now),
"KC-API-KEY": API_KEY,
"KC-API-PASSPHRASE": passphrase,
"KC-API-KEY-VERSION": "2",
"Content-Type": "application/json"
}
try:
res = requests.post(
url, headers=headers, data=data_json).json()
print(res)
except Exception as err:
print(err)
Hope it will help.
Did you consider using wrapped library like Python-kucoin ?
https://python-kucoin.readthedocs.io/en/stable/index.html
it is really great and will definitely help you. Have a look to the documentation
from kucoin.client import Client
api_key = '<api_key>'
api_secret = '<api_secret>'
api_passphrase = '<api_passphrase>'
client = Client(api_key, api_secret, api_passphrase)
# place a market buy order
order = client.create_market_order('BTC-USDT', Client.SIDE_BUY, size=0.001)
try removing the spaces from :
data = {"clientOid": "AAA", "side": "sell", "symbol": "BTC-USDT", "type": "market", "size": "0.001"}
I use below code and send message to kafka. It works.
But I want to send message without schema because I have schema on kafka topic. I register it first. I do not want to send schema everytime.
from confluent_kafka import avro
from confluent_kafka.avro import AvroProducer
value_schema_str = """
{
"type":"record",
"name":"myrecord",
"fields":[
{
"name":"id",
"type":[
"null",
"int"
],
"default":null
},
{
"name":"product",
"type":[
"null",
"string"
],
"default":null
},
{
"name":"quantity",
"type":[
"null",
"int"
],
"default":null
},
{
"name":"price",
"type":[
"null",
"int"
],
"default":null
}
]
}
"""
key_schema_str = """
{
"type":"record",
"name":"key_schema",
"fields":[
{
"name":"id",
"type":"int"
}
]
}
"""
def delivery_report(err, msg):
""" Called once for each message produced to indicate delivery result.
Triggered by poll() or flush(). """
if err is not None:
print('Message delivery failed: {}'.format(err))
else:
print('Message delivered to {} [{}]'.format(msg.topic(), msg.partition()))
if __name__ == '__main__':
value_schema = avro.loads(value_schema_str)
key_schema = avro.loads(key_schema_str)
#value = {"id": 1, "product": "myProduct", "quantity": 10, "price": 100}
key = {"id": 1}
avroProducer = AvroProducer({
'bootstrap.servers': '10.0.0.0:9092',
'on_delivery': delivery_report,
'schema.registry.url': 'http://10.0.0.0:8081'
}, default_key_schema=key_schema, default_value_schema=value_schema)
avroProducer.produce(topic='orders', key=key)
avroProducer.flush()t
thanks in advance
I do not want to send schema everytime.
Avro requires a Schema. Full stop
I have schema on kafka topic
Kafka topics do not have schemas. I assume you mean you have a schema in the registry? Then you must fetch that before you use it in your producer
from confluent_kafka.avro import CachedSchemaRegistryClient
sr_client = CachedSchemaRegistryClient({'url': "http://10.0.0.0:8081"})
Then use the client to do a get_schema call
Using confluent-kafka-python
from confluent_kafka.avro.cached_schema_registry_client import CachedSchemaRegistryClient
sr = CachedSchemaRegistryClient({"url": "http://localhost:8081"})
value_schema = sr.get_latest_schema("orders-value")[1]
key_schema= sr.get_latest_schema("orders-key")[1]
Using SchemaRegistryClient
# pip install python-schema-registry-client
from schema_registry.client import SchemaRegistryClient
sr = SchemaRegistryClient('localhost:8081')
value_schema = sr.get_schema('orders-value', version='latest').schema
key_schema = sr.get_schema('orders-key', version='latest').schema
And finally:
from confluent_kafka import avro
from confluent_kafka.avro import AvroProducer
def delivery_report(err, msg):
""" Called once for each message produced to indicate delivery result.
Triggered by poll() or flush(). """
if err is not None:
print('Message delivery failed: {}'.format(err))
else:
print('Message delivered to {} [{}]'.format(msg.topic(), msg.partition()))
if __name__ == '__main__':
value = {"id": 1, "product": "myProduct", "quantity": 10, "price": 100}
key = {"id": 1}
avroProducer = AvroProducer({
'bootstrap.servers': '10.0.0.0:9092',
'on_delivery': delivery_report,
'schema.registry.url': 'http://10.0.0.0:8081'
}, default_key_schema=key_schema, default_value_schema=value_schema)
avroProducer.produce(topic='orders', key=key, value=value)
avroProducer.flush()
I wrote a python code for the dialog flow using the flask and webhook. I am able to get the response but it not displayed in the dialog flow. This code running perfectly.
CODE:
# import os
import json
# import urllib
import datetime
from config import Configuration
from swe_commands import SweCommands
from flask import Flask, request, make_response
# Flask application should start in global layout
app = Flask(__name__)
#app.route('/webhook', methods=['POST'])
def webhook():
req = request.get_json(silent=True, force=True)
print "Request:"
print json.dumps(req, indent=1)
res = make_webhook_result(req)
res = json.dumps(res, indent=1)
print "Response:"
print res
r = make_response(res)
r.headers['Content-Type'] = 'application/json'
return r
def make_webhook_result(req):
# if req.get("queryResult").get("action") != "nakshatra":
# return {}
swe_path = Configuration.swe_path()
date_and_time = str(datetime.datetime.now())[:19]
panchang_dictionary = SweCommands.find_panchang(swe_path, date_and_time)
result = req.get("queryResult")
parameters = result.get("parameters")
angam = parameters.get("nakshatra")
nakshatra = panchang_dictionary[angam]
speech = "Current nakshatra is %s" % nakshatra
source = "Panchangam"
output = {'speech': speech, "displayText": speech, "source": source}
return output
if __name__ == '__main__':
port = 5000
print "Starting app in port %s" % port
app.run(debug=True, port=port, host='127.0.0.1')
REQUEST:
**{
"queryResult": {
"fulfillmentMessages": [
{
"text": {
"text": [
""
]
}
}
],
"allRequiredParamsPresent": true,
"parameters": {
"nakshatra": "nakshatra"
},
"languageCode": "en",
"intentDetectionConfidence": 0.6725314,
"action": "nakshatra",
"intent": {
"displayName": "PanchangFind",
"name": "projects/my-project-1536557558293/agent/intents/6d1d46bf-3787-48cd-9b45-0766d5f2b107"
},
"queryText": "What is nakshatra"
},
"originalDetectIntentRequest": {
"payload": {}
},
"session": "projects/my-project-1536557558293/agent/sessions/08857865-1d08-2eef-5d4f-83b92107f09b",
"responseId": "2137da9d-23a9-4735-aec2-7adb7ae52d85-9cc28bb4"
}**
RESPONSE:
**{
"displayText": "Current nakshatra is Shravana",
"speech": "Current nakshatra is Shravana",
"source": "Panchangam"
}**
But it not get displayed in the dialog flow panel? Whether I have to set any parameters for dialog flow panel to receive the response in a dialog flow. Please let me know.
I got an answer to this. When we use V1 in dialog flow, the response key is displayText. But in V2 the response key is fulfillmentText. When I added the response key in this name it able to detect the output.