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

(aws-cloudwatch): GraphWidget.to_json not returning not-tokenised JSON #15222

Closed
ciaranevans opened this issue Jun 21, 2021 · 7 comments
Closed
Labels
@aws-cdk/aws-cloudwatch Related to Amazon CloudWatch guidance Question that needs advice or information.

Comments

@ciaranevans
Copy link

ciaranevans commented Jun 21, 2021

When using aws_cloudwatch.GraphWidget, I expect to_json to return me a JSON object that I could dump to a JSON string with json.dumps(). However the JSON object returned instead has references to <jsii._reference_map.InterfaceDynamicProxy object at 0x1052041c0> like objects.

For context, I'm trying to expose Widget JSONs as CfnOutputs of my Stack.

Reproduction Steps

import json

from aws_cdk import aws_cloudwatch, core


class CdkStack(core.Stack):
    def __init__(
        self, scope: core.Construct, construct_id: str, **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        metric_1 = aws_cloudwatch.Metric(
            metric_name="metric-1", namespace="my-metrics"
        )

        widget = aws_cloudwatch.GraphWidget(
            left=[
                metric_1
            ],
            period=core.Duration.minutes(1),
            title="My Widgets"
        )

        core.CfnOutput(self, "widget-json", value=json.dumps(widget.to_json()))

What did you expect to happen?

A CfnOutput is created with the JSON String representation of my Widget.

What actually happened?

Traceback (most recent call last):
  File "cdk/app.py", line 11, in <module>
    CdkStack(
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_runtime.py", line 83, in __call__
    inst = super().__call__(*args, **kwargs)
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/cdk/cdk_stack.py", line 83, in __init__
    core.CfnOutput(self, "widget-json", value=json.dumps(widget.to_json()))
  File "/Users/ciaran/.pyenv/versions/3.8.10/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/Users/ciaran/.pyenv/versions/3.8.10/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/Users/ciaran/.pyenv/versions/3.8.10/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/Users/ciaran/.pyenv/versions/3.8.10/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type InterfaceDynamicProxy is not JSON serializable

If I take out the json.dumps:

Traceback (most recent call last):
  File "cdk/app.py", line 11, in <module>
    CdkStack(
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_runtime.py", line 83, in __call__
    inst = super().__call__(*args, **kwargs)
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/cdk/cdk_stack.py", line 83, in __init__
    core.CfnOutput(self, "widget-json", value=widget.to_json())
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_runtime.py", line 83, in __call__
    inst = super().__call__(*args, **kwargs)
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/aws_cdk/core/__init__.py", line 16420, in __init__
    jsii.create(CfnOutput, self, [scope, id, props])
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 278, in create
    args=_make_reference_for_native(self, args),
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 144, in _make_reference_for_native
    return [_make_reference_for_native(kernel, i) for i in d]
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 144, in <listcomp>
    return [_make_reference_for_native(kernel, i) for i in d]
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 161, in _make_reference_for_native
    "data": {
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 162, in <dictcomp>
    jsii_name: _make_reference_for_native(
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 144, in _make_reference_for_native
    return [_make_reference_for_native(kernel, i) for i in d]
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 144, in <listcomp>
    return [_make_reference_for_native(kernel, i) for i in d]
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 138, in _make_reference_for_native
    "$jsii.map": {
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 139, in <dictcomp>
    k: _make_reference_for_native(kernel, v) for k, v in d.items()
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 138, in _make_reference_for_native
    "$jsii.map": {
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 139, in <dictcomp>
    k: _make_reference_for_native(kernel, v) for k, v in d.items()
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 144, in _make_reference_for_native
    return [_make_reference_for_native(kernel, i) for i in d]
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 144, in <listcomp>
    return [_make_reference_for_native(kernel, i) for i in d]
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 184, in _make_reference_for_native
    kernel.create(d.__class__, d)
  File "/Users/ciaran/dev/cdk-cloudwatch-custom-metrics/.venv/lib/python3.8/site-packages/jsii/_kernel/__init__.py", line 277, in create
    fqn=klass.__jsii_type__ or "Object",
AttributeError: type object 'InterfaceDynamicProxy' has no attribute '__jsii_type__'

Environment

  • CDK CLI Version : 1.109.0 (build c647e38)
  • Framework Version:
$ pip list
...
aws-cdk.aws-cloudwatch              1.109.0
aws-cdk.core                        1.109.0
  • Node.js Version: v14.17.1
  • OS : MacOS BigSur 11.4
  • Language (Version): Python 3.8.10

Other

I have tried playing around with core.Lazy.string|list|any but also have had no luck.

At this point it might just be easier to construct the Widget JSON myself 😅


This is 🐛 Bug Report

@ciaranevans ciaranevans added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Jun 21, 2021
@ciaranevans ciaranevans changed the title aws_cloudwatch.GraphWidget: to_json not returning not-tokenised JSON (aws_cloudwatch): GraphWidget.to_json not returning not-tokenised JSON Jun 21, 2021
@ciaranevans ciaranevans changed the title (aws_cloudwatch): GraphWidget.to_json not returning not-tokenised JSON (aws-cloudwatch): GraphWidget.to_json not returning not-tokenised JSON Jun 21, 2021
@github-actions github-actions bot added the @aws-cdk/aws-cloudwatch Related to Amazon CloudWatch label Jun 21, 2021
@ciaranevans
Copy link
Author

Hey @madeline-k sorry for the tag but the bot seems to have picked you 😅

Whilst I appreciate a fix/change isn't likely #soon, are you possibly able to confirm to me if this is the intended behaviour?

to_json to me, would indicate 'valid/dumpable' JSON.

@madeline-k
Copy link
Contributor

madeline-k commented Jun 28, 2021

Hey @ciaranevans, thanks for your patience on this! There should be a way to grab a valid JSON of your graph widgets, but it will probably not be as simple as to_json.

A stack.resolve(myWidget).to_json() might work, or you might need to do some manipulation of the string given from stack.resolve().

I will take a deeper look into this, and let you know what I find.

(Edited to remove guidance that was more complicated than necessary, to avoid confusion for any future readers.)

@madeline-k
Copy link
Contributor

madeline-k commented Jun 28, 2021

@ciaranevans Can you also explain your use-case? Why are you trying to output just the GraphWidget Json from your Cfn stack? I think it is more common to just create the Widgets and the Dashboards that will contain them in the same stack. But I am curious to understand your use-case to see how we can make the Cloudwatch module better!

@ciaranevans
Copy link
Author

Hi @madeline-k thanks for getting back to me! 😄

Sure, my use-case might be a bit fringe, we have a client who has several stacks deployed by different people (a few are from us) and we're hoping to get to a point where a stack can make a opinionated decision on what metrics it deems are useful, and how they're displayed.

We can then make it so that we make another 'Dashboard Stack' that merely combs over all the stacks, grabs their exported Widget definitions and creates one dashboard with the metrics.

A lot of these stacks are ETL pipelines which just download data in the clients systems, so most of them will be exporting Widgets that will likely just be counts of files ingested, storage used etc.

This is why we'd love to be able to define the widgets in-stack, then export them, where the dashboard stack will just create a big JSON body from them all.

Hopefully that makes sense 😅

@madeline-k
Copy link
Contributor

Hi @ciaranevans thanks for explaining your use-case! That definitely makes sense 👍

I looked into it a little more, and I found the right way grab the JSON that you need. Change the last line of your code sample to:

core.CfnOutput(self, "widget-json", value=json.dumps(self.resolve(widget)))

And you should be good to go! I'll be closing this issue, feel free to re-open if you have any further questions on this topic.

@madeline-k madeline-k added guidance Question that needs advice or information. and removed bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Jun 29, 2021
@madeline-k madeline-k removed their assignment Jun 29, 2021
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

@ciaranevans
Copy link
Author

@madeline-k oh awesome! That works a treat!

Many thanks for the help! Out of curiosity, for next time I might find myself in a similar situation, what did you look up to find that out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-cloudwatch Related to Amazon CloudWatch guidance Question that needs advice or information.
Projects
None yet
Development

No branches or pull requests

2 participants