Skip to content

added initial telemetry work #386

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
95bd528
added initial telemetry work
Jul 9, 2021
5430b78
added telemetry queue size
Jul 12, 2021
d7bf70d
added unit tests
Jul 23, 2021
9cc6c8b
fixing problem
Jul 23, 2021
00b76b7
corrected tests
Jul 23, 2021
5f85940
added dependency
Jul 23, 2021
5c831e8
added chardet==3.0.4
Jul 23, 2021
b489291
added idna==2.7
Jul 23, 2021
5b3979f
added mock==3.0.5
Jul 23, 2021
9f5f317
installing more dependencies
Jul 23, 2021
c4267fc
added dependencies
Jul 23, 2021
99988fc
fixed dependencies
Jul 23, 2021
8c126a7
added chardet==3.0.4 idna==2.7 mock==3.0.5
Jul 23, 2021
5e459f7
added dependency to pyramid
Jul 23, 2021
9549e0d
fixing versions
Jul 23, 2021
3336002
fixing dependencies
Jul 23, 2021
f5d9139
fixing dependencies
Jul 23, 2021
7cebc64
fixing mock version
Jul 23, 2021
ab02383
fixing mock version
Jul 23, 2021
b1628cd
fixing mock version
Jul 23, 2021
6a902d7
added mock to TWISTED
Jul 23, 2021
353dba8
added mock
Jul 24, 2021
5a82b30
added mock to starlette
Jul 26, 2021
52a8318
fix tests
Jul 26, 2021
766e10a
corrected tests
Jul 26, 2021
d2bf643
corrected tests
Jul 26, 2021
53132d1
corrected tests
Jul 26, 2021
ec5208f
added mock to TWISTED
Jul 26, 2021
ca9df67
Update rollbar/lib/telemetry.py
pawelsz-rb Aug 4, 2021
9f0d61d
Update rollbar/test/test_telemetry.py
pawelsz-rb Aug 4, 2021
e59e34c
Update rollbar/__init__.py
pawelsz-rb Aug 4, 2021
5797a30
Update rollbar/test/test_telemetry.py
pawelsz-rb Aug 4, 2021
cfafa97
Update rollbar/lib/telemetry.py
pawelsz-rb Aug 4, 2021
0f09f7e
Update rollbar/lib/telemetry.py
pawelsz-rb Aug 4, 2021
16e6a9b
Update rollbar/lib/telemetry.py
pawelsz-rb Aug 4, 2021
070b188
Update rollbar/lib/telemetry.py
pawelsz-rb Aug 4, 2021
b317564
Update rollbar/lib/telemetry.py
pawelsz-rb Aug 4, 2021
88d8da3
Update rollbar/test/test_telemetry.py
pawelsz-rb Aug 4, 2021
1f1d8da
addressing PR comments
Aug 5, 2021
7f57fae
corrected tests
Aug 5, 2021
2e09a11
corrected tests
Aug 5, 2021
1d27b19
addressing PR comments
Aug 5, 2021
2d270df
correcting tests
Aug 5, 2021
5d7c1f9
added support for urllib
Aug 6, 2021
91f8338
added support for httpx
Aug 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 81 additions & 69 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,53 @@ jobs:
matrix:
python-version: [2.7, 3.4, 3.5, 3.6, 3.7, 3.8]
framework:
- FLASK_VERSION=0.10.1 Werkzeug\>=0.7,\<1.0
- FLASK_VERSION=0.11.1 Werkzeug\>=0.7,\<1.0
- FLASK_VERSION=0.12.4 Werkzeug\>=0.7,\<1.0
- FLASK_VERSION=1.0.2
- TWISTED_VERSION=15.5.0 treq==15.1.0 zope.interface==4.1.3
- TWISTED_VERSION=16.1.0 treq==16.12.0 zope.interface==4.1.3
- TWISTED_VERSION=16.2.0 treq==16.12.0 zope.interface==4.1.3
- TWISTED_VERSION=16.3.0 treq==16.12.0 zope.interface==4.2.0
- TWISTED_VERSION=16.4.0 treq==16.12.0 zope.interface==4.5.0
- TWISTED_VERSION=16.5.0 treq==16.12.0 zope.interface==4.5.0
- TWISTED_VERSION=16.6.0 treq==16.12.0 zope.interface==4.5.0
- TWISTED_VERSION=17.1.0 treq==16.12.0 zope.interface==4.5.0
- DJANGO_VERSION=1.11.20
- DJANGO_VERSION=2.0.13
- DJANGO_VERSION=2.1.7
- DJANGO_VERSION=2.1.15
- PYRAMID_VERSION=1.9.2
- PYRAMID_VERSION=1.10.4
- STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5
- STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5
- STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5
- FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5
- FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5
- FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5
- FLASK_VERSION=0.10.1 Werkzeug\>=0.7,\<1.0 chardet==3.0.4 idna==2.7 mock==3.0.5
- FLASK_VERSION=0.11.1 Werkzeug\>=0.7,\<1.0 chardet==3.0.4 idna==2.7 mock==3.0.5
- FLASK_VERSION=0.12.4 Werkzeug\>=0.7,\<1.0 chardet==3.0.4 idna==2.7 mock==3.0.5
- FLASK_VERSION=1.0.2 chardet==3.0.4 idna==2.7 mock==3.0.5
- TWISTED_VERSION=15.5.0 treq==15.1.0 zope.interface==4.1.3 mock==2.0.0
- TWISTED_VERSION=16.1.0 treq==16.12.0 zope.interface==4.1.3 mock==2.0.0
- TWISTED_VERSION=16.2.0 treq==16.12.0 zope.interface==4.1.3 mock==2.0.0
- TWISTED_VERSION=16.3.0 treq==16.12.0 zope.interface==4.2.0 mock==2.0.0
- TWISTED_VERSION=16.4.0 treq==16.12.0 zope.interface==4.5.0 mock==2.0.0
- TWISTED_VERSION=16.5.0 treq==16.12.0 zope.interface==4.5.0 mock==2.0.0
- TWISTED_VERSION=16.6.0 treq==16.12.0 zope.interface==4.5.0 mock==2.0.0
- TWISTED_VERSION=17.1.0 treq==16.12.0 zope.interface==4.5.0 mock==2.0.0
- DJANGO_VERSION=1.11.20 chardet==3.0.4 idna==2.7 mock==3.0.5
- DJANGO_VERSION=2.0.13 mock==2.0.0
- DJANGO_VERSION=2.1.7 mock==2.0.0
- DJANGO_VERSION=2.1.15 mock==2.0.0
- PYRAMID_VERSION=1.9.2 chardet==3.0.4 idna==2.7 mock==3.0.5
- PYRAMID_VERSION=1.10.4 chardet==3.0.4 idna==2.7 mock==3.0.5
- STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
Comment on lines +17 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All Python versions from the matrix except 2.7 have the mock module included in the standard library. We don't need to install it manually.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, but it does not hurt to install it, and just for that I would need to pull 2.7 out of this matrix and have a different definition.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO requiring the installation of unnecessary packages hurts quality.

