<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Exceptionless</title>
    <description>The latest articles on Forem by Exceptionless (@exceptionless).</description>
    <link>https://forem.com/exceptionless</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3056%2Fb9109659-1e5a-44bf-a69d-79f86257ac45.png</url>
      <title>Forem: Exceptionless</title>
      <link>https://forem.com/exceptionless</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/exceptionless"/>
    <language>en</language>
    <item>
      <title>How To Monitor Events in Your Svelte App</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Mon, 11 Oct 2021 11:53:30 +0000</pubDate>
      <link>https://forem.com/exceptionless/how-to-monitor-events-in-your-svelte-app-2n39</link>
      <guid>https://forem.com/exceptionless/how-to-monitor-events-in-your-svelte-app-2n39</guid>
      <description>&lt;p&gt;It seems there is a new JavaScript framework launched everyday. And while that is largely true, some standout above the rest. When &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; first came out, it would have been easy to write it off as "yet another JS framework." However, Svelte quickly found its community. It has passionate supporters, great contributors, and was recently &lt;a href="https://insights.stackoverflow.com/survey/2021#section-most-loved-dreaded-and-wanted-web-frameworks" rel="noopener noreferrer"&gt;named the most-loved web framework&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Svelte differentiates itself from other JavaScript web frameworks by NOT including a virtual DOM. Basically, it is the antithesis to React. Direct DOM manipulation was once the norm with plain old JavaScript and jQuery, but its since been replaced by the many many frameworks out there that implement a virtual/shadow DOM. &lt;/p&gt;

&lt;p&gt;With Svelte taking a different approach to JavaScript web frameworks, we should explore how (if at all) handling events and monitoring those events works in Svelte. Open-source ❤️ open-source, so we'll use the open-source event monitoring tool, &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; alongside our Svelte app. &lt;/p&gt;

&lt;p&gt;What you'll need: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js v12 or higher &lt;/li&gt;
&lt;li&gt;A free Exceptionless account &lt;/li&gt;
&lt;li&gt;Text editor &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;We'll get started by signing up for Exceptionless. Note, you can also run this locally by grabbing the source code and &lt;a href="https://github.com/exceptionless/Exceptionless" rel="noopener noreferrer"&gt;following the instructions here&lt;/a&gt;. When you have signed up, you'll be prompted to create a new project. As we create the new project, we'll be prompted ot select the type of project. For this choose "browser application": &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqz0cm4cn4m00ou6mzp96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqz0cm4cn4m00ou6mzp96.png" alt="New project set up" width="800" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will give you the install instructions, but don't worry, I'll provide those here as well. Next, click Manage Project and you'll want to grab your API key from the API keys tab. &lt;/p&gt;

&lt;p&gt;Now, we can generate our Svelte project. We'll use deget so that we can get a full project scaffolding set up easily. &lt;a href="https://svelte.dev/blog/the-easiest-way-to-get-started" rel="noopener noreferrer"&gt;Read more about that here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx degit sveltejs/template exceptionless-svelte
cd exceptionless-svelte

npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, our last step before opening up a code editor is to install the new Exceptionless JavaScript client. You can do so by running this from inside your project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @exceptionless/browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can fire up the app by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't worry about how it looks, we're going to instead focus on how to capture events and errors in the app using Exceptionless. Let's dive into that!&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Events With Exceptionless
&lt;/h2&gt;

&lt;p&gt;Svelte, like other JavaScript frameworks, allows you to build apps through a collection of components. However, to keep this tutorial simple, we will keep everything in out &lt;code&gt;App.svelte&lt;/code&gt; file. So, let's start there. Open your &lt;code&gt;exceptionless-svelte&lt;/code&gt; project in your favorite code editor, then find the &lt;code&gt;App.svelte&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;You'll notice that with Svelte, we have a normal-looking script tag at the top of the file and then some HTML. This is because there is no virtual DOM. We're really just dealing with templating, reactive state, and plain JavaScript—which is pretty fun. &lt;/p&gt;

&lt;p&gt;Let's import Exceptionless at the top of our script tag, and then let's start Exceptionless up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Exceptionless&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@exceptionless/browser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;Exceptionless&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR API KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we had to wrap our startup call in a function. This is because &lt;a href="https://github.com/sveltejs/svelte/issues/5501" rel="noopener noreferrer"&gt;Svelte doesn't yet support to-level awaits&lt;/a&gt;. If it did, we would simply call &lt;code&gt;await Exceptionless.startup("YOUR API KEY")&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This &lt;code&gt;App.svelte&lt;/code&gt; file doesn't have a lot going on, so let's change that. Let's make the name variable you see in our code above dynamic. We're not going to go deep into state/props with Svelte, but if you look in the &lt;code&gt;main.js&lt;/code&gt; file, you'll see a prop variable called &lt;code&gt;name&lt;/code&gt;. We also have that variable at the top of our &lt;code&gt;App.svelte&lt;/code&gt; file. Changing it is as simple as assigning a new value. Which is exactly what we'll do. This is not the reactive way of handling state variables, so I encourage you to check out the docs &lt;a href="https://svelte.dev/tutorial/reactive-declarations" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;So, first, in the HTML, between your &lt;code&gt;main&lt;/code&gt; tags, change things to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello {name}!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Type a new name below to change the name variable.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;on:change=&lt;/span&gt;&lt;span class="s"&gt;{handleChange}&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"new name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in your &lt;code&gt;script&lt;/code&gt; tag, add a &lt;code&gt;handleChange&lt;/code&gt; function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save your code, then visit localhost:5000. Type a new name in the input field and you'll see Hello World change to Hello ${new name}. Very cool. But we came here to montior events and take names!&lt;/p&gt;

&lt;p&gt;Let's change our &lt;code&gt;handleChange&lt;/code&gt; function to track that event with Exceptionless. This is a feature of our app, and Exceptionless includes a nice feature usage method in its JS client. We'll use that. &lt;/p&gt;

&lt;p&gt;Change the &lt;code&gt;handleChange&lt;/code&gt; function to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Exceptionless&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitFeatureUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name Change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are submitting the name change event to Exceptionless and tracking it as a feature usage event called "Name Change". Let's take a look at how this looks in our Exceptionless dashboard. Log in again and click on the Feature Usages tab on the left. Then click on Most Frequest. Here you'll see your new Feature Usage events. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhgoghhv9dgcdbh8ys1r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhgoghhv9dgcdbh8ys1r.png" alt="Feature Usage" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty cool, huh! There's a lot more you can layer in, including user details. This is powerful when you want to see how often particular user cohorts use a particular feature. &lt;/p&gt;

&lt;p&gt;Now, we can't talk about event monitoring without talking about errors, right? Let's see what error handling looks like in Exceptionless and Svelte. Let's first start by adding a button to our app and some code that will throw an error when that button is clicked. &lt;/p&gt;

&lt;p&gt;Under the input element in your &lt;code&gt;main&lt;/code&gt; html tags, add this button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{unhandledError}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Throw Error&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in your script tag, add the &lt;code&gt;unhandledError&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unhandledError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You shouldn't be clicking that!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We aren't even doing anything to handle this error. What?! That's because Exceptionless will automatically send unhandled errors through so you can track them. &lt;/p&gt;

&lt;p&gt;Go ahead and click the button. When you do so, nothing will happen. You can wire up your app to show some message if you want, but what we're really focused on is capturing the error in Exceptionless. Head over to your Exceptionless dashboard and click on Exceptions then Most Frequent. You should see something like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9nkqg1mpkodpnd2ahag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9nkqg1mpkodpnd2ahag.png" alt="Exception" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The beauty of this is you can click all the way through that exception and see the details of the error: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F441uk332s39qidwed1ub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F441uk332s39qidwed1ub.png" alt="error details" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, what if you do want to handle errors and add in some additional context? Exceptionless has you covered. Create a new function called &lt;code&gt;handleError&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Handled error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Exceptionless&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;handled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;setUserDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;joe@email.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;power user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see in our catch we are adding a lot more info to the event. We are adding a tag letting us know this was a handled error (you would have much better tags, I'm sure). We are also adding a user with a description to the event. &lt;/p&gt;

&lt;p&gt;Let's create a button in the app and test this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{handleError}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Handled Error&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when you click that and go back to Exceptionless, you'll see your event come through. When you click into the details, you'll see the tags and the user information. Pretty cool, huh?&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Exceptionless is a powerful, flexible, and open-source event monitoring service. It works well with any language, but with the new JavaScript client, it works especially well with JavaScript apps and frameworks. In just a few lines of code, we were able to automate the collection of feature usage data and send errors to our Exceptionless dashboard. &lt;/p&gt;

&lt;p&gt;But it doesn't stop there. You can track just about anything you can imagine with &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt;. Svelte plus Exceptionless work...uhhh...&lt;strong&gt;exceptionionally&lt;/strong&gt; well together. Give them both a try today!&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>svelte</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How To Use Error Boundaries in React With Error Monitoring</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Thu, 19 Aug 2021 12:27:06 +0000</pubDate>
      <link>https://forem.com/exceptionless/how-to-use-error-boundaries-in-react-with-error-monitoring-435h</link>
      <guid>https://forem.com/exceptionless/how-to-use-error-boundaries-in-react-with-error-monitoring-435h</guid>
      <description>&lt;p&gt;Backend engineers have all the tools. Nice error handling. Reporting. Metrics. What about us frontend devs? Sure, we can catch errors in our functions, but what about errors in our presentational code? Take React for example. Write some bad code in your function component and the whole app crashes.&lt;/p&gt;

&lt;p&gt;Fortunately, frontend devs are getting more and more tools to help them with error handling. In fact, with the release of React 16, a new tool was added to the toolbox designed to specifically handle errors in components. &lt;a href="https://reactjs.org/docs/error-boundaries.html" rel="noopener noreferrer"&gt;Error Boundaries allow developers to catch and handle errors&lt;/a&gt; in the presentational layer of React applications. From the React team's announcement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the past, JavaScript errors inside components used to corrupt React’s internal state and cause it to emit cryptic errors on next renders. These errors were always caused by an earlier error in the application code, but React did not provide a way to handle them gracefully in components, and could not recover from them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That all changed with React 16. However, if you wanted to recover from a presentational layer error AND report it, there wasn't anything out of the box to help you. This is where &lt;a href="https://exceptionless.com/?utm_source=first_signup&amp;amp;utm_medium=blog&amp;amp;utm_campaign=error_boundary" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; (an open-source error handling and monitoring tool) and React work really well together.&lt;/p&gt;

