diff --git a/config.json b/config.json index af7c26b..7865517 100644 --- a/config.json +++ b/config.json @@ -53,6 +53,12 @@ "label": "Bi-directional refresh of CRM properties", "path": "property-refresh", "insertPath": null + }, + { + "name": "custom-logger-example", + "label": "Custom Logger Example", + "path": "custom-logger-example", + "insertPath": null } ] } diff --git a/custom-logger-example/.gitignore b/custom-logger-example/.gitignore new file mode 100644 index 0000000..669b555 --- /dev/null +++ b/custom-logger-example/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +target/ +dist/ +package-lock.json +hubspot.config.yml +.env* +!.env.sample diff --git a/custom-logger-example/LICENSE.md b/custom-logger-example/LICENSE.md new file mode 100644 index 0000000..9dcf390 --- /dev/null +++ b/custom-logger-example/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 HubSpot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/custom-logger-example/README.md b/custom-logger-example/README.md new file mode 100644 index 0000000..6742dd1 --- /dev/null +++ b/custom-logger-example/README.md @@ -0,0 +1,31 @@ +# Custom Logger Example + +This is an app that demonstrates the main features of the custom logger. + +1. Multiple logging levels + - `info` + - `debug` + - `warn` + - `error` +1. Built-in logging for serverless requests +1. Local development niceties like logging to the console +1. Using Trace IDs to investigate extension failures + +For documentation about the custom logger itself, please visit https://developers.hubspot.com/docs/platform/ui-extensions-sdk#send-custom-log-messages-for-debugging. + + +## Testing when deployed + +When [deployed](https://developers.hubspot.com/docs/platform/project-cli-commands#upload-to-hubspot), the custom logger will persist the logs in the HubSpot logging system. Don't forget to add the extension card to the middle pane. + +![logger demo deployed](./images/logger-example-deployed.gif) + +Logs can be retrieved from the app dashboard. + +`https://app.hubspot.com/private-apps//` + +## Testing in local development + +When [running the project locally](https://developers.hubspot.com/docs/platform/create-private-apps-with-projects), click the buttons and watch the events log to the console. + +![logger demo local dev](./images/logger-example-local.gif) diff --git a/custom-logger-example/hsproject.json b/custom-logger-example/hsproject.json new file mode 100644 index 0000000..ae96316 --- /dev/null +++ b/custom-logger-example/hsproject.json @@ -0,0 +1,5 @@ +{ + "name": "custom-logger-example", + "srcDir": "src", + "platformVersion": "2023.2" +} diff --git a/custom-logger-example/images/logger-example-deployed.gif b/custom-logger-example/images/logger-example-deployed.gif new file mode 100644 index 0000000..e1cd567 Binary files /dev/null and b/custom-logger-example/images/logger-example-deployed.gif differ diff --git a/custom-logger-example/images/logger-example-local.gif b/custom-logger-example/images/logger-example-local.gif new file mode 100644 index 0000000..23fdd27 Binary files /dev/null and b/custom-logger-example/images/logger-example-local.gif differ diff --git a/custom-logger-example/package.json b/custom-logger-example/package.json new file mode 100644 index 0000000..7282f65 --- /dev/null +++ b/custom-logger-example/package.json @@ -0,0 +1,11 @@ +{ + "name": "custom-logger-example", + "version": "0.1.0", + "description": "A simple demo of the custom logger.", + "scripts": { + "postinstall": "cd ./src/app/extensions/ && npm install && cd ../app.functions && npm install", + "build": "npm run build --prefix ./src/app/extensions/" + }, + "author": "HubSpot", + "license": "MIT" +} diff --git a/custom-logger-example/src/app/app.functions/.env.sample b/custom-logger-example/src/app/app.functions/.env.sample new file mode 100644 index 0000000..d11541a --- /dev/null +++ b/custom-logger-example/src/app/app.functions/.env.sample @@ -0,0 +1,13 @@ +# FOR LOCAL DEVELOPMENT ONLY: Use .env files to configure your +# environment during local development. +# +# NOTE: Do not add your PRIVATE_APP_ACCESS_TOKEN to your secrets or +# any other configs, it's provided automatically for deployed apps + +# Find your token by: +# - Visiting https://app.hubspot.com/l/private-apps +# - Choose the portal you're using for active development +# - On the "Private Apps" screen, select your app, then click the "Auth" tab +# - Click "Show Token", then "Copy" +# - Paste that value between the quotes below ⬇️ +PRIVATE_APP_ACCESS_TOKEN="" diff --git a/custom-logger-example/src/app/app.functions/README.md b/custom-logger-example/src/app/app.functions/README.md new file mode 100644 index 0000000..7441422 --- /dev/null +++ b/custom-logger-example/src/app/app.functions/README.md @@ -0,0 +1,3 @@ +## custom-logger-example-serverless + +This module contains two simple serverless functions. One that succeeds and one that throws an error. diff --git a/custom-logger-example/src/app/app.functions/package.json b/custom-logger-example/src/app/app.functions/package.json new file mode 100644 index 0000000..60740e2 --- /dev/null +++ b/custom-logger-example/src/app/app.functions/package.json @@ -0,0 +1,10 @@ +{ + "name": "custom-logger-example-serverless", + "version": "0.1.0", + "author": "HubSpot", + "license": "MIT", + "dependencies": { + "@hubspot/api-client": "^7.0.1", + "axios": "^0.27.2" + } +} diff --git a/custom-logger-example/src/app/app.functions/serverless-error.js b/custom-logger-example/src/app/app.functions/serverless-error.js new file mode 100644 index 0000000..e1f315e --- /dev/null +++ b/custom-logger-example/src/app/app.functions/serverless-error.js @@ -0,0 +1,3 @@ +exports.main = async () => { + throw new Error('Serverless has errored'); +}; diff --git a/custom-logger-example/src/app/app.functions/serverless-success.js b/custom-logger-example/src/app/app.functions/serverless-success.js new file mode 100644 index 0000000..2dd36d2 --- /dev/null +++ b/custom-logger-example/src/app/app.functions/serverless-success.js @@ -0,0 +1,3 @@ +exports.main = async () => { + return 'Serverless has succeeded'; +}; diff --git a/custom-logger-example/src/app/app.functions/serverless.json b/custom-logger-example/src/app/app.functions/serverless.json new file mode 100644 index 0000000..1eca8aa --- /dev/null +++ b/custom-logger-example/src/app/app.functions/serverless.json @@ -0,0 +1,12 @@ +{ + "appFunctions": { + "serverless-success": { + "file": "serverless-success.js", + "secrets": [] + }, + "serverless-error": { + "file": "serverless-error.js", + "secrets": [] + } + } +} diff --git a/custom-logger-example/src/app/app.json b/custom-logger-example/src/app/app.json new file mode 100644 index 0000000..45ea52c --- /dev/null +++ b/custom-logger-example/src/app/app.json @@ -0,0 +1,19 @@ +{ + "name": "Custom Logger Example", + "description": "An example app demonstrating usage of the custom logger.", + "uid": "custom-logger-example", + "scopes": ["crm.objects.contacts.read"], + "public": false, + "extensions": { + "crm": { + "cards": [ + { + "file": "extensions/sidebar-logging.json" + }, + { + "file": "extensions/middle-tab-logging.json" + } + ] + } + } +} diff --git a/custom-logger-example/src/app/extensions/MiddleTabLogging.tsx b/custom-logger-example/src/app/extensions/MiddleTabLogging.tsx new file mode 100644 index 0000000..2daafc4 --- /dev/null +++ b/custom-logger-example/src/app/extensions/MiddleTabLogging.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { + Button, + CrmContext, + Divider, + Flex, + GenericContext, + hubspot, + logger, + Text, +} from '@hubspot/ui-extensions'; + +logger.warn('Warning in the middle tab, before my extension'); + +hubspot.extend(({ context }) => ); + +type Props = { context: GenericContext | CrmContext }; + +const MiddleTabLogging = ({ context }: Props) => { + logger.debug(JSON.stringify(context, null, 2)); + + const callServerlessSuccess = () => { + return hubspot + .serverless('serverless-success') + .then((result) => logger.info(result)) + .catch((error) => logger.error(error.message)); + }; + + const callServerlessFail = () => { + return hubspot + .serverless('serverless-error') + .then((result) => logger.info(result)) + .catch((error) => logger.error(error.message)); + }; + + return ( + + Test out the logger with the following buttons. + + The browser's developer console will show your events in local dev. + + + Test serverless functions + + + + + + + Test different log levels. + + + + + + + + + + Deploy the app and crash the card. Use the Trace ID to see what happened + in the Log Traces tab in your private app's dashboard. + + + + ); +}; diff --git a/custom-logger-example/src/app/extensions/SidebarLogging.jsx b/custom-logger-example/src/app/extensions/SidebarLogging.jsx new file mode 100644 index 0000000..172fe6c --- /dev/null +++ b/custom-logger-example/src/app/extensions/SidebarLogging.jsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { + Button, + Divider, + Flex, + hubspot, + logger, + Text, +} from '@hubspot/ui-extensions'; + +logger.warn('Warning in the sidebar, before my extension'); + +hubspot.extend(({ context }) => ); + +const SidebarLogging = ({ context }) => { + logger.debug(JSON.stringify(context, null, 2)); + + const callServerlessSuccess = () => { + return hubspot + .serverless('serverless-success') + .then((result) => logger.info(result)) + .catch((error) => logger.error(error.message)); + }; + + const callServerlessFail = () => { + return hubspot + .serverless('serverless-error') + .then((result) => logger.info(result)) + .catch((error) => logger.error(error.message)); + }; + + return ( + + Test out the logger with the following buttons. + + The browser's developer console will show your events in local dev. + + + Test serverless functions + + + + + + + Test different log levels. + + + + + + + + + + Deploy the app and crash the card. Use the Trace ID to see what happened + in the Log Traces tab in your private app's dashboard. + + + + ); +}; diff --git a/custom-logger-example/src/app/extensions/middle-tab-logging.json b/custom-logger-example/src/app/extensions/middle-tab-logging.json new file mode 100644 index 0000000..3748371 --- /dev/null +++ b/custom-logger-example/src/app/extensions/middle-tab-logging.json @@ -0,0 +1,12 @@ +{ + "type": "crm-card", + "data": { + "title": "Middle Tab Logging", + "uid": "middle-tab-logging", + "location": "crm.record.tab", + "module": { + "file": "MiddleTabLogging.tsx" + }, + "objectTypes": [{ "name": "contacts" }] + } +} diff --git a/custom-logger-example/src/app/extensions/package.json b/custom-logger-example/src/app/extensions/package.json new file mode 100644 index 0000000..4b808f6 --- /dev/null +++ b/custom-logger-example/src/app/extensions/package.json @@ -0,0 +1,10 @@ +{ + "name": "custom-logger-example-ui", + "version": "0.1.0", + "author": "HubSpot", + "license": "MIT", + "dependencies": { + "@hubspot/ui-extensions": "latest", + "react": "^18.2.0" + } +} diff --git a/custom-logger-example/src/app/extensions/sidebar-logging.json b/custom-logger-example/src/app/extensions/sidebar-logging.json new file mode 100644 index 0000000..0b253bd --- /dev/null +++ b/custom-logger-example/src/app/extensions/sidebar-logging.json @@ -0,0 +1,12 @@ +{ + "type": "crm-card", + "data": { + "title": "Sidebar Logging", + "uid": "sidebar-logging", + "location": "crm.record.sidebar", + "module": { + "file": "SidebarLogging.jsx" + }, + "objectTypes": [{ "name": "contacts" }] + } +}