Our other test suites solve it in this way:

try:
from unittest import mock
except ImportError:
import mock

You should follow the pattern. In my opinion, this PR does not require any changes in the CI builds. The builds failed for a good reason.

The installation of the mock package for Python <3.3 is already implemented:

pyrollbar/setup.py

Lines 20 to 24 in f67253a

tests_require = [
'webob',
'blinker',
'unittest2',
'mock<=3.0.5; python_version < "3.3"',

exclude:
- python-version: 2.7
framework: DJANGO_VERSION=2.0.13
framework: DJANGO_VERSION=2.0.13 mock==2.0.0
- python-version: 2.7
framework: DJANGO_VERSION=2.1.7
framework: DJANGO_VERSION=2.1.7 mock==2.0.0
- python-version: 2.7
framework: DJANGO_VERSION=2.1.15
framework: DJANGO_VERSION=2.1.15 mock==2.0.0
- python-version: 3.4
framework: DJANGO_VERSION=2.1.7
framework: DJANGO_VERSION=2.0.13 mock==2.0.0
- python-version: 3.4
framework: DJANGO_VERSION=2.1.15
framework: DJANGO_VERSION=2.1.7 mock==2.0.0
- python-version: 3.4
framework: DJANGO_VERSION=2.1.15 mock==2.0.0
- python-version: 3.5
framework: DJANGO_VERSION=2.1.15 mock==2.0.0
- python-version: 3.5
framework: DJANGO_VERSION=2.0.13 mock==2.0.0
- python-version: 3.5
framework: DJANGO_VERSION=2.1.15
framework: DJANGO_VERSION=2.1.7 mock==2.0.0
- python-version: 3.6
framework: DJANGO_VERSION=2.1.15
framework: DJANGO_VERSION=2.1.15 mock==2.0.0
- python-version: 3.7
framework: DJANGO_VERSION=2.1.15
framework: DJANGO_VERSION=2.1.15 mock==2.0.0
Comment on lines -43 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a result of the comment above these changes are also not required.


# twisted/treq setup.py allows:
# Twisted < 18.7.0 on python < 3.7
Expand Down Expand Up @@ -95,83 +101,89 @@ jobs:
framework: TWISTED_VERSION=17.1.0 treq==20.4.1 zope.interface==4.3.0

- python-version: 2.7
framework: STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 2.7
framework: STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 2.7
framework: STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.4
framework: STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.4
framework: STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.4
framework: STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.5
framework: STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.12.12 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.5
framework: STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.5
framework: STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5
framework: STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5

- python-version: 2.7
framework: FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 2.7
framework: FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 2.7
framework: FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.4
framework: FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.4
framework: FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.4
framework: FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.5
framework: FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.5
framework: FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
- python-version: 3.5
framework: FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5
framework: FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5 mock==3.0.5
Comment on lines -98 to +139
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

include:
- python-version: 2.7
framework: FLASK_VERSION=0.9
- python-version: 3.3
framework: FLASK_VERSION=0.10.1
framework: FLASK_VERSION=0.10.1 mock==2.0.0
- python-version: 3.3
framework: FLASK_VERSION=0.11.1
framework: FLASK_VERSION=0.11.1 mock==2.0.0
- python-version: 3.3
framework: FLASK_VERSION=0.12.4
framework: FLASK_VERSION=0.12.4 mock==2.0.0
- python-version: 3.3
framework: FLASK_VERSION=1.0.2
framework: FLASK_VERSION=1.0.2 mock==2.0.0
- python-version: 3.3
framework: DJANGO_VERSION=1.6.11
framework: DJANGO_VERSION=1.6.11 mock==2.0.0
- python-version: 3.3
framework: DJANGO_VERSION=1.8.19
framework: DJANGO_VERSION=1.8.19 mock==2.0.0
- python-version: 3.4
framework: DJANGO_VERSION=1.7.11
framework: DJANGO_VERSION=1.7.11 chardet==3.0.4 idna==2.7 mock==3.0.5
- python-version: 3.4
framework: DJANGO_VERSION=1.8.19
framework: DJANGO_VERSION=1.8.19 chardet==3.0.4 idna==2.7 mock==3.0.5
- python-version: 3.4
framework: DJANGO_VERSION=1.9.13
framework: DJANGO_VERSION=1.9.13 chardet==3.0.4 idna==2.7 mock==3.0.5
- python-version: 3.4
framework: DJANGO_VERSION=1.10.8
framework: DJANGO_VERSION=1.10.8 chardet==3.0.4 idna==2.7 mock==3.0.5
- python-version: 3.4
framework: DJANGO_VERSION=2.0.13 chardet==3.0.4 idna==2.7 mock==3.0.5
- python-version: 3.5
framework: DJANGO_VERSION=1.8.19 mock==3.0.5
- python-version: 3.5
framework: DJANGO_VERSION=1.9.13 mock==3.0.5
- python-version: 3.5
framework: DJANGO_VERSION=1.8.19
framework: DJANGO_VERSION=1.10.8 mock==3.0.5
- python-version: 3.5
framework: DJANGO_VERSION=1.9.13
framework: DJANGO_VERSION=2.0.13 mock==3.0.5
- python-version: 3.5
framework: DJANGO_VERSION=1.10.8
framework: DJANGO_VERSION=2.1.7 mock==3.0.5
- python-version: 3.7
framework: TWISTED_VERSION=18.9.0 treq==20.4.1 zope.interface==4.5.0
framework: TWISTED_VERSION=18.9.0 treq==20.4.1 zope.interface==4.5.0 mock==3.0.5
- python-version: 3.7
framework: TWISTED_VERSION=19.10.0 treq==20.4.1 zope.interface==4.6.0
framework: TWISTED_VERSION=19.10.0 treq==20.4.1 zope.interface==4.6.0 mock==3.0.5
- python-version: 3.7
framework: TWISTED_VERSION=20.3.0 treq==20.4.1 zope.interface==4.7.0
framework: TWISTED_VERSION=20.3.0 treq==20.4.1 zope.interface==4.7.0 mock==3.0.5
- python-version: 3.8
framework: TWISTED_VERSION=18.9.0 treq==20.4.1 zope.interface==4.5.0
framework: TWISTED_VERSION=18.9.0 treq==20.4.1 zope.interface==4.5.0 mock==3.0.5
- python-version: 3.8
framework: TWISTED_VERSION=19.10.0 treq==20.4.1 zope.interface==4.6.0
framework: TWISTED_VERSION=19.10.0 treq==20.4.1 zope.interface==4.6.0 mock==3.0.5
- python-version: 3.8
framework: TWISTED_VERSION=20.3.0 treq==20.4.1 zope.interface==4.7.0
framework: TWISTED_VERSION=20.3.0 treq==20.4.1 zope.interface==4.7.0 mock==3.0.5
Comment on lines -138 to +186
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 3.3+ includes the mock module. I don't think it is necessary.

steps:
- uses: actions/checkout@v2
with:
Expand Down
30 changes: 27 additions & 3 deletions rollbar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import socket
import sys
import threading
import time
import traceback
import types
import uuid
Expand All @@ -20,7 +19,8 @@
import requests
import six

from rollbar.lib import events, filters, dict_merge, parse_qs, text, transport, urljoin, iteritems, defaultJSONEncode
from collections import deque
from rollbar.lib import events, filters, dict_merge, parse_qs, telemetry, text, transport, urljoin, iteritems, defaultJSONEncode, get_current_timestamp


__version__ = '0.16.1'
Expand Down Expand Up @@ -322,8 +322,12 @@ def _get_fastapi_request():
'request_pool_connections': None,
'request_pool_maxsize': None,
'request_max_retries': None,
'telemetry_queue_size': 50,
}