&lt;p&gt;Let's run through a quick tutorial that creates a React app that does the following:&lt;/p&gt;

&lt;h2&gt;
  
  
  Creates an Error Boundary
&lt;/h2&gt;

&lt;p&gt;Forces an error in a function component&lt;br&gt;
Recovers from that error&lt;br&gt;
Reports it to our monitoring service (Exceptionless)&lt;br&gt;
Getting Started&lt;br&gt;
For this tutorial, you will need to have the following installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js v12 or greater&lt;/li&gt;
&lt;li&gt;NPM&lt;/li&gt;
&lt;li&gt;Text editor&lt;/li&gt;
&lt;li&gt;&lt;a href="https://exceptionless.com/?utm_source=second_signup&amp;amp;utm_medium=blog&amp;amp;utm_campaign=error_boundary" rel="noopener noreferrer"&gt;Free account on Exceptionless&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With those things in place, let's generate our React app. From the command line, run the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-react-app error-boundary-example&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When your app is created, change into the directory and install the Exceptionless React package:&lt;/p&gt;

&lt;p&gt;cd error-boundary-example &amp;amp;&amp;amp; npm i @exceptionless/react&lt;/p&gt;

&lt;p&gt;This should get you set up with an app and the required package. Now, let's write a bit of code to show off the functionality. We'll walk through setting up an Error Boundary first.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating an Error Boundary in React
&lt;/h2&gt;

&lt;p&gt;The first thing we need to do is create an Error Boundary file. This will act as a wrapper component for the rest of our application. In src folder of your React application, create a new file called ErrorBoundary.js. This will allow us to render a fallback when we hit an error in our component. We'll use Exceptionless's built-in Error Boundary to actually handle reporting the error. You'll see that soon, but let's focus on rendering the fallback for now.&lt;/p&gt;

&lt;p&gt;Inside your new file, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return (
        &amp;lt;div&amp;gt;
          &amp;lt;h1&amp;gt;Uh oh!&amp;lt;/h1&amp;gt;
          &amp;lt;p&amp;gt;
            This wasn't supposed to happen. If you continue to see this message,
            please reach out to support.
          &amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file will, again, wrap our main application code. So it will work throughout all of our components. If there's an error in a component, rather than totally crashing the application, it will render what we have in our render method here. You can change this to include whatever styling and information you'd like. I kept mine pretty simple.&lt;/p&gt;

&lt;p&gt;Now, we need to connect this to our application components.&lt;/p&gt;

&lt;p&gt;Wrapping The App Component&lt;br&gt;
You may have many providers in your application that all wrap your main App component. That's OK. This new Error Boundary component will simply wrap everything at the top level. Go to your index.js and update your file to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import ErrorBoundary from './ErrorBoundary';

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;ErrorBoundary&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/ErrorBoundary&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
);

reportWebVitals();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, before we handle reporting the error to Exceptionless, let's make sure this code works. Start up your application with npm start. We need to force an error. So, go into your App.js file and add an undefined variable into your component body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import logo from './logo.svg';
import './App.css';

function App() {
  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;header className="App-header"&amp;gt;
        &amp;lt;p&amp;gt;{undefinedVariable}&amp;lt;/p&amp;gt;
        &amp;lt;img src={logo} className="App-logo" alt="logo" /&amp;gt;
        &amp;lt;p&amp;gt;
          Edit &amp;lt;code&amp;gt;src/App.js&amp;lt;/code&amp;gt; and save to reload.
        &amp;lt;/p&amp;gt;
        &amp;lt;a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        &amp;gt;
          Learn React
        &amp;lt;/a&amp;gt;
      &amp;lt;/header&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;export default App;&lt;br&gt;
You can see I've added undefinedVariable into the component. Because that variable is, well, undefined, the component will break. Save your code and check out the app. You'll see...&lt;/p&gt;

&lt;p&gt;...an error message still. What gives?&lt;/p&gt;

&lt;p&gt;Well, in development mode, React is going to try to help you out by rendering the error on screen. If you refresh the page, you should see your fallback component render for a split-second before the error appears on screen. When this code is deployed to a production environment, the error won't be displayed on screen. You know this because you've seen your production React apps crash. We all have. It shows a white screen. That's it. Now, though, your app will show the fallback screen.&lt;/p&gt;

&lt;p&gt;Pretty cool!&lt;/p&gt;

&lt;p&gt;Now, we need to make sure the error is reported back to our monitoring system. We will surely get emails from customers about this, but having the details handy might help us solve the problem before our support team can even get to those emails.&lt;/p&gt;
&lt;h2&gt;
  
  
  Capturing Errors
&lt;/h2&gt;

&lt;p&gt;Now that we can display a message, Let's work on capturing the error and sending it to our reporting system—Exceptionless.&lt;/p&gt;

&lt;p&gt;The Exceptionless React package includes an Error Boundary helper called ExceptionlessErrorBoundary. All we need to do is import this into our index.js and wrap our App component with it. You'll need to grab yourself an API key from your Exceptionless account for this. You can follow &lt;a href="https://exceptionless.com/docs/getting-started/" rel="noopener noreferrer"&gt;this guide to do so&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's take a look at what the code looks like. This is what you should update your index.js file to look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {
  Exceptionless, 
  ExceptionlessErrorBoundary
} from "@exceptionless/react";
import ErrorBoundary from './ErrorBoundary';

const startExceptionless = async () =&amp;gt; {
  await Exceptionless.startup((c) =&amp;gt; {
    c.apiKey = "YOUR API KEY";
    c.useDebugLogger();

    c.defaultTags.push("Example", "React");
  });
};

startExceptionless();

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;ErrorBoundary&amp;gt;
      &amp;lt;ExceptionlessErrorBoundary&amp;gt;
        &amp;lt;App /&amp;gt;
      &amp;lt;/ExceptionlessErrorBoundary&amp;gt;
    &amp;lt;/ErrorBoundary&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
);

reportWebVitals();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go back to your React app and re-load. You won't necessarily see it there, but the error event was sent to Exceptionless. Open up your Exceptionless dashboard and take a look at the Exceptions events:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoujav9b76u8x4k4kdwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoujav9b76u8x4k4kdwh.png" alt="exception events with error boundary example" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click into your exceptions to get more details. In this case, we will see what the variable was and the full stack trace for our React app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Error Boundaries in React are powerful tools in helping you debug and quickly fix your applications. You can see how quickly we set this up to not only render a fallback UI and to report to an error monitoring service. You could write even less code and only report the error if you wanted to, but I'll leave that up to you.&lt;/p&gt;

&lt;p&gt;There are plenty of error monitoring services out there that you can plug this into, but if you're interested in an open-source solution, get started with &lt;a href="https://exceptionless.com/?utm_source=third_signup&amp;amp;utm_medium=blog&amp;amp;utm_campaign=error_boundary" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; today.&lt;/p&gt;

</description>
      <category>react</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>How to Build a Custom Go Client For a REST API</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Mon, 29 Mar 2021 13:16:25 +0000</pubDate>
      <link>https://forem.com/exceptionless/how-to-build-a-custom-go-client-for-a-rest-api-2b1a</link>
      <guid>https://forem.com/exceptionless/how-to-build-a-custom-go-client-for-a-rest-api-2b1a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydr1qvydafn9jn9u2x13.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydr1qvydafn9jn9u2x13.jpg" alt="Go gophers" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; is powered by a REST API. When you interact with the dashboard UI, when you use the .NET client, and when you use the JavaScript client, you are interacting with the REST API. It is well-documented, and it can be used without any client libraries. This paradigm makes it simple for developers to create their own wrappers around the API. In fact, we recently started work on building an official Go client for Exceptionless. Along the way, we learned some tips and tricks that may be helpful for others that want to build clients and SDKs in Go that wrap RESTful APIs. &lt;/p&gt;

&lt;p&gt;First, a little about Go. &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; is a statically typed language, built originally by the folks at Google. Go, while close in syntax to many other statically typed languages, differs in that it is no object oriented. Go is also very well suited for &lt;a href="https://www.programmableweb.com/news/what-grpc-api-and-how-does-it-work/analysis/2020/10/08" rel="noopener noreferrer"&gt;gRPC APIs&lt;/a&gt;, but that does not prevent it from being used with REST APIs, as we'll see here today. &lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;In order to build our Go client, we will need to have Go installed. Honestly, this can be the hardest step as it involves setting environment variables and updating your profile source PATH. So rather than risk confusing you with the steps to install Go and get started, I'm going to simply point you to Go's official install instructions. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://golang.org/doc/install" rel="noopener noreferrer"&gt;You can find those instructions here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you've installed Go, you will need to have a text editor handy so that we can write our new Go code. From the command line, create a new folder and call it "go-rest". Change into that directory, and let's start writing some code. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Main File
&lt;/h3&gt;

&lt;p&gt;In Go, you will always have a &lt;code&gt;main.go&lt;/code&gt; file which acts as the entry point for your source code. We need to set that up first, so let's do that now. In the root of your project folder, create your &lt;code&gt;main.go&lt;/code&gt; file. Inside that file, let's start by declaring our package and importing a module. Add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your file won't do anything yet, but we're laying the groundwork. We have declared our package as &lt;code&gt;main&lt;/code&gt;, and we have imported the built-in &lt;code&gt;fmt&lt;/code&gt; library from Go for formatting. &lt;/p&gt;

&lt;p&gt;Next, we need a &lt;code&gt;main&lt;/code&gt; function, so let's create that. Add the following below your import statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the example program Go's example docs show, so we might as well run it. From your command line, inside your project directory, run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go run .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;Hello, world&lt;/code&gt; printed in the command line terminal window. &lt;/p&gt;

&lt;p&gt;Now that we have the fundamentals down, let's talk about how Go works so that we can build our REST API client. You can include as many functions in your &lt;code&gt;main.go&lt;/code&gt; file as you'd like and you can call those function from within other functions. But, like any other programming language, it's probably smart to separate code to make it easier to work with. &lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an API Helper
&lt;/h3&gt;

&lt;p&gt;The nice thing about Go is that when you create a new file, that file is automatically available from any of your other files as long as they share the same main package. &lt;/p&gt;

&lt;p&gt;Since we are building a REST client, it probably makes sense to create a file that would handle all our API routing request. So, create a file in the root of your project called &lt;code&gt;api.go&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Inside that file, make sure to reference the main package at the top like this: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;pacakage main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We are also going to import a couple packages here as well, so your file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These packages are all built into Go itself. You can install external packages as well, and we'll explore that soon. &lt;/p&gt;

