Basic Cumulocity IoT Microservice Monitoring
Tags: cumulocity, iot, microservices, monitoring
Published: 2023-03-23 15:30:44

---
title: Basic Cumulocity IoT Microservice Monitoring
published: true
date: 2023-03-07 15:24:16 UTC
tags: cumulocity, iot, microservices, monitoring
canonical_url: https://tech.forums.softwareag.com/t/basic-cumulocity-iot-microservice-monitoring/275424
---

 

## Overview

Once you deploy a [Microservice](https://cumulocity.com/guides/microservice-sdk/introduction/) on the Cumulocity Platform, the Status tab of the Microservice in the Administration application can show you whether it is active or not. And the health endpoint can also help you to monitor the status of the Microservice.

However, if state monitoring does not fulfill your requirements for microservice monitoring, you need to monitor a wider variety of detailed system statistics, how can you easily access this data from a microservice hosted on Cumulocity IoT Platform? This article will show you a basic approach to monitor your Microservice directly on the platform.

## Idea

This example is based on the [Python Microservice example of C8Y](https://cumulocity.com/guides/microservice-sdk/http/#hello-microservice-python). A dummy device registered to the platform will be used to display the data from the Microservice. Right after the system statistics are obtained within the Microservice, they will be sent to the device. The connection between the microservice and the device can be checked or established in the Microservice. When the Microservice is running, the users with right permissions can monitor it in the Device Management application like a device or even create a dashboard for it in the Cockpit application.

## Pros & Cons of basic Microservice Monitoring

### Pros

> - No additional infrastructure or tool needed
> - No additional maintenance required
> - Take advantage of platform features for visualisation and alerting
> - Take advantage of Cumulocity SDK

### Cons

> - Microservices with “single-tenant” [isolation](https://cumulocity.com/guides/microservice-sdk/concept/#isolation-levels) can be only monitored in the same tenant they are deployed
> - Not suitable for multiple Microservices monitoring
> - Metrics must be converted to the Cumulocity-acceptable form
> - Dependent on Cumulocity infrastructure - no monitoring/alerting possible if instance/tenant is down.

This approach is recommended when:

- you have small number of Microservices in one tenant and want to monitor them on the platform directly
- you want to monitor a few metrics of the Microservices
- 3rd party monitoring tools are not available to you

If you have a large number of Microservices subscribed to multiple tenants, or you want to obtain a more professional and comprehensive monitoring of the Microservices, here is an [advanced monitoring approach](https://tech.forums.softwareag.com/t/advanced-cumulocity-iot-microservice-monitoring-part-1/274963) that may be more meaningful for you.

## Details

### Step 1: Bootstrap Service to the Device

The external ID and the type are the key values that link the service to the device. External ID is the same as the name of the service in order to make sure that the connection is unique. The first step aims to find the device with the required external ID and to identify its internal device ID for following steps. If there isn’t any matching device, a new device will be created and the required external ID will be assigned for it.

```
c8y = CumulocityApi(
    base_url = os.environ.get('C8Y_BASEURL'),
    tenant_id= os.environ.get('C8Y_TENANT'),
    username = os.environ.get('C8Y_USER'),
    password= os.environ.get('C8Y_PASSWORD')
)

ms_device_name = os.environ.get('APPLICATION_NAME')
device_type = 'service_device'
external_type = 'c8y_ServiceId'
device_id = None

def bootstrapServiceDevice():
    global device_id    
    try:
        logger.info('Finding the device connected to the service')
        device_id = c8y.identity.get_id(external_id=ms_device_name, external_type=external_type)
    except KeyError:
        logger.info('Device not found, creating new device')
        ms_device = Device(c8y,device_type,ms_device_name).create()
        device_id = ms_device.id
        c8y.identity.create(external_id=ms_device_name, external_type=external_type, managed_object_id=device_id)
        logger.info(f'Device created, Device ID: {device_id}')
    except ValueError:
        logger.error('Invalid credentials')
        sys.exit()

```

In this step, the identity function of the [Cumulocity Python API](https://github.com/SoftwareAG/cumulocity-python-api) is used to find and create the external ID, and the Device method is used to create the device.

### Step 2: Collect metrics

The functions from [psutil](https://psutil.readthedocs.io/en/latest/) python library which are used for gathering the system statistics return different kinds of results. As an examples we chosen to monitor CPU utiliy and thread count of the Microservice. All data needs to be convered to the Cumulocity-acceptable json format. In this basic monitoring use case, we focus on the Microservice itself. Therefore, the statistics come from the process in which the Microservice are running.

```
request_count = 0 
task_queue = queue.Queue()

def collectMetrics():
    while True:
        num_threads = psutil.Process(os.getpid()).num_threads()
        metrics_dict = {
            'cpu_percent': {},
            'num_threads': {'num_threads': {'value': num_threads}},
            'task_queue_size':{'task_queue_size': {'value': task_queue.qsize()}}
        }
        cpu_num = psutil.Process(os.getpid()).cpu_num()
        cpu_percent = psutil.cpu_percent(interval=1, percpu=True)
        metrics_dict['cpu_percent']['cpu'] = {'value':cpu_percent[cpu_num]}
        if not task_queue.empty():
            task_queue.get()
            metrics_dict.update({'request_count': {'request_count': {'value': request_count}}})
        for key, value in metrics_dict.items():
            exec('Measurement(c8y, type=\'c8y_Monitoring\', source=device_id, {}={}).create()'.format('c8y_'+key,value))
        if task_queue.empty():
            time.sleep(10)

```

In addition, we set a dummy task list and an endpoint for the service. Once the endpoint is touched, a new task will be added into the list and the usage of the endpoint will also be counted. These self-defined variables will also be part of the metrics to be sent to the platform. In this way, you can monitor the Microservice with common system statistics and any kind of variable you need.

```
app = Flask( __name__ )

@app.route('/')
def add_metrics():
    global request_count
    request_count += 1
    task_queue.put('A new task has been added')
    return "Added new task!"

```

### Step 3: Monitor the Microservice on the platform

After deploy this Microservice on the platform, a new device will be created to display the data from the service. You can monitor it and check the history data in the [Device Management](https://cumulocity.com/guides/users-guide/device-management/) applicatioin. For even more convienient monitoring, you can add a dashboard for this device in the [Cockpit](https://cumulocity.com/guides/users-guide/cockpit/) application. In the Cockpit, [Smart Rules](https://cumulocity.com/guides/users-guide/cockpit/#smart-rules) can support your monitoring by rising alarms or sending emails. Other features of Cumulocity IoT Platform can also be used for monitoring your Microservice just like monitoring a device.

[![Screenshot 2023-03-02 at 13.36.19](https://global.discourse-cdn.com/techcommunity/optimized/3X/b/f/bf7024e15eae3987c5ec45012822aad133be8ad3_2_690x395.png)](https://global.discourse-cdn.com/techcommunity/original/3X/b/f/bf7024e15eae3987c5ec45012822aad133be8ad3.png "Screenshot 2023-03-02 at 13.36.19")

## Conclusion

Here is the entire Microservice python code. When you create your very first Microservice, you can already monitor it without much effort. As there is no knowledge requirement for additional monitoring applications. This example shows you an easy approach to monitor the Microservice on the platform, but it is more suitable for monitoring a Microservice with single-tenant isolation level. If you want to learn more about monitoring of multiple Microservices or multi-tenant Microservices please check out this [article](https://tech.forums.softwareag.com/t/advanced-cumulocity-iot-microservice-monitoring-part-1/274963).

```
import logging
import sys, os, time
from c8y_api import CumulocityApi
from c8y_api.model import Device, Measurement, Event
import psutil
import queue
import threading
from flask import Flask

logger = logging.getLogger('')
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger.info('Logger was initialized')

c8y = CumulocityApi(
    base_url = os.environ.get('C8Y_BASEURL'),
    tenant_id= os.environ.get('C8Y_TENANT'),
    username = os.environ.get('C8Y_USER'),
    password= os.environ.get('C8Y_PASSWORD')
)

ms_device_name = os.environ.get('APPLICATION_NAME')
device_type = 'service_device'
external_type = 'c8y_ServiceId'
device_id = None

request_count = 0 
task_queue = queue.Queue()

def bootstrapServiceDevice():
    global device_id    
    try:
        logger.info('Finding the device connected to the service')
        device_id = c8y.identity.get_id(external_id=ms_device_name, external_type=external_type)
    except KeyError:
        logger.info('Device not found, creating new device')
        ms_device = Device(c8y,device_type,ms_device_name).create()
        device_id = ms_device.id
        c8y.identity.create(external_id=ms_device_name, external_type=external_type, managed_object_id=device_id)
        logger.info(f'Device created, Device ID: {device_id}')
    except ValueError:
        logger.error('Invalid credentials')
        sys.exit()

def collectMetrics():
    while True:
        num_threads = psutil.Process(os.getpid()).num_threads()
        metrics_dict = {
            'cpu_percent': {},
            'num_threads': {'num_threads': {'value': num_threads}},
            'task_queue_size':{'task_queue_size': {'value': task_queue.qsize()}}
        }
        cpu_num = psutil.Process(os.getpid()).cpu_num()
        cpu_percent = psutil.cpu_percent(interval=1, percpu=True)
        metrics_dict['cpu_percent']['cpu'] = {'value':cpu_percent[cpu_num]}
        if not task_queue.empty():
            task_queue.get()
            metrics_dict.update({'request_count': {'request_count': {'value': request_count}}})
        for key, value in metrics_dict.items():
            exec('Measurement(c8y, type=\'c8y_Monitoring\', source=device_id, {}={}).create()'.format('c8y_'+key,value))
        if task_queue.empty():
            time.sleep(10)

        
app = Flask( __name__ )

@app.route('/')
def add_metrics():
    global request_count
    request_count += 1
    task_queue.put('A new task has been added')
    return "Added new task!"

if __name__ == ' __main__':
    bootstrapServiceDevice()
    Event(c8y, type='service_event', source=device_id, time='now', text='Service started').create()
    t1 = threading.Thread(target=collectMetrics, args=())
    t1.start()
    app.run(host='0.0.0.0', port=80)

```

[Read full topic](https://tech.forums.softwareag.com/t/basic-cumulocity-iot-microservice-monitoring/275424)