TELEMETRY_QUEUE = deque([], SETTINGS['telemetry_queue_size'])

_CURRENT_LAMBDA_CONTEXT = None
_LAST_RESPONSE_STATUS = None

Expand Down Expand Up @@ -381,6 +385,18 @@ def init(access_token, environment='production', scrub_fields=None, url_fields=N
if SETTINGS.get('allow_logging_basic_config'):
logging.basicConfig()

queue_size = SETTINGS.get('telemetry_queue_size')
if queue_size:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is buggy. You use the value as a number in other parts of the code but the value pulled from SETTINGS['set_custom_queue_size'] may be passed as a string like "0" that would raise exception later or the condition's result can be incorrect.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine. We have more settings that accept a number. Not sure why you would want to pass a string when it expects a number.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python does not support strong typing, and you can't assume a source of the configuration data for the SDKs. It's common to read configuration settings from a serialized text file or even from a keyboard.
So there can be many cases where the value can be of type string and lead to the bug.

We have more settings that accept a number.

I am not against accepting numbers but the context of use. If you noticed any other settings that can lead to any bug, you can fix them by the way.

TELEMETRY_QUEUE = deque([], queue_size)

if SETTINGS.get('log_telemetry'):
formatter = SETTINGS.get('log_telemetry_formatter')
telemetry.enable_log_telemetry(formatter)
if SETTINGS.get('network_telemetry'):
enable_req_headers = SETTINGS.get('enable_req_headers')
enable_resp_headers = SETTINGS.get('enable_resp_headers')
telemetry.enable_network_telemetry(enable_req_headers, enable_resp_headers)

if SETTINGS.get('handler') == 'agent':
agent_log = _create_agent_log()

Expand Down Expand Up @@ -777,6 +793,7 @@ def _report_exc_info(exc_info, request, extra_data, payload_data, level=None):
_add_request_data(data, request)
_add_person_data(data, request)
_add_lambda_context_data(data)
_add_telemetry(data)
data['server'] = _build_server_data()

if payload_data:
Expand Down Expand Up @@ -857,6 +874,7 @@ def _report_message(message, level, request, extra_data, payload_data):
_add_request_data(data, request)
_add_person_data(data, request)
_add_lambda_context_data(data)
_add_telemetry(data)
data['server'] = _build_server_data()

if payload_data:
Expand Down Expand Up @@ -887,7 +905,7 @@ def _check_config():

def _build_base_data(request, level='error'):
data = {
'timestamp': int(time.time()),
'timestamp': get_current_timestamp(),
'environment': SETTINGS['environment'],
'level': level,
'language': 'python %s' % '.'.join(str(x) for x in sys.version_info[:3]),
Expand Down Expand Up @@ -1119,6 +1137,12 @@ def _add_request_data(data, request):
data['request'] = request_data


def _add_telemetry(data):
telemetry_data = list(TELEMETRY_QUEUE)
if telemetry_data:
data['body']['telemetry'] = telemetry_data


def _check_add_locals(frame, frame_num, total_frames):
"""
Returns True if we should record local variables for the given frame.
Expand Down
6 changes: 5 additions & 1 deletion rollbar/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import sys
from array import array
import json
import time

try:
# Python 3
Expand Down Expand Up @@ -229,3 +229,7 @@ def defaultJSONEncode(o):
o._setup()
return o._wrapped
return repr(o) + " is not JSON serializable"


def get_current_timestamp():
return int(time.time())
Loading