&lt;p&gt;Now that we have the start of our API file, it's good to think about what our client needs to do. With a REST API, you may have the following request methods: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET&lt;/li&gt;
&lt;li&gt;POST&lt;/li&gt;
&lt;li&gt;PUT&lt;/li&gt;
&lt;li&gt;DELETE&lt;/li&gt;
&lt;li&gt;PATCH&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may not need all of these for your client, but it's good to know that they exist. In our case, we are going to implement the GET and POST methods and with those as a template, you should be able to extend your code to implement PUT, PATCH, and DELETE. &lt;/p&gt;

&lt;p&gt;Let's start by building the POST method since its the backbone of our client. In your &lt;code&gt;api.go&lt;/code&gt; file, below the import statement, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//Post posts to the Exceptionless Server&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;postBody&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"YOUR API URL/"&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jsonStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;postBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonStr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our real-world use case, we are making requests to the Exceptionless API, so we know the post body needs to be a JSON string. This is why the &lt;code&gt;postBody&lt;/code&gt; is of type &lt;code&gt;string&lt;/code&gt;. If your API is expecting a different format, make sure you type your variable properly here. The other two arguments in our &lt;code&gt;Post&lt;/code&gt; function are pretty self explanatory. The &lt;code&gt;endpoint&lt;/code&gt; string is the endpoint on your API you want to call. The &lt;code&gt;authorization&lt;/code&gt; string is the token/API key needed to authenticate into the API. You could choose to handle the authorization differently, if you wanted. For example, if your API expected basic authentication, your authorization variable might be a string mapping of username and password. &lt;/p&gt;

&lt;p&gt;One of the tricks here is if you are sending JSON to your REST API, you will need to convert the body into a format the http client library within Go can handle. We're doing that with the &lt;code&gt;bytes.NewBuffer(jsonStr)&lt;/code&gt; call. &lt;/p&gt;

&lt;p&gt;Now, let's put together our &lt;code&gt;GET&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//GET makes api GET requests&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"YOUR API URL/"&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;baseURL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;

    &lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"accept"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much like out &lt;code&gt;POST&lt;/code&gt; request, our &lt;code&gt;GET&lt;/code&gt; request takes in arguments. We only need the &lt;code&gt;endpoint&lt;/code&gt; and the &lt;code&gt;authorization&lt;/code&gt; arguments for this function. This function is pretty straight forward. However, if you want to read the response as JSON, you need to take an extra step as I've shown above. &lt;/p&gt;

&lt;p&gt;You will want to a string mapping by unmarshaling the JSON returned by the API. Of course, your API may not return JSON, so use this accordingly. If you do need to unmarshal the JSON, you simply need to pass the response body into the &lt;code&gt;json.Unmarshal()&lt;/code&gt; as shown above. &lt;/p&gt;

&lt;p&gt;These two functions should help you build your other REST-related functions. Now, let's take a look at helper functions that will make your client easy to use while sending the correct data to your API. &lt;/p&gt;

&lt;h2&gt;
  
  
  Convenience Functions
&lt;/h2&gt;

&lt;p&gt;A good SDK or client API wrapper will include helper functions so the developer using it doesn't have to still manually build requests to your API. The best way to build helper functions is to start with your data model. Let's say, for example, your API expects a JSON payload like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"BookTitle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Great Gatsby"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"Author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"F. Scott Fitzgerald"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"Rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we'd probably want to create a struct type variable that we can use to build our payload for the reqest. That might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;BookRating&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;BookTitle&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Author&lt;/span&gt;          &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Rating&lt;/span&gt;                  &lt;span class="kt"&gt;uint&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick note on Go variables and functions. If the variable or the function name is capitalized, it is exported and available throughout your program. &lt;/p&gt;

&lt;p&gt;Now that we have a struct we can use, we can start to build a helper function that would build a payload for our API. In keeping with the example in the JSON and the struct above, let's pretend our API take a &lt;code&gt;POST&lt;/code&gt; request to rate a specific book. For some reason, our API needs the string title and string author of the book, and it needs an interger for the rating. You might create a helper function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;RateBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;newRating&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;BookRating&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;BookTitle&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;Rating&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rating&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newRating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rateBook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"API KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;   

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;RateBook&lt;/code&gt; function, we are allowing the developer to simply pass in the title, author, and the rating. We then build the JSON payload for the developer and send it to the &lt;code&gt;Post&lt;/code&gt; function we created earlier. When we are building the JSON payload, we must use &lt;code&gt;json.Marshal&lt;/code&gt; to convert our struct to a type that can be used with our REST API. &lt;/p&gt;

&lt;p&gt;You'll note, the authorization argument in the above example is "API KEY", but a good SDK will have stored that API Key when the client was initialized. I'll leave it up to you on how you'd like to handle this, but it could be as simple as calling &lt;code&gt;Configure&lt;/code&gt; function with the developer's API Key and storing the key in memory. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;This is a simple example of how you might build a Go client for a REST API. The concepts are general, but they hopefully help you if you find yourself needing to build your own client. Exceptionless will be launching its own Go client soon. If you haven't tried Exceptionless for your application's event monitoring, &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;give it a shot now&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>monitoring</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Debug Electron Apps</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Tue, 23 Feb 2021 14:59:54 +0000</pubDate>
      <link>https://forem.com/exceptionless/how-to-debug-electron-apps-48jg</link>
      <guid>https://forem.com/exceptionless/how-to-debug-electron-apps-48jg</guid>
      <description>&lt;p&gt;Electron is a great framework that makes developing cross-platform desktop applications easy. If you're a JavaScript developer, it is probably the first thing you'll reach for when you decide to build a desktop application. I know I did. In building my first and second desktop applications, I used Electron. In that process, I learned some tricks to help the development process go a little smoother. One such trick is how to better debug issues that may arise in the packaged, production version of your Electron app that you won't see in development. &lt;/p&gt;

&lt;p&gt;If you're not familiar with &lt;a href="https://www.electronjs.org/" rel="noopener noreferrer"&gt;Electron&lt;/a&gt;, it is a framework that allows you to write apps with web technologies and use them on the desktop. This is accomplished by packaging your app within its own dedicated Chromium-based application. Think of a web browser. All it is is a desktop application that allows you to explore web apps and web pages. That's what Electron does for your app. It creates a one off desktop browser. In doing so, you get access to native desktop functionalities that are not available to traditional web applications. &lt;/p&gt;

&lt;p&gt;Like with many software projects, you might find that your local development experience doesn't exactly match what happens in production. When an app is minified, built, compiled, and packaged for production use, there can be subtle changes that can break the experience of the application or break the app entirely. This is especially true when dealing with desktop applications that have more access than you might be used to with web apps. Debugging problems when your application works locally but doesn't work in its production state can be frustrating. This becomes even more frustrating in Electron when you only have access to the web application's JavaScript output in production and not the underling Electron code's output. Fortunately, we can solve this by using an error monitoring service. &lt;/p&gt;

&lt;p&gt;We're going to be making use of &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; and the Exceptionless JavaScript client to debug and monitor our Electron application. Exceptionless is free to get started and totally open-source. Let's get started. &lt;/p&gt;

&lt;p&gt;From within your Electron app's project directory run &lt;code&gt;npm i exceptionless&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now, we can configure the Exceptionless client and use it anywhere. This means we can use it in both the "front end" (web app) code and the "back end" Electron code. For the sake of this tutorial, we are only going to be focusing on the Electron code. Inside your &lt;code&gt;main.js&lt;/code&gt; file, add the following below your other import/require statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { ExceptionlessClient } = require("exceptionless")
const client = ExceptionlessClient.default.config.apiKey = "YOUR API KEY"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can get your project API key in the Exceptionless project settings page. &lt;/p&gt;

&lt;p&gt;Now, with the client configured, you can start using Exceptionless to log events. The cool thing is these don't need to just be errors. If you want to log when a particular function is called within your main Electron code, you can use &lt;code&gt;client.submitLog("Function called")&lt;/code&gt; but with something more descriptive. By submitting log events for particular functions, you will know for sure the function is being called. Of course, you can and should also track errors. This is as simple as calling &lt;code&gt;client.submitException(error)&lt;/code&gt; with your error. &lt;/p&gt;

&lt;p&gt;This is all very abstract, though. So, let's look at a practical example. Let's say your Electron app is listening to some event in order to write some data to the computer's hard disk. We need a trigger to come from our "frontend" html/js code, and then we need to read that trigger and take some action. In Electron, we use &lt;code&gt;ipcMain&lt;/code&gt; to listen for events from the frontend code. An example of this might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ipcMain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Save File&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/path/to/where/you/want/to/store/the/file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Wrote file successfully with the following content: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added a log event that is sent to Exceptionless in the try and I catch the error and send that to Exceptionless in the catch. The beauty of this is we know when the event is successful, which is comforting, but we also know when it fails and why. This is important, because a failure here would be a silent failure in your app. &lt;/p&gt;

&lt;p&gt;Let's say the file path you think you're trying to write to does not exist after your Electron app is built and packaged (a common issue is that PATH variables exposed by default to applications can be different than what you use and have available in your development environment). If that path did not exist, the &lt;code&gt;writeFileSync&lt;/code&gt; command would not work. You would have no idea why, and your users would only know it when they tried to fetch the file that should have been written. &lt;/p&gt;

&lt;p&gt;Imagine trying to debug that without error and event monitoring. You'd fire it up locally on your machine, run some tests, try to replicate the steps exactly as the user did them. And everything would work. You wouldn't see the error because your development environment is just different enough from the production environment to keep you from realizing that the write path in production doesn't exist. &lt;/p&gt;

&lt;p&gt;There are a million other ways your Electron app can fail silently. By adding error and event monitoring, you can quickly debug problems that would otherwise have you banging your head off your desk. &lt;/p&gt;

</description>
      <category>electron</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Saying Thanks to the Open Source Community Through Sponsorship</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Wed, 27 Jan 2021 17:27:03 +0000</pubDate>
      <link>https://forem.com/exceptionless/saying-thanks-to-the-open-source-community-through-sponsorship-1hpp</link>
      <guid>https://forem.com/exceptionless/saying-thanks-to-the-open-source-community-through-sponsorship-1hpp</guid>
      <description>&lt;p&gt;&lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; has always been committed to the open-source software ecosystem. In fact, &lt;a href="https://github.com/Exceptionless" rel="noopener noreferrer"&gt;Exceptionless is entirely open-source&lt;/a&gt;, and we try our best to make it easy for anyone to host their own instance of our software. Our main repository has nearly 2,000 stars on Github and has seen contributions from 26 different people. Across all our repositories, we've seen hundreds of issues opened, dozens of pull requests, and countless comments. And for all of that, we are so appreciative. But we wanted to show our appreciation by doing more than just saying thanks. &lt;/p&gt;

