Skip to content

Commit dfdc2ae

Browse files
authored
New features for rate limiting (#19)
* Time and Size based rate limit, gzip compression and psutil for system properties * addressed review comment * resonseInterface to responseInterface * updated the testcases * added try-except for json.dumps and introduced constants for size limiting * Addressed comments regarding linting in code using Flake8
1 parent d35dd27 commit dfdc2ae

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+4762
-4592
lines changed

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
# -- Project information -----------------------------------------------------
3030
_version = {}
3131
with open("../../logicmonitor_data_sdk/version.py") as fp:
32-
exec(fp.read(), _version)
32+
exec(fp.read(), _version)
3333

3434
project = 'LogicMonitor DATA SDK Python'
3535
copyright = '2021, Logicmonitor'

example/cpu_metrics.py

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@
1212
import os
1313
import sys
1414
import time
15+
import psutil
1516

16-
import psutil as psutil
17-
18-
sys.path.append("..")
1917
import logicmonitor_data_sdk
20-
from logicmonitor_data_sdk.api.response_interface import ResonseInterface
18+
from logicmonitor_data_sdk.api.response_interface import ResponseInterface
2119
from logicmonitor_data_sdk.models import Resource, DataSource, DataPoint, \
22-
DataSourceInstance
20+
DataSourceInstance
2321

2422
from logicmonitor_data_sdk.api.metrics import Metrics
2523

24+
sys.path.append("..")
2625
logger = logging.getLogger('lmdata.api')
2726
logger.setLevel(logging.INFO)
2827

@@ -31,39 +30,39 @@
3130
configuration.debug = False
3231

3332

34-
class MyResponse(ResonseInterface):
35-
"""
36-
Sample callback to handle the response from the REST endpoints
37-
"""
33+
class MyResponse(ResponseInterface):
34+
"""
35+
Sample callback to handle the response from the REST endpoints
36+
"""
3837

39-
def success_callback(self, request, response, status, request_id):
40-
logger.info("%s: %s: %s", response, status, request_id)
38+
def success_callback(self, request, response, status, request_id):
39+
logger.info("%s: %s: %s", response, status, request_id)
4140

42-
def error_callback(self, request, response, status, request_id, reason):
43-
logger.error("%s: %s: %s %s", response, status, reason, request_id)
41+
def error_callback(self, request, response, status, request_id, reason):
42+
logger.error("%s: %s: %s %s", response, status, reason, request_id)
4443

4544

4645
def MetricRequest():
47-
"""
48-
Main function to get the CPU values using `psutil` and send to Metrics REST endpoint
49-
"""
50-
device_name = os.uname()[1]
51-
resource = Resource(ids={'system.displayname': device_name}, name=device_name,
52-
create=True)
53-
datasource = DataSource(name="CPU")
54-
instance = DataSourceInstance(name='cpu-1')
55-
datapoint = DataPoint(name="cpu_utilization")
56-
metric_api = Metrics(batch=True, interval=10, response_callback=MyResponse())
57-
while True:
58-
values = {str(int(time.time())): str(psutil.cpu_percent())}
46+
"""
47+
Main function to get the CPU values using `psutil` and send to Metrics REST endpoint
48+
"""
49+
device_name = os.uname()[1]
50+
resource = Resource(ids={'system.displayname': device_name}, name=device_name,
51+
create=True)
52+
datasource = DataSource(name="CPU")
53+
instance = DataSourceInstance(name='cpu-1')
54+
datapoint = DataPoint(name="cpu_utilization")
55+
metric_api = Metrics(batch=True, interval=10, response_callback=MyResponse())
56+
while True:
57+
values = {str(int(time.time())): str(psutil.cpu_percent())}
5958

60-
metric_api.send_metrics(resource=resource,
61-
datasource=datasource,
62-
instance=instance,
63-
datapoint=datapoint,
64-
values=values)
65-
time.sleep(10)
59+
metric_api.send_metrics(resource=resource,
60+
datasource=datasource,
61+
instance=instance,
62+
datapoint=datapoint,
63+
values=values)
64+
time.sleep(10)
6665

6766

6867
if __name__ == "__main__":
69-
MetricRequest()
68+
MetricRequest()

example/disk_metrics.py

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
import logicmonitor_data_sdk
1818
from logicmonitor_data_sdk.api.metrics import Metrics
19-
from logicmonitor_data_sdk.api.response_interface import ResonseInterface
19+
from logicmonitor_data_sdk.api.response_interface import ResponseInterface
2020
from logicmonitor_data_sdk.models import Resource, DataSource, DataPoint, \
21-
DataSourceInstance
21+
DataSourceInstance
2222

2323
logger = logging.getLogger('lmdata.api')
2424
logger.setLevel(logging.INFO)
@@ -28,50 +28,50 @@
2828
configuration.debug = False
2929

3030

31-
class MyResponse(ResonseInterface):
32-
"""
33-
Sample callback to handle the response from the REST endpoints
34-
"""
31+
class MyResponse(ResponseInterface):
32+
"""
33+
Sample callback to handle the response from the REST endpoints
34+
"""
3535

36-
def success_callback(self, request, response, status, request_id):
37-
logger.info("%s: %s: %s", response, status, request_id)
36+
def success_callback(self, request, response, status, request_id):
37+
logger.info("%s: %s: %s", response, status, request_id)
3838

39-
def error_callback(self, request, response, status, request_id, reason):
40-
logger.error("%s: %s: %s %s", response, status, reason, request_id)
39+
def error_callback(self, request, response, status, request_id, reason):
40+
logger.error("%s: %s: %s %s", response, status, reason, request_id)
4141

4242

4343
def MetricRequest():
44-
"""
45-
Main function to get the CPU values using `psutil` and send to Metrics REST endpoint
46-
"""
47-
device_name = os.uname()[1]
48-
resource = Resource(ids={'system.displayname': device_name}, name=device_name,
49-
create=True)
50-
datasource = DataSource(name="DiskUsingSDK")
51-
datapoints = ['total', 'used', 'free']
52-
metric_api = Metrics(batch=True, interval=30, response_callback=MyResponse())
53-
while True:
54-
partitions = psutil.disk_partitions()
55-
for p in partitions:
56-
# Using the device as instance name. We can use the mountpoint as well.
44+
"""
45+
Main function to get the CPU values using `psutil` and send to Metrics REST endpoint
46+
"""
47+
device_name = os.uname()[1]
48+
resource = Resource(ids={'system.displayname': device_name}, name=device_name,
49+
create=True)
50+
datasource = DataSource(name="DiskUsingSDK")
51+
datapoints = ['total', 'used', 'free']
52+
metric_api = Metrics(batch=True, interval=30, response_callback=MyResponse())
53+
while True:
54+
partitions = psutil.disk_partitions()
55+
for p in partitions:
56+
# Using the device as instance name. We can use the mountpoint as well.
5757

58-
instance_name = p.device
59-
usage = psutil.disk_usage(instance_name)._asdict()
58+
instance_name = p.device
59+
usage = psutil.disk_usage(instance_name)._asdict()
6060

61-
# Create the instance object for every device. Name should not have the
62-
# special characters so replacing it with the '-'.
63-
instance = DataSourceInstance(name=instance_name.replace('/', '-'),
64-
display_name=instance_name)
65-
for one_datapoint in datapoints:
66-
datapoint = DataPoint(name=one_datapoint)
67-
values = {str(int(time.time())): str(usage[one_datapoint])}
68-
metric_api.send_metrics(resource=resource,
69-
datasource=datasource,
70-
instance=instance,
71-
datapoint=datapoint,
72-
values=values)
73-
time.sleep(5)
61+
# Create the instance object for every device. Name should not have the
62+
# special characters so replacing it with the '-'.
63+
instance = DataSourceInstance(name=instance_name.replace('/', '-'),
64+
display_name=instance_name)
65+
for one_datapoint in datapoints:
66+
datapoint = DataPoint(name=one_datapoint)
67+
values = {str(int(time.time())): str(usage[one_datapoint])}
68+
metric_api.send_metrics(resource=resource,
69+
datasource=datasource,
70+
instance=instance,
71+
datapoint=datapoint,
72+
values=values)
73+
time.sleep(5)
7474

7575

7676
if __name__ == "__main__":
77-
MetricRequest()
77+
MetricRequest()

example/log_non_batch.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,41 @@
99
"""
1010

1111
# Sample Program to send Logs to LogicMonitor Platform
12-
#
13-
import os
1412
import logicmonitor_data_sdk
15-
1613
from logicmonitor_data_sdk.api.logs import Logs
1714
from logicmonitor_data_sdk.models import Resource
15+
from logicmonitor_data_sdk.api.response_interface import ResponseInterface
16+
from example import system_properties
17+
18+
19+
class MyResponse(ResponseInterface):
20+
"""
21+
Sample callback to handle the response from the REST endpoints
22+
"""
23+
24+
def success_callback(self, request, response, status, request_id):
25+
# logging.info("%s: %s: %s", response, status, request_id)
26+
print(response, status, request_id)
27+
28+
def error_callback(self, request, response, status, request_id, reason):
29+
# logging.error("%s: %s: %s %s", response, status, reason, request_id)
30+
print(response, status, reason, request_id)
31+
1832

1933
# Initialize LM SDK and provide required authentication parameters
2034
# On LM Portal, create 'API Token' for the user to get access Id and access Key
21-
configuration = logicmonitor_data_sdk.Configuration( company='your_company',
22-
id='API access id',
23-
key='API access key')
35+
configuration = logicmonitor_data_sdk.Configuration(company='your_company',
36+
id='API access id',
37+
key='API access key')
2438

2539
# The resource which is already present on LM Platform. Use a unique property to match
26-
# the resource and send log for that.
27-
resource = Resource(ids={"system.hostname": 'your_system'})
40+
# the resource and send log for that.
41+
resource = Resource(ids={"system.hostname": 'your_system'}, properties=system_properties.get_system_info())
2842

29-
#Create an api handle for sending the logs
43+
# Create an api handle for sending the logs
3044
# "batch" would club logs for 8MB size or 30 Sec - whichever is earlier. Its default is "True".
31-
log_api = Logs(batch = False)
45+
log_api = Logs(batch=False)
3246

33-
return_value = log_api.send_logs(resource=resource, msg= "this is sample log")
47+
return_value = log_api.send_logs(resource=resource, msg="this is sample log")
3448

3549
print(return_value)

example/simple_example.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,64 +8,63 @@
88
=======
99
"""
1010

11-
import time
12-
from random import seed, random
13-
14-
import logicmonitor_data_sdk
15-
1611
# LogicMonitor metric data model is as below
1712
#
18-
#Company
13+
# Company
1914
# |--- Resource (like device/service. Ex: VM)
2015
# |--- Data Source (Ex. CPU)
2116
# |--- Instance (of a Data Source on a resource. Ex. CPU-1)
2217
# |--- Data Point (the metric which is being monitored. Ex. %Used)
2318
# |- <Time> : <Metric Value>
2419
# |- <Time> : <Metric Value>
2520
# |...
26-
#
21+
import time
22+
from random import random
23+
24+
import logicmonitor_data_sdk
2725
from logicmonitor_data_sdk.api.metrics import Metrics
28-
from logicmonitor_data_sdk.api.response_interface import ResonseInterface
26+
from logicmonitor_data_sdk.api.response_interface import ResponseInterface
2927
from logicmonitor_data_sdk.api_client import ApiClient
30-
from logicmonitor_data_sdk.models import DataSource, \
31-
Resource, DataSourceInstance, DataPoint
28+
from logicmonitor_data_sdk.models import DataSource, Resource, DataSourceInstance, DataPoint
29+
from example import system_properties
3230

3331
# Configure SDK with Account and access information
3432
# On your LogicMonitor portal, create API token (LMv1) for user and get
3533
# Access Id and Access Key
3634
configuration = logicmonitor_data_sdk.Configuration(company='your_company',
3735
id='API_ACCESS_ID',
3836
key='API_ACCESS_KEY')
39-
class MyResponse(ResonseInterface):
37+
38+
39+
class MyResponse(ResponseInterface):
4040
"""
4141
Sample callback to handle the response from the REST endpoints
4242
"""
4343

4444
def success_callback(self, request, response, status, request_id):
45-
#logging.info("%s: %s: %s", response, status, request_id)
45+
# logging.info("%s: %s: %s", response, status, request_id)
4646
print(response, status, request_id)
4747

48-
4948
def error_callback(self, request, response, status, request_id, reason):
50-
#logging.error("%s: %s: %s %s", response, status, reason, request_id)
49+
# logging.error("%s: %s: %s %s", response, status, reason, request_id)
5150
print(response, status, reason, request_id)
5251

5352

5453
# Create api handle for Metrics use case (we also support Logs)
5554
api_client = ApiClient(configuration=configuration)
56-
metric_api = Metrics(batch=False,interval=10,response_callback=MyResponse(),api_client=api_client)
55+
metric_api = Metrics(batch=False, interval=10, response_callback=MyResponse(), api_client=api_client)
5756
return_val = metric_api.send_metrics(
58-
resource=Resource(
59-
ids={"system.hostname": "SampleDevice"}, #Core Properties of the Resource
60-
create=True, #Auto-create resource if does not exist
61-
name="SampleDevice", #Name of the resource
62-
properties={"using.sdk": "true"}), #Additional Properties [Optional]
63-
datasource=DataSource(
64-
name="SampleDS"), #Name of data source is must. Rest optional
65-
instance=DataSourceInstance(
66-
name="SampleInstance"), #Name of instance is must. Rest optional
67-
datapoint=DataPoint(
68-
name="SampleDataPoint"), #The metric
69-
values={str(int(time.time())): str(random())} #Values at specific time(s)
57+
resource=Resource(
58+
ids={"system.hostname": "SampleDevice"}, # Core Properties of the Resource
59+
create=True, # Auto-create resource if does not exist
60+
name="SampleDevice", # Name of the resource
61+
properties=system_properties.get_system_info()), # Additional Properties [Optional]
62+
datasource=DataSource(
63+
name="SampleDS"), # Name of data source is must. Rest optional
64+
instance=DataSourceInstance(
65+
name="SampleInstance"), # Name of instance is must. Rest optional
66+
datapoint=DataPoint(
67+
name="SampleDataPoint"), # The metric
68+
values={str(int(time.time())): str(random())} # Values at specific time(s)
7069
)
71-
print("Return Value = ",return_val)
70+
print("Return Value = ", return_val)

example/system_properties.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import psutil
2+
3+
4+
def sanitize_for_serialization(obj):
5+
dict_obj = {}
6+
fields = obj._fields
7+
for i in fields:
8+
dict_obj[i] = str(obj.__getattribute__(i))
9+
return dict_obj
10+
11+
12+
def get_system_info():
13+
swap_memory = sanitize_for_serialization(psutil.swap_memory())
14+
virtual_memory = sanitize_for_serialization(psutil.virtual_memory())
15+
system = {
16+
"using.sdk": "true",
17+
'boot_time': str(psutil.boot_time()),
18+
'cpu_count': str(psutil.cpu_count()),
19+
'swap_memory_total': swap_memory["total"],
20+
'swap_memory_used': swap_memory["used"],
21+
'swap_memory_free': swap_memory["free"],
22+
'virtual_memory_total': virtual_memory["total"],
23+
'virtual_memory_available': virtual_memory["available"],
24+
'virtual_memory_used': virtual_memory["used"]
25+
}
26+
return system

example/test_property.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
import logging
1212
import sys
1313

14-
sys.path.append("..")
1514
import logicmonitor_data_sdk
1615
from logicmonitor_data_sdk.api.metrics import Metrics
1716

17+
sys.path.append("..")
1818
logger = logging.getLogger('lmdata.api')
1919
logger.setLevel(logging.INFO)
2020

@@ -35,7 +35,7 @@
3535

3636
response = metric_api.update_instance_property(
3737
resource_ids={'system.deviceId': '233267'}, datasource='dsname_1',
38-
instancename='instance_1', instance_properties={
38+
instance_name='instance_1', instance_properties={
3939
'ins.property': 'values'},
4040
)
41-
logger.info(response)
41+
logger.info(response)

0 commit comments

Comments
 (0)