Skip to content

Add Flashduty Alerter - #1649

Merged
jertel merged 9 commits into
jertel:masterfrom
pijiang3:master
Mar 26, 2025
Merged

Add Flashduty Alerter#1649
jertel merged 9 commits into
jertel:masterfrom
pijiang3:master

Conversation

@pijiang3

@pijiang3 pijiang3 commented Mar 18, 2025

Copy link
Copy Markdown
Contributor

Description

Checklist

  • I have reviewed the contributing guidelines.
  • I have included unit tests for my changes or additions.
  • I have successfully run make test-docker with my changes.
  • I have manually tested all relevant modes of the change in this PR.
  • I have updated the documentation.
  • I have updated the changelog.

Questions or Comments

@nsano-rururu

Copy link
Copy Markdown
Collaborator

・You forgot to update CHANGELOG.md
・Please add test code.

@nsano-rururu

Copy link
Copy Markdown
Collaborator

The following items are not included in the schema.yaml. Is this intentional?

flashduty_check
flashduty_service
flashduty_cluster
flashduty_resource
flashduty_metric
flashduty_group
flashduty_env
flashduty_app

@nsano-rururu

Copy link
Copy Markdown
Collaborator

In the following text, please enclose the string values ​​in double quotes.

Example usage::

    alert_text: "**{0}** - ALERT on host {1}"
    alert_text_args:
      - name
      - hostname
    alert:
      - flashduty
    flashduty_url: https://api.flashcat.cloud/event/push/alert/standard?integration_key=xxx
    flashduty_title: elastalert 
    flashduty_event_status: Warning
    flashduty_alert_key: abc
    flashduty_description: log error
    flashduty_check: Too many occurrences of error logs
    flashduty_resource: index_name
    flashduty_service: service_name
    flashduty_metric: The number of error logs is greater than 5
    flashduty_group: sre
    flashduty_cluster: k8s
    flashduty_app: app
    flashduty_env: dev

@pijiang3

Copy link
Copy Markdown
Contributor Author

Updated as requested, thanks

nsano-rururu
nsano-rururu previously approved these changes Mar 21, 2025
Comment thread docs/source/alerts.rst Outdated
Comment thread elastalert/schema.yaml Outdated
@nsano-rururu

Copy link
Copy Markdown
Collaborator

@jertel

Any other comments?

@jertel

jertel commented Mar 21, 2025

Copy link
Copy Markdown
Owner
  1. The description reads like an advertisement. It is expected that someone reading about Flashduty already knows what it is and is more interested in how tightly ElastAlert 2 integrates with it, limitations, cost concerns, etc.
  2. The other alerters have documentation around all required and optional parameters, whereas this alerter simply shows an example and expects the reader to figure out what each parameter means, and what the input bounds are.
  3. The URL is unclear to me whether it should default to the flashcat.cloud server/path, or whether the user will be installing FlashDuty on their own system. If most users will be using the hosted offering by the vendor, why not make that the default value?

@pijiang3

Copy link
Copy Markdown
Contributor Author
  • The description reads like an advertisement. It is expected that someone reading about Flashduty already knows what it is and is more interested in how tightly ElastAlert 2 integrates with it, limitations, cost concerns, etc.
  • The other alerters have documentation around all required and optional parameters, whereas this alerter simply shows an example and expects the reader to figure out what each parameter means, and what the input bounds are.
  • The URL is unclear to me whether it should default to the flashcat.cloud server/path, or whether the user will be installing FlashDuty on their own system. If most users will be using the hosted offering by the vendor, why not make that the default value?

You are right, I have made modifications based on your feedback. Thank you

@nsano-rururu

Copy link
Copy Markdown
Collaborator

@pijiang3

The test code I added is failing

_____________________________ test_flashduty_alert _____________________________
[gw1] linux -- Python 3.13.2 /home/elastalert/tests/.tox/py313/bin/python

caplog = <_pytest.logging.LogCaptureFixture object at 0x7f8f7969d010>

    def test_flashduty_alert(caplog):
        caplog.set_level(logging.INFO)
        rule = {
            'name': 'Test Flashduty Rule',
            'type': 'any',
            'flashduty_integration_key': 'xxx',
            'flashduty_title': 'Test Alert',
            'flashduty_description': 'Test Description',
            'flashduty_event_status': 'Info',
            'flashduty_alert_key': 'test-alert',
            'flashduty_check': 'test-check',
            'flashduty_service': 'test-service',
            'flashduty_cluster': 'test-cluster',
            'flashduty_resource': 'test-resource',
            'flashduty_metric': 'test-metric',
            'flashduty_group': 'test-group',
            'flashduty_env': 'test-env',
            'flashduty_app': 'test-app',
            'alert': [],
        }
        rules_loader = FileRulesLoader({})
        rules_loader.load_modules(rule)
        alert = FlashdutyAlerter(rule)
        match = {
            '@timestamp': '2025-03-20T00:00:00',
            'somefield': 'foobar'
        }
    
        with mock.patch('requests.post') as mock_post_request:
            alert.alert([match])
    
        expected_data = {
            'title': 'Test Alert',
            'description': 'Test Description',
            'event_status': 'Info',
            'alert_key': 'test-alert',
            'labels': {
                'check': 'test-check',
                'service': 'test-service',
                'cluster': 'test-cluster',
                'resource': 'test-resource',
                'metric': 'test-metric',
                'group': 'test-group',
                'env': 'test-env',
                'app': 'test-app',
                'information': '@timestamp: 2025-03-20T00:00:00\nsomefield: foobar\n'
            }
        }
    
        mock_post_request.assert_called_once_with(
            'https://api.flashcat.cloud/event/push/alert/standard?integration_key=' + rule['flashduty_integration_key'],
            data=mock.ANY,
            headers={'Content-Type': 'application/json'}
        )
    
        actual_data = json.loads(mock_post_request.call_args_list[0][1]['data'])