&lt;h2&gt;
  
  
  Thanking Open Source Contributions Through Sponsorship
&lt;/h2&gt;

&lt;p&gt;Today, we're excited to announce that &lt;a href="https://github.com/sponsors/benaadams" rel="noopener noreferrer"&gt;we have sponsored Ben Adams&lt;/a&gt; through the Github Sponsors program. As you all know, we are huge fans of .NET, and Exceptionless is one of the only monitoring tools built around the .NET ecosystem first. Ben, like us, cares deeply about open-source software and the .NET community. We hope that by sponsoring him, we will be giving back in a tangible way, not just to Ben but to the sustainability of open-source. &lt;/p&gt;

&lt;p&gt;Before diving into more about who Ben is and why we're sponsoring him specifically, it might be good to reflect on the importance of sustainable open-source development. Exceptionless survives through a hosted service, but many open-source projects don't have that option. This leaves maintainers in the unenviable position of having to write software, fix bugs, and respond to issues while receiving nothing more than "thanks" as payment. &lt;/p&gt;

&lt;p&gt;"Thanks" doesn't pay the bills. Exposure doesn't pay the bills. &lt;/p&gt;

&lt;p&gt;We don't want to see open-source developers shut down their projects. We want developers to have optionality. &lt;a href="https://medium.com/@kitze/github-stars-wont-pay-your-rent-8b348e12baed" rel="noopener noreferrer"&gt;A quote from Kitze&lt;/a&gt;, the founder of Sizzy and other products, really illustrates this sentiment well: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Open source, writing blog posts, and playing with tweaking lint settings and editor themes all day are completely fine until your landlord knocks on your door or you’re at the checkout at the grocery store.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's not just the viability of creating open-source software that becomes a problem, it's also the long-term sustainability when larger companies use that software. When we see companies like Amazon abuse open-source contributions, we see a door closing on the viability of software that is designed to survive through community and contribution. &lt;/p&gt;

&lt;p&gt;So, while Exceptionless might not change the world by itself with its sponsorship, we want to lead by example. As Kitze said, Github stars don't pay the bills, but money does. So, we're opening our wallet and helping Ben Adams do what he's done so well for years. &lt;/p&gt;

&lt;h2&gt;
  
  
  Ben Adams
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyssobmkjw8wosbtnpqn9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyssobmkjw8wosbtnpqn9.png" alt="Ben Admas Github Profile" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ben has been working on open-source projects for years. He has thousands of contributions across dozens of repositories. In fact, he is so prolific in his .NET contributions that everyone else with more contributions than him are Microsoft employees. It doesn't get more impressive than that. Here's a quick summary of Ben's open-source contributions: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;His projects have 2,600 Github stars (which, again, don't pay the bills 😉)&lt;/li&gt;
&lt;li&gt;He has over 20,000 commits&lt;/li&gt;
&lt;li&gt;He has contributed to 25 different projects&lt;/li&gt;
&lt;li&gt;He's opened over 1,500 pull requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should be clear by now that Ben knows his stuff. As mentioned before, Ben cares a whole lot about .NET, and so do we. So, this sponsorship makes perfect sense for us. &lt;/p&gt;

&lt;p&gt;For the gamers and the game developers, Ben has you covered too. He is the CTO of Illyriad Games which makes &lt;a href="https://www.ageofascent.com/" rel="noopener noreferrer"&gt;Age of Ascent&lt;/a&gt;. Age of Ascent is a real-time MMO that puts players in the cockpits of fighter ships in space. As you might expect, the game's tech stack &lt;a href="https://youtu.be/dqYlKkexth0" rel="noopener noreferrer"&gt;makes heavy use of .NET&lt;/a&gt; and other Microsoft-related services. &lt;/p&gt;

