Skip to content
13 changes: 13 additions & 0 deletions THIRD_PARTY_LICENSES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,24 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.


--------------------------------------------------------------------------------

pyarrow
License: Apache License 2.0, a copy of the license is included at the end of this file.


--------------------------------------------------------------------------------

py_zipkin
Copyright (c) 2018, Yelp, Inc. All Rights reserved. Apache v2
License: Apache License 2.0, a copy of the license is included at the end of this file.


--------------------------------------------------------------------------------



================================================================================
Apache License
Version 2.0, January 2004
Expand Down
100 changes: 100 additions & 0 deletions samples/trace-functions-with-apm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
## Tracing Functions with APM and Zipkin

This is an example to show how you can use APM Tracing and Zipkin to trace your function code.

As you make your way through this tutorial, look out for this icon ![user input icon](./images/userinput.png).
Whenever you see it, it's time for you to perform an action.


## Prerequisites

Before you deploy this sample function, make sure you have run steps A, B
and C of the [Oracle Functions Quick Start Guide for Cloud Shell](https://www.oracle.com/webfolder/technetwork/tutorials/infographics/oci_functions_cloudshell_quickview/functions_quickview_top/functions_quickview/index.html)
* A - Set up your tenancy
* B - Create application
* C - Set up your Cloud Shell dev environment


## List Applications

Assuming you have successfully completed the prerequisites, you should see your
application in the list of applications.

```
fn ls apps
```


## Create or Update IAM Policies

Create a new policy that allows the user group to manage apm-domains in the compartment.

Create a new policy that allows service FaaS to use apm-domains in the compartment.

![user input icon](./images/userinput.png)

Your policy should look something like this:
```
Allow group <user-group-name> to manage apm-domains in compartment <compartment-name>
Allow service FaaS to use apm-domains in compartment <compartment-name>
```
e.g.
```
Allow group functions-developers to manage apm-domains in compartment demo-func-compartment
Allow service FaaS to use apm-domains in compartment demo-func-compartment
```

For more information on how to create policies, go [here](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policysyntax.htm).


## Create an APM Domain

First, you need to create an APM Domain.

1. From the [OCI Console](https://cloud.oracle.com) navigation menu, select **Application Performance Monitoring**, and then select **Administration**.

2. Select the compartment **demo-func-compartment** that you created.

3. Click **Create APM Domain**. Enter a Name **demo-apm-domain**, and a suitable Description. Select a Compartment, and optionally, select "Create an Always Free Domain".


## Enable tracing on the Functions Application

Next, enable tracing for your Functions Application and select an APM Domain to send traces to.

1. From the [OCI Console](https://cloud.oracle.com) navigation menu, select **Developer Services**, and then select **Functions**.

2. Select the compartment **demo-func-compartment** that you created.

3. Click on the application name to go to the Application Details screen.

4. Click on **Traces** under the **Resources** section.

5. Click on the **Enable Trace** toggle switch. Select the compartment **demo-func-compartment**, and the APM Domain **demo-apm-domain** that you created.


## Review and customize the function

Refer to the readme for each function:

* [Python](./python/README.md)


## Deploy the function

Refer to the readme for each function:

* [Python](./python/README.md)


### Test

Refer to the readme for each function:

* [Python](./python/README.md)


## Monitoring Functions

Learn how to configure basic observability for your function using metrics, alarms and email alerts:
* [Basic Guidance for Monitoring your Functions](../basic-observability/functions.md)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions samples/trace-functions-with-apm/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
## Tracing Python Functions with APM Tracing and Zipkin

This sample shows how you can trace your Python function code with APM Tracing and Zipkin.

As you make your way through this tutorial, look out for this icon ![user input icon](../images/userinput.png).
Whenever you see it, it's time for you to perform an action.


## Prerequisites

Before you proceed further, ensure you have followed all the steps outlined
in the parent README file located in [trace-functions-with-apm](../README.md)


## Review and customize the function

Review the following files in the current folder:
* the code of the function, [func.py](./func.py)
* its dependencies, [requirements.txt](./requirements.txt)
* the function metadata, [func.yaml](./func.yaml)


## Deploy the function

In Cloud Shell, run the `fn deploy` command to build *this* function and its dependencies as a Docker image,
push the image to the specified Docker registry, and deploy *this* function to Oracle Functions
in the application created earlier:

![user input icon](../images/userinput.png)
```
fn -v deploy --app <app-name>
```
e.g.
```
fn -v deploy --app myapp
```

## Enable tracing for the function

We have already enabled tracing for the Functions application. Now, enable tracing for your function.

1. From the [OCI Console](https://cloud.oracle.com) navigation menu, select **Developer Services**, and then select **Functions**.

2. Select the compartment **demo-func-compartment** that you created.

3. Click on the application name to go to the Application Details screen.

4. Click on **Functions** under the **Resources** section.

5. Click on the **Enable Trace** toggle switch for the function you deployed.


## Test the function

In Cloud Shell, run the following `fn invoke` command to unit test this function:

![user input icon](../images/userinput.png)
```
fn invoke <app-name> <function-name>
```
e.g.,
```
fn invoke myapp apm-fn-int-python
```

You should see your function traces in the APM Trace Explorer.


## View your function traces in the APM Trace Explorer

1. From the [OCI Console](https://cloud.oracle.com) navigation menu, select **Application Performance Monitoring**, and then select **Trace Explorer**.

2. Select the compartment **demo-func-compartment** and the **demo-apm-domain** that you created.

3. Select a time window e.g., "Last 15 minutes".

4. You should see your function traces listed on the page. Click on a trace for your function and it will open the "Trace Details" page and show all your spans and the time taken by each span.

5. Click on one of the spans to get the span details, including errors, if any.

84 changes: 84 additions & 0 deletions samples/trace-functions-with-apm/python/func.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#
# trace-functions-with-apm-python version 1.0.
#
# Copyright (c) 2021 Oracle, Inc.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl
#

import io
import json
import logging
from fdk import response
import requests

#
# The following imports are required. Includ py_zipkin and requests in the requirements.txt file.
#
from py_zipkin import Encoding
from py_zipkin.zipkin import zipkin_span

# this method is used by the zipkin library to emit spans to the apm endpoint, data key is included in this url.
def apm_transport_handler(encoded_span):
logging.getLogger().info("Inside app: " + app_name + " | function: " + func_name + " | method: apm_transport_handler")
return requests.post(
apm_domain_url,
data=encoded_span,
headers={'Content-Type': 'application/json'},
)


# this is the entry point of the function
def handler(ctx, data: io.BytesIO = None):
global app_name, func_name, apm_domain_url, apm_service_name, apm_binary_annotations
app_name = ctx.AppName()
func_name = ctx.FnName()
logging.getLogger().info("Inside app: " + app_name + " | function: " + func_name + " | method: handler")
tracing_context = ctx.TracingContext()
apm_domain_url = tracing_context.trace_collector_url()
apm_service_name = tracing_context.service_name()
logging.getLogger().info("Inside app: " + app_name + " | function: " + func_name + " | method: handler | apm_service_name: " + apm_service_name)
apm_binary_annotations = tracing_context.annotations()

with zipkin_span(
service_name = apm_service_name,
span_name = "handler method (custom child span)",
transport_handler = apm_transport_handler,
zipkin_attrs = tracing_context.zipkin_attrs(),
encoding = Encoding.V2_JSON,
binary_annotations = apm_binary_annotations
):
# this is the actual unit of work performed by the function
message = say_hello(data)
logging.getLogger().info("Inside app: " + app_name + " | function: " + func_name + " | method: handler | returned message: " + message)
return response.Response(
ctx, response_data=json.dumps(
{"message": message}),
headers={"Content-Type": "application/json"}
)

# Here's an example of showing an error in a child span.
# In this example, if we do not receive a name in the input message body,
# we will show an error in the span, and return a hello greeting using
# a default name instead.
def say_hello(data: io.BytesIO = None):
logging.getLogger().info("Inside app: " + app_name + " | function: " + func_name + " | method: say_hello")
with zipkin_span(
service_name = apm_service_name,
span_name = "say_hello method (custom child span)",
binary_annotations = apm_binary_annotations
) as span_context:
name = "OCI Functions-APM integration!"
try:
body = json.loads(data.getvalue())
name = body.get("name")
except (Exception, ValueError) as ex:
logging.getLogger().info("Inside app: " + app_name + " | function: " + func_name + " | method: say_hello | error parsing json payload: " + str(ex))
errors = {
"Error": True,
"ErrorMessage": str(ex)
}
span_context.update_binary_annotations(errors)

message = "Hello {0}".format(name)
logging.getLogger().info("message: " + message)
return message
6 changes: 6 additions & 0 deletions samples/trace-functions-with-apm/python/func.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schema_version: 20180708
name: apm-fn-int-python
version: 0.0.21
runtime: python
entrypoint: /python/bin/fdk /function/func.py handler
memory: 256
3 changes: 3 additions & 0 deletions samples/trace-functions-with-apm/python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fdk
requests
py_zipkin