Various Helper Tools to make working with azure functions easier
Project description
🎷 FuncTown 🎷
FuncTown
is a python library to make working with azure functions easier and remove boilerplate.
Getting Started
pip install functown
After installing you can easily get your functions error checked (with an auto-response for execptions triggered):
from functown import handle_errors
@handle_errors(debug=True)
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
# ...
return func.HttpResponse("success", status_code=200)
Should an exception happening in the middle, the decorator will auto-parse it (and write to logs if debug is true), then provide a response.
You can also parse JWT tokens and validate them (this currently requires to set the B2C_ISSUER_URL
and B2C_APP_ID
environment variables):
from functown.auth import verify_user
def main(req: func.HttpRequest) -> func.HttpResponse:
user, user_id, user_scp, local = verify_user(req, scope=scopes.SCOPE_WRITE)
Finally the library also allows you to easily parse arguments coming from the HttpRequest
:
from functown import RequestArgHandler
def main(req: func.HttpRequest) -> func.HttpResponse:
args = RequestArgHandler(req)
data = args.get_body_query("data_name", required=True, allowed=["foo", "bar"])
switch = args.get_body("bool_name", map_fct='bool')
file = args.get_file('file_name', required=True)
All this should remove boilerplate from Azure-Functions.
🎷 Welcome to FuncTown! 🎷
Decorators
Most of the functionality that FuncTown
provides is through decorators.
These decorators can be used to wrap your functions and provide additional functionality.
Note that almost all decorators pass along additional arguments to your function. So it is generally a good idea to modify your function signature to accept these arguments:
# instead of main(req: func.HttpRequest) -> func.HttpResponse:
def main(req: func.HttpRequest, *params, **kwargs) -> func.HttpResponse:
# ...
Note: The
last_decorator
parameter is used to indicate that this is the last decorator in the chain. This makes sure that the signature of the function is consumable by Azure Functions. Alternatively you can also the the@functown.clean
decorator to clean up the signature.
handle_errors
The handle_errors
decorator can be used to wrap your function and provide error handling.
It will catch any exception that is thrown in the function and provide a response to the user.
from functown import handle_errors
@handle_errors(debug=True, last_decorator=True)
def main(req: func.HttpRequest, *params, **kwargs) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
# ...
return func.HttpResponse("success", status_code=200)
You can also specify the degree to which debug information is returned as part of the response with the following parameters:
debug
(bool): Defines if general exceptions are written to the logs with stack trace (default:False
)log_all_errors
(bool): Defines if all exceptions are written to the logs with stack trace (including errors that might explicitly contain user data such asTokenError
) (default:False
)return_errors
(bool): Defines if the error message is returned as part of the response (for quicker debugging) (default:False
)
metrics_all
The metrics_all
decorator can be used to wrap your function and provide logging of metrics in Application Insights.
This includes 4 major categories:
enable_logger
: Enables sending of generalTrace
data to Application Insights through the use of alogger
object passed to the function (of typelogging.Logger
)enable_events
: Enables sending ofCustomEvent
data to Application Insights through the use of aevents
object passed to the function (of typelogging.logger
)enable_tracer
: Enables sending ofRequest
data to Application Insights through the use of atracer
object passed to the function (of typeopencensus.trace.tracer.Tracer
) FIXME: update metrics hereenable_metrics
: Enables sending ofMetric
data to Application Insights through the use of ametrics
object passed to the function (of typeopencensus.stats.stats.Stats
)
Note that each of these elements has additional sub-parameters that can be set.
logger
from functown import metrics_logger
from logging import Logger
@metrics_logger(enable_logger=True, last_decorator=True)
def main(req: func.HttpRequest, logger: Logger, *params, **kwargs) -> func.HttpResponse:
logger.info('Python HTTP trigger function processed a request.')
# ...
return func.HttpResponse("success", status_code=200)
events
from functown import metrics_events
from logging import Logger
@metrics_events(enable_events=True, last_decorator=True)
def main(req: func.HttpRequest, events: Logger, *params, **kwargs) -> func.HttpResponse:
# log event
events.info('Custom Event', extra={'custom_dimensions': {'foo': 'bar'}})
# ...
return func.HttpResponse("success", status_code=200)
tracer
from functown import metrics_tracer
from opencensus.trace.tracer import Tracer
@metrics_tracer(enable_tracer=True, tracer_sample=1.0, last_decorator=True)
def main(req: func.HttpRequest, tracer: Tracer, *params, **kwargs) -> func.HttpResponse:
# start span
with tracer.span(name="span_name") as span:
# everything in this block will be part of the span (and send sampled to Application Insights)
# ...
# ...
return func.HttpResponse("success", status_code=200)
metrics
from functown import log_metrics
# FIXME: implement
Versioning
We use SemVer for versioning. For the versions available, see the tags on this repository.
Run Example
The source folder also includes an example
function that provides a basic azure function,
that leverages the different functionality of the library.
You can create a new Functions app in your Azure Subscripton to test it. Follow these steps:
- Login to your Azure Portal in the browser
- Create a new Functions App (note that this should at least be Python 3.8 and a consumption tier is recommended)
- Publish the content of the example folder to the functions app (through VS Code Plug-In or through CLI) - I usually use VSCode directly:
- Create a new Application Insights Instance through your Browser in the same resource group as the Functions App
- Note: Check here - sometimes this instance is already created directly with your Function App
- Take the
instrumentation key
from the App Insights (found in overview blade) and copy it - Go to the Function App in Azure and to the Configuration Blade. There create the config settings specified in
example/config.tmp.json
(use the copied App Insights Instrumentation Key here) - To run the curl commands (you could also test by going on the
TestFuncTown
Example function in your browser) we need a function app key (found under theApp Keys
blade):
You can now use curl
to test various commands against the endpoint:
# Write a list of curl commands to test the different functionality of the example function
# set the name of your function app (e.g. functownexample) and the key
# note that the function app name might vary and you can find it on the overview blade of your function app
FAPP="functownexample"
FAPP_KEY="YOUR_APP_KEY"
# test the basic functionality
curl -X POST -H "Content-Type: application/json" -d '{"print_num": "2", "req": "some req param"}' "https://${FAPP}.azurewebsites.net/api/TestFuncTown?code=${FAPP_KEY}"
# Expected output:
# {
# "completed": true,
# "results": {
# "body_param": "no body param",
# "query_param": "no query param",
# "use_exeption": null,
# "print_num": 2,
# "print_list": null,
# "req_param": "some req param"
# },
# "logs": [
# "Using functown v0.1.7",
# "body_param: no body param",
# "query_param: no query param",
# "use_exeption: None",
# "print_num: 2",
# "print_num: 0",
# "print_num: 1",
# "print_list: None",
# "req_param: some req param"
# ]
# }
# you can also test throwing an exception:
curl -X POST -H "Content-Type: application/json" -d '{"use_exeption": "true"}' "https://${FAPP}.azurewebsites.net/api/TestFuncTown?code=${FAPP_KEY}"
# Expected output:
# {
# "user_message": "This function executed unsuccessfully",
# "type": "<class 'TypeError'>",
# "value": "'str' object cannot be interpreted as an integer",
# "trace": [
# "error_decorator.py:79:111 - Vars: ('req', 'ex')",
# "__init__.py:22:54 - Vars: ('req', 'logger', 'logs', 'args', 'body_param', 'query_param', 'use_exeption', 'print_num', 'i', 'print_list', 'req_param', 'payload')"
# ]
# }
# some further curl commands to try:
curl -X POST -H "Content-Type: application/json" -d '{"print_num": "2", "print_list": ["a", "b", "c"]}' "https://${FAPP}.azurewebsites.net/api/TestFuncTown?code=${FAPP_KEY}"
curl -X POST -H "Content-Type: application/json" -d '{"body_param": "some body param", "query_param": "some query param", "req": "required"}' "https://${FAPP}.azurewebsites.net/api/TestFuncTown?code=${FAPP_KEY}"
⛔ Note: ️Think about shutting down your azure resources after you used them to avoid additional costs! ⛔️
(esp. when using a non-consumption tier)
Note on App Insights: Metrics and traces take a time to show up in the App Insights. You can also use the logs
field in the response to see the logs of the function.
Testing functown Code
This function also allows to test changes to functown in the development process.
For that simply copy the current functown
folder into the example
folder and rename it to functown_local
, then redeploy the function app.
You should also update the version number in the __init__.py
file of the functown
folder before (which needs to be done for any changes, see section on Versioning
).
Note: When you update dependencies you also need to temporarily add these dependencies to the
requirements.txt
file in theexample
folder (and remove them before commiting!).
You can verify that the new version of the code was picked up by the first log statement in your return.
Notes
- The
@handle_error
decorator returns additional information to be used in the development process. This can also expose infrormation to attackers, so use responsibly (i.e. make sure to disable for production environments).
If you want to develop on the library or execute tests, you can install the conda environment:
# remove old:
# conda env remove -n functown
conda env create -f conda-dev.yml
conda activate functown
‼️ If you find this library helpful or have suggestions please let me know. Also any contributions are welcome! ‼️
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file functown-1.0.0a1.tar.gz
.
File metadata
- Download URL: functown-1.0.0a1.tar.gz
- Upload date:
- Size: 26.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.9.16
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 90c754d06271a2284c9c257b8bc3afa284679ec4541703bc4a91a422a85fd43b |
|
MD5 | 8db8778ee78154f2ea6d8dd47ecec941 |
|
BLAKE2b-256 | 042b33a40464afa3290a882a4e7270cf4ba35cd96883293bad0694e4909bb0c2 |
File details
Details for the file functown-1.0.0a1-py3-none-any.whl
.
File metadata
- Download URL: functown-1.0.0a1-py3-none-any.whl
- Upload date:
- Size: 29.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.9.16
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 17bf5db7c5f6b28ac8c064b3961faa6ebcbc08c1290f6a4dde54fbb8d296b6bb |
|
MD5 | 648adaddf04a429f0e9ff9b13da7b51f |
|
BLAKE2b-256 | 901f5b107f8970282226f3a2c93407683801bf93be44ab1561cb7664054a4390 |