&lt;p&gt;Other people recognize Ben's contributions too: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Since the beginning of the .NET Core journey we’ve had some amazing contributors but I seriously enjoy working with &lt;br&gt;
@ben_a_adams!&lt;br&gt;
-&lt;a href="https://twitter.com/davidfowl/status/1353087429364879361" rel="noopener noreferrer"&gt;David Fowler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's smart, then there's crazy. Then there's Crazy Smart. That's Ben (and he's a lovely chap, too)!&lt;br&gt;
-&lt;a href="https://twitter.com/bitcrazed/status/1354144181837414400" rel="noopener noreferrer"&gt;Rich Turner&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Junior .Net Developer&lt;br&gt;
Senior .Net Developer&lt;br&gt;
Ben Adams .Net Developer&lt;br&gt;
😁 😁 😁&lt;br&gt;
-&lt;a href="https://twitter.com/MarcoRossignoli/status/1166733777206468608" rel="noopener noreferrer"&gt;Marco Rossignoli&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Does Sponsorship Work?
&lt;/h2&gt;

&lt;p&gt;Github Sponsors allows each developer to define what comes along with sponsorship at various levels. Ben was gracious enough to offer his own development time to Gold Level sponsors, and we simply could not pass that up. While we would be happy to simply sponsor Ben's work, having him contribute code to our open-source repositories will help Exceptionless take a major step forward. &lt;/p&gt;

&lt;p&gt;Sponsoring open-source developers is not a new concept, but having it built into Github has help elivate the visibility of portential sponsorship opportunities. We hope that by having companies like Exceptionless sponsor (and publicize those sponsorships) developers, it will encourage others to do the same. Open-source sustainability still has a long way to go, but any step forward we can help the ecosystem take, we're willing to do it. &lt;/p&gt;

&lt;p&gt;Thanks so much, Ben! We look forward to working with you and following your continued contributions across the open-source community. &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>How to Use React Hooks to Monitor Events in Your App</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Tue, 19 Jan 2021 14:58:59 +0000</pubDate>
      <link>https://forem.com/exceptionless/how-to-use-react-hooks-to-monitor-events-in-your-app-4mgc</link>
      <guid>https://forem.com/exceptionless/how-to-use-react-hooks-to-monitor-events-in-your-app-4mgc</guid>
      <description>&lt;p&gt;The &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;introduction of Hooks in React&lt;/a&gt; was a game-changer. Developers now had options when it came to creating stateful components. It used to be that if you had a stateful component, you'd have to use a class component, and if you had a presentational component, you could choose between a class or a function component. Now, with hook, state can be managed inside function components. But that's not all Hooks did for React developers. &lt;/p&gt;

&lt;p&gt;Hooks introduced a better way to reuse stateful functions. Today, we're going to explore how to build a custom React hook that will allow us to monitor events in our application. Those events can be errors, messages, feature usage, logs, or anything you want. There are plenty of error monitoring services out there, but we're going to make use of &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; for three reasons: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Real-time updates&lt;/li&gt;
&lt;li&gt;It's open-source&lt;/li&gt;
&lt;li&gt;The Exceptionless JavaScript client gives us a singleton option (which makes for a good example in this post)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's get started by starting a new React project. You'll need to have the following available on your machine: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node &amp;gt;= 8.10&lt;/li&gt;
&lt;li&gt;npm &amp;gt;= 5.6&lt;/li&gt;
&lt;li&gt;Text editor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assuming you have that ready, open up a terminal. To create a new React project, simply run: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-react-app Monitoring-App&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Replace &lt;code&gt;Monitoring-App&lt;/code&gt; with whatever you'd like to call your project. When everything is done, change into your new application's directory (&lt;code&gt;cd Monitoring-App&lt;/code&gt;). Now, we need to install the Exceptionless JavaScript client. &lt;/p&gt;

&lt;p&gt;To do so, simple run: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install exceptionless&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When that's done installing, start your app (&lt;code&gt;npm start&lt;/code&gt;) and open your project directory in the text editor of your choice. &lt;/p&gt;

&lt;h3&gt;
  
  
  What are Hooks?
&lt;/h3&gt;

&lt;p&gt;React's docs have the simplest definition of Hooks and I think it's worth calling that out here: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The popularity of classes in JavaScript in general has oscillated greatly. However, within the React ecosystem, it was the ONLY option for creating components that could actually do &lt;em&gt;anything&lt;/em&gt;. Because many JavaScript developers do not like and do not want to use classes, the option to write function components was a huge step forward. But outside of developer preferences, React Hooks open up new ways to write code in React apps, and hopefully help you reduce your code footprint in the process. &lt;/p&gt;

&lt;p&gt;Hooks introduced a new way to handle lifecycle events in React as well. Gone are the &lt;code&gt;componentDidMount&lt;/code&gt; and &lt;code&gt;componentDidUpdate&lt;/code&gt; methods. In is the simple and elegant &lt;code&gt;useEffect&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;You can read a lot more about the logic behind React's introduction of hooks &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;, but for the sake of this tutorial, I think that's enough of an intro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating our first Hook
&lt;/h2&gt;

&lt;p&gt;A hook is just a function that returns a value. The big gotcha with Hooks, though, is that they can only be called within the body of a function component. Keep that in mind as we progress. It's still relatively early in the life of Hooks, but there are some standards and conventions in place. Convention is to house your custom hooks in a folder called something like &lt;code&gt;hooks&lt;/code&gt;. Let's do that. &lt;/p&gt;

&lt;p&gt;Create a folder within the &lt;code&gt;src&lt;/code&gt; directory of your project called &lt;code&gt;hooks&lt;/code&gt;. Inside that folder, we're going to create a file using another convention within the React Hooks community. Developers will generally name their hooks with a &lt;code&gt;useFunctionPurpose&lt;/code&gt; type of pattern. For example, if you were building a Hook that determined whether a navigation bar should show up or not, you might name the Hook file &lt;code&gt;useNavigation&lt;/code&gt;. For us, we're going to call our file &lt;code&gt;useMonitoring&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Create that file inside the &lt;code&gt;hooks&lt;/code&gt; directory, and then we can begin building the function. We'e going to go line by line and then I'll show the whole file in one snippet. Let's start by importing the necessary functions from React. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;import { useState, useEffect } from 'react';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I briefly touched on &lt;code&gt;useEffect&lt;/code&gt;. It can be thought of in the same context as &lt;code&gt;componentDidMount&lt;/code&gt; or &lt;code&gt;componentDidUpdate&lt;/code&gt;. We'll make use of this to handle some logic in the setup of our Exceptionless client. &lt;code&gt;useState&lt;/code&gt; can be thought of like &lt;code&gt;this.state&lt;/code&gt; and &lt;code&gt;this.setState&lt;/code&gt; in React class components. &lt;/p&gt;

&lt;p&gt;Next, we'll get access to the Exceptionless JavaScript client like this: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;import { ExceptionlessClient } from "exceptionless/dist/exceptionless";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note: it's important to reference the &lt;code&gt;/dist/exceptionless&lt;/code&gt; file because Exceptionless targets multiple environments and we want to make sure to import the right one. &lt;/p&gt;

&lt;p&gt;Next we're going to handle something I mentioned earlier. Exceptionless is a class-based client. This means we have the option of instantiating that class everytime we use it, or we can make use of a singleton provided to us out of the box by Exceptionless. We set up the singleton patter first and then we will use some logic to handle situations where that singleton may not need to be used. Go ahead and grab the &lt;code&gt;default&lt;/code&gt; client from Exceptionless like this: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;const defaultClient = ExceptionlessClient.default;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you haven't done so, get yourself an API Key from Exceptionless. You can &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;sign up for a free account here&lt;/a&gt;. Once you have that, we're going to provide that key to to the default Exceptionless client. I like to make use of environment variables even when using keys that are safe to expose in the browser. So mine looks like this: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;defaultClient.config.apiKey = process.env.REACT_APP_EXCEPTIONLESS_API_KEY;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that we've handled all our imports and initial configuration, we can frame out our hook function. The bare bones function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useMonitoring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useDefault&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Code goes here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's not much to look at, but there are two things I want to call out. The function name follows the convention I mentioned before, and this function takes two props: &lt;code&gt;config&lt;/code&gt; and &lt;code&gt;useDefault&lt;/code&gt;. If we are making use of the default singleton instance of the Exceptionless client, &lt;code&gt;useDefault&lt;/code&gt; would be true and &lt;code&gt;config&lt;/code&gt; would be null. However, if we are creating a custom instance of the Exceptionless client, &lt;code&gt;config&lt;/code&gt; would be an object and &lt;code&gt;useDefault&lt;/code&gt; would be either null or false. &lt;/p&gt;

&lt;p&gt;Let's handle that logic. At the top of your function add the following: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;const [client, setClient] = useState(defaultClient);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We are making use of the built-in &lt;code&gt;useState&lt;/code&gt; hook here. We are simply defining a &lt;code&gt;client&lt;/code&gt; state variable, defining a function that will be used to update that variable (&lt;code&gt;setClient&lt;/code&gt;), and setting a defualt value for our variable. As you can see, we set the default value to use the default client from Exceptionless. Makes sense, right?&lt;/p&gt;

&lt;p&gt;Next, we're going to use the built-in &lt;code&gt;useEffect&lt;/code&gt; hook to determine what client should be returned for use in the particular part of the app that requested it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;useDefault&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_EXCEPTIONLESS_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      
      &lt;span class="nf"&gt;setClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExceptionlessClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please pass useDefault as true or a config object in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, it's best to think of our &lt;code&gt;useEffect&lt;/code&gt; function in the same way you think of &lt;code&gt;componentDidUpdate&lt;/code&gt;. Any update to the component that called our &lt;code&gt;useMonitoring&lt;/code&gt; Hook will trigger another event within our &lt;code&gt;useEffect&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;If you wanted this &lt;code&gt;useEffect&lt;/code&gt; method to operate more like &lt;code&gt;componentDidMount&lt;/code&gt;, you would structure it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- This array says only run this function once when the component mounts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The empty array in the above example can be filled with a list of dependencies. Say, for example, you want your &lt;code&gt;useEffect&lt;/code&gt; method to run everytime some specific variable changes, you would just pass that variable name into the array. &lt;/p&gt;

&lt;p&gt;Ok back to our &lt;code&gt;useEffect&lt;/code&gt; method. You can see we are checking the &lt;code&gt;useDefault&lt;/code&gt; prop I mentioned before. If it is truthy, we return the client state variable. We had already set that variable to use the singleton Exceptionless client, so all we have to do is return it. If &lt;code&gt;useDefault&lt;/code&gt; is falsey, we then check for the config object. If it's there, we add the apiKey to whatever values were passed into the config object, and then we instantiate a new Exceptionless client. &lt;/p&gt;

&lt;p&gt;If no &lt;code&gt;config&lt;/code&gt; object is provided, we throw an error. You could take this a step further and check if the &lt;code&gt;config&lt;/code&gt; prop is actually of type object, but, hey, that's what Typescript is for, right? We're living dangerously in this crazy, crazy dynamically typed world. &lt;/p&gt;

&lt;p&gt;The final thing you need to do in your &lt;code&gt;useMonitoring&lt;/code&gt; function is return the client. Just as easy as it sounds: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;return client;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here's the whole, complete file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ExceptionlessClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;exceptionless/dist/exceptionless&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ExceptionlessClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;defaultClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_EXCEPTIONLESS_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useMonitoring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useDefault&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setClient&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaultClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;useDefault&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_EXCEPTIONLESS_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      
      &lt;span class="nf"&gt;setClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExceptionlessClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please pass useDefault as true or a config object in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ready to use this bad boy?&lt;/p&gt;

&lt;h2&gt;
  
  
  Using your custom Hook
&lt;/h2&gt;

&lt;p&gt;We created a basic React app, so let's just make use of what comes out of the box. Open your &lt;code&gt;App.js&lt;/code&gt; file, and import your new custom Hook. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;import { useMonitoring } from "./hooks/useMonitoring";&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You'll also need to import the built-in &lt;code&gt;useEffect&lt;/code&gt; Hook from React: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;import { useEffect } from 'react';&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, withing the main &lt;code&gt;App&lt;/code&gt; function, you can use your new custom Hook: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;const exceptionlessClient = useMonitoring({ useDefault: true });&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;How can we test this now? Well, let's make use of the &lt;code&gt;useEffect&lt;/code&gt; function to throw an error as soon as the component mounts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;throwException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you remember, the empty array at the end of the function says this should only run once when the component mounts. &lt;/p&gt;

&lt;p&gt;Now, define the actual &lt;code&gt;throwException&lt;/code&gt; function like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;throwException&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Whoops, it broke&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;exceptionlessClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ready to test this out? If you previously started your React app, it probably already has worked. If you haven't started the app, go ahead and do that now. &lt;/p&gt;

&lt;p&gt;You won't see much beyond the default starter React boiletplate. But that's OK. Open up your Exceptionless dashboard, and you should see an exception has, in fact, been captured.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpdy2e36tjh0ozkubr6xl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpdy2e36tjh0ozkubr6xl.png" alt="Example exception React" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you click into that exception, you'll get a bunch of additional, useful, information. You can start to see how this can be helpful. &lt;/p&gt;

&lt;p&gt;Now is the time where I remind you, our custom Hook can only be used within the body of your component functions. If you were to try to use your Hook in a Redux action function, you'd see an error. The beauty is, even if you're using Redux or something else, you can still throw errors back to your component and handle the error with your &lt;code&gt;useMonitoring&lt;/code&gt; hook. &lt;/p&gt;

&lt;p&gt;But Exceptionless is more than just errors. Let's build a quick, more practical example. &lt;/p&gt;

&lt;h2&gt;
  
  
  Usage Tracking
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;App.js&lt;/code&gt; file, we're going to remove all the boilerplate and add some ugly buttons. No styling in this post. This is what your &lt;code&gt;App.js&lt;/code&gt; file should look like now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMonitoring&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./hooks/useMonitoring&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exceptionlessClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMonitoring&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;useDefault&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleButtonClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;planName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;exceptionlessClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitFeatureUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;planName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Free&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Free&lt;/span&gt; &lt;span class="nx"&gt;Plan&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;More&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Starter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Starter&lt;/span&gt; &lt;span class="nx"&gt;Plan&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;More&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleButtonClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Premium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Premium&lt;/span&gt; &lt;span class="nx"&gt;Plan&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;Learn&lt;/span&gt; &lt;span class="nx"&gt;More&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see we have what might be a pricing page in an app. There are three buttons, one for each plan. We have wired up a button that will call a function that ultimately sends a feature usage event to Exceptionless. Go ahead and try clicking the buttons. &lt;/p&gt;

&lt;p&gt;If you go to your Exceptionless dashboard and click the Feature Usage link on the left, you'll see these events have been captured in a dedicated section that makes it easy for you to track, well, feature usage. This may not replace your analytics provider, but it goes a long way. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl7qthhf6cdz1ynvntgmh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl7qthhf6cdz1ynvntgmh.png" alt="Feature usage example React" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;There is a lot more you can do with Exceptionless. For example, you may have noticed, we have only passed in the &lt;code&gt;useDefault&lt;/code&gt; prop to our custom Hook. You can completely customize your Exceptionless configuration and pass in a &lt;code&gt;config&lt;/code&gt; prop instead. I would encourage you to &lt;a href="https://exceptionless.com/docs/clients/javascript/client-configuration/" rel="noopener noreferrer"&gt;read up on the options here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Exceptionless &lt;a href="https://exceptionless.com/docs/clients/javascript/sending-events/" rel="noopener noreferrer"&gt;provides a lot of methods&lt;/a&gt; built into its JavaScript client that will make debugging, logging, and tracking easier. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>tutorial</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Debugging a .NET Serverless App</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Tue, 12 Jan 2021 15:35:31 +0000</pubDate>
      <link>https://forem.com/exceptionless/debugging-a-net-serverless-app-4cfg</link>
      <guid>https://forem.com/exceptionless/debugging-a-net-serverless-app-4cfg</guid>
      <description>&lt;p&gt;Serverless development has become the hot thing in tech. Renting time on a virtual machine only when you need it saves money and resources. However, there are many gotchas that can make working with serverless technology difficult if you're not prepared. One such gotcha is event handling. &lt;/p&gt;

&lt;p&gt;Unlike a Web Server applications, events in a serverless function act very similarly to console applications. Take AWS Lambda, for example. A Lambda function is going to spin up, execute, and spin down as quickly as it can. You want this. This is one of the key selling points of serverless, and how developers can ultimately save money. However, this can lead to problems when trying to process asynchronous events. We'll cover how to solve that in this post. &lt;/p&gt;

&lt;p&gt;Today, we're going to build a simple .NET Hello World serverless application and we're going to implement event handling to log errors and other events. We're going to use the &lt;code&gt;dotnet&lt;/code&gt; cli to install a new Lambda template, but first we need to make sure we have the &lt;a href="https://www.nuget.org/packages/Amazon.Lambda.Templates" rel="noopener noreferrer"&gt;Amazon Lambda Templates Package&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Once that's installed, create a new directory. I'm calling mine &lt;code&gt;MyFunction&lt;/code&gt;, but you can call yours whatever you'd like. Change into that directory and run the following command: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet new lambda.EmptyFunction --name MyFunction&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will create your new serverless function project in .NET. If you open up your project in Visual Studio or whatever IDE or code editor you prefer, you'll see your main file is &lt;code&gt;Function.cs&lt;/code&gt;. You'll also have a &lt;em&gt;very&lt;/em&gt; helpful README, and a json file with some default configuration. We're not going to be editing anything besides the &lt;code&gt;Function.cs&lt;/code&gt; file, but it's good to know what's provided out of the box when generating a new lambda project. &lt;/p&gt;

&lt;p&gt;We now need to add &lt;a href="https://exceptionless.com?utm_source=serverless-blog-post" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; to the project. Exceptionless is an open-source event monitoring service available to all programming languages, but dedicated to .NET. Let's install it by running this command at the command line: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet add package Exceptionless&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;This will install the most recent version of Exceptionless and is the foundation to you adding event handling in your serverless app. Once Exceptionless is installed, we can take a look at our code and see about where we might want to utilize Exceptionless. &lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;Function.cs&lt;/code&gt; file again and add the Exceptionless namespace like this: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;using Exceptionless;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, let's take a look at the function itself. It's a pretty simple function that returns a string in its uppercase form. We're going to change this around to instead return "Hello" plus the string passed in. Of course, that's not the focus of the tutorial, so we're going to also wire up error handling and event processing. &lt;/p&gt;

&lt;p&gt;So, let's start with error handling. We can manually force an error that will fall into the catch block of a try/catch by not passing in a string to our function. Update your function to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Exceptionless&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Amazon.Lambda.Core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;assembly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;LambdaSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Amazon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serialization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SystemTextJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultLambdaJsonSerializer&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyFunction&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;FunctionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILambdaContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExceptionlessClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"YOUR EXCEPTIONLESS API KEY"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ProcessQueueDeferred&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;try&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input value is required"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello, "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SubmitException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've added the Exceptionless namespace, we've converted the function to take in a string and return a hello world string.&lt;/p&gt;

&lt;p&gt;To test error handling, we have set up a try/catch that will throw if no string is passed into our function. If that happens, we send the exception to Exceptionless. &lt;/p&gt;

&lt;p&gt;Because we need to make sure events are sent to Exceptionless before the function ends, we are using the Exceptionless method &lt;code&gt;ProcessQueueDeferred()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now, it's time to test. Fortunately, there's a super easy way to test our code before we deploy to AWS. In your root directory, find the &lt;code&gt;test&lt;/code&gt; folder. Nested in that folder is a test file called &lt;code&gt;MyFunction.Test.cs&lt;/code&gt;. We're going to edit this file a bit and run our tests from the command line. &lt;/p&gt;

&lt;p&gt;Update the file to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Xunit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Amazon.Lambda.Core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Amazon.Lambda.TestUtilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;MyFunction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyFunction.Tests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FunctionTest&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;HelloWorldFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TestLambdaContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;upperCase&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FunctionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, John!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upperCase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test should pass and we should not be sending anything to Exceptionless. To test it, switch into &lt;code&gt;MyFunction/test/MyFunction.Tests&lt;/code&gt; and run &lt;code&gt;dotnet test&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If your test passed, you're in great shape! But we don't just want to test our function. We want to make sure errors are sent to Exceptionless. So let's force an error. &lt;/p&gt;

&lt;p&gt;Add the following to your test file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ErrorTest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ErrorFunctionTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TestLambdaContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FunctionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, John!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test should pass because we don't get a response of "Hello, John!". But what we want to do is check to see if the exception was sent to Exceptionless. &lt;/p&gt;

&lt;p&gt;Open up your Exceptionless dashboard and you shoud see something like &lt;code&gt;Exception in FunctionHandler input value is required&lt;/code&gt;. If you click on it, you'll see more details like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa4ezgwz4elxp3yuw92of.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa4ezgwz4elxp3yuw92of.png" alt="Example exception" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are three tabs on the details page. In the above screenshot, I have selected the "Overview" tab. However, if you explore the other tabs, you'll see value data captured for you automatically. &lt;/p&gt;

&lt;p&gt;Cool, so we created an exception. What about something a little more complex? &lt;/p&gt;

&lt;p&gt;Let's say we want to track the usage of our new serverless function. We can do that pretty easily with Exceptionless. Let's change the current try/catch block to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input value is required"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SubmitFeatureUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Serverless Function"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello, "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SubmitException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are sending a feature usage event to Exceptionless as soon as the serverless function is triggered and we're sure the input is not null. The nice thing about this is that it doesn't rely on any errors being thrown and the rest of your function can continue to execute. &lt;/p&gt;

&lt;p&gt;Let's run our tests again. We should get the feature usage event as well as an additional error because, remember, one of our tests forces a null exception. &lt;/p&gt;

&lt;p&gt;In our dashboard, if we look at all event, we will see our feature usage event logged. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F50pqfti1rnjnrvgb3m2j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F50pqfti1rnjnrvgb3m2j.png" alt="feature usage example" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These types of events (features, logs, errors) because especially useful in serverless environments. Often, default logging in a serverless environment is either non-existent or much more difficult to set up. By dropping &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; into your serverless application, you can track just about anything you're interested in. If you'd like to see full examples of Exceptionless in Lambda functions, check out our examples &lt;a href="https://github.com/exceptionless/Exceptionless.Net/tree/master/samples/Exceptionless.SampleLambda" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/exceptionless/Exceptionless.Net/tree/master/samples/Exceptionless.SampleLambdaAspNetCore" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>serverless</category>
      <category>aws</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why You Should be Practicing Exception Driven Development</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Mon, 07 Dec 2020 16:21:30 +0000</pubDate>
      <link>https://forem.com/exceptionless/why-you-should-be-practicing-exception-driven-development-54p4</link>
      <guid>https://forem.com/exceptionless/why-you-should-be-practicing-exception-driven-development-54p4</guid>
      <description>&lt;p&gt;You've heard of test-driven development. You've heard of behavior-driven development. Maybe you've even heard of acceptance-driven development. But you probably haven't heard much about exception-driven development. Let's take a look at what that type of development process is and why you should be practicing it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Exception Driven Development
&lt;/h2&gt;

&lt;p&gt;Jeff Atwood, of &lt;a href="https://blog.codinghorror.com/" rel="noopener noreferrer"&gt;Coding Horror&lt;/a&gt;, wrote a &lt;a href="https://blog.codinghorror.com/exception-driven-development/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; almost 12 years ago about this topic. In those dozen years since his post, the need for exception-driven development has only increased, but developers and companies need a clear understanding of how and why to practice this type of development.&lt;/p&gt;

&lt;p&gt;At a high-level, exception-driven development is simply the practice of monitoring for exceptions in your code and shipping fixes quickly. To ensure you are monitoring the right things and shipping the right fixes, all without burdening your users, you have to make sure you are collecting the right data. &lt;/p&gt;

&lt;p&gt;Contextual data is the key to exception-driven development. Arbitrary data from various points of input may not be useful. Data that is highly contextual to user actions, user experiences, and points in time during the use of your app will allow you to target better solutions and ship faster. &lt;/p&gt;

&lt;p&gt;With your contextual data in hand, you can start to fix issues. But here's the rub: You can't wait until you "have enough" fixed for a deployment. Part of the exception-driven development process is deploying often. Have a single bug that took one line to fix? Cool, ship it. Know that you'll have additional features to put out in a few days and you're considering holding your bug fix for that deployment? Don't. Ship the bug fix, then ship the features. &lt;/p&gt;

&lt;p&gt;Exception-driven development isn't a mysterious new process for most developers, but it is a mindset shift within many organizations. Bug fixes, listening to the data, and responsiveness must take priority if you are to transition to an exception-driven development cycle. While it may not take much effort to change your company's internal process, it may still take some convincing. So, why should you and your company practice exception-driven development?  &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Exception Driven Development
&lt;/h2&gt;

&lt;p&gt;The first reason you should care is the most obvious reason. Your code has bugs. It does. No matter how good you are, you're going to ship bugs and you need to be ready to fix those bugs. Jeff Atwood probably said it best in his post about exception-driven development: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The question isn't how many bugs you will ship but how fast you can fix them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bugs are a part of code. Some never get fixed. But the ones that need to be fixed need to be fixed quickly. The trouble, of course, is that if you are relying on your users to tell you about these bugs, you've already taken too long to fix the issue. &lt;/p&gt;

&lt;p&gt;Wait, what? &lt;/p&gt;

&lt;p&gt;It's true. If your users have told you about bugs through email or Slack or Discord, you have already taken too long to resolve the issue. This is where the heart of exception-driven development comes in. You need to know about issues the second they arise. &lt;/p&gt;

&lt;p&gt;You don't want to end up like this guy, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Febuve2xlqy7ctt1z7y7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Febuve2xlqy7ctt1z7y7z.png" alt="Image of angry cat acting as tech support" width="800" height="759"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think about it this way. How many lines of code does your application have? Got that number in mind? Ok, now divide it by 1000. Take your resulting number and multiply it by 15. &lt;a href="https://www.quora.com/What-is-the-average-ratio-of-bugs-to-a-line-of-code" rel="noopener noreferrer"&gt;That is possibly how many bugs&lt;/a&gt; you have in your software &lt;em&gt;right now&lt;/em&gt;. Knowing this, don't you think it's important to try to find these bugs before your users have to tell you about them?  &lt;/p&gt;

&lt;p&gt;By practicing exception-driven development, you make your customers happier which protects your brand image. Do you want to be the brand that has a ton of bugs or do you want to be the brand that solves problems? You also make your developers happier. Would you rather fix a bug on a piece of code shortly after you were working on it, or do you want to try to fix it six months later after you've long forgotten about that code? &lt;/p&gt;

&lt;p&gt;Customer retention, customer conversion, productivity, morale, and more are the reasons exception-driven development is important. Convinced yet? Good, now how do you do it?&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Practice Exception Driven Development
&lt;/h2&gt;

&lt;p&gt;If you remember, the first step of exception-driven development is to collect &lt;em&gt;contextual&lt;/em&gt; data. Contextual data means data more than the stack trace itself. You should be collecting those traces, but the stack trace is just part of the picture. Some of the questions your contextual data should be answering include: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What user had this problem? &lt;/li&gt;
&lt;li&gt;Where in the application did the problem occur?&lt;/li&gt;
&lt;li&gt;Has the problem occurred previously? &lt;/li&gt;
&lt;li&gt;What actions did the user take leading up to the issue?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can probably think of other questions you'd like answered to help you with the bugs that come in. But notice that the suggestion here is not to collect this information directly from your users. Don't wait for an email from them. Don't follow-up with questions about their operating system and browser. Collect that information upfront without the user having to take action, and you will have your contextual data. Services like &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; make this easy.&lt;/p&gt;

&lt;p&gt;But why use a service like Exceptionless? You're a developer, you can just build the solution yourself. Sure you can, but then you have to manage that solution. You have to fix bugs on that solution while also fixing bugs you've found from your actual production application. You're not in the business of running an error monitoring service. But &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; is. &lt;/p&gt;

&lt;p&gt;Once you've collected your contextual data, you should know what to fix, where to fix it, and why it needs to be fixed. So, the logical thing to do is—well—fix it. The trick, though, is not to allow code creep to slow your release down. It's easy (trust me we all do it) to say, "oh, I'll just add this little feature or change this one other thing" when you're trying to fix a bug. You have to fight that urge, fix the bug, commit the code, and ship it. Then, you can go back and work on the shiny thing that &lt;strong&gt;almost&lt;/strong&gt; distracted you. &lt;/p&gt;

&lt;p&gt;Once your code is shipped, if you are using &lt;a href="https://exceptionless" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt;, you can mark the version that fixed the bug right within your dashboard. By doing this, you'll automatically know if you have any regressions. Exceptionless will track new occurrences of the error and compare the occurrence against the version of software the user is using and the version you marked as solving the problem. If those versions match, it's a regression. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The whole flow of collecting data, analyzing the data, writing code, and shipping should not be foreign to you. Yet, exception-driven development is still not practiced everywhere. Hopefully, this article helps you understand why you should change your ways and how to do it. &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>monitoring</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Comparing Error Monitoring Services</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Mon, 02 Nov 2020 14:09:51 +0000</pubDate>
      <link>https://forem.com/exceptionless/comparing-error-monitoring-services-15km</link>
      <guid>https://forem.com/exceptionless/comparing-error-monitoring-services-15km</guid>
      <description>&lt;p&gt;Error monitoring is vital to the success of any application. Console logs only get you so far. Once your app is out in the wild, asking your customers to open up the developer tools window and inspect it for errors is a deal-breaker. This is where error monitoring services come in. Let's take a look at three different services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log Rocket&lt;/li&gt;
&lt;li&gt;Sentry&lt;/li&gt;
&lt;li&gt;Exceptionless. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each service, generally speaking, handles errors and logging for your applications, but not all services are created equally. Let's take a closer look at each and see how they stack up.&lt;/p&gt;

&lt;h1&gt;
  
  
  Log Rocket
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://logrocket.com" rel="noopener noreferrer"&gt;Log Rocket&lt;/a&gt; was founded in 2015 and is an error monitoring service that focuses on replaying the events that led up to the error. While some services focus on digging into the error details themselves, Log Rocket uses HTML from the user's session to reconstruct a playback of what the user experienced.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What LogRocket does is we capture a recording in real time of all the user activity so the developer on the other end can replay exactly what went wrong and troubleshoot issues faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://techcrunch.com/2019/03/21/logrocked-nabs-11m-series-a-to-fix-web-application-errors-faster/?guccounter=1&amp;amp;guce_referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8&amp;amp;guce_referrer_sig=AQAAAIPY3DnugxcKUD8lyUXLl-FXSS29_pkxK32gWJb_Kp0lGk2YWj19tXm2PCHIjj4kFV6DBtRurKKebhBH5czcymF2Ct0k_D1UFvoJtxkD-76DSFmTqD07uaoxVS69YzFZLa-QsEcsoiwVbHWBFkLyRywxOBu8baLFu34hztJrZSCa" rel="noopener noreferrer"&gt;Matthew Arbesfeld, co-founder of Log Rocket&lt;br&gt;
Log Rocket example&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyir1usa327tgdgmyg1uu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyir1usa327tgdgmyg1uu.png" alt="Log Rocket" width="628" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Log Rocket is a venture-backed company that has raised $30 million in its history. It provides its tools exclusively as a for-profit, hosted solution. They do offer self-hosted options, but only as part of their enterprise, custom pricing.&lt;/p&gt;

&lt;p&gt;Their focus is on user experience through the tracking of everything a user does on the site. While this is helpful, it is also a bit invasive in the fact that the default installation of Log Rocket captures just about everything a user does in the application.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sentry
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://sentry.io" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt; was founded in 2012 and is focused on capturing errors at the code-level and sending them to a repository for review and organization. Sentry allows you to configure the groupings of errors and presents them in an interface designed to surface the most-pressing errors first.&lt;/p&gt;

&lt;p&gt;In addition to surfacing errors, Sentry allows users to create custom alerts. For example, should a specific event occur, you can set up a trigger to send an email to your team. This is generally used for errors, but it could be used for just about any event sent through to Sentry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl4ri1uglsmpjc9wn3c9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl4ri1uglsmpjc9wn3c9n.png" alt="Sentry Example" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sentry, like Log Rocket, is also a venture-backed company. They have raised over $66 million in their history. Unlike Log Rocket, Sentry provides an open-source and self-hosted solution for free. For users that do not want to pay for Sentry's hosted option, they can utilize Docker to run a self-hosted, containerized version of the Sentry platform.&lt;/p&gt;

&lt;p&gt;One big differentiator for Sentry is its focus on providing services for a wide array of platforms.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sentry differentiates from legacy application performance monitoring solutions by focusing on software that runs on devices its developers have no control over, including mobile and IoT devices and smart sensor networks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://techcrunch.com/2019/09/24/sentry-raises-40-million-series-c-led-by-accel-for-its-error-tracking-software/" rel="noopener noreferrer"&gt;Techcrunch, 2019&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Exceptionless
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://exceptionless" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; has been around the longest of the three services reviewed here. Created as a software offering from the parent company CodeSmith Tools, Exceptionless was established in 2010 and is privately held. It is positioned as a tool to help first and a product second. This is why one of Exceptionless's main focuses is the open-source community.&lt;/p&gt;

&lt;p&gt;Exceptionless lets developers capture logs, events, and errors. However, Exceptionless's real differentiator is its real-time delivery mechanisms. Rather than costly code deployments to change your error monitoring configurations, Exceptionless allows you to make changes from their user interface and those changes will apply instantly in your application. This is key when it becomes clear that additional errors need to be surfaced quickly.&lt;/p&gt;

&lt;p&gt;From the user experience and customer experience front, Exceptionless works hard to stand out from the competition. In Exceptionless 7.0, customers are now able to mark stacks of errors and logs as "discarded", the events will no longer count against plan quotas. Combine that with their chat, email, and Discord support, and Exceptionless proves its focus on customers.&lt;/p&gt;

&lt;p&gt;Digging into the product features, Exceptionless provides one of the cleanest views for understanding events and errors in your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fck6frel9tl82zentawe4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fck6frel9tl82zentawe4.png" alt="Exceptionless Example" width="776" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the information you need about errors and events are captured in a simple, easy to read view. From your dashboard, you can consolidate events into stacks to help group relevant issues. You can also indicate the resolution of events based not just on the fact that the issue was resolve but based on the version of your software that fixed the event. Exceptionless will automatically recognize any new errors that come in with an older version and group them in the resolved bucket. However, should the error surface on the version of your software in which you marked the issue fixed, Exceptionless will classify this event as a regression without you having to manually do so.&lt;/p&gt;

&lt;h1&gt;
  
  
  So Which One is Right For You?
&lt;/h1&gt;

&lt;p&gt;The answer to this often comes down to what's most important for your application. Each service has its merits, but the value provided differs based on use-cases. Log Rocket offers full session replays, but may not be the right solution for digging deep into stack traces. Sentry offers full stack trace reviews and error categorization, but it may not be the right solution if you need the ability to update your error handling configuration in real-time. Exceptionless provides real-time error monitoring and configuration, and it is committed to the open-source community.&lt;/p&gt;

&lt;p&gt;In the end, the choice is yours.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>javascript</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>How to Self-Host Your Error Monitoring Service</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Wed, 30 Sep 2020 14:05:55 +0000</pubDate>
      <link>https://forem.com/exceptionless/how-to-self-host-your-error-monitoring-service-258k</link>
      <guid>https://forem.com/exceptionless/how-to-self-host-your-error-monitoring-service-258k</guid>
      <description>&lt;p&gt;The beauty of open-source solutions is that you are often given the option to self-host or pay for an easy hosted solution by the company or people who created the project. This is true of many projects. &lt;a href="https://ghost.org" rel="noopener noreferrer"&gt;Ghost&lt;/a&gt; is a popular example of this from the blogging world. Some analytics serves, including &lt;a href="https://matomo.org/matomo-on-premise/" rel="noopener noreferrer"&gt;Matomo&lt;/a&gt;, allow users to choose between a hosted and a self-hosted solution. In that same vein, &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt; provides a self-hosted option for those who would like to host their own error monitoring. &lt;/p&gt;

&lt;p&gt;Today, we're going to walk through setting up a self-hosted Exceptionless instance. Let's get started!&lt;/p&gt;

&lt;p&gt;Exceptionless provides a simple Docker image to help get started with self-hosting. We're going to make use of that, so the first step is to &lt;a href="https://www.docker.com/get-started" rel="noopener noreferrer"&gt;download Docker for desktop&lt;/a&gt; if you don't already have it. Once you're able to download that and start it, you should then be able to execute &lt;code&gt;docker&lt;/code&gt; commands from the command line. Test it out by running &lt;code&gt;docker stats&lt;/code&gt; in the command line. &lt;/p&gt;

&lt;p&gt;Pretty cool, right? Just by downloading and running the desktop application, you also have access to the Docker CLI. That CLI is what we'll need to run our self-hosted instance of Docker. &lt;/p&gt;

&lt;p&gt;Let's make sure we can get Exceptionless running locally. Ready for how easy this is? Are you?&lt;/p&gt;

&lt;p&gt;Ok, start up Docker Dekstop, then in your command line, run: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run --rm -it -p 5000:80 exceptionless/exceptionless:latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will check to see if you've already downloaded the latest Exceptionless release, and if not, it will install all of the necessary dependencies. This is important because Exceptionless is split into a client-side front-end and a server-side back-end. Docker lets all of this be combined. &lt;/p&gt;

&lt;p&gt;When the process in your command line finishes up, open your browser and navigate to &lt;code&gt;http://localhost:5000&lt;/code&gt;. If all went well, you should see the Exceptionless login page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2jpms2g62169ejw66g7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2jpms2g62169ejw66g7.png" alt="Exceptionless self-hosted login page" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and sign up for an account. Keep in mind, this is not a good production solution, but it's a great way to get started with a self-hosted error monitoring solution. &lt;/p&gt;

&lt;p&gt;Along with the front-end that we're looking at now, you also have a full Exceptionless server running. To prove it, let's run a simple cURL command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl --location --request POST 'http://localhost:5000/api/v2/auth/login' \
--header 'Content-Type: application/json' \
--data-raw '{
    "email": EMAIL_ADDRESS, 
    "password": PASSWORD
}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to use the email and password you just signed up with. You should get a token back. This shows you that the API is running successfully and you can now do everything you would with a hosted Exceptionless instance, but locally. Go ahead and try it out. &lt;a href="https://api.exceptionless.io/docs/index.html" rel="noopener noreferrer"&gt;Here are the full API docs for Exceptionless&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem here is the data you save in this run of your self-hosted Exceptionless instance will not be saved between runs. As soon as you shut down Docker and exit the application, your data will be deleted and you'll be starting from scratch. That's no fun. Let's fix it.&lt;/p&gt;

