Skip to content
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

feat: Expose metric dictionary to make logging metrics as JSON easier #2162

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

edgarrmondragon
Copy link
Collaborator

@edgarrmondragon edgarrmondragon commented Jan 20, 2024


📚 Documentation preview 📚: https://meltano-sdk--2162.org.readthedocs.build/en/2162/

Summary by Sourcery

Expose metric dictionary to make logging metrics as JSON easier.

Enhancements:

  • Adds a to_dict method to the Point class to convert a metric to a dictionary.
  • Adds a SingerMetricsFormatter class to format metrics as JSON.
  • Updates the default logging configuration to include a metrics formatter.
  • Updates the log function to include the metric dictionary in the log record.
  • Updates the documentation to include an example of how to log metrics as JSON.

Copy link

codspeed-hq bot commented Jan 20, 2024

CodSpeed Performance Report

Merging #2162 will not alter performance

Comparing edgarrmondragon/refactor/metrics-json-logging (9740d7a) with main (2f8151b)

Summary

✅ 7 untouched benchmarks

@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from 2c3ec58 to 815b748 Compare January 20, 2024 00:32
Copy link

codecov bot commented Jan 20, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 91.40%. Comparing base (2f8151b) to head (9740d7a).
Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2162   +/-   ##
=======================================
  Coverage   91.40%   91.40%           
=======================================
  Files          63       63           
  Lines        5291     5294    +3     
  Branches      676      676           
=======================================
+ Hits         4836     4839    +3     
  Misses        321      321           
  Partials      134      134           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch 4 times, most recently from 64e71fd to 75dc465 Compare January 26, 2024 23:43
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch 3 times, most recently from 8edd581 to 2125742 Compare January 31, 2024 19:28
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from 2125742 to 5add1e7 Compare February 5, 2024 18:59
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from 5add1e7 to 2f2cc7d Compare February 13, 2024 22:50
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from 2f2cc7d to 2d3bf56 Compare March 4, 2024 19:22
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from 2d3bf56 to fe99021 Compare April 5, 2024 04:10
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch 2 times, most recently from a80e01c to de62b92 Compare May 8, 2024 17:22
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from de62b92 to ac3e32a Compare May 29, 2024 16:04
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from ac3e32a to 2f89e10 Compare August 9, 2024 18:42
@edgarrmondragon edgarrmondragon self-assigned this Mar 4, 2025
@edgarrmondragon edgarrmondragon force-pushed the edgarrmondragon/refactor/metrics-json-logging branch from f7542b5 to 6de3bf6 Compare March 4, 2025 23:03
@edgarrmondragon edgarrmondragon added this to the v0.45 milestone Mar 5, 2025
@edgarrmondragon edgarrmondragon marked this pull request as ready for review March 5, 2025 00:01
@edgarrmondragon edgarrmondragon requested review from a team as code owners March 5, 2025 00:01
Copy link
Contributor

sourcery-ai bot commented Mar 5, 2025

Reviewer's Guide by Sourcery

This pull request introduces a new SingerMetricsFormatter class that formats metric log records as JSON. It also updates the log function to include the metric point in the log record's extra data, and adds a to_dict method to the Point class to convert a metric point to a dictionary. The default logging configuration and documentation are updated to reflect these changes.

Sequence diagram for logging a metric

sequenceDiagram
    participant Logger
    participant metrics.log
    participant Point
    Logger->>metrics.log: info("METRIC", extra={"point": point.to_dict()})
    activate metrics.log
    metrics.log->>Point: to_dict()
    activate Point
    Point-->>metrics.log: Returns dictionary
    deactivate Point
    metrics.log-->>Logger: Returns
    deactivate metrics.log
Loading

File-Level Changes

Change Details Files
Introduces a SingerMetricsFormatter class to format metric log records as JSON.
  • Creates a SingerMetricsFormatter class that inherits from logging.Formatter.
  • Implements a format method that adds a metric_json field to the log record, containing the JSON representation of the metric point.
  • If no point exists, the metric_json field will be an empty string.
singer_sdk/metrics.py
Updates the log function to include the metric point in the log record's extra data.
  • Modifies the log function to pass the metric point as part of the extra argument to the logger's info method.
  • The extra argument is a dictionary containing the metric point, which will be accessible to the formatter.
singer_sdk/metrics.py
Adds a to_dict method to the Point class to convert a metric point to a dictionary.
  • Adds a to_dict method to the Point class.
  • The to_dict method returns a dictionary representation of the metric point, including the metric type, metric name, value, and tags.
singer_sdk/metrics.py
Updates the default logging configuration to include the new SingerMetricsFormatter for the singer_sdk.metrics logger.
  • Adds a metrics formatter to the formatters section, using the SingerMetricsFormatter class.
  • Adds a metrics handler to the handlers section, using the metrics formatter.
  • Configures the singer_sdk.metrics logger to use the metrics handler and to not propagate logs to the root logger.
singer_sdk/default_logging.yml
Updates the documentation to reflect the changes in metric logging.
  • Updates the documentation to describe how to configure metric logging to output JSON format.
  • Provides an example of a logging configuration that sends metrics to a file in JSON format.
docs/implementation/logging.md
Updates tests to reflect the changes in metric logging.
  • Adds a test case for the SingerMetricsFormatter class.
  • Updates existing test cases to assert that the metric point is correctly logged as a dictionary.
tests/core/test_metrics.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @edgarrmondragon - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider renaming SingerMetricsFormatter to JSONMetricsFormatter to better reflect its purpose.
  • The default logging config should include the pythonjsonlogger library as a dependency.
Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

def to_json(self) -> str:
"""Convert this measure to a JSON object.

class SingerMetricsFormatter(logging.Formatter):
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider using a JSON logging library or formatting the metric explicitly in the log call to avoid the complexity of a custom formatter for logging metrics as JSON..

The new custom formatter introduces extra complexity by manually injecting the JSON-formatted metric into each log record. If the goal is simply to log metrics as JSON, you could simplify this by using a JSON logging library (like python-json-logger) or by formatting the metric before logging. For example:

Using python-json-logger:

from pythonjsonlogger import jsonlogger
import logging

handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter('%(asctime)s %(levelname)s %(message)s %(point)s')
handler.setFormatter(formatter)
logger = logging.getLogger("my_logger")
logger.addHandler(handler)
logger.setLevel(logging.INFO)

# Log with a dictionary already provided.
logger.info("METRIC", extra={"point": point.to_dict()})

Or, format the metric explicitly in your log call:

logger.info("METRIC: %s", json.dumps(point.to_dict(), default=str))

Both approaches eliminate the need for a custom formatter while keeping the functionality intact.

@edgarrmondragon edgarrmondragon modified the milestones: v0.45, v0.46 Mar 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant