cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Monitoring Google Cloud Function

rbillicado
Frequent Guest

Hello,

 

I'm having a trouble activating trace from Google Cloud Function.

I set up this python code allowing me to check if the snapshot of the day-1 is well done.

So far so good.

I want to activate the traces behind to trace the information in Dynatrace.

I followed the following documentation (here), but the trace does not go up.

Code content of main :

 

# isort: off
import setup_tracing  # import the module containing your setup code
# isort: on

# import other modules
import google.auth
import google.auth.transport.requests
from google.auth.transport.requests import AuthorizedSession
import requests
import json
from datetime import date
from datetime import timedelta

credentials, project = google.auth.default()
request = google.auth.transport.requests.Request()
credentials.refresh(request)
authed_session = AuthorizedSession(credentials)

import flask
from dynatrace.opentelemetry.gcf import wrap_handler
@wrap_handler
def main(data, context):
    yesterday = date.today() - timedelta(days=1)
    trigger_run_url = "https://compute.googleapis.com/compute/v1/projects/project_id/global/snapshots"
    r = authed_session.get(trigger_run_url)
    data = r.json()
    print(data)
    items_list = data["items"]
    result = False
    for item in items_list:
        creationTime = item["creationTimestamp"]
        if yesterday.strftime("%Y-%m-%d") in creationTime:
            result = True
    print(result)
    message = "Hello World"
    return flask.Response(message, 200)

 

 Content code of setup_tracing : 

 

from opentelemetry.sdk.resources import Resource
from opentelemetry.semconv.resource import ResourceAttributes

from dynatrace.opentelemetry.tracing.api import configure_dynatrace

tracer_provider = configure_dynatrace(
  resource=Resource.create({ResourceAttributes.SERVICE_NAME: "snapshot-list"})
)

 

When i run my cloud function, it doesn't give me an error in execution. 

Does somebody have an idea ?

Thanks,

Romain.

4 REPLIES 4

bradley_danyo
Dynatrace Mentor
Dynatrace Mentor

Did you make sure to complete the prerequisites outlined below?

https://www.dynatrace.com/support/help/shortlink/monitor-gcf-otel

Also, make sure the settings in the UI are correct from the link here.  I'd double check the code instrumentation as well.  I'm wondering if you potentially need the OTel exporters?

https://www.dynatrace.com/support/help/shortlink/otel-wt-python

 

Hello,

About the prerequisites

  • Dynatrace version 1.240+

I am on a SaaS environment

  • OneAgent version 1.193+ for all OneAgents participating in a trace

I don't think going through OneAgent. I set up the GCP subscription by Dynatrace Operation Suite which supervises the projects defined in scope and monitors each service added to my environment (Including Cloudfunction).

  • In the Dynatrace menu, go to Settings > Preferences > OneAgent features and activate the Forward Tag 4 trace context extension OneAgent feature.

It is well activated.
Also the feature minimum opt in version 

  • For tracing, W3C Trace Context is enabled
    1. From the Dynatrace menu, go to Settings > Preferences > OneAgent features.
    2. Turn on Send W3C Trace Context HTTP headers.

This feature is also activated.

I will exploit the track to export the trace by Otel and come back to you.

 

Thanks,

Romain.

Hello,

I tested Otel instrumentation to ingest traces into Dynatrace.

The result is not conclusive but I'm now able to provide more information following the implementation of logs at debug level in my cloudfunction.

Here is the new version of code :

import logging
import google.cloud.logging

client = google.cloud.logging.Client()
client.setup_logging()
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

import google.auth
import google.auth.transport.requests
from google.auth.transport.requests import AuthorizedSession
import requests
import json
from datetime import date
from datetime import timedelta

credentials, project = google.auth.default()
request = google.auth.transport.requests.Request()
credentials.refresh(request)
authed_session = AuthorizedSession(credentials)

from opentelemetry.sdk.resources import Resource

# Import exporters
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

# Trace imports
from opentelemetry.trace import set_tracer_provider
from opentelemetry.trace import get_tracer_provider
from opentelemetry.sdk.trace import TracerProvider, sampling
from opentelemetry.sdk.trace.export import BatchSpanProcessor

# ===== GENERAL SETUP =====

DT_API_URL = "https://{environmentid}.live.dynatrace.com/api/v2/otlp"
DT_API_TOKEN = "api_token"


merged = dict()
for name in ["dt_metadata_e617c525669e072eebe3d0f08212e8f2.json", "/var/lib/dynatrace/enrichment/dt_metadata.json"]:
  try:
    data = ''
    with open(name) as f:
      data = json.load(f if name.startswith("/var") else open(f.read()))
      merged.update(data)
  except:
    pass

merged.update({
  "service.name": "python-test", #TODO Replace with the name of your application
  "service.version": "1.0.0", #TODO Replace with the version of your application
})
resource = Resource.create(merged)


# ===== TRACING SETUP =====

tracer_provider = TracerProvider(sampler=sampling.ALWAYS_ON, resource=resource)
set_tracer_provider(tracer_provider)

tracer_provider.add_span_processor(
  BatchSpanProcessor(
    OTLPSpanExporter(
      endpoint = DT_API_URL + "/v1/traces",
      headers = {
        "Authorization": "Api-Token " + DT_API_TOKEN
      }
    )
  )
)

def main(data, context):

  tracer = get_tracer_provider().get_tracer("my-tracer")
  with tracer.start_as_current_span("rbe") as span:
      logger.debug("This is a log message.")

      span.set_attribute("http.method", "GET")
      span.set_attribute("net.protocol.version", "1.1")
      
      yesterday = date.today() - timedelta(days=1)
      trigger_run_url = "https://compute.googleapis.com/compute/v1/projects/project_id/global/snapshots"
      r = authed_session.get(trigger_run_url)
      # Check the response.
      if r.status_code == 200:
        logger.debug("The API call was successful.")
      else:
        logger.debug("The API call failed.")
      d = r.json()
      print(d)
      items_list = d["items"]
      result = False
      for item in items_list:
        creationTime = item["creationTimestamp"]
        if yesterday.strftime("%Y-%m-%d") in creationTime:
            result = True
      print(result)
      span.end()

You can find in attachment, the screenshot of the logs.

I already put forward a first hypothesis on this subject:
The service name "python-test" is not known in my environment.
I imagine it's to associate the trace with a service.
If the service is not known, does it trace it anyway?
And how can I define the name of my service that I don't know?
As a reminder, this is a cloudfunction discovered by a GCP subscription and visible in my environment by the following path:
GCP > project_id > cloudfunction_name

 

Thanks,

Romain.

Hello,

My problem is no longer relevant. Using gcf python instrumentation runs flawlessly.

The cause has been identified. It was an absence of DDUs on my subscription.

 

Thanks again for your time,

Romain.

Featured Posts