&lt;p&gt;Go ahead and shut down Exceptionless either by exiting in the command line or by going into your Docker Desktop Dashboard and clicking the stop button your Exceptionless instance. Once it's stopped, open up your command line again and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -it -p 5000:80 \
    -v $(pwd)/esdata:/usr/share/elasticsearch/data \
    exceptionless/exceptionless:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using PowerShell, you'll instead want to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -it -p 5000:80 `
    -v ${PWD}/esdata:/usr/share/elasticsearch/data `
    exceptionless/exceptionless:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when you sign up at &lt;code&gt;http://localhost:5000&lt;/code&gt;, your data will be persisted. You can start tracking errors locally and that data will be shown in your Exceptionless dashboard even after you shut down Docker/Exceptionless and restart it. &lt;/p&gt;

&lt;p&gt;Your homework: Try running this locally with SSL and SMTP enabled. It's just as simple as everything else we've done so far because Exceptionless has really taken the time to make sure the developer experience is top-notch. &lt;a href="https://github.com/exceptionless/Exceptionless/wiki/Self-Hosting#simple-setup-wssl-support-and-smtp" rel="noopener noreferrer"&gt;Check out the instructions here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Error monitoring is incredibly important to both your customer's experience and your own sanity. To give yourself true control over error monitoring, you can choose a solution like Exceptionless, and as you've seen here, self-host it pretty easily. Of course, if you'd rather let Exceptionless take care of hosting, &lt;a href="https://exceptionless.com" rel="noopener noreferrer"&gt;that's covered too&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Now, you can go and experiment with your newly installed, self-hosted, error monitoring service. Will you let it run on your machine? Will you tinker and get it production-ready? Will you deploy it to a remote server somewhere? (That last one might be the subject of a future post 😉)&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>opensource</category>
      <category>dotnet</category>
      <category>docker</category>
    </item>
    <item>
      <title>Why We Upgraded Our Production Application to .NET 5.0</title>
      <dc:creator>Justin Hunter</dc:creator>
      <pubDate>Thu, 24 Sep 2020 18:12:12 +0000</pubDate>
      <link>https://forem.com/exceptionless/why-we-upgraded-our-production-application-to-net-5-0-26mf</link>
      <guid>https://forem.com/exceptionless/why-we-upgraded-our-production-application-to-net-5-0-26mf</guid>
      <description>&lt;p&gt;For anyone who has built an application, you've probably built it on some library or framework that changes over time. To keep up, you have to upgrade your application. However, there are varying schools of thought around when you should upgrade. At &lt;a href="https://exceptionless" rel="noopener noreferrer"&gt;Exceptionless&lt;/a&gt;, we like to be on the bleeding edge. As an open-source company, we feel a responsibility to the community to know and understand the open-source tools we use. As such, we have already upgraded Exceptionless to use .NET 5.0. &lt;/p&gt;