>       assert expected_data == actual_data
E       AssertionError: assert {'alert_key':...v', ...}, ...} == {'alert_key':...v', ...}, ...}
E         
E         Omitting 4 identical items, use -vv to show
E         Differing items:
E         {'labels': {'app': 'test-app', 'check': 'test-check', 'cluster': 'test-cluster', 'env': 'test-env', ...}} != {'labels': {'app': 'test-app', 'check': 'test-check', 'cluster': 'test-cluster', 'env': 'test-env', ...}}
E         Use -v to get more diff

alerters/flashduty_test.py:69: AssertionError
------------------------------ Captured log call -------------------------------
INFO     elastalert:flashduty.py:68 Trigger sent to flashduty

@pijiang3

Copy link
Copy Markdown
Contributor Author

@pijiang3

The test code I added is failing

_____________________________ test_flashduty_alert _____________________________
[gw1] linux -- Python 3.13.2 /home/elastalert/tests/.tox/py313/bin/python

caplog = <_pytest.logging.LogCaptureFixture object at 0x7f8f7969d010>

    def test_flashduty_alert(caplog):
        caplog.set_level(logging.INFO)
        rule = {
            'name': 'Test Flashduty Rule',
            'type': 'any',
            'flashduty_integration_key': 'xxx',
            'flashduty_title': 'Test Alert',
            'flashduty_description': 'Test Description',
            'flashduty_event_status': 'Info',
            'flashduty_alert_key': 'test-alert',
            'flashduty_check': 'test-check',
            'flashduty_service': 'test-service',
            'flashduty_cluster': 'test-cluster',
            'flashduty_resource': 'test-resource',
            'flashduty_metric': 'test-metric',
            'flashduty_group': 'test-group',
            'flashduty_env': 'test-env',
            'flashduty_app': 'test-app',
            'alert': [],
        }
        rules_loader = FileRulesLoader({})
        rules_loader.load_modules(rule)
        alert = FlashdutyAlerter(rule)
        match = {
            '@timestamp': '2025-03-20T00:00:00',
            'somefield': 'foobar'
        }
    
        with mock.patch('requests.post') as mock_post_request:
            alert.alert([match])
    
        expected_data = {
            'title': 'Test Alert',
            'description': 'Test Description',
            'event_status': 'Info',
            'alert_key': 'test-alert',
            'labels': {
                'check': 'test-check',
                'service': 'test-service',
                'cluster': 'test-cluster',
                'resource': 'test-resource',
                'metric': 'test-metric',
                'group': 'test-group',
                'env': 'test-env',
                'app': 'test-app',
                'information': '@timestamp: 2025-03-20T00:00:00\nsomefield: foobar\n'
            }
        }
    
        mock_post_request.assert_called_once_with(
            'https://api.flashcat.cloud/event/push/alert/standard?integration_key=' + rule['flashduty_integration_key'],
            data=mock.ANY,
            headers={'Content-Type': 'application/json'}
        )
    
        actual_data = json.loads(mock_post_request.call_args_list[0][1]['data'])
>       assert expected_data == actual_data
E       AssertionError: assert {'alert_key':...v', ...}, ...} == {'alert_key':...v', ...}, ...}
E         
E         Omitting 4 identical items, use -vv to show
E         Differing items:
E         {'labels': {'app': 'test-app', 'check': 'test-check', 'cluster': 'test-cluster', 'env': 'test-env', ...}} != {'labels': {'app': 'test-app', 'check': 'test-check', 'cluster': 'test-cluster', 'env': 'test-env', ...}}
E         Use -v to get more diff

alerters/flashduty_test.py:69: AssertionError
------------------------------ Captured log call -------------------------------
INFO     elastalert:flashduty.py:68 Trigger sent to flashduty

@nsano-rururu Sorry , it was my negligence , The root cause of the issue is that the FlashdutyAlerter code automatically adds rule['name'] (i.e., "Test Flashduty Rule\n\n") to the labels['information'] field, but expected_data does not include this part, resulting in an assertion failure. The new submission has been revised.

@jertel jertel left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for your contribution!

@jertel
jertel merged commit 6ceeb2c into jertel:master Mar 26, 2025
@nsano-rururu

Copy link
Copy Markdown
Collaborator

I think that flashduty_event_status should have input value(Critical, Warning, Info, Ok) restrictions in schema.xml and all items should be set to string type in schema.xml.
https://docs.flashcat.cloud/en/flashduty/elastalert2-integration-guide
image

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators May 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants