Giter Site home page Giter Site logo

idealista / prom2teams Goto Github PK

View Code? Open in Web Editor NEW
262.0 29.0 84.0 701 KB

prom2teams is an HTTP server built with Python that receives alert notifications from a previously configured Prometheus Alertmanager instance and forwards it to Microsoft Teams using defined connectors

License: Apache License 2.0

Python 73.93% Shell 15.51% Dockerfile 2.44% Mustache 2.27% Jinja 5.85%
prometheus webhook microsoft-teams alerting prom2teams prometheus-alertmanager monitoring docker devops alertmanager

prom2teams's Introduction

logo

Build Status Quality Gate Status Docker Build Status Docker Hub Pulls

prom2teams: Prometheus Alertmanager/Microsoft Teams integration

Alert example

prom2teams is a service built with Python that receives alert notifications from a previously configured Prometheus Alertmanager instance and forwards it to Microsoft Teams using defined connectors.

It presents grouping of alerts, labels/annotations exclusion and a Teams' alert retry policy among its key features.

Getting Started

Prerequisites

The application has been tested with Prometheus 2.2.1, Python 3.8.0 and pip 9.0.1.

Newer versions of Prometheus/Python/pip should work but could also present issues.

Installing

prom2teams is present on PyPI, so could be installed using pip3:

$ pip3 install prom2teams

Note: Works since v1.1.1

Usage

Important: Config path must be provided with at least one Microsoft Teams Connector. Check the options to know how you can supply it.

# To start the server (enable metrics, config file path , group alerts by, log file path, log level and Jinja2 template path are optional arguments):
$ prom2teams [--enablemetrics] [--configpath <config file path>] [--groupalertsby ("name"|"description"|"instance"|"severity"|"summary")] [--logfilepath <log file path>] [--loglevel (DEBUG|INFO|WARNING|ERROR|CRITICAL)] [--templatepath <Jinja2 template file path>]

# To show the help message:
$ prom2teams --help

Other options to start the service are:

export APP_CONFIG_FILE=<config file path>
$ prom2teams

Note: Grouping alerts works since v2.2.1

Docker image

Every new Prom2teams release, a new Docker image is built in our Dockerhub. We strongly recommend you to use the images with the version tag, though it will be possible to use them without it.

There are two things you need to bear in mind when creating a Prom2teams container:

  • The connector URL must be passed as the environment variable PROM2TEAMS_CONNECTOR
  • In case you want to group alerts, you need to pass the field as the environment variable PROM2TEAMS_GROUP_ALERTS_BY
  • You need to map container's Prom2teams port to one on your host.

So a sample Docker run command would be:

$ docker run -it -d -e PROM2TEAMS_GROUP_ALERTS_BY=FIELD_YOU_WANT_TO_GROUP_BY -e PROM2TEAMS_CONNECTOR="CONNECTOR_URL" -p 8089:8089 idealista/prom2teams:VERSION

Provide custom config file

If you prefer to use your own config file, you just need to provide it as a Docker volume to the container and map it to /opt/prom2teams/config.ini. Sample:

$ docker run -it -d -v pathToTheLocalConfigFile:/opt/prom2teams/config.ini -p 8089:8089 idealista/prom2teams:VERSION

Helm chart

Installing the Chart

To install the chart with the release name my-release run:

$ helm install --name my-release /location/of/prom2teams_ROOT/helm

After a few seconds, Prom2Teams should be running.

Tip: List all releases using helm list, a release is a name used to track a specific deployment

Uninstalling the Chart

To uninstall/delete the my-release deployment:

Helm 2
$ helm delete my-release

Tip: Use helm delete --purge my-release to completely remove the release from Helm internal storage

The command removes all the Kubernetes components associated with the chart and deletes the release.

Helm 3
$ helm uninstall my-release

The command removes all the Kubernetes components associated with the chart and deletes the release.

Configuration

The following table lists the configurable parameters of the Prom2teams chart and their default values.

Parameter Description Default
image.repository The image repository to pull from idealista/prom2teams
image.tag The image tag to pull <empty>
image.pullPolicy The image pull policy IfNotPresent
resources.requests.cpu CPU requested for being run in a node 100m
resources.requests.memory Memory requested for being run in a node 128Mi
resources.limits.cpu CPU limit 200m
resources.limits.memory Memory limit 200Mi
service.type Service Map (NodePort/ClusterIP) ClusterIP
service.port Service Port 8089
prom2teams.host IP to bind to 0.0.0.0
prom2teams.port Port to bind to 8089
prom2teams.connector Connector URL <empty>
prom2teams.connectors A map where the keys are the connector names and the values are the connector webhook urls {}
prom2teams.group_alerts_by Group_alerts_by field <empty>
prom2teams.loglevel Loglevel INFO
prom2teams.templatepath Custom Template path (files/teams.j2) /opt/prom2teams/helmconfig/teams.j2
prom2teams.config Config (specific to Helm) /opt/prom2teams/helmconfig/config.ini
prom2teams.extraEnv Dictionary of arbitrary additional environment variables for deployment (eg. HTTP_PROXY) <empty>

Production

For production environments you should prefer using a WSGI server. uWSGI dependency is installed for an easy usage. Some considerations must be taken to use it:

The binary prom2teams_uwsgi launches the app using the uwsgi server. Due to some incompatibilities with wheel you must install prom2teams using sudo pip install --no-binary :all: prom2teams (pypa/wheel#92)

$ prom2teams_uwsgi <path to uwsgi ini config>

And uwsgi would look like:

[uwsgi]
master = true
processes = 5
#socket = 0.0.0.0:8001
#protocol = http
socket = /tmp/prom2teams.sock
chmod-socket = 777
vacuum = true
env = APP_ENVIRONMENT=pro
env = APP_CONFIG_FILE=/etc/default/prom2teams.ini

Consider not provide chdir property neither module property.

Also you can set the module file, by doing a symbolic link: sudo mkdir -p /usr/local/etc/prom2teams/ && sudo ln -sf /usr/local/lib/python3.7/dist-packages/usr/local/etc/prom2teams/wsgi.py /usr/local/etc/prom2teams/wsgi.py (check your dist-packages folder)

Another approach is to provide yourself the module file module example and the bin uwsgi call uwsgi example

Note: default log level is DEBUG. Messages are redirected to stdout. To enable file log, set the env APP_ENVIRONMENT=(pro|pre)

Config file

The config file is an INI file and should have the structure described below:

[Microsoft Teams]
# At least one connector is required here
Connector: <webhook url>
AnotherConnector: <webhook url>   
...

[HTTP Server]
Host: <host ip> # default: localhost
Port: <host port> # default: 8089

[Log]
Level: <loglevel (DEBUG|INFO|WARNING|ERROR|CRITICAL)> # default: DEBUG
Path: <log file path>  # default: /var/log/prom2teams/prom2teams.log

[Template]
Path: <Jinja2 template path> # default: app resources default template (./prom2teams/resources/templates/teams.j2)

[Group Alerts]
Field: <Field to group alerts by> # alerts won't be grouped by default

[Labels]
Excluded: <Comma separated list of labels to ignore>

[Annotations]
Excluded: <Comma separated list of annotations to ignore>

[Teams Client]
RequestTimeout: <Configures the request timeout> # defaults to 30 secs
RetryEnable: <Enables teams client retry policy> # defaults to false
RetryWaitTime: <Wait time between retries> # default: 60 secs
MaxPayload: <Teams client payload limit in bytes> # default: 24KB

Note: Grouping alerts works since v2.2.0

Configuring Prometheus

The webhook receiver in Prometheus allows configuring a prom2teams server.

The url is formed by the host and port defined in the previous step.

Note: In order to keep compatibility with previous versions, v2.0 keep attending the default connector ("Connector") in the endpoint 0.0.0.0:8089. This will be removed in future versions.

// The prom2teams endpoint to send HTTP POST requests to.
url: 0.0.0.0:8089/v2/<Connector1>

Prom2teams Prometheus metrics

Prom2teams uses Flask and, to have the service monitored, we use @rycus66's Prometheus Flask Exporter. This will enable an endpoint in /metrics where you could find interesting metrics to monitor such as number of responses with a certain status. To enable this endpoint, just either:

  • Use the --enablemetrics or -m flag when launching prom2teams.
  • Set the environment variable PROM2TEAMS_PROMETHEUS_METRICS=true.

Templating

prom2teams provides a default template built with Jinja2 to render messages in Microsoft Teams. This template could be overrided using the 'templatepath' argument ('--templatepath ') during the application start.

Some fields are considered mandatory when received from Alert Manager. If such a field is not included a default value of 'unknown' is assigned.

All non-mandatory labels not in excluded list are injected in extra_labels key. All non-mandatory annotations not in excluded list are injected in extra_annotations key.

Alertmanager fingerprints are available in the fingerprint key. Fingerprints are supported by Alertmanager 0.19.0 or greater.

Documentation

Swagger UI

Accessing to <Host>:<Port> (e.g. localhost:8089) in a web browser shows the API v1 documentation.

Swagger UI

Accessing to <Host>:<Port>/v2 (e.g. localhost:8089/v2) in a web browser shows the API v2 documentation.

Swagger UI

Testing

To run the test suite you should type the following:

// After cloning prom2teams :)
$ pip install -r requirements.txt
$ python3 -m unittest discover tests
$ cd tests/e2e
$ ./test.sh

Built With

Python 3.8.0 pip 9.0.1

Versioning

For the versions available, see the tags on this repository.

Additionaly you can see what change in each version in the CHANGELOG.md file.

Authors

See also the list of contributors who participated in this project.

License

Apache 2.0 License

This project is licensed under the Apache 2.0 license - see the LICENSE file for details.

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

prom2teams's People

Contributors

aaron-ml avatar alexdcraig avatar blalop avatar caldito avatar dependabot[bot] avatar dkobras avatar dortegau avatar gjermy avatar gkrlo avatar jboclara avatar jdvr avatar jmonterrubio avatar jperera avatar krmichel avatar lazybisa avatar lindhor avatar maglo avatar manuhortet avatar marcelogalmor avatar mdelagrange avatar miguel-chacon avatar nryabkov avatar nvx avatar ommarmol avatar pierrediancourt avatar santi-eidu avatar smartinsempere avatar sorobon avatar srl295 avatar vicsufer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

prom2teams's Issues

Some JSON alerts attributes should be optional

In the current version, the following values are parsed and returned in order to create the Teams message:

'alert_name': json_alerts_labels_attr['alertname'],
'alert_instance': json_alerts_labels_attr['instance'],
'alert_severity': json_alerts_labels_attr['severity'],
'alert_summary': json_alerts_annotations_attr['summary'],
'alert_description': json_alerts_annotations_attr['description'],
'alert_status': json_alerts_attr['status']

Problem is that, depending on the query and/or the alarm rule, instance, summary or description could not be sent by Prometheus. In case this happens, prom2teams fails to parser the input and won't forward the alarm to Microsoft Teams.

Check the Teams's response "text" attribute ='1' for validating a message was sent correctly.

Prerequisites

Description

[Description of the issue]
Teams's "status_code" is always 200 even if the request failed. Checking the text attribute "= 1" ensure that the request was correctly sent.

Versions

All

Log filename cannot be provided

Logging config cannot be overriden and should be for define the location of 'debug.log' and other things like logrotate, etc.

Alerts with reserved JSON strings in tags result in MicrosoftTeamsRequestException

Prerequisites

Description

Prometheus Alert Rules which contains JSON-restricted chars in the descritption and/or summary annotations aren't sent successfully to the Teams webhook, because the JSON body in the POST request is invalid.

Example debug log:

2018-12-13 11:55:00,500 - prom2teams - DEBUG - The message that will be sent is: {
    "@type": "MessageCard",
    "@context": "http://schema.org/extensions",
    "themeColor": " FF9A0B ",
    "summary": "Apache SSL Certitficate "/path/to/my/certificate.crt" is going to expire soon",
    "title": "Prometheus alarm ",
    "sections": [{
        "activityTitle": "Apache SSL Certitficate "/path/to/my/certificate.crt" is going to expire soon",
        "facts": [{
            "name": "Alarm",
            "value": "Apache_SSL_Certificate_Expiring_60d"
        },{
            "name": "In host",
            "value": "web-server"
        },{
            "name": "Severity",
            "value": "warning"
        },{
            "name": "Description",
            "value": "The Apache SSL Certitficate "/path/to/my/certificate.crt" in web-server will expire in less than 60 days"
        },{
            "name": "Status",
            "value": "firing"
        }],
           "markdown": true
    }]
}
[2018-12-13 11:55:00,518] ERROR in app: Exception on /v2/Connector [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.6/site-packages/flask_restplus/api.py", line 557, in error_router
    return original_handler(e)
  File "/usr/local/lib/python3.6/site-packages/flask_restplus/api.py", line 557, in error_router
    return original_handler(e)
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.6/site-packages/flask_restplus/api.py", line 313, in wrapper
    resp = resource(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/flask/views.py", line 84, in view
    return self.dispatch_request(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/flask_restplus/resource.py", line 44, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/prom2teams/app/versions/v2/namespace.py", line 27, in post
    self.sender.send_alarms(alerts, app.config['MICROSOFT_TEAMS'][connector])
  File "/usr/local/lib/python3.6/site-packages/prom2teams/app/sender.py", line 26, in send_alarms
    post(teams_webhook_url, team_alarm)
  File "/usr/local/lib/python3.6/site-packages/prom2teams/app/teams_client.py", line 17, in post
    str(response.text)))
prom2teams.app.exceptions.MicrosoftTeamsRequestException: Error performing request to: https://outlook.office.com/webhook/XYZ/IncomingWebhook/XYZ/XYZ. Returned status code: 400. Returned data: Bad payload received by generic incoming webhook.
2018-12-13 11:55:00,518 - werkzeug - INFO - 172.17.0.1 - - [13/Dec/2018 11:55:00] "POST /v2/Connector HTTP/1.1" 500 -

My Prometheus Alert rule configuration:

groups:
- name: sslcert_rules
  rules:
  - alert: Apache_SSL_Certificate_Expiring_60d
    expr: round(((apache_certificate_expire_time - time()) / 60 / 60 / 24 )) < 60
    for: 5m
    labels:
      severity: warning
    annotations:
      description: The Apache SSL Certitficate "{{ $labels.certificate_path }}" in {{ $labels.instance }} will expire in less than 60 days
      summary: Apache SSL Certitficate "{{ $labels.certificate_path }}" is going to expire soon

Steps to Reproduce

  1. Create a test Alert Rule in Prometheus using the " char in the annotations text
  2. Route the alert in Alertmanager to Prom2Teams endpoint
  3. Force the alert trigger while checking the DEBUG logs

Expected behavior: The JSON Payload sent to Teams Webhook is properly escaped when there are JSON-restricted strings

Actual behavior: Alerts which have JSON-restricted chars in the annotations fails while trying to be posted to the Teams Webhook

Reproduces how often: 100%

Versions

Tested with v2.0.4 and v2.2.3, using the official Docker images

Additional Information

It seems to me that the issue is somewhere between the TemplateComposer() and marshmallow's serialization to JSON, but I wasn't able to fix it properly in my local env. I would appreciate some help in how to address it, and thus send a PR.

Add "Resolved" to activity title

Prerequisites

Description

In the mobile apps, there's no difference between an alert notification and the resolved notification of the alert itself so it could be a bit confusing. Having "Resolved" in the activity title will let the user know if the notification is for a new alert or for a resolved one.

Versions

All.

Additional Information

This is the file to be modified:

"activityTitle": "{{ msg_text.summary }}",

[Question] Use of custom alert labels in template

Prerequisites

Description

I am using prom2teams in Kubernetes, and would like to add additional metadata to the message in teams - things like namespace, pod, etc... All of these are values on the alert when viewed in prometheus or in alertmanager.

I've created and configured a template to use with prom2teams, but I'm not able to figure out how to use any "custom" labels on the alerts. Is this possible? Looking at this line of code it appears that the template may be limited to some default labels/meta-data on the alert. Is there any way to access all the labels on the alert? I couldn't find any examples of this, and couldn't get it working by trial and error.

Here's a screenshot of an example alert I'd like to leverage the labels on.

Docker image creation

Prerequisites

Description

Automated docker image builds are failing in ๐Ÿ’ฉ DockerHub ๐Ÿ’ฉ
Delegate this task to travis
[Description of the issue]

Steps to Reproduce

  1. [First Step]
  2. [Second Step]
  3. [and so on...]

Expected behavior: [What you expect to happen]
Completely automated docker images release
Actual behavior: [What actually happens]
Prone to error
Reproduces how often: [What percentage of the time does it reproduce?]

Versions

v2.3.1

Additional Information

Any additional information, configuration or data that might be necessary to reproduce the issue.

[Question]Is that possible to reload config without restarting prom2teams?

Prerequisites

Description

We are trying to run prom2teams in kubernetes. I go through the code and it seems that restarting prom2teams is the only way to reload the configuration. It is not easy to add new teams/connectors. Like alertmanager and prometheus, they will reload the config file via API calls without restarting the app. If prom2teams have similar feature, it would be great help for using it in kubernetes.

prom2teams could go on diet...

Prerequisites

Description

There are some things that could be improved:

  • We could use Alpine Linux instead of Debian
  • build-essential is not needed, the image only needs gcc
  • We should remove cache after needed packages installation
  • We could add a Docker ignore to ignore some files not needed in the context
  • As multiple ADD commands are executed, this creates a multilayer that could be improved using a single COPY command.

Additional Information

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

Allow to be installed under Python 3.5.x

Debian doesn't have Python 3.6.0 in its stable repositories.

Instead to install this version in Debian, we could allow to install under Python 3.5.x which is currently the default version

ValidationError for startsAt and endsAt fields

Prerequisites

Description

promt2teams is trowing the exception bellow after receiving a valid alert from alertmanager:

2019-06-06 13:53:17,619 - flask.app - ERROR - Exception on /v2/ToolsSquadTestes [POST]
Traceback (most recent call last):
...
  File "/usr/local/lib/python3.6/site-packages/prom2teams/app/versions/v2/namespace.py", line 26, in post
    alerts = self.schema.load(request.get_json())
  File "/usr/local/lib/python3.6/site-packages/marshmallow/schema.py", line 707, in load
    postprocess=True,
  File "/usr/local/lib/python3.6/site-packages/marshmallow/schema.py", line 867, in _do_load
    raise exc
marshmallow.exceptions.ValidationError: {'alerts': {0: {'endsAt': ['Not a valid date.'], 'startsAt': ['Not a valid date.']}}}

Steps to Reproduce

1 - Alertmanager sends an alert including valid RFC3339 dates. But the format does not conform with the validation message_schema.py:

Excerpt of a sample alert:

{
...
      "startsAt": "2019-06-05T16:22:28.29468897Z",
      "endsAt": "0001-01-01T00:00:00Z",
...
}

message_schema.py defines those fields as:

startsAt = fields.Date('%Y-%m-%dT%H:%M:%S.%fZ')
endsAt = fields.Date('%Y-%m-%dT%H:%M:%S.%fZ')

The problem here is the use of %f for the second fraction. This limits the fraction to microsseconds. But higher precision is valid in RFC3339. It also rejects valid dates that do not have the fractions.

A quickfix is to change the fields to:

startsAt = fields.DateTime()
endsAt = fields.DateTime()

But this will accept other date formats too.

Expected behavior: prom2teams shoud accept any RFC3339 valid format for startsAt and endsAt

Actual behavior: prom2teams is trowing an exception when the second fraction is higher precision than microseconds or when there is no second fraction.

Reproduces how often: Every time one of startsAt and endsAt contains a higher precision fractions for seconds or does not contains the fractions.

Versions

python 3.6.8
alertmanager 0.17.0
prometheus 2.10.0
prom2teams 2.3.1 (installed via pip)
marshmallow 3.0.0rc6 (installed via pip as prom2teams dependecy)

Microsoft Teams endpoint returned HTTP error 429

Description

Alertmanager sends some alerts and prom2teams tries to forward them to MS-Teams.
But after some successfully forwarded messages to the MS-Teams service it replies with http status code 429.

2019-09-04 06:34:11,948 - flask.app - ERROR - Exception on /v2/Connector [POST]
Traceback (most recent call last):
File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/api.py", line 583, in error_router
return original_handler(e)
File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/api.py", line 583, in error_router
return original_handler(e)
File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/_compat.py", line 35, in reraise
raise value
File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1799, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/api.py", line 325, in wrapper
resp = resource(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/views.py", line 88, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python3.5/site-packages/prom2teams-2.4.0-py3.5.egg/prom2teams/app/versions/v2/namespace.py", line 27, in post
self.sender.send_alarms(alerts, app.config['MICROSOFT_TEAMS'][connector])
File "/usr/local/lib/python3.5/site-packages/prom2teams-2.4.0-py3.5.egg/prom2teams/app/sender.py", line 30, in send_alarms
post(teams_webhook_url, team_alarm)
File "/usr/local/lib/python3.5/site-packages/prom2teams-2.4.0-py3.5.egg/prom2teams/app/teams_client.py", line 17, in post
str(response.text)))

prom2teams.app.exceptions.MicrosoftTeamsRequestException: Error performing request to: https://outlook.office.com/webhook/**********. Returned status code: 200. Returned data: Webhook message delivery failed with error: Microsoft Teams endpoint returned HTTP error 429 with ContextId tcid=7728202280260441716,server=AM3PEPF00000A5B,cv=t2bhHDB4DEie8pMbHqcw8w.0.

the prometheus alertmanager gets back http status code 500

level=error ts=2019-09-04T03:31:08.009985306Z caller=dispatch.go:280 component=dispatcher msg="Notify for alerts failed" num_alerts=42 err="unexpected status code 500 from http://prom2teams-service:8089/v2/Connector"

and tries so resend after a short timeout...this triggers the error again and again....

The major problem: the first alerts are come thru MS-Teams (can see them in the channel). But with http return code 500 to alertmanager it tries to resend all 42 alerts....we got >500 alerts message last night from 42 real alerts. Only restarting alertmanager stopped these endless loop.

the status code 429 from teams should be handled carefully (send slower...).

Versions

2.4.0

marshmallow.exceptions.ValidationError

Prerequisites

Description

Getting marshmallow.exceptions.ValidationError when trying to post to the prom2teams V2 api on
curl http://localhost:8089/

Steps to Reproduce

curl http://localhost:8089/v2/prometheus-tool-dev -H "Content-Type: application/json" -v --data '

{
"@type": "Test Type",
"summary": "Test Summary",
"title": "Test Title"
}
'

  1. Response

  • Hostname was NOT found in DNS cache
  • Trying localhost...
  • Connected to localhost (localhost) port 8089 (#0)

POST /v2/prometheus-tool-dev HTTP/1.1
User-Agent: curl/7.39.0
Host: localhost:8089
Accept: /
Content-Type: application/json
Content-Length: 83

  • upload completely sent off: 83 out of 83 bytes
  • HTTP 1.0, assume close after body
    < HTTP/1.0 500 INTERNAL SERVER ERROR
    < Content-Type: text/html
    < Content-Length: 291
    < Server: Werkzeug/0.14.1 Python/3.5.2
    < Date: Mon, 14 Jan 2019 08:39:10 GMT
    <
<title>500 Internal Server Error</title>

Internal Server Error

The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

* Closing connection 0 -------------------------
  1. Entries in the logs

2019-01-14 08:39:10,688 - flask.app - ERROR - Exception on /v2/prometheus-tool-dev [POST]
Traceback (most recent call last):
File "/home/azureuser/.local/lib/python3.5/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/home/azureuser/.local/lib/python3.5/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.5/dist-packages/flask_restplus/api.py", line 558, in error_router
return original_handler(e)
File "/usr/local/lib/python3.5/dist-packages/flask_restplus/api.py", line 558, in error_router
return original_handler(e)
File "/home/azureuser/.local/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/azureuser/.local/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/home/azureuser/.local/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/home/azureuser/.local/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/lib/python3.5/dist-packages/flask_restplus/api.py", line 314, in wrapper
resp = resource(*args, **kwargs)
File "/home/azureuser/.local/lib/python3.5/site-packages/flask/views.py", line 88, in view
return self.dispatch_request(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/flask_restplus/resource.py", line 44, in dispatch_request
resp = meth(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/prom2teams/app/versions/v2/namespace.py", line 26, in post
alerts = self.schema.load(request.get_json())
File "/usr/local/lib/python3.5/dist-packages/marshmallow/schema.py", line 529, in load
postprocess=True,
File "/usr/local/lib/python3.5/dist-packages/marshmallow/schema.py", line 682, in _do_load
raise exc
marshmallow.exceptions.ValidationError: {'title': ['Unknown field.'], 'summary': ['Unknown field.'], '@type': ['Unknown field.']}
2019-01-14 08:39:10,689 - werkzeug - INFO - 172.18.37.14 - - [14/Jan/2019 08:39:10] "POST /v2/prometheus-tool-dev HTTP/1.1" 500 -

Expected behavior: I should be able to get 200 response

Actual behavior: Getting error response as 500

Reproduces how often: Everytime. New imolementation

Versions

Latest

Additional Information

Please see the above logs which i pasted for more information

Allow Docker container to accept config file

Prerequisites

Description

I'm using prom2teams in a docker container, and finding the environment variable config approach to be a little difficult to use and limits the user to one connector. A typical pattern I've followed in the past with Prometheus, Alertmanager and several other utilities is to mount the config via a docker volume.

I propose removing the existing environment variables and other docker-specific workflow items in favor of a more standard approach using docker volumes. This would have several advantages:

  • Allow multiple connector definitions
  • Consistent behavior and config patterns across all platforms

Default values aren't preserved in config.ini file

If the default config.ini file is overridden but some predefined values are not, these predefined values are not preserved.

e.g:

# If I provide a config.ini file with the HTTP Server section intentionally undefined
[Microsoft Teams]
Connector: <conector_url>

The server raises an KeyError exception trying to read the keys defined under the [HTTP Server] section, even if are defined in the default config.ini file.

Add ExtraAnnotations field extraction

Prerequisites

Description

Currently using prometheus-operator and it comes with a ton of useful prometheus rules, a lot of them include message and runbook_url fields as annotations in the rule definition. Is there any way of extracting this like we do with the extra_labels field?

Benefits

A more flexible template

Possible Drawbacks

None

Version 2.20 does not work

Description

Version 2.2.0 neither works installed through pip nor inside Docker image.

Steps to Reproduce

For the three problems:
Every check was done just by sending a message stored in
https://github.com/idealista/prom2teams/blob/master/tests/data/jsons/all_ok.json to POST /v2/Connector

  1. Docker image (installed version is 2.1.2)

  2. Installed through PIP fails for two reasons:

    • typo in AlertReceiver -> app.config('GROUP_ALERTS') instead of app.config['GROUP_ALERTS_BY']
    • once typo is fixed message cannot be sent to any Teams channel. Due to lack of adapters in config.

    The same config worked for Docker Image 2.2.1. The config is enclosed.

Expected behavior:
To send notifications.

Actual behavior:
Exception: requests.exceptions.InvalidSchema: No connection adapters were found for '<Section: Microsoft Teams>'. See the attached log file for the stack.

Reproduces how often:
100 % of calls

Version

2.2.0

Config and logs: prom2teams.zip

Support alerts with missing mandatory attributes

Prerequisites

Description

prom2teams should be able to handle incoming messages no matter what attributes are received. For missing attributes that are required in the output, default values should be assigned.

alertname='unknown'
status='firing'
instance='unknown'
summary='no alert summary specified'

The current list of mandatory attributes is too strict, since it for example includes instance which is not always sent.

Steps to Reproduce

Create an absent rule like IF absent(container_cpu_load_average_10s{name='mycriticalcontainer}) (cAdvisor) and the alert sent will not include the attribute instance

Expected behavior:

The alert should be sent with the available attributes filled out.

Actual behavior:

The alert from prom2teams to MS Teams will say Incorrect JSON received. At least one mandatory field (instance) is absent.

Reproduces how often:

All the time.

Versions

1.1.3

Additional Information

prom2teams-config.ini is not working with [Group Alerts]

prom2teams latest version.

prom2teams-config.ini ๐Ÿ‘

[Microsoft Teams]
# At least one connector is required here
Connector: MYURL

[HTTP Server]
Host: 0.0.0.0
Port: 8089
Name: 0.0.0.0:8089

[Group Alerts]
Field: "alertname"

prom2teams.stdout.log:

description': 'The `redis_exporter` at `10.233.171.199:9121` was unable to scrape metrics during the last 10m'}}], 'groupKey': '{}/{severity="critical"}:{alertname="RedisExporterScrapeError"}'}
2019-05-07 06:53:08,454 - flask.app - ERROR - Exception on /v2/Connector [POST]
Traceback (most recent call last):
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask_restplus/api.py", line 557, in error_router
    return original_handler(e)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask_restplus/api.py", line 557, in error_router
    return original_handler(e)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask_restplus/api.py", line 313, in wrapper
    resp = resource(*args, **kwargs)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask/views.py", line 88, in view
    return self.dispatch_request(*args, **kwargs)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/flask_restplus/resource.py", line 44, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/prom2teams/app/versions/v2/namespace.py", line 27, in post
    self.sender.send_alarms(alerts, app.config['MICROSOFT_TEAMS'][connector])
  File "/var/vcap/packages/python/lib/python3.6/site-packages/prom2teams/app/sender.py", line 27, in send_alarms
    sending_alarms = self._create_alarms(alerts)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/prom2teams/app/sender.py", line 21, in _create_alarms
    alarms = map_and_group(alerts, self.group_alerts_by)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/prom2teams/teams/alarm_mapper.py", line 29, in map_and_group
    grouped_alerts = group_alerts(alerts[same_status_alerts], group_alerts_by)
  File "/var/vcap/packages/python/lib/python3.6/site-packages/prom2teams/teams/alarm_mapper.py", line 53, in group_alerts
    groups[alert.__dict__[group_alerts_by]].append(alert)
KeyError: '"alertname"'

If i add --groupalertsby "alertname" to :
exec prom2teams --configpath /var/vcap/jobs/prom2teams/config/prom2teams-config.ini
it's works ok, troubles only with Config file.

docker image built from supplied Dockerfile "server 500"

Description

Created a container using the provided Dockerfile then used curl to send it a test alert. Server logs an error message rather than sending:

Steps to Reproduce

  1. build the image docker build .
  2. run the image docker run -d -p 8089:8089 <imagename>
  3. curl some dummy data to test
curl -H "Content-type: application/json" -X POST   -d '{"receiver": "prom2teams", "status": "firing", "alerts": [{"status": "firing", "labels": {"alertname": "TestAlert", "key": "value"} }], "groupLabels": {"alertname": "TestAlert"}}'   http://<appropriateip>:8089

Expected behavior: [What you expect to happen]
an alert to be generated to teams

Actual behavior: [What actually happens]
curl returns:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
        <title>Error response</title>
    </head>
    <body>
        <h1>Error response</h1>
        <p>Error code: 500</p>
        <p>Message: Error processing request.</p>
        <p>Error code explanation: 500 - Server got itself in trouble.</p>
    </body>
</html>

Reproduces how often: 100%

Versions

tested in latest

[Question] Multiple connectors

I have seen this already been addressed in #22
However I could not find any references on how to do this in docs. Could you please point me in right direction? Again, we need to be able to pass multiple connectors to Docker container via env variables.

Fix prom2teams uwsgi bin startup

Prerequisites

Description

[Description of the issue]

Steps to Reproduce

  1. Create a well-formed uwsgi.ini
  2. run: prom2teams_uwsgi uwsgi.ini

Expected behavior: start prom2teams using a uwsgi server

Actual behavior: Error

Reproduces how often: Always

Versions

2.0.0

Additional Information

Any additional information, configuration or data that might be necessary to reproduce the issue.

Fix PyPI deployments

Prerequisites

Description

Travis do deployments twice failing in the second one because it's already deployed

Steps to Reproduce

  1. [First Step]
  2. [Second Step]
  3. [and so on...]

Expected behavior: [What you expect to happen]
One succeeding deployment

Actual behavior: [What actually happens]
Two deployments, latest one failing

Reproduces how often: [What percentage of the time does it reproduce?]
Always

Versions

Additional Information

Update service startup for production environment

Prerequisites

Description

Enable the use of a WSGI application server for production environment

Steps to Reproduce

Expected behavior: A WSGI app server serving prom2teams requests

Actual behavior: Cannot run a WSGI app server to serve prom2teams requests

Reproduces how often: Always

Versions

1.*

Additional Information

None

Getting 404 on endpoints when using the docker image V2.0.2

Prerequisites

Description

Getting 404 on endpoints when using the docker image V2.0.2

Steps to Reproduce

  1. Navigate to http://host:port/v2

Hey guys, the documentation is a little confusing on what the appropriate endpoint is for this application. When using the docker image, I am unable to hit the endpoints. I'm getting a 404. I tried http://host:port/v2 and http://host:port/v2/Connector. Also I wasn't able to hit the swagger-ui. I was hoping for some clarification on this. Thanks!

Excluded fields broken in v2.3.2

Prerequisites

Description

After upgrade to 2.3.2 all requests fail with HTTP 500.

Steps to Reproduce

  1. Start docker container via docker compose
  msteams-gateway:
    image: idealista/prom2teams:2.3.2
    container_name: ms_teams_gateway
    expose:
     - "8089"
    environment:
      - "PROM2TEAMS_CONNECTOR=<URL>"
  1. Send alert from prometheus

Expected behavior: See message in MSTeam

Actual behavior: No message and error in log

2019-06-11 13:19:27,996 - werkzeug - INFO - 172.19.0.9 - - [11/Jun/2019 13:19:27] "POST /v2/Connector HTTP/1.1" 500 -

2019-06-11 13:19:34,467 - flask.app - ERROR - Exception on /v2/Connector [POST]

Traceback (most recent call last):

  File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 2292, in wsgi_app

    response = self.full_dispatch_request()

  File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1815, in full_dispatch_request

    rv = self.handle_user_exception(e)

  File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/api.py", line 583, in error_router

    return original_handler(e)

  File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/api.py", line 583, in error_router

    return original_handler(e)

  File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1718, in handle_user_exception

    reraise(exc_type, exc_value, tb)

  File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/_compat.py", line 35, in reraise

    raise value

  File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1813, in full_dispatch_request

    rv = self.dispatch_request()

  File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/app.py", line 1799, in dispatch_request

    return self.view_functions[rule.endpoint](**req.view_args)

  File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/api.py", line 325, in wrapper

    resp = resource(*args, **kwargs)

  File "/usr/local/lib/python3.5/site-packages/Flask-1.0.2-py3.5.egg/flask/views.py", line 88, in view

    return self.dispatch_request(*args, **kwargs)

  File "/usr/local/lib/python3.5/site-packages/flask_restplus-0.12.1-py3.5.egg/flask_restplus/resource.py", line 44, in dispatch_request

    resp = meth(*args, **kwargs)

  File "/usr/local/lib/python3.5/site-packages/prom2teams-2.3.2-py3.5.egg/prom2teams/app/versions/v2/namespace.py", line 26, in post

    alerts = self.schema.load(request.get_json())

  File "/usr/local/lib/python3.5/site-packages/marshmallow-3.0.0rc6-py3.5.egg/marshmallow/schema.py", line 707, in load

    postprocess=True,

  File "/usr/local/lib/python3.5/site-packages/marshmallow-3.0.0rc6-py3.5.egg/marshmallow/schema.py", line 856, in _do_load

    original_data=data,

  File "/usr/local/lib/python3.5/site-packages/marshmallow-3.0.0rc6-py3.5.egg/marshmallow/schema.py", line 1039, in _invoke_load_processors

    data=data, many=many, original_data=original_data,

  File "/usr/local/lib/python3.5/site-packages/marshmallow-3.0.0rc6-py3.5.egg/marshmallow/schema.py", line 1161, in _invoke_processors

    data = processor(data)

  File "/usr/local/lib/python3.5/site-packages/prom2teams-2.3.2-py3.5.egg/prom2teams/prometheus/message_schema.py", line 29, in get_alerts

    excluded = base_labels + self.exclude_fields

TypeError: can only concatenate tuple (not "list") to tuple

Reproduces how often: 100%

Versions

v2.3.2

pip3 install prom2teams error ImportError: No module named req. New pip version 10 changed api

for some reason now i am getting an error after:
pip3 install prom2teams

$ sudo pip3 install prom2teams
Collecting prom2teams
Downloading prom2teams-2.0.3.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "/tmp/pip-install-2tkA24/prom2teams/setup.py", line 2, in
from pip.req import parse_requirements
ImportError: No module named req

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

Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-2tkA24/prom2teams/

Provide generatorURL to the template

It would be very nice to have the generatorURL as a fact in the Teams message as this would make it very easy to get to the raw data from the message.

Publish Helm chart

Prerequisites

Description

Publish Helm chart package on Github Pages

Steps to Reproduce

Expected behavior:

Actual behavior:

Reproduces how often:

Versions

All

Additional Information

Completely automate release process

Description

To release a new version, setup.py L23 has to be update. In case we don't update the line with a new version, Travis CI won't update the package version in PyPi. This is really forgotten-prone, so it would be great if there are (or we can create) release "pre-hooks" that update that line so Travis can update the version in PyPi.

@dortegau suggests https://github.com/peritus/bumpversion

Not picking up config file, provided via docker

I converted the docker command to b e used as a helm deployment and mounted a volume with config.ini.
For some reason its not picking up the new file and still using the one at home/prom2teams/.

When i login to container and check i can see the config .ini at the correct location of opt/prom2teams

Prom2teams parses only the first received alarm

A JSON sent by Prometheus could have this format, with more than one alert:

{
  "receiver": "test_webhook",
  "status": "resolved",
  "alerts": [
    {
      "status": "resolved",
      "labels": {
        "alertname": "DiskSpace",
        "device": "rootfs",
        "fstype": "rootfs",
        "instance": "cs30.evilcorp",
        "job": "fsociety",
        "mountpoint": "/",
        "severity": "severe"
      },
      "annotations": {
        "description": "disk usage 73% on rootfs device",
        "summary": "Disk usage alert on CS30.evilcorp"
      },
      "startsAt": "2015-05-09T07:01:37.803Z",
      "endsAt": "2015-05-09T07:08:37.818278068Z",
      "generatorURL": "my.prometheusserver.url"
    },
    {
      "status": "resolved",
      "labels": {
        "alertname": "DiskSpace",
        "device": "/dev/mapper/vg1-lv1",
        "fstype": "ext4",
        "instance": "cs30.evilcorp",
        "job": "fsociety",
        "mountpoint": "/whiterose",
        "severity": "severe"
      },
      "annotations": {
        "description": "disk usage 52% on /dev/mapper/vg1-lv1 device",
        "summary": "Disk usage alert on cs30.evilcorp"
      },
      "startsAt": "2015-05-09T07:01:37.803Z",
      "endsAt": "2015-05-09T07:08:37.818278068Z",
      "generatorURL": "my.prometheus.url"
    }
  ],
  "groupLabels": {
    "alertname": "DiskSpace",
    "instance": "cs30.evilcorp",
    "severity": "severe"
  },
  "commonLabels": {
    "alertname": "DiskSpace",
    "instance": "cs30.evilcorp",
    "job": "fsociety",
    "severity": "severe"
  },
  "commonAnnotations": {
    "summary": "Disk usage alert on cs30.evilcorp"
  },
  "externalURL": "my.prometheusalertmanager.url",
  "version": "4",
  "groupKey": "{}/{severity=~\"^(?:severe)$\"}:{alertname=\"DiskSpace\", instance=\"cs30.evilcorp\", severity=\"severe\"}"
}

Problem is that prom2teams, in this line https://github.com/idealista/prom2teams/blob/master/prom2teams/message/parser.py#L13 (and I take the blame for that one, didn't expect Prometheus to send more than one alert per JSON) just parses the first alarm.

So parser.py has to be changed, parse more than one alert and then prom2teams should send these alarms (changes needed as well in server.py, I think)

Capture KeyboardInterrupt and log program exit

When I try to close prom2teams using KeyboardInterrupt signal (CTRL + C) an ugly trace like this is printed in console:

Traceback (most recent call last): File "bin/prom2teams", line 23, in <module> run(args.configpath, args.templatepath, args.logfilepath, args.loglevel) File "/Users/dortega/workspace/prom2teams/app/server.py", line 63, in run httpd.serve_forever() File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socketserver.py", line 236, in serve_forever ready = selector.select(poll_interval) File "/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/selectors.py", line 376, in select fd_event_list = self._poll.poll(timeout) KeyboardInterrupt

Add hot reload in WSGI

Prerequisites

Description

As in #104 #132, add the ability of reload Prom2teams' configuration without restarting it.

Steps to Reproduce

  1. [First Step]
  2. [Second Step]
  3. [and so on...]

Expected behavior: [What you expect to happen]

Actual behavior: [What actually happens]

Reproduces how often: [What percentage of the time does it reproduce?]

Versions

The version/s you notice the behavior.

Additional Information

Any additional information, configuration or data that might be necessary to reproduce the issue.

Duplicated debug message

Before calling the parser, the JSON received is printed if log level is DEBUG:

logger.debug('Data received: %s', post_data)
message = compose(self.template_path, parse(post_data))

and is printed too the very moment we call the parser:

def parse(json_str):
    logger.debug('received: %s', json_str)
[...]

So second time is not necessary.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.