&lt;p&gt;To give you a little background, .NET 5.0 was &lt;a href="https://devblogs.microsoft.com/dotnet/introducing-net-5/" rel="noopener noreferrer"&gt;introduced in May of 2019&lt;/a&gt;. The announcement was a big one as Microsoft chose to drop the .NET Core distinction. Going forward, we will just see cross-platform support in the form of ".NET X.X". The first release candidate for .NET 5.0 was &lt;a href="https://devblogs.microsoft.com/dotnet/announcing-net-5-0-rc-1/" rel="noopener noreferrer"&gt;announced September 13, 2020&lt;/a&gt;. We chose to upgrade and begin using .NET 5.0 immediately. That decision was driven by Microsoft's commitment to supporting production usage of the rc1 release. And as it turned out, the upgrade process was not too painful at all. &lt;/p&gt;

&lt;p&gt;All in, the upgrade took about one hour and was a very small commit. You can actually &lt;a href="https://github.com/exceptionless/Exceptionless/commit/874f08e70a3ded2762f8d34df0378de38d7a3193" rel="noopener noreferrer"&gt;see the commit here&lt;/a&gt;. This is really a testament to the foundation we've built here combined with the long-running foundation Microsoft has built with the .NET framework. Exceptionless is no small application and yet we were able to upgrade to an early release candidate in order to capitalize on new capabilities. To highlight the scale of Exceptionless and the relatively minor impact the upgrade process had, let's take a look at some of our numbers. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1.4 TB Elasticsearch Cluster
&lt;/li&gt;
&lt;li&gt;173M Elasticsearch Documents
&lt;/li&gt;
&lt;li&gt;384M Redis Operations/Day
&lt;/li&gt;
&lt;li&gt;122M HTTP Requests/Day
&lt;/li&gt;
&lt;li&gt;2,476 GitHub Stars
&lt;/li&gt;
&lt;li&gt;568 GitHub Forks
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are always multiple schools of thought around running pre-release code on production applications, but for us, the decision was a no-brainer. The top motivators were performance improvements, availability of new C# features, support for our work with other partners, and Docker improvements for our self-hosted solution. &lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Improvements
&lt;/h2&gt;

&lt;p&gt;We are a developer tool, and as such, performance is important. .NET 5.0 allows us to leverage the performance boosts associated with the upgrade and pass that along to our customers and the community around us. We compared our memory and performance from .NET Core 3.1 to the .NET 5.0 rc-1 release and saw enough gains to help support our decision to move forward with rolling this out to production. &lt;/p&gt;

&lt;p&gt;The .NET team's focus on pushing the boundaries of garbage collection was an important factor for us. GC is such a critical component to performance, and it impacts almost everything within the framework. We were excited to see the &lt;a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/#gc" rel="noopener noreferrer"&gt;focus Microsoft put on continuing to improve performance&lt;/a&gt; in this area and felt the gains were enough to really tilt us towards our production release of Exceptionless using .NET 5.0. &lt;/p&gt;

&lt;p&gt;As a quick, visual example, of other improvements, here’s a table Ben Adams tweeted that gives us glimpse into the performance gains of .NET 5.0 over .NET 3.1:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1306817978927902720-585" src="https://platform.twitter.com/embed/Tweet.html?id=1306817978927902720"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1306817978927902720-585');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1306817978927902720&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  New C# Features
&lt;/h2&gt;

&lt;p&gt;With the release of C# 9, we, once again, get significant improvements. Anytime a programming language releases new features, it's important to ask yourself whether those features are necessary for your application. In the case of C# 9, there are multiple features we believe will help improve the code legibility, overall codebase size, and ultimately performance. It always comes back to performance! &lt;/p&gt;

&lt;p&gt;Pattern matching in C# 9 is a feature we are particularly excited about. If you're interested in a deep dive on the improvements here, &lt;a href="https://anthonygiretti.com/2020/06/23/introducing-c-9-improved-pattern-matching/" rel="noopener noreferrer"&gt;Anthony Giretti has a great post&lt;/a&gt; highlighting the new functionality. For Exceptionless, pattern matching represents a better way for us to execute logical operations we already support. In doing so, we can reduce code complexity, improve performance, and deliver a better experience. &lt;/p&gt;

&lt;p&gt;Records are an exciting new feature in C# 9 as well. Data immutability is important, once again, for—you guessed it—performance. The way &lt;a href="https://daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records" rel="noopener noreferrer"&gt;Dave Brock puts it&lt;/a&gt; on his blog is apt: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Immutable types reduce risk, are safer, and help to prevent a lot of nasty bugs that occur when you update your object. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Data records give us immutability in the form of a dedicated struct. Rather than extending the functionality of C#'s existing structs, records give us the ability to reach for a data-specific type that offers built-in immutability. &lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Improvements
&lt;/h2&gt;

&lt;p&gt;We are proud of our open-source roots. We want to make self-hosting Exceptionless as easy as possible, and Docker has made this a reality. Our Docker image is the fastest and easiest way to get started with self-hosting and .NET 5.0 only improves the Docker experience. &lt;/p&gt;

&lt;p&gt;.NET 5.0 enables better resource compaction which, in turn, reduces the cost associated with Docker images. This is important to the bottom line, but .NET 5.0's improvements go beyond dollar-savings with Docker. The new features also improve memory constraints which—say it with me now—improve performance. &lt;/p&gt;

&lt;p&gt;One additional benefit of the .NET 5.0 rc-1 release candidate is how our Docker image now works better with Kubernetes resource constraints. We're pretty big fans of Docker and Kubernetes, so anything to improve the experience around both is a win in our eyes. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We took an early release candidate from a massive framework and rolled it out to production almost immediately after it was announced. Are we crazy? We don't think so, but you decide. &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>microsoft</category>
    </item>
  </channel>
</rss>
