diff --git a/.github/workflows/build-arm64.yml b/.github/workflows/build-arm64.yml index 156041be31..6b8c9a6f99 100644 --- a/.github/workflows/build-arm64.yml +++ b/.github/workflows/build-arm64.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-24.04-arm steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 - name: Setup .NET Core diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 62279308d3..449d60b20f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -33,7 +33,7 @@ jobs: steps: - name: Resolve preview pull request id: pr - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | if (context.eventName === "repository_dispatch") { @@ -89,7 +89,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }} @@ -135,7 +135,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }} @@ -144,7 +144,7 @@ jobs: with: dotnet-version: 10.0.301 - - uses: actions/cache@v5 + - uses: actions/cache@v6 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.lock.json') }} @@ -187,7 +187,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }} @@ -197,7 +197,7 @@ jobs: node-version: 24 - name: Cache node_modules - uses: actions/cache@v5 + uses: actions/cache@v6 id: cache-node-modules with: path: src/Exceptionless.Web/ClientApp/node_modules @@ -233,7 +233,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }} @@ -382,7 +382,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload.head_sha) || github.event.pull_request.head.sha || github.sha }} @@ -464,6 +464,16 @@ jobs: echo "- **Deployment**: Skipped" >> $GITHUB_STEP_SUMMARY fi + deploy-website: + name: Deploy website + if: ${{ needs.version.outputs.is_prod_deploy == 'true' }} + needs: [version, deploy] + permissions: + contents: read + pages: write + id-token: write + uses: ./.github/workflows/website.yml + preview-comment-result: needs: [preview-context, version, test-api, test-client, docker-build, docker-publish, deploy] if: ${{ always() && needs.preview-context.outputs.pr-number != '' }} diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 2d7a9c8d05..0809e4fb80 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 @@ -38,7 +38,7 @@ jobs: echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH" aspire --version - - uses: actions/cache@v5 + - uses: actions/cache@v6 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/packages.lock.json') }} @@ -54,7 +54,7 @@ jobs: node-version: 24 - name: Cache node_modules - uses: actions/cache@v5 + uses: actions/cache@v6 id: cache-node-modules with: path: src/Exceptionless.Web/ClientApp/node_modules diff --git a/.github/workflows/dev-environment-reset.yml b/.github/workflows/dev-environment-reset.yml index 5e40565e7e..7ef521fa35 100644 --- a/.github/workflows/dev-environment-reset.yml +++ b/.github/workflows/dev-environment-reset.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Azure Login run: az login --service-principal --username ${{ secrets.AZ_USERNAME }} --password ${{ secrets.AZ_PASSWORD }} --tenant ${{ secrets.AZ_TENANT }} --output none diff --git a/.github/workflows/dev-environment-start.yml b/.github/workflows/dev-environment-start.yml index 3220c2bb5f..1f1f4f3fe6 100644 --- a/.github/workflows/dev-environment-start.yml +++ b/.github/workflows/dev-environment-start.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Azure Login run: az login --service-principal --username ${{ secrets.AZ_USERNAME }} --password ${{ secrets.AZ_PASSWORD }} --tenant ${{ secrets.AZ_TENANT }} --output none diff --git a/.github/workflows/dev-environment-stop.yml b/.github/workflows/dev-environment-stop.yml index ef7f60fef6..76a13c432d 100644 --- a/.github/workflows/dev-environment-stop.yml +++ b/.github/workflows/dev-environment-stop.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Check Schedule Window id: schedule_window diff --git a/.github/workflows/elasticsearch-docker-8.yml b/.github/workflows/elasticsearch-docker-8.yml index 26eb91d46c..6f65a4ccd6 100644 --- a/.github/workflows/elasticsearch-docker-8.yml +++ b/.github/workflows/elasticsearch-docker-8.yml @@ -12,7 +12,7 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') != true steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Setup .NET Core uses: actions/setup-dotnet@v5 with: diff --git a/.github/workflows/preview-command.yml b/.github/workflows/preview-command.yml index 54f2cdebd0..fe94875393 100644 --- a/.github/workflows/preview-command.yml +++ b/.github/workflows/preview-command.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Prepare Preview id: preview - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const owner = context.repo.owner; @@ -136,7 +136,7 @@ jobs: - name: Dispatch Preview if: ${{ steps.preview.outputs.pr-number != '' }} - uses: actions/github-script@v8 + uses: actions/github-script@v9 env: PR_NUMBER: ${{ steps.preview.outputs.pr-number }} HEAD_REF: ${{ steps.preview.outputs.head-ref }} diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml new file mode 100644 index 0000000000..00531e089e --- /dev/null +++ b/.github/workflows/website.yml @@ -0,0 +1,75 @@ +name: Website + +on: + workflow_dispatch: + workflow_call: + push: + tags: ["v*"] + pull_request: + paths: + - "docs/**" + - ".github/workflows/website.yml" + +permissions: + contents: read + +jobs: + build: + name: Build website + runs-on: ubuntu-latest + timeout-minutes: 10 + defaults: + run: + working-directory: docs + + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Setup Deno + uses: denoland/setup-deno@v2 + with: + deno-version: lts + cache: true + + - name: Check + run: deno task check + + - name: Verify + run: deno task verify + + - name: Check unused assets + run: deno run --allow-read scripts/find-unused.ts + + - name: Upload Pages artifact + if: github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@v5 + with: + path: docs/_site + + deploy: + name: Deploy website + if: github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + pages: write + id-token: write + concurrency: + group: github-pages + cancel-in-progress: false + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Setup Pages + uses: actions/configure-pages@v6 + with: + enablement: true + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v5 diff --git a/.gitignore b/.gitignore index 1ab442acbd..277a474586 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ k8s/ex-*-snapshots.yaml tmpclaude* dogfood-output/ debug-storybook.log +docs/_cache/ .devcontainer/devcontainer-lock.json diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..5ed9cd645a --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,4 @@ +_site/ +.cache/ +_data/generated.ts +snapshots/ diff --git a/docs/404.md b/docs/404.md new file mode 100644 index 0000000000..32bd784adb --- /dev/null +++ b/docs/404.md @@ -0,0 +1,11 @@ +--- +title: "Not Found" +layout: "layouts/page.vto" +permalink: "404.html" +--- + +Sorry, but the page you were trying to view does not exist. +It looks like this was the result of either: + +- a mistyped address +- an out-of-date link diff --git a/docs/_config.ts b/docs/_config.ts new file mode 100644 index 0000000000..d31c755189 --- /dev/null +++ b/docs/_config.ts @@ -0,0 +1,97 @@ +import lume from "lume/mod.ts" +import codeHighlight from "lume/plugins/code_highlight.ts" +import picture from "lume/plugins/picture.ts" +import transformImages from "lume/plugins/transform_images.ts" +import { docsNavHtml, siteDataJson } from "./scripts/site-collections.ts" + +const site = lume({ + src: ".", + dest: "_site", + location: new URL("https://exceptionless.com/"), +}) + +site.ignore( + ".cache", + ".gitignore", + ".npmrc", + "_site", + "deno.json", + "deno.lock", + "news/index.md", + "news/2020/2020-11-11-self-hosted-error-monitoring-on-azure.md", + "package-lock.json", + "package.json", + "public", + "README.md", + "scripts", + "serialization-architecture.md", + "site-migration-plan.md", + "snapshots", +) + +site.use(codeHighlight()) +site.use(picture()) +site.use(transformImages()) +site.add("public/assets/img/dashboard-2-1024x594.png", "assets/img/dashboard-2-1024x594.png") +site.add("public/assets/img/toexceptionless.png", "assets/img/toexceptionless.png") +site.add("public/assets/img/logs-2.jpg", "assets/img/logs-2.jpg") +site.add("public/assets/img/slider-github.jpg", "assets/img/slider-github.jpg") + +site.hooks.markdownIt((markdownIt: any) => { + const defaultHeadingOpen = markdownIt.renderer.rules.heading_open ?? + ((tokens: any[], index: number, options: unknown, env: Record, self: any) => { + return self.renderToken(tokens, index, options) + }) + + markdownIt.renderer.rules.heading_open = ( + tokens: any[], + index: number, + options: unknown, + env: Record, + self: any, + ) => { + const token = tokens[index] + if (!token.attrGet("id")) { + const content = tokens[index + 1]?.content ?? "" + token.attrSet("id", uniqueHeadingSlug(content, env)) + } + + return defaultHeadingOpen(tokens, index, options, env, self) + } +}) + +site.data("docsNavHtml", docsNavHtml) +site.data("siteDataJson", siteDataJson) +site.data("copyrightYear", new Date().getFullYear()) + +export default site + +function uniqueHeadingSlug(value: string, env: Record): string { + const counts = getHeadingSlugCounts(env) + const baseSlug = slugifyHeading(value) || "section" + const count = counts.get(baseSlug) ?? 0 + counts.set(baseSlug, count + 1) + return count ? `${baseSlug}-${count}` : baseSlug +} + +function getHeadingSlugCounts(env: Record): Map { + const key = "__headingSlugCounts" + const existing = env[key] + if (existing instanceof Map) { + return existing as Map + } + + const counts = new Map() + env[key] = counts + return counts +} + +function slugifyHeading(value: string): string { + return value + .trim() + .toLowerCase() + .replace(/\s+/g, "-") + .replace(/\./g, "") + .replace(/[^a-z0-9_-]/g, "") + .replace(/^-+|-+$/g, "") +} diff --git a/docs/_data/site.json b/docs/_data/site.json new file mode 100644 index 0000000000..240b47a7ee --- /dev/null +++ b/docs/_data/site.json @@ -0,0 +1,10 @@ +{ + "url": "https://exceptionless.com", + "title": "Exceptionless", + "description": "Real-time exception reporting for ASP.NET, Web API, WebForms, WPF, Console, and MVC applications. Includes event organization, notifications, and more.", + "author": "Exceptionless Team", + "twitter": "@Exceptionless", + "signupUrl": "https://be.exceptionless.io/signup?domain=exceptionless.com&type=organic", + "appUrl": "https://be.exceptionless.io", + "githubUrl": "https://github.com/exceptionless/Exceptionless" +} \ No newline at end of file diff --git a/docs/_includes/layouts/base.vto b/docs/_includes/layouts/base.vto new file mode 100644 index 0000000000..2e8171a9a5 --- /dev/null +++ b/docs/_includes/layouts/base.vto @@ -0,0 +1,149 @@ + + + + + + + +{{ title ? title + " - Exceptionless" : "Exceptionless" }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{{ for style of extraStyles || [] }} + +{{ /for }} + + + + + + {{ content }} + + + {{ for script of extraScripts || [] }} + + {{ /for }} + + + diff --git a/docs/_includes/layouts/docs.vto b/docs/_includes/layouts/docs.vto new file mode 100644 index 0000000000..19cdd14025 --- /dev/null +++ b/docs/_includes/layouts/docs.vto @@ -0,0 +1,42 @@ +--- +layout: layouts/base.vto +extraStyles: + - /assets/css/prism.css +--- + + +
+
+
+
+
+ + +
+ {{ docsNavHtml(search, url) }} +
+
+ {{ content }} +
+
+
+ + diff --git a/docs/_includes/layouts/page.vto b/docs/_includes/layouts/page.vto new file mode 100644 index 0000000000..f9fd774110 --- /dev/null +++ b/docs/_includes/layouts/page.vto @@ -0,0 +1,16 @@ +--- +layout: layouts/base.vto +--- + + +
+
+
+
+ {{ content }} +
+
+
+
\ No newline at end of file diff --git a/docs/_includes/layouts/post.vto b/docs/_includes/layouts/post.vto new file mode 100644 index 0000000000..cb2c0d69c0 --- /dev/null +++ b/docs/_includes/layouts/post.vto @@ -0,0 +1,23 @@ +--- +layout: layouts/base.vto +extraStyles: + - /assets/css/prism.css +--- + + +
+
+
+
+
+

{{ title }}

+
+
+ {{ content }} +
+
+
+
+
diff --git a/docs/about.md b/docs/about.md new file mode 100644 index 0000000000..12ce8e4747 --- /dev/null +++ b/docs/about.md @@ -0,0 +1,19 @@ +--- +title: "About Us" +layout: "layouts/page.vto" +--- + +![Exceptionless Logo](/assets/img/exceptionless-logoBLK-300x75.png) + +Exceptionless is a privately-held software company, established in 2013, specializing in the creation of software tools that help developers fight errors within their apps. + +Company Vision +-------------- + +Our goal is to build the best developer tools available to help developers around the world get their jobs done faster and more efficiently. + +Mission +------- + +We believe in being open and available to our customers, and listening to what they have to say. Our highest priority is the success of our customers, +followed by continued innovation with our products. diff --git a/docs/contact.vto b/docs/contact.vto new file mode 100644 index 0000000000..5ddb8f3133 --- /dev/null +++ b/docs/contact.vto @@ -0,0 +1,105 @@ +--- +title: Contact Us +layout: layouts/page.vto +description: Contact the Exceptionless team. +--- +
+

Questions about hosted plans, self-hosting, support, or partnerships? Send the Exceptionless team a message.

+ +
+
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ + + +
+ + +
+
+
+ + diff --git a/docs/deno.json b/docs/deno.json new file mode 100644 index 0000000000..720bedd653 --- /dev/null +++ b/docs/deno.json @@ -0,0 +1,45 @@ +{ + "tasks": { + "lume": "deno run -P=lume lume/cli.ts", + "build": "deno task lume && deno task postbuild", + "serve": "deno task build && deno run --allow-read=_site --allow-net=localhost,127.0.0.1 scripts/serve.ts", + "postbuild": "deno run --allow-read --allow-write scripts/postbuild.ts", + "check": "deno check _config.ts scripts/site-collections.ts scripts/postbuild.ts scripts/serve.ts scripts/verify-links.ts scripts/find-unused.ts", + "verify": "deno task build && deno run --allow-read scripts/verify-links.ts", + "unused": "deno task build && deno run --allow-read scripts/find-unused.ts" + }, + "imports": { + "lume/": "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/" + }, + "nodeModulesDir": "auto", + "permissions": { + "lume": { + "read": true, + "write": [ + "_cache", + "_site" + ], + "env": true, + "net": [ + "cdn.jsdelivr.net", + "localhost", + "127.0.0.1", + "0.0.0.0" + ], + "run": true, + "sys": true, + "ffi": true, + "import": [ + "cdn.jsdelivr.net", + "deno.land", + "jsr.io" + ] + } + }, + "fmt": { + "lineWidth": 120, + "indentWidth": 2, + "semiColons": false, + "singleQuote": false + } +} diff --git a/docs/deno.lock b/docs/deno.lock new file mode 100644 index 0000000000..a2f2375c2a --- /dev/null +++ b/docs/deno.lock @@ -0,0 +1,735 @@ +{ + "version": "5", + "specifiers": { + "jsr:@cliffy/command@1.1.0": "1.1.0", + "jsr:@cliffy/flags@1.1.0": "1.1.0", + "jsr:@cliffy/internal@1.1.0": "1.1.0", + "jsr:@cliffy/table@1.1.0": "1.1.0", + "jsr:@std/cli@1.0.29": "1.0.29", + "jsr:@std/cli@^1.0.29": "1.0.29", + "jsr:@std/collections@^1.1.3": "1.2.0", + "jsr:@std/crypto@1.0.5": "1.0.5", + "jsr:@std/encoding@^1.0.10": "1.0.10", + "jsr:@std/fmt@1.0.10": "1.0.10", + "jsr:@std/fmt@^1.0.10": "1.0.10", + "jsr:@std/fmt@^1.0.9": "1.0.10", + "jsr:@std/front-matter@1.0.9": "1.0.9", + "jsr:@std/fs@1.0.23": "1.0.23", + "jsr:@std/fs@^1.0.23": "1.0.23", + "jsr:@std/html@^1.0.6": "1.0.7", + "jsr:@std/http@1.1.0": "1.1.0", + "jsr:@std/internal@^1.0.12": "1.0.14", + "jsr:@std/json@^1.0.2": "1.1.0", + "jsr:@std/jsonc@1.0.2": "1.0.2", + "jsr:@std/media-types@1.1.0": "1.1.0", + "jsr:@std/media-types@^1.1.0": "1.1.0", + "jsr:@std/net@^1.0.6": "1.0.6", + "jsr:@std/path@1.1.4": "1.1.4", + "jsr:@std/path@^1.1.4": "1.1.4", + "jsr:@std/semver@1.0.8": "1.0.8", + "jsr:@std/streams@^1.1.0": "1.1.1", + "jsr:@std/text@^1.0.17": "1.0.19", + "jsr:@std/toml@1.0.11": "1.0.11", + "jsr:@std/toml@^1.0.3": "1.0.11", + "jsr:@std/yaml@1.1.0": "1.1.0", + "jsr:@std/yaml@^1.0.5": "1.1.0", + "npm:@resvg/resvg-wasm@2.6.2": "2.6.2", + "npm:esbuild@0.28.0": "0.28.0", + "npm:highlight.js@11.11.1": "11.11.1", + "npm:ico-endec@0.1.6": "0.1.6", + "npm:lightningcss-wasm@1.32.0": "1.32.0", + "npm:markdown-it-attrs@4.5.0": "4.5.0_markdown-it@14.1.1", + "npm:markdown-it-deflist@3.0.0": "3.0.0", + "npm:markdown-it@14.1.1": "14.1.1", + "npm:sharp@0.34.5": "0.34.5" + }, + "jsr": { + "@cliffy/command@1.1.0": { + "integrity": "963019e2aa13272195b79256a7d8e0f2c60ba8c1b733e023f0aa241b4de87bf7", + "dependencies": [ + "jsr:@cliffy/flags", + "jsr:@cliffy/internal", + "jsr:@cliffy/table", + "jsr:@std/fmt@^1.0.9", + "jsr:@std/text" + ] + }, + "@cliffy/flags@1.1.0": { + "integrity": "da161133ea19997d42ae5833226485a8e7598cf82b86d7c1a2ea10e974ecf21c", + "dependencies": [ + "jsr:@cliffy/internal", + "jsr:@std/text" + ] + }, + "@cliffy/internal@1.1.0": { + "integrity": "433dd7755680d0da6b0a6186694327f6fd8e80807be314cf4bb06270bab28023" + }, + "@cliffy/table@1.1.0": { + "integrity": "6579680c9900628ccd0e05272e89ae483391d74a4f1dfe7c55c919e8a7320bcd", + "dependencies": [ + "jsr:@std/fmt@^1.0.9" + ] + }, + "@std/cli@1.0.29": { + "integrity": "fa4ef29130baa834d8a13b7d138240c3a2fcfba740bfb7afa646a360a15ec84f" + }, + "@std/collections@1.2.0": { + "integrity": "47627a21d3a13138b77fd0e4d790ba9d2e603c3510b686cde6b132fe9aa98a88" + }, + "@std/crypto@1.0.5": { + "integrity": "0dcfbb319fe0bba1bd3af904ceb4f948cde1b92979ec1614528380ed308a3b40" + }, + "@std/encoding@1.0.10": { + "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" + }, + "@std/fmt@1.0.10": { + "integrity": "90dfba288802ac6de82fb31d0917eb9e4450b9925b954d5e51fc29ac07419db5" + }, + "@std/front-matter@1.0.9": { + "integrity": "ee6201d06674cbef137dda2252f62477450b48249e7d8d9ab57a30f85ff6f051", + "dependencies": [ + "jsr:@std/toml@^1.0.3", + "jsr:@std/yaml@^1.0.5" + ] + }, + "@std/fs@1.0.23": { + "integrity": "3ecbae4ce4fee03b180fa710caff36bb5adb66631c46a6460aaad49515565a37", + "dependencies": [ + "jsr:@std/path@^1.1.4" + ] + }, + "@std/html@1.0.7": { + "integrity": "175c818905a6e75743c69c251395e273d82698e58cfe7dd76268d70e28b8d8fe" + }, + "@std/http@1.1.0": { + "integrity": "265cd9a589fea924c5bb0bbed8bebb4bb2fa19129f760bd014e78dbd7a365a51", + "dependencies": [ + "jsr:@std/cli@^1.0.29", + "jsr:@std/encoding", + "jsr:@std/fmt@^1.0.10", + "jsr:@std/fs@^1.0.23", + "jsr:@std/html", + "jsr:@std/media-types@^1.1.0", + "jsr:@std/net", + "jsr:@std/path@^1.1.4", + "jsr:@std/streams" + ] + }, + "@std/internal@1.0.14": { + "integrity": "291516b3d4c35024d6ffbc0a9df5bf4c64116e05b50012cf846710152d2ffdf7" + }, + "@std/json@1.1.0": { + "integrity": "93330d3ed4054d6b1ffe54b075432c80a5f671be77277b978931e018014cb1cc" + }, + "@std/jsonc@1.0.2": { + "integrity": "909605dae3af22bd75b1cbda8d64a32cf1fd2cf6efa3f9e224aba6d22c0f44c7", + "dependencies": [ + "jsr:@std/json" + ] + }, + "@std/media-types@1.1.0": { + "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" + }, + "@std/net@1.0.6": { + "integrity": "110735f93e95bb9feb95790a8b1d1bf69ec0dc74f3f97a00a76ea5efea25500c" + }, + "@std/path@1.1.4": { + "integrity": "1d2d43f39efb1b42f0b1882a25486647cb851481862dc7313390b2bb044314b5", + "dependencies": [ + "jsr:@std/internal" + ] + }, + "@std/semver@1.0.8": { + "integrity": "dc830e8b8b6a380c895d53fbfd1258dc253704ca57bbe1629ac65fd7830179b7" + }, + "@std/streams@1.1.1": { + "integrity": "92556d350e537e9dce527a6d08f6f15be3ff65e656079dea69d15252187c7613" + }, + "@std/text@1.0.19": { + "integrity": "003a0e032d360e8c3a4e0410fb792c77a66bd6553fee9d60c6ec1bce30d29223" + }, + "@std/toml@1.0.11": { + "integrity": "e084988b872ca4bad6aedfb7350f6eeed0e8ba88e9ee5e1590621c5b5bb8f715", + "dependencies": [ + "jsr:@std/collections" + ] + }, + "@std/yaml@1.1.0": { + "integrity": "fc1c5c63e05c4c5eb6118355f557958035d41940d6c29d35b306ef7155d6edb0" + } + }, + "npm": { + "@emnapi/runtime@1.11.2": { + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "dependencies": [ + "tslib" + ] + }, + "@esbuild/aix-ppc64@0.28.0": { + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "os": ["aix"], + "cpu": ["ppc64"] + }, + "@esbuild/android-arm64@0.28.0": { + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "os": ["android"], + "cpu": ["arm64"] + }, + "@esbuild/android-arm@0.28.0": { + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "os": ["android"], + "cpu": ["arm"] + }, + "@esbuild/android-x64@0.28.0": { + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "os": ["android"], + "cpu": ["x64"] + }, + "@esbuild/darwin-arm64@0.28.0": { + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@esbuild/darwin-x64@0.28.0": { + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@esbuild/freebsd-arm64@0.28.0": { + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "os": ["freebsd"], + "cpu": ["arm64"] + }, + "@esbuild/freebsd-x64@0.28.0": { + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "@esbuild/linux-arm64@0.28.0": { + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@esbuild/linux-arm@0.28.0": { + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@esbuild/linux-ia32@0.28.0": { + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "os": ["linux"], + "cpu": ["ia32"] + }, + "@esbuild/linux-loong64@0.28.0": { + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "os": ["linux"], + "cpu": ["loong64"] + }, + "@esbuild/linux-mips64el@0.28.0": { + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "os": ["linux"], + "cpu": ["mips64el"] + }, + "@esbuild/linux-ppc64@0.28.0": { + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@esbuild/linux-riscv64@0.28.0": { + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@esbuild/linux-s390x@0.28.0": { + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@esbuild/linux-x64@0.28.0": { + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@esbuild/netbsd-arm64@0.28.0": { + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "os": ["netbsd"], + "cpu": ["arm64"] + }, + "@esbuild/netbsd-x64@0.28.0": { + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "os": ["netbsd"], + "cpu": ["x64"] + }, + "@esbuild/openbsd-arm64@0.28.0": { + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "os": ["openbsd"], + "cpu": ["arm64"] + }, + "@esbuild/openbsd-x64@0.28.0": { + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "os": ["openbsd"], + "cpu": ["x64"] + }, + "@esbuild/openharmony-arm64@0.28.0": { + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "os": ["openharmony"], + "cpu": ["arm64"] + }, + "@esbuild/sunos-x64@0.28.0": { + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "os": ["sunos"], + "cpu": ["x64"] + }, + "@esbuild/win32-arm64@0.28.0": { + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@esbuild/win32-ia32@0.28.0": { + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@esbuild/win32-x64@0.28.0": { + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@img/colour@1.1.0": { + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==" + }, + "@img/sharp-darwin-arm64@0.34.5": { + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "optionalDependencies": [ + "@img/sharp-libvips-darwin-arm64" + ], + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@img/sharp-darwin-x64@0.34.5": { + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "optionalDependencies": [ + "@img/sharp-libvips-darwin-x64" + ], + "os": ["darwin"], + "cpu": ["x64"] + }, + "@img/sharp-libvips-darwin-arm64@1.2.4": { + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@img/sharp-libvips-darwin-x64@1.2.4": { + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@img/sharp-libvips-linux-arm64@1.2.4": { + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@img/sharp-libvips-linux-arm@1.2.4": { + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "os": ["linux"], + "cpu": ["arm"] + }, + "@img/sharp-libvips-linux-ppc64@1.2.4": { + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@img/sharp-libvips-linux-riscv64@1.2.4": { + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@img/sharp-libvips-linux-s390x@1.2.4": { + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "os": ["linux"], + "cpu": ["s390x"] + }, + "@img/sharp-libvips-linux-x64@1.2.4": { + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@img/sharp-libvips-linuxmusl-arm64@1.2.4": { + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@img/sharp-libvips-linuxmusl-x64@1.2.4": { + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@img/sharp-linux-arm64@0.34.5": { + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "optionalDependencies": [ + "@img/sharp-libvips-linux-arm64" + ], + "os": ["linux"], + "cpu": ["arm64"] + }, + "@img/sharp-linux-arm@0.34.5": { + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "optionalDependencies": [ + "@img/sharp-libvips-linux-arm" + ], + "os": ["linux"], + "cpu": ["arm"] + }, + "@img/sharp-linux-ppc64@0.34.5": { + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "optionalDependencies": [ + "@img/sharp-libvips-linux-ppc64" + ], + "os": ["linux"], + "cpu": ["ppc64"] + }, + "@img/sharp-linux-riscv64@0.34.5": { + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "optionalDependencies": [ + "@img/sharp-libvips-linux-riscv64" + ], + "os": ["linux"], + "cpu": ["riscv64"] + }, + "@img/sharp-linux-s390x@0.34.5": { + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "optionalDependencies": [ + "@img/sharp-libvips-linux-s390x" + ], + "os": ["linux"], + "cpu": ["s390x"] + }, + "@img/sharp-linux-x64@0.34.5": { + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "optionalDependencies": [ + "@img/sharp-libvips-linux-x64" + ], + "os": ["linux"], + "cpu": ["x64"] + }, + "@img/sharp-linuxmusl-arm64@0.34.5": { + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "optionalDependencies": [ + "@img/sharp-libvips-linuxmusl-arm64" + ], + "os": ["linux"], + "cpu": ["arm64"] + }, + "@img/sharp-linuxmusl-x64@0.34.5": { + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "optionalDependencies": [ + "@img/sharp-libvips-linuxmusl-x64" + ], + "os": ["linux"], + "cpu": ["x64"] + }, + "@img/sharp-wasm32@0.34.5": { + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "dependencies": [ + "@emnapi/runtime" + ], + "cpu": ["wasm32"] + }, + "@img/sharp-win32-arm64@0.34.5": { + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@img/sharp-win32-ia32@0.34.5": { + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "os": ["win32"], + "cpu": ["ia32"] + }, + "@img/sharp-win32-x64@0.34.5": { + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@resvg/resvg-wasm@2.6.2": { + "integrity": "sha512-FqALmHI8D4o6lk/LRWDnhw95z5eO+eAa6ORjVg09YRR7BkcM6oPHU9uyC0gtQG5vpFLvgpeU4+zEAz2H8APHNw==" + }, + "argparse@2.0.1": { + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "detect-libc@2.1.2": { + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==" + }, + "entities@4.5.0": { + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "esbuild@0.28.0": { + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "optionalDependencies": [ + "@esbuild/aix-ppc64", + "@esbuild/android-arm", + "@esbuild/android-arm64", + "@esbuild/android-x64", + "@esbuild/darwin-arm64", + "@esbuild/darwin-x64", + "@esbuild/freebsd-arm64", + "@esbuild/freebsd-x64", + "@esbuild/linux-arm", + "@esbuild/linux-arm64", + "@esbuild/linux-ia32", + "@esbuild/linux-loong64", + "@esbuild/linux-mips64el", + "@esbuild/linux-ppc64", + "@esbuild/linux-riscv64", + "@esbuild/linux-s390x", + "@esbuild/linux-x64", + "@esbuild/netbsd-arm64", + "@esbuild/netbsd-x64", + "@esbuild/openbsd-arm64", + "@esbuild/openbsd-x64", + "@esbuild/openharmony-arm64", + "@esbuild/sunos-x64", + "@esbuild/win32-arm64", + "@esbuild/win32-ia32", + "@esbuild/win32-x64" + ], + "scripts": true, + "bin": true + }, + "highlight.js@11.11.1": { + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==" + }, + "ico-endec@0.1.6": { + "integrity": "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==" + }, + "lightningcss-wasm@1.32.0": { + "integrity": "sha512-SteAkCtRuSCDYPGHKhLV/dDs5Bk+7I4QUxWxfk4xwsTI1rQk8MQyYtpGcd3NECsUGzK0q2/KqoVS+YHCqKHUTQ==" + }, + "linkify-it@5.0.1": { + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "dependencies": [ + "uc.micro" + ] + }, + "markdown-it-attrs@4.5.0_markdown-it@14.1.1": { + "integrity": "sha512-dsuEyK/MDAYsdZLDIaDAQXz5+gP0AAbJ4ZjOSB0w+ZGe4lLbzyCgGg0LApC6j9zUK2F+2SA9VkzXfyNG9hL/8g==", + "dependencies": [ + "markdown-it" + ] + }, + "markdown-it-deflist@3.0.0": { + "integrity": "sha512-OxPmQ/keJZwbubjiQWOvKLHwpV2wZ5I3Smc81OjhwbfJsjdRrvD5aLTQxmZzzePeO0kbGzAo3Krk4QLgA8PWLg==" + }, + "markdown-it@14.1.1": { + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dependencies": [ + "argparse", + "entities", + "linkify-it", + "mdurl", + "punycode.js", + "uc.micro" + ], + "bin": true + }, + "mdurl@2.0.0": { + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, + "punycode.js@2.3.1": { + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==" + }, + "semver@7.8.5": { + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "bin": true + }, + "sharp@0.34.5": { + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dependencies": [ + "@img/colour", + "detect-libc", + "semver" + ], + "optionalDependencies": [ + "@img/sharp-darwin-arm64", + "@img/sharp-darwin-x64", + "@img/sharp-libvips-darwin-arm64", + "@img/sharp-libvips-darwin-x64", + "@img/sharp-libvips-linux-arm", + "@img/sharp-libvips-linux-arm64", + "@img/sharp-libvips-linux-ppc64", + "@img/sharp-libvips-linux-riscv64", + "@img/sharp-libvips-linux-s390x", + "@img/sharp-libvips-linux-x64", + "@img/sharp-libvips-linuxmusl-arm64", + "@img/sharp-libvips-linuxmusl-x64", + "@img/sharp-linux-arm", + "@img/sharp-linux-arm64", + "@img/sharp-linux-ppc64", + "@img/sharp-linux-riscv64", + "@img/sharp-linux-s390x", + "@img/sharp-linux-x64", + "@img/sharp-linuxmusl-arm64", + "@img/sharp-linuxmusl-x64", + "@img/sharp-wasm32", + "@img/sharp-win32-arm64", + "@img/sharp-win32-ia32", + "@img/sharp-win32-x64" + ], + "scripts": true + }, + "tslib@2.8.1": { + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "uc.micro@2.1.0": { + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + } + }, + "remote": { + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/build/deno-wasm/deno-wasm-dynamic.js": "fd05e83a855aa68b09396dc47a7638ef526c39917971715ac37e0fc3227db886", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/build/deno-wasm/deno-wasm.js": "ccde5219e42040b8f7a8b653acc6c8cca197c29f98d6b75f74c48111e34bcbea", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/build/deno-wasm/deno-wasm_bg-wasm.js": "52c57905a74047d1574f0b96e301ef1d5974cd962705615555b5e46b5ac420e4", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/build/deno-wasm/deno-wasm_bg.wasm": "b5fbd7ede316f7c13e4a7b927a053a35b475a9acce7c7cae864e91d9b8dd24c7", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/build/deno-wasm/env.js": "17da784c11b192c591dbf7df21ec6f65f63f45ca9a713e4ca100f3c886b4023f", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/build/deno-wasm/wbg.js": "b5b6de12bc010fa23438c8a8276067b9044a405da516d0bbe4ae61b7c6d61a22", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/deno-dom-wasm.ts": "34f0654b452568fbd95b8d1b2a493de19710ac9ceeb6b82f541d09c29613572d", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/api.ts": "0ff5790f0a3eeecb4e00b7d8fbfa319b165962cf6d0182a65ba90f158d74f7d7", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/constructor-lock.ts": "0e7b297e8b9cf921a3b0d3a692ec5fb462c5afc47ec554292e20090b9e16b40a", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/deserialize.ts": "514953418b7ae558ed7361ad9be21013f46cba2f58bd7f4acc90cf1e89f9c8cf", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/document-fragment.ts": "0b915d094830d43b330dc2fb8012b990f2c815773c6cdcd4a9fdff99fe47412e", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/document.ts": "ad584ac4ce6dce03f0ff6ef4b7db86fd598f9c7824da1387f7f2acd7d6948e4a", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/dom-parser.ts": "ab5e8382700bc3936ac67e8d11b7bb9c6999a994ac8b070b7cae94e2d2ecee5a", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/element.ts": "9726ebf139b97ae96671d38da720988cfd6481ff9068ba13f3b0d00e72f0c8c0", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/elements/html-template-element.ts": "1707dfb4cbb145f3bcb94426d7cdedbaa336620d0afed30e99f50fe87ba24a98", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/html-collection.ts": "dcf328e883877f7748d3e20fb6319e739f297a6e24f4b00ec5b1a2f390cfa3c6", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/node-list.ts": "be9793475d82539da8b97a17b6b5538cc723538c10cc5820a23e5e4b2248845d", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/node.ts": "53ada9e4b2ae21f10f5941ff257ed4585920ae392020544648f349c05d15d30c", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/selectors/custom-api.ts": "852696bd58e534bc41bd3be9e2250b60b67cd95fd28ed16b1deff1d548531a71", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/selectors/nwsapi-types.ts": "c43b36c36acc5d32caabaa54fda8c9d239b2b0fcbce9a28efb93c84aa1021698", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/selectors/nwsapi.js": "985d7d8fc1eabbb88946b47a1c44c1b2d4aa79ff23c21424219f1528fa27a2ff", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/selectors/selectors.ts": "83eab57be2290fb48e3130533448c93c6c61239f2a2f3b85f1917f80ca0fdc75", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/selectors/sizzle-types.ts": "78149e2502409989ce861ed636b813b059e16bc267bb543e7c2b26ef43e4798b", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/selectors/sizzle.js": "c3aed60c1045a106d8e546ac2f85cc82e65f62d9af2f8f515210b9212286682a", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/string-cache.ts": "8e935804f7bac244cc70cec90a28c9f6d30fea14c61c2c4ea48fca274376d786", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/utils-types.ts": "96db30e3e4a75b194201bb9fa30988215da7f91b380fca6a5143e51ece2a8436", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/dom/utils.ts": "bc429635e9204051ba1ecc1b212031b5ee7c6bcd95120c91bef696804aa67e74", + "https://cdn.jsdelivr.net/gh/b-fuze/deno-dom@0.1.56/src/parser.ts": "e06b2300d693e6ae7564e53dfa5c9a9e97fdb8c044c39c52c8b93b5d60860be3", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/cli.ts": "d8fc878eb1d52c85d5778ec2965d7c0084a351c90741c5f629e24c16e8b53ba5", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/cli/build.ts": "61290fc7d533f605d4d96a258775b50006f07b769346451d3d63abd883b9342f", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/cli/build_worker.ts": "688f4ee7a37a55587e032bb470e99b51ecc1005c904df111f5c660c8b53c6c14", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/cli/create.ts": "78208f4c5e19f9f18b5d4ed3762c69d9e4ea666a2d139bdca4b6eb1c6b164720", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/cli/missing_worker_apis.ts": "70625ded7fee5de7d215e0829ce8dc4bb7060f6a496c09db880ebaec8b3efb92", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/cli/upgrade.ts": "a11e7c9024f78c2e7376c57b4a99e389dbf490769779d2d37a4a3ccd6ef27d9e", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/cli/utils.ts": "71e1ee512aa630cf4b2b3ddd646f1ef5f20b43b538d396ad4e27128f7a8439c3", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/cache.ts": "bec945853a7111babf1fb465090d84dbf4176af0ad465b63b51031134ad6ea2a", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/components.ts": "549ffbcddbe5dbb05589e89c0e918799e13e32cd8f107f40be72b1cdd849732c", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/data_loader.ts": "8698a9e9b1aac27147dc835ba89a0e30828c81338eceae86630607d78f146215", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/debugbar.ts": "89f3ea8dcffd6b2333b8ff30eb1ef39f0c1ffc1857bf6e51f6d123fa1f8f109a", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/events.ts": "e4fd1786eb7dd4a041d7d922779b9edf1ee89e51fd17ba5e756f380879ccb557", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/file.ts": "4058ca45d07eb5940bddc6b0384df3dcac389ab7d3b2dca48f30ba75e196df1b", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/formats.ts": "e65130e5c5f2e49435619479710c812199b480a9e145fdc6b2bac11cfe6ea08e", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/fs.ts": "ad0b1eb43361f76f36674505ef6b8870176ef386c43ee962e6c750506b40a071", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/loaders/binary.ts": "bb1e1cf3faac49f6007dc6814168dc0f633da17356db18e68862e4b2a87a3f33", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/loaders/json.ts": "ae28e711196215ca2772e9e31f2646ff4c3cf3f66ae75bf8cbcab94de5dbd24f", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/loaders/module.ts": "d2df9c49df5f8845f34c1363d48b8cfbcae4c9683201fd8513dd8db9933dca18", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/loaders/text.ts": "42860fc3482651fa6cfba18a734bb548d6e6e1163bf1015c2abc447ab150acbd", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/loaders/toml.ts": "72ddfef2deea62815c28e27faa2c5356e09b3109e9547e47a6defea3d3332452", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/loaders/yaml.ts": "241dc41fbe51b92e38dc748eda614c35d80fb8c63a6d40253453c6bb78c9c47e", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/processors.ts": "047a87b0c9a0377ef15daaf1b671a29d541e4bb744c152f02a5c4f0a80fbbb64", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/renderer.ts": "ed142d18f74d24cf8710e47e13a6c12636a937a9c07d08a402a5f1ebb40d45cf", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/scopes.ts": "dbdf93d7a9cead84833779e974f190b1379356ec7c0ccd34aa92f917c2cdd2f9", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/scripts.ts": "286969b120d2290ba57a7fdd9b37e587aacf4e4162d92f51f1f1e9e18c864f30", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/searcher.ts": "580fd9a81c67ae33df416f80525a3dacbf49790ea7990a721f76719e15fa4878", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/server.ts": "7b98b19422f69a17ed1877f4b6d38ce6b6228128064d88e9430a071846311cbc", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/site.ts": "33c8ea3eff51bf2f8941d801a161f73bda754e40a17b753e7538f42c92fdd9bd", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/source.ts": "24ac00674f4beafdf01ba0e1c887bfceca4458c22e812e87edbfa02b9b450335", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/cdn.ts": "4309cb725106091d5d92a91f1599a6d5eacaaa5303fe7835ea27d55f97144e03", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/cli_options.ts": "88141f97850ff2e8e821dda6abed1f2d7993db2f1f23c8d6f2e6306eda094761", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/concurrent.ts": "f0172230b25d83aca497c64d92a08d9a373b9ffd13cf57c273a51d8a3a3a2a9e", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/date.ts": "3eb0b0e2ea15a95cdfe737be70cd4f48cbe49401928cb04c25a230f411ab2478", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/digest.ts": "edc8fc07f34fa3c748fea98704361d88e2449e8e91c0f2800fdab38bfad24bae", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/dom.ts": "8337af56c8d447b5ad1b021a0981f9cec912dba820b2ba346820258b80b5f12a", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/env.ts": "0f2d7ab9c1c39727803e1b22abeb1d6d9798ec4e76cf85d213a01f5db42de978", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/format.ts": "bad71315eefd5ad0413841bbe5e8406d636d58d3ed3ef48674655b3a21a0aab0", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/generator.ts": "1e664e9fd4c469e38a0acf5c94fd49dac4f38cb6334563ea4b7fc498b5958877", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/log.ts": "d91930a4a08f0ccc9bdd8c82db3b76a39582e6913b34f4210bbe9cd8481ef478", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/lume_config.ts": "20eca22ebba2c8c2d99da73b463e09104e1335e3ea588a35602dcefae56679f8", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/lume_version.ts": "c1c63818097e4a273183429ab5b2446a253307f7bc2d0d6361a17b4f230a617d", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/merge_data.ts": "8433920c7e66f27ae558777ed9add637f8c2f67adf9ca2c9ca60d566b9b3583f", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/net.ts": "d0d58c95668effc13669015c219295532f67e4a02396286308c772871b615a9b", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/object.ts": "9b2d1c20503137b612fcbb311b42d1f5500ae170b68f1dca43cc6b057423bc6e", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/page_content.ts": "bbadb588f9d9fcf1a2af156ce4b68974dfad39b65c3c8d42a6f1895b194c7eec", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/page_date.ts": "2a3d9c203df298ca61f568fdf509945f127f990769623c3edfd753d39807b757", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/page_url.ts": "13d07d54c6d8db0b83df655de999909230d56267e69c0fbe849b4f38689dcecf", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/path.ts": "73db7b3bf8df81b7af4085a9fef4d5648ac083a4e826ae98c0dcb96b0fa64e6b", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/read.ts": "32010c32c2d99be0fd6ba2566f04a30c8b16f5d0c9eaee18ca80e472d5ab2644", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/utils/tokens.ts": "7bb3731b4ee3232f38a6aec9c5364d7492b2ea4fcfe7321115a9af25a1ff2038", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/watcher.ts": "f70b927c6bd54e213e53ca8b34ac47773cc0e34eccb3aa06c8697302c19c7de5", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/core/writer.ts": "1c36d4a846dd4621b4b4d7aea56077dc43614400428ae3316390b2190e9fe1b5", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/cli.ts": "0cb49fc88dd6d699297f288d432562f20dde3e498f51993688ccf98f28c83d54", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/cliffy.ts": "a86b348c3e675d4051037536802caa9c9ce2e36933e950f10c43971f8ea3ee83", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/colors.ts": "eae71a8d83eb15ab20c140b94987a1c789e1ece31d99b3ec2841506eaff854bc", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/crypto.ts": "0939b1e974472d1db1d611b4160a5a51d796da1368289277d2e26803243959d5", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/dom.ts": "08bdf42363093cae0e0a3f6efb3c500cfc8a7a6ab09d73fa69d212a6c907d547", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/esbuild.ts": "dcdff1214c796ab5c076b054a6aad586345e291bfc6cc9e5e464387aeb0544d6", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/front_matter.ts": "f5e5780d4a0502d50cde1f42a4aa7830756dc9bd0251ba7448cecd1eaa60878f", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/fs.ts": "976956b66a86d5ad001043e8ce92cbc08bb29eb6f7703c73eda99b05f49069d4", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/highlight.ts": "e8f830a1137ff7e8246ce21518452b8cbf8089db409458c6d9c31040c11d8428", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/http.ts": "6fd6334e70a106201e1d5159d61d6b72b0cd907d6ab9c430a9ff6232bc4d19de", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/init.ts": "8efb3ecd7a3c716e1bad9deb3b687e622d3802c5b7f3a81daefa169e1f054be3", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/jsonc.ts": "abe9c7b88ded304adac6e1eec70a858ae5dcce95ca53d91bde425a2edf3a653d", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/lightningcss.ts": "18b9aa9bbd7c6d522f719dfb337502402c9916fd69826bc5f0c9d385ea4ba641", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/markdown_it.ts": "6045278bba08ed2fa0c384441d8fe60693cac2b85fd90321e8ce6d3e4408349a", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/media_types.ts": "ede0e4fc3e86e563b38e66d765ef5508d35bef4fecfa552724d9ef1a31486747", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/path.ts": "173ff2317c7a2efefb79aa51e09a6b2a6618a705c802c7fe24c912a50afb0818", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/resvg.ts": "6713e407f4dfd358becba703a60106b35a7d6a5d33f30647bfbafe6c81897a59", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/semver.ts": "4089dbcbad21636cb3d743eb61b3727674c133fba17556f0738b799f1a5a9441", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/sharp.ts": "9efd1598d624a715f43305f4ec1d035c37019667878728892c908e5052f4d6fc", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/toml.ts": "61831fd046e8df6b35ccdacc7fc3b3ae7c0a2450b2f368cf933e518d243b3881", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/vento.ts": "dda80130df3c9ae6ebc50ccc4ef81bbad548241058c45f702dfdcca811390ccc", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/deps/yaml.ts": "8c5a777049063cf15db6cf8814fd43ce6811469a800341f0cc9af962ef6110fe", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/middlewares/basic_auth.ts": "c18f0da9f88be4581e5e3da99214fd7abdad829ab00dbdd2fb3116f1f876add2", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/middlewares/logger.ts": "c96f1a9f9d5757555b6f141865ce8551ac176f90c8ee3e9ad797b2b400a9a567", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/middlewares/no_cache.ts": "0119e3ae3a596ab12c42df693b93e5b03dd9608e289d862242751a9739438f35", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/middlewares/no_cors.ts": "4d24619b5373c98bcc3baf404db47ba088c87ac8538ea1784e58d197b81d4d02", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/middlewares/not_found.ts": "0f92cd91239444247a1c3dce1bed4e978445687ca76f544a0ccd483a352f761a", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/middlewares/reload.ts": "9f7fa7e376b0a510f5f69b90372c2f61fd6edb1244166c9aa6a9d52f267c3b33", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/middlewares/reload_client.js": "9026da20a25fe58ad36233539ada3f38d56d935c5b0c1c69b7fcd21511efadee", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/mod.ts": "349b3b7fe199bc6703b1e1fb77f3ab92699fce966da2261d3419a951b1ef2c5d", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/code_highlight.ts": "065e0f48819cc74899b987069b16ac7d92ccd10195c5cda9463bd13d5dd7c5f0", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/json.ts": "5c49499e56b919ec848d4118ec97dd4fe0a323a6cc4c648dc45ab55297614c12", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/lume_cms.ts": "c7f7807c8a9c1c39acd85cf6ca41d4b9acc38f71cabf995721d9ff9c33da7604", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/markdown.ts": "7e82d897c1e35bf119dcd18b6aec7a6ba5aa06848897b34ff9cd161ec7c8757e", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/modules.ts": "4e177c0ffe972b9deef10db2bf0ae52b405418af4dbac03db9e7ffbd6a3ec6ae", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/paginate.ts": "5ed0524fc0a69eb75142abd2ade37d9ff8f1e31516fdafb7a3676532b5f2db63", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/picture.ts": "b61d4a0b3bb0899b9a0248aa782b9d50435b83cd1ab1642d1271d4c39e10967b", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/search.ts": "5acb5be828bbbd012fb9226cb97ec3e370d43d05aa44d16e7e7d50bab368b442", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/toml.ts": "e5bf35ed4915587acd453f002b00ae9b88c1782cadc25c703d7642a390af43ea", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/transform_images.ts": "c47f17043ad50726e93f4e6864680dc067066f8f5fa8b212c3b1284dede32301", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/url.ts": "15f2e80b6fcbf86f8795a3676b8d533bab003ac016ff127e58165a6ac3bffc1a", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/vento.ts": "11272f4de3a02e97e91ec31d9efd7568b74334352b141ff302844d8f309a225a", + "https://cdn.jsdelivr.net/gh/lumeland/lume@3.2.6/plugins/yaml.ts": "d0ebf37c38648172c6b95c502753a3edf60278ab4f6a063f3ca00f31e0dd90cc", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/core/environment.ts": "db44bd90da767fd35c735261badc5a060b581d0ef22231945d16ec0fea110d8b", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/core/errors.ts": "8606b682b465d598a394feea135dd2f84033b5ef2a61a23d116ccb782a0a547a", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/core/js.ts": "83084240150d7e8b83e43ec8fcf78564a8ba8599c3d517976efbb11b208903b2", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/core/reserved.ts": "e3ccafb4e5524b9c51fa14fa0e4bf17fd9bdd791848f17afa2aeb97835c486d1", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/core/tokenizer.ts": "460faa3de0e561e5046c46528c8bcbfc46b9de576af7ec8c4a8954a61a80ec76", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/loaders/file.ts": "83f579ac39838642bb45c6ddf48c05c08134cdd95fa7364d004fb443e972196a", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/mod.ts": "26081287509a87d81c51917795ff94ea80056c43599af8140bb5f666f0aaa767", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/auto_trim.ts": "5df5091763543493dba1160f805652c67892d3ecf06293bbfecdac71ed3c7d90", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/default.ts": "bab4f1f3e38a6ea3673d6aaa8409ca79ec241daa07a18582b4f2549cc5532200", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/echo.ts": "26109b7d47d33621dd764136be665052a48b3e68aeda2bd961504702f14c829f", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/empty.ts": "901df5c44bf0355a7b57819c1e565067de15a4f64fcd72e42904b1b5dc8314c5", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/escape.ts": "1db6eb7b22f88bbf94d21636c9b156ec4868e10bbcfa7dc5eae7113c36ef7b8a", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/export.ts": "40308665aeee8edeab4618d1838c1843c03cba8a7803ed9a27fceadf7a10bbef", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/for.ts": "a893a3de2c5cab43d5018cb80718ea46377c172d550e7a8ead076f00c58d59bf", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/function.ts": "472bdbe0bffb7d38c59003b02510cf85a78a35927219bc6a02ac2d4fde8b6597", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/if.ts": "db13776a5b9e7988f65c27943c344bec7463c5f3162a06cc4da1a313d7109195", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/import.ts": "b6fb6cc922c0897d15918d10766bbbd51069336780acdc8bbf23922ed870a1b3", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/include.ts": "7b39ae093e4c25f0de5f0b174c00c06c30bf7092b55f00a58a64968fa8ceabde", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/js.ts": "f5a7fd8cc48cb1b1dc0b396e3d1fee4664cf28932dc5f5f301e38243e0e987dc", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/layout.ts": "9c90bb58cc5302af48b97320f8eb128b37bb29f6128d7a75c8dd7b6625b870e1", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/mod.ts": "2bd756b503b1d100014fa02f92e2e8d07d894c6297358232a685c4a1527908c7", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/set.ts": "cbe42b771a04203b6fc1c178e655fa2536ab90ae67e52c083cf7c71f37c62711", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/trim.ts": "8d33271327b09ffd8f569ebde85125b1324fa9538a54d6072ac97a9fb5d24264", + "https://cdn.jsdelivr.net/gh/ventojs/vento@2.3.1/plugins/unescape.ts": "1c56f0310c7757880df7684fc6b7bf9efd27fdb6b929b89626802f5a99cb93ee" + } +} diff --git a/docs/docs/FAQ.md b/docs/docs/FAQ.md new file mode 100644 index 0000000000..9a7591b655 --- /dev/null +++ b/docs/docs/FAQ.md @@ -0,0 +1,73 @@ +--- +title: "FAQ" +--- + +# FAQ + +- [Will Exceptionless slow my application down?](#will-exceptionless-slow-my-application-down) +- [Why is my organization throttled?](#why-is-my-organization-throttled) +- [What happens if the organization plan limit is reached?](#what-happens-if-the-organization-plan-limit-is-reached) +- [What will happen if my application throws a bunch of exceptions in a very short amount of time?](#what-will-happen-if-my-application-throws-a-bunch-of-exceptions-in-a-very-short-amount-of-time) +- [Can I reset my event data?](#can-i-reset-my-event-data) +- [What happens if my internet connection goes down?](#what-happens-if-my-internet-connection-goes-down) +- [How can I disable event reporting during testing?](#how-can-i-disable-event-reporting-during-testing) +- [Is there a minimum version of .NET you need to be targeting to use the Exceptionless client.](#is-there-a-minimum-version-of-net-you-need-to-be-targeting-to-use-the-exceptionless-client) +- [Can I use Exceptionless under medium trust?](#can-i-use-exceptionless-under-medium-trust) + +*** + +## Will Exceptionless slow my application down? + +Exceptionless queues all events submissions to an in memory queue and then processes them in a background thread. We do everything we can to make sure that we do not slow your app down or crash your app. + +*** + +## Why is my organization throttled? + +Every plan has both a monthly limit as well as an hourly limit. The hourly limit resets every hour and is [calculated](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Extensions/OrganizationExtensions.cs#L51-L65) based on the remaining event limit divided by the number of hours left in the month times 10. We do this to prevent your event limit from being reached in seconds or minutes, thus giving you a greater sample size. _The limit can be increased at any time by upgrading the plan which boosts the monthly limit as well as hourly limit._ + +*** + +## What happens if the organization plan limit is reached? + +When the organization is throttled (hourly limit) or the plan limit (monthly limit) is reached, the clients will automatically discard any submitted events for a short period of time (usually five minutes) and resume automatically. Your app will continue to work as expected this entire time. _The limit can be increased at any time by upgrading the plan which boosts the monthly limit as well as hourly limit._ + +*** + +## What will happen if my application throws a bunch of exceptions in a very short amount of time? + +Exceptionless will intelligently try to ensure that the right amount of data is sent in. First, the client will intelligently ensure that the same event occurrence isn't submitted repeatedly. Lets assume you have ten of the exact events submitted over a period of a minute. The first one comes through as expected, the next 9 events will be rolled up into a single event with a counter and last occurred date and submitted at the end of the 60 seconds. This allows us to show you a total of how many times the event occurred. Finally, in some cases the server logic will step in to remove error occurrences that it feels are spam. For example: Your site might be scanned by a bot and throw a bunch of unique 404 errors. Our system will see all of these within a small window of time submitted by a specific IP address. Once it hits a configurable threshold of error occurrences within a specific amount of time, these error occurrences will be removed from the system. + +*** + +## Can I reset my event data? + +You can reset your event data at the project level by going into the manage project page and clicking the Reset Project Data button. You can also delete all event data for a specific stack by going to the stack page, clicking the Options button and clicking Delete. _Please note that this will not reset any plan limits._ + +*** + +## What happens if my internet connection goes down? + +If persistent storage is configured, the Exceptionless client will queue all events submissions to disk and will retry them later. + +*** + +## How can I disable event reporting during testing? + +Set the enabled attribute to false in the exceptionless config section. + +*** + +## Is there a minimum version of .NET you need to be targeting to use the Exceptionless client. + +Yes, your application needs to be targeting .NET 4.5 or newer. + +*** + +## Can I use Exceptionless under medium trust? + +Yes, you will need to set the requirePermission attribute to false in the exceptionless config section. This attribute allows the exceptionless client to read the exceptionless config settings. When you are running in medium trust, unhandled exceptions will not be caught. This means that you must submit exceptions to Exceptionless manually. + +--- + +[Next > Comparison](/docs/comparison) diff --git a/docs/docs/_data.yml b/docs/docs/_data.yml new file mode 100644 index 0000000000..129f7503ac --- /dev/null +++ b/docs/docs/_data.yml @@ -0,0 +1,2 @@ +layout: layouts/docs.vto +author: Exceptionless Team diff --git a/docs/docs/api/api-getting-started.md b/docs/docs/api/api-getting-started.md new file mode 100644 index 0000000000..cc48cef564 --- /dev/null +++ b/docs/docs/api/api-getting-started.md @@ -0,0 +1,55 @@ +--- +title: "Getting Started" +--- + +# Getting Started + +Remember, you can refer to the full, self-updating, documentation [here](https://api.exceptionless.io). But let's get started with some real examples to get you authenticated, which will allow access to other endpoints. Exceptionless protects your account by requiring authentication which takes the form of a `Bearer` Authorization header. + +Before we generate a user-scoped token, let's talk a little bit about scopes. + +## Authentication Scopes + +When you eventually create an API Key/token for your project, you will need to pass in a scope (if you are creating this token programmatically). Exceptionless recognizes two scopes: + +* user +* client + +The `user` scope has full admin access to the account. This scope creates a token that can do everything from create projects to update billing info. + +The `client` scope has access to post events, getting events, and reading the client configuration for a project. + +## Get Your User Scoped Token + +Before you can post project-specific events and make project-specific API requests, you'll need to first generate a user token which can then be used to generate tokens for your projects. It is incredibly important to protect user-scoped tokens as they act as the keys to the kingdom. **Never let anyone else access your user token**. + +*NOTE: If you signed up using an OAuth flow with Google or something else, you will need to create a local login to be able to use this endpoint.* + +Let's take a look at an example. + +POST `/api/v2/auth/login` + +```shell +curl --location --request POST "https://api.exceptionless.com/api/v2/auth/login" \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "email": YOUR_EMAIL, + "password": PASSWORD +}' +``` + +Your response should look like this: + +```json +{ + "token": "ojcQ1YVtKBnFITzJB3RFkdWRaVGdghHZoHvGKbx4" +} +``` + +Now that you have your token, you can get your project-specific API key (or token) which will allow you to execute API requests against a specific project. It's worth also noting that you can easily update your requests to authenticate via a URL query string and your access token. + +For example, if we want to view our organizations, we simply navigate to , add the query string `?access_token={token}` rather than a Bearer token authorization header. + +--- + +[Next > Getting Project Tokens](/docs/api/project-tokens) diff --git a/docs/docs/api/getting-events.md b/docs/docs/api/getting-events.md new file mode 100644 index 0000000000..c8dc7cb494 --- /dev/null +++ b/docs/docs/api/getting-events.md @@ -0,0 +1,164 @@ +--- +title: "Getting Events" +--- + +# Getting Events + +There may be times where you need to access the events you've sent through to Exceptionless without going through the Exceptionless UI. For those situations, you can use the API to fetch events. You can specify events across your organization or specific to a project. Let's take a look at the options. + +*Note: organization-level requests require your [Scoped User Token](/docs/api/api-getting-started) while projects-specific requests can use your [Project Token](/docs/api/project-tokens).* + +### Get Count of All Events + +GET `api/v2/events/count` + +```shell +curl --location --request GET "https://api.exceptionless.com/api/v2/events/count" \ +--header 'Authorization: Bearer YOUR_SCOPED_USER_TOKEN' +``` + +The response will look like this: + +```json +{ + "total": 74 +} +``` + +### Get Count of All Events For a Single Project + +Remember, you can get your Project ID in the UI when logged in or by [following the instructions here](/docs/api/project-tokens#get-projects). + +GET `api/v2/projects/YOUR_PROJECT_ID/events/count` + +```shell +curl --location --request GET "https://api.exceptionless.com/api/v2/projects/YOUR_PROJECT_ID/events/count" \ +--header 'Authorization: Bearer YOUR_PROJECT_TOKEN' +``` + +The response will be just like the global event search: + +```json +{ + "total": 74 +} +``` + +### Get All Events For Organization + +GET `api/v2/events` + +```shell +curl --location --request GET 'https://api.exceptionless.com/api/v2/events' \ +--header 'Authorization: Bearer YOUR_SCOPED_USER_TOKEN' +``` + +The default results returned will be paginated and limited to 10 results per page. However, you can configure the results limit and a bunch of other properties for your search through query string parameters. The full options [are listed here](https://api.exceptionless.io/docs/index.html). + +Your response will look like this: + +```json +[ + { + "type": "string", + "source": "string", + "date": "2020-11-06T13:57:46.773Z", + "tags": [ + "string" + ], + "message": "string", + "geo": "string", + "value": 0, + "count": 0, + "data": {}, + "referenceId": "string", + "id": "string", + "organizationId": "string", + "projectId": "string", + "stackId": "string", + "isFirstOccurrence": true, + "createdUtc": "2020-11-06T13:57:46.773Z", + "idx": {} + } +] +``` + +### Get All Events For a Project + +Similar to getting all events or your organization, you can get all events for a project. You have the same query string filtering capabilities with this request, but we'll keep the example simple. + +GET `api/v2/projects/YOUR_PROJECT_ID/events` + +```shell +curl --location --request GET 'https://api.exceptionless.com/api/v2/projects/YOUR_PROJECT_ID/events' \ +--header 'Authorization: Bearer YOUR_PROJECT_TOKEN' +``` + +Again, the response will look like this: + +```json +[ + { + "type": "string", + "source": "string", + "date": "2020-11-06T13:57:46.773Z", + "tags": [ + "string" + ], + "message": "string", + "geo": "string", + "value": 0, + "count": 0, + "data": {}, + "referenceId": "string", + "id": "string", + "organizationId": "string", + "projectId": "string", + "stackId": "string", + "isFirstOccurrence": true, + "createdUtc": "2020-11-06T13:57:46.773Z", + "idx": {} + } +] +``` + +### Getting an Event by ID + +You can get the details of a single event by passing in the ID for the event. + +GET `api/v2/events/YOUR_EVENT_ID` + +```shell +curl --location --request GET 'https://api.exceptionless.com/api/v2/events/YOUR_EVENT_ID' \ +--header 'Authorization: Bearer YOUR_PROJECT_TOKEN' +``` + +The response will be a single object with the details of the event like this: + +```json +{ + "type": "string", + "source": "string", + "date": "2020-11-06T14:02:45.101Z", + "tags": [ + "string" + ], + "message": "string", + "geo": "string", + "value": 0, + "count": 0, + "data": {}, + "referenceId": "string", + "id": "string", + "organizationId": "string", + "projectId": "string", + "stackId": "string", + "isFirstOccurrence": true, + "createdUtc": "2020-11-06T14:02:45.101Z", + "idx": {} +} +``` + +--- + +[Next > Clients](/docs/clients/) diff --git a/docs/docs/api/index.md b/docs/docs/api/index.md new file mode 100644 index 0000000000..9a74360c85 --- /dev/null +++ b/docs/docs/api/index.md @@ -0,0 +1,13 @@ +--- +title: "API Usage" +--- + +# API Usage + +Our [API](https://api.exceptionless.io) utilizes Swagger and Swashbuckle to automatically generate, update, and display documentation (which means it works without any work on your end when you are self-hosting). It is a great resource for our users that want to get their hands dirty and use Exceptionless data to roll their own tools, dashboards, etc. + +To view the full API documentation, visit and click on the `API Documentation` link to be taken to the API documentation. With Swagger, you will have examples for all endpoints that include required parameters and potential responses. + +--- + +[Next > Getting Started](/docs/api/api-getting-started) diff --git a/docs/docs/api/posting-events.md b/docs/docs/api/posting-events.md new file mode 100644 index 0000000000..dda1fac664 --- /dev/null +++ b/docs/docs/api/posting-events.md @@ -0,0 +1,66 @@ +--- +title: "Posting Events" +--- + +# Posting Events + +This is the meat of what Exceptionless does. This is what you care about. So, let's explore some of the possibilities. + +Events passed through to Exceptionless take three forms: + +- [Posting Messages](#posting-messages) +- [Posting Logs](#posting-logs) +- [Posting Errors](#posting-errors) + +We'll explore how to send through events for each category. First, it's important to remind you that you should not being user-scoped tokens for these API endpoints. If you have not yet generated a client-scoped token, [do so through the UI](/docs/project-settings) or [follow the guide here to do so programmatically here](/docs/api/project-tokens). + +### Posting Messages + +Messages are arbitrary pieces of information that can mean or relate to anything. They don't have to be errors or logs. Configuring a message event is simple. + +POST `api/v2/events` + +```shell +curl --location --request POST "https://api.exceptionless.com/api/v2/events" \ +--header 'Authorization: Bearer YOUR_PROJECT_TOKEN' \ +--header 'Content-Type: application/json' \ +--data-raw '{ "message": "Exceptionless is amazing!" }' +``` + +You will receive a `202` response if the message was successfully posted. You can check out your Exceptionless dashboard to immediately see this message show up. + +### Posting Logs + +Logs will generally have a little more information associated with them than messages. Logs can take fields like date, message, and name. Let's take a look at an example. + +POST `api/v2/events` + +```shell +curl --location --request POST "https://api.exceptionless.com/api/v2/events" \ +--header 'Authorization: Bearer YOUR_PROJECT_TOKEN' \ +--header 'Content-Type: application/json' \ +--data-raw '{ "type": "log", "message": "Exceptionless is amazing!", "date":"2030-01-01T12:00:00.0000000-05:00", "@user":{ "identity":"123456789", "name": "Test User" } }' +``` + +You will receive a `202` response if the log was successfully posted. You can check out your Exceptionless dashboard to immediately see this log show up. + +### Posting Errors + +Errors will generally be the most comprehensive events you send through to Exceptionless. They contain many details about the problems your users are facing. Let's take a look at the fields you'll need to provide and how to submit errors. + +POST `api/v2/events` + +```shell +curl --location --request POST "https://api.exceptionless.com/api/v2/events" \ +--header 'Authorization: Bearer YOUR_PROJECT_TOKEN' \ +--header 'Content-Type: application/json' \ +--data-raw '{ "type": "error", "date":"2030-01-01T12:00:00.0000000-05:00", "@simple_error": { "message": "Simple Exception", "type": "System.Exception", "stack_trace": " at Client.Tests.ExceptionlessClientTests.CanSubmitSimpleException() in ExceptionlessClientTests.cs:line 77" } }' +``` + +With an error event, you will be able to explore additional details for your event through Exceptionless's dashboard. These additional details include the full stack trace if you provided it. + +Next up, we'll take a look at how we fetch events. + +--- + +[Next > Getting Events](/docs/api/getting-events) diff --git a/docs/docs/api/project-tokens.md b/docs/docs/api/project-tokens.md new file mode 100644 index 0000000000..419ac51200 --- /dev/null +++ b/docs/docs/api/project-tokens.md @@ -0,0 +1,77 @@ +--- +title: "Client-Scoped Tokens" +--- + +# Client-Scoped Tokens + +You'll likely want your events associated with a specific project, and you may want to fetch data from a specific project. To ensure this, you need to generate a project-specific API key (or token). You can do this in the Exceptionless interface by clicking the All Projects link in the navigation header, then hover over the project name and click the gear icon. On the Settings page, you'll see a tab for API Keys. You can generate a token there. + +However, you can programmatically generate these tokens as well. Let's use the [User Scoped Token](/docs/api/api-getting-started) you generated previously to get a list of projects. + +### Get Projects + +GET `api/v2/projects` + +```shell +curl --location --request GET "https://api.exceptionless.com/api/v2/projects" \ +--header 'Authorization: Bearer YOUR_USER_SCOPED_TOKEN' +``` + +The response to this request will be an array of all of your projects that looks like this: + +```json +[ + { + "id": "YOUR PROJECT ID", + "created_utc": "2016-01-11T20:05:59.7185672", + "organization_id": "YOUR ORG ID", + "organization_name": "YOUR ORG NAME", + "name": "YOUR PROJECT NAME", + "delete_bot_data_enabled": false, + "is_configured": true, + "stack_count": 0, + "event_count": 0, + "has_premium_features": true, + "has_slack_integration": false + } +] +``` + +You'll need the `id` field from this response to generate your new project-specific token. Let's generate that now. In addition to using the project ID, we will also need to pass in scopes for the token. In this case, we are going to pass in the `client` scope which provides access to post events and read events, but doesn't provide full user-token access. [Read more about scopes here](/docs/api/api-getting-started). + +### Generate Client-Scoped Token + +POST `api/v2/projects/PROJECT_ID` + +```shell +curl --location --request POST "https://api.exceptionless.com/api/v2/projects/YOUR_PROJECT_ID/tokens" \ +--header 'Authorization: Bearer YOUR_USER_SCOPED_TOKEN' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "scopes": [ + "client" + ] +}' +``` + +The response you'll receive will look like this: + +```json +{ + "id": "TOKEN", + "organization_id": "YOUR_ORG_ID", + "project_id": "YOUR_PROJECT_ID", + "scopes": [ + "client" + ], + "is_disabled": false, + "created_utc": "2020-11-05T14:02:54.1866886Z", + "updated_utc": "2020-11-05T14:02:54.1867055Z" +} +``` + +This `TOKEN` can now be used as your API key in Bearer authorization headers for subsequent API requests related to your project. + +--- + +[Next > Posting Events](/docs/api/posting-events) diff --git a/docs/docs/bulk-actions.md b/docs/docs/bulk-actions.md new file mode 100644 index 0000000000..f7911e0f46 --- /dev/null +++ b/docs/docs/bulk-actions.md @@ -0,0 +1,17 @@ +--- +title: "Bulk Actions" +--- + +# Bulk Actions + +Bulk Actions is the ability to select multiple exceptions or occurrences of a single exception and do with them as you please, all at once. Simply select multiple occurrences, click the "Bulk Actions" button below the list, and choose your action. + +![Exceptionless Bulk Actions Demo](img/exceptionless-bulk-actions.gif) + +## Watch the Video! + +[![Exceptionless Bulk Actions](img/bulk-actions-video-screenshot.png)](http://www.youtube.com/watch?v=pQXk3ayK8P8) + +--- + +[Next > Project Settings](/docs/project-settings) diff --git a/docs/docs/clients/custom-clients/index.md b/docs/docs/clients/custom-clients/index.md new file mode 100644 index 0000000000..ac1a4f6dfb --- /dev/null +++ b/docs/docs/clients/custom-clients/index.md @@ -0,0 +1,121 @@ +--- +title: "Custom Exceptionless Clients" +--- + +# Custom Exceptionless Clients + +Exceptionless provides a [.NET Client](/docs/clients/dotnet/) and a [JavaScript Client](/docs/clients/javascript/) to make things convenient. However, we recognize that developers write code in all sorts of languages beyond .NET and JS. It is possible to use Exceptionless with any programming language. In fact, our API makes it really simple. However, to get the full power of Exceptionless, you may want to create your own custom client in the language of your choice. + +This guide will focus on the concepts necessary to successfully implement your custom client. Building a client in Exceptionless requires three main things: + +1. Authentication +2. Understanding of the data models +3. Usage of the correct API endpoints + +### Authentication + +One of the key things to understand when creating a custom client (or when using the Exceptionless API) is the security implications of the API token generated and used. Exceptionless has two types of API tokens: + +* User-scoped +* Client/Project-scoped + +Think of a user-scoped key as the master key for that particular user. It allows for EVERYTHING. This includes password resets, deleting organizations, deleting users, and more. This is not the type of key you want to generate with your custom client. You also don't want to manually generate and use these types of keys within your client. + +Instead, you should use a client-scoped key. A client-scoped key only has access to very specific endpoints and provides a significantly increased level of security compared to using a user-scoped key. + +In the Exceptionless UI, you can create a project API key by going to a project's settings page. To do so, click on the project dropdown in the top-menu, hover over the project's name, and then click the gear icon. On the settings page, you'll see an API Keys tab. Click that and you can generate a new client-scoped key. + +![Generate API Key in UI](../../img/apiKeyGeneration.png) + +This is the key that will need to be passed into the configuration settings of your custom client. + +### Understanding the Data Models + +Exceptionless is designed to be as flexible as possible. In fact, you can send in almost any data you want with an event. We will display some pieces of data better than others, and if you make use of well-known keys, we can use those to make sure your events are stacked properly and displayed in a usable way within your dashboard. + +However, before you can begin to throw any and everything at Exceptionless, it's important to understand the basic structure of an event. Let's take a look at the event model: + +```json +{ + "type": "error", + "source": "code.js line 655", + "reference_id": "123", + "message": "some event message", + "geo": "stringified lat and long values separated by a comma", + "date":"2030-01-01T12:00:00.0000000-05:00", + "value": 0, + "tags": ["string", "string", "string"], + "data": {}, +} +``` + +Let's take each of these properties and explain them one-by-one. + +#### type + +The type property is an important one because it tells Exceptionless how to treat your event. Remember that Exceptionless is not just for errors. If you look at your Dashboard, you'll see categories like Exceptions, Logs, and Feature Usage. We group events into these categories for you based on the `type` value you pass in. + +You can pass in any type value you'd like as long as it is a string value. However, we recommend the following type values: + +* error +* log +* usage +* 404 +* session +* sessionend + +These values are pretty self-explanatory. If you have an error, use the `error` value, if you are logging an event, use `log`, and so on and so forth. + +#### source + +The source value should be a string representing where the error happened in your code. This usually comes from the error object in whatever programming language you are writing in. This should be a string value representing the error location. + +#### reference_id + +The reference id is an identifier you can pass in in order to use later. For example, if you know that you will have other events that reference this one, you can make use of the reference identifier you pass in. This identifier can be any unique string value. UUID is good option here, but as long as the value is unique, you'll be good to go. + +#### message + +The message can mean different things depending on the type of event you're passing through. If it's an error event, you may want to pick off the error message from the error object you receive, or you may want to create a custom error message. For a log event, you can simply pass in whatever message makes sense for the event. + +Whatever message you send through, just make sure it is a string value. + +#### geo + +If you are capturing ip information, you may have location-based information. If so, and if you want to capture that alongside your events, you can pass that as a value for the `geo` property. This needs to be a string value, so you should pass in the longitude followed by a comma then the latitude. + +#### value + +The value property is an open-ended integer field that allows you capture additional information about your events. This could be number of ice cream scoops served before the event happened, it could be number of dogs walked, or any other arbitrary piece of information. + +#### tags + +The tags property is a string array of values you want to use to categorize your events. We have some built-in understanding of how certain tags should work. For example, events with a "critical" tag will be labels and handled as such in the interface. + +The tags array takes string values only, and all tags will be visibile on the event details page. + +#### data + +This is the most flexible of the properties that you send into Exceptionless. It is a dictionary object containing key/value pairs of any bits of information you want. That said, there are some know keys that will help Exceptionless better display information in this data dictionary: + +`@error` - this indicates to Exceptionless that the event is an error. We will handle the event as such. +`@simple_error` - this, like @error, indicates that the event is in an error. However, a simple error is less complex and the event object itself fits more neatly into what we've defined here so far. +`@request` - Events from a web server will have a request object. [Here is an example of how this data should be formed](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/packages/core/src/models/data/RequestInfo.ts). +`@environment` - This would be a string environment about your user's environment. [Here is an example of how that model should be formed](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/packages/core/src/models/data/EnvironmentInfo.ts). +`@user` - This is an object that can contain the following: `identity`: string value, `name`: string value, `data`: any value. +`@user_description` - This is an object that can contain the following: `email_address`: string value, `description`: string value, `data`: any value. +`@level` - This is designed for log events to represent the log level. It can also be used to prevent logs from being captured depending on your log level settings in Exceptionless. +`@submission_method` - Many apps have both global event listeners and specific areas where an event can be captured manually or ad hoc. To separate the submission methods of events, you can pass in whether an event was captured in a global listener, ad hoc, or however you want to describe the capturing of the event. +`@stack` - This is the stringified error stack for an exception. + +When providing data to the Exceptionless server, there are specific data models dependent on the information you're trying to provide. We'll cover those models here. + +### Using the API + +When building your custom client, the consumers of your client will be calling methods you create, but you, of course, will be wiring up those methods to reach out to the Exceptionless API. The API is well-documented with auto-generating docs for each endpoint. To get started, you can take a look at our [API Usage docs here](/docs/api/). + +### Wrapping Up + +A custom client gives you full flexibility. While the two clients provided by Exceptionless do all of the above work for you, extending them would require forking the code. If you want extended capabilities or client support for additional programming languages, building a custom client might be the right move for you. + +We can't way to see what you build. diff --git a/docs/docs/clients/dotnet/client-configuration-values.md b/docs/docs/clients/dotnet/client-configuration-values.md new file mode 100644 index 0000000000..9042db13ee --- /dev/null +++ b/docs/docs/clients/dotnet/client-configuration-values.md @@ -0,0 +1,99 @@ +--- +title: "Client Configuration Values" +order: 3 +--- + +# Client Configuration Values + +## Index + +- [Index](#index) +- [About](#about) +- [Usage Example](#usage-example) +- [.NET Helpers](#net-helpers) + - [Helpers](#helpers) +- [Updating Client Configuration settings](#updating-client-configuration-settings) +- [Subscribing to Client Configuration Setting changes](#subscribing-to-client-configuration-setting-changes) + +## About + +[Read about client configuration and view in-depth examples](/docs/project-settings) + +## Usage Example + +The below example demonstrates **how we would turn on or off log event submissions at runtime** without redeploying the app or changing server config settings. + +First, we add a (completely arbitrary for this example) `enableLogSubmission` client configuration value key with value `true` in the Project's Settings in the Exceptionless dashboard. + +Then, we register a new client side plugin that runs each time an event is created. If our key (`enableLogSubmission`) is set to false and the event type is set to log, we will discard the event. + +```csharp +ExceptionlessClient.Default.Configuration.AddPlugin("Conditionally cancel log submission", 100, context => { + var enableLogSubmission = context.Client.Configuration.Settings.GetBoolean("enableLogSubmission", true); + + // only cancel event submission if it's a log event and enableLogSubmission is false + if (context.Event.Type == Event.KnownTypes.Log && !enableLogSubmission) { + context.Cancel = true; + } +}); +``` + +*** + +## .NET Helpers + +The `GetBoolean` method checks the `enableLogSubmission` key. This helper method makes it easy to consume saved client configuration values. The first parameter defines the settings key (name). The second parameter is optional and allows you to set a default value if the key doesn’t exist in the settings or was unable to be converted to the proper type (e.g., a boolean). + +We have a few helpers to convert string configuration values to different system types. These methods also contain overloads that allow you to specify default values. + +### Helpers + +- `GetString` +- `GetBoolean` +- `GetInt32` +- `GetInt64` +- `GetDouble` +- `GetDateTime` +- `GetDateTimeOffset` +- `GetGuid` +- `GetStringCollection` (breaks a comma delimited list into an IEnumerable of strings) + +*** + +## Updating Client Configuration settings + +All project settings are synced to the client in almost real time. When an event is submitted to Exceptionless we send down a response header with the current configuration version. If a newer version is available we will immediately retrieve and apply the latest configuration. + +By default the client will check after `5 seconds` on client startup (*if no events are submitted on startup*) and then every `2 minutes` after the last event submission for updated configuration settings. + +- Checking for updated settings doesn't count towards plan limits. +- Only the current configuration version is sent when checking for updated settings (no user information will ever be sent). +- If the settings haven't changed, then no settings will be retrieved. + +You can also **turn off the automatic updating of configuration settings when idle** using the code below. + +```csharp +ExceptionlessClient.Default.Configuration.UpdateSettingsWhenIdleInterval = TimeSpan.Zero; +``` + +You can also manually update the configuration settings using the code below. + +```csharp +await Exceptionless.Configuration.SettingsManager.UpdateSettingsAsync(ExceptionlessClient.Default.Configuration); +``` + +## Subscribing to Client Configuration Setting changes + +To be notified when client configuration settings change, subscribe to them using the below code. + +```csharp +ExceptionlessClient.Default.Configuration.Settings.Changed += SettingsOnChanged; + +private void SettingsOnChanged(object sender, ChangedEventArgs> args) { + Console.WriteLine("The key {0} was {1}", args.Item.Key, args.Action); +} +``` + +--- + +[Next > Platform Guides](/docs/clients/dotnet/guides/) diff --git a/docs/docs/clients/dotnet/configuration.md b/docs/docs/clients/dotnet/configuration.md new file mode 100644 index 0000000000..b807877465 --- /dev/null +++ b/docs/docs/clients/dotnet/configuration.md @@ -0,0 +1,236 @@ +--- +title: "Configuration" +order: 1 +--- + +# Configuration + +There are a few ways to configure Exceptionless in your project. We'll cover them here or you can jump to app-specific examples: [Console App Example](/docs/clients/dotnet/guides/console-apps-example), [Web Server Example](/docs/clients/dotnet/guides/web-server-example). + +--- + +- [ExceptionlessClient Configuration](#exceptionlessclient-configuration) + - [Configuring With Code](#configuring-with-code) + - [Configuring With Attributes](#configuring-with-attributes) + - [Configuring With Environment Variables](#configuring-with-environment-variables) + - [Using Web.config](#using-webconfig) + - [Available Configuration Options](#available-configuration-options) + - [ServerUrl](#serverurl) + - [IncludePrivateInformation](#includeprivateinformation) + - [Extended Data](#extended-data) + - [Default Tags](#default-tags) + - [Default Data](#default-data) +- [Versioning](#versioning) +- [Offline storage](#offline-storage) + - [Configuration File](#configuration-file) + - [Code](#code) +- [Disabling Exceptionless](#disabling-exceptionless) + - [Configuration File](#configuration-file-1) + - [Attribute](#attribute) +- [Self Hosted Options](#self-hosted-options) + - [Configuration file](#configuration-file-2) + - [Attribute](#attribute-1) + +## ExceptionlessClient Configuration + +You have a few options for how you might configure your Exceptionless client. Here are some examples of how to do this. + +### Configuring With Code + +The examples below show the various ways (configuration file, attributes or code) that Exceptionless can be configured in your application. + +```csharp +using Exceptionless; + +var client = new ExceptionlessClient(c => { + c.ApiKey = "YOUR_API_KEY"; + c.SetVersion(version); +}); + +// You can also set the api key directly on the default instance. +ExceptionlessClient.Default.Configuration.ApiKey = "YOUR_API_KEY" +``` + +### Configuring With Attributes + +You can also configure Exceptionless using attributes like this: + +```csharp +using Exceptionless.Configuration; +[assembly: Exceptionless("YOUR_API_KEY")] +``` + +The Exceptionless assembly attribute will only be picked up if it’s defined in the entry or calling assembly. If you have placed the above attribute in different location you’ll need to call the method below during startup. + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.ReadFromAttributes(typeof(MyClass).Assembly) +``` + +### Configuring With Environment Variables + +You can also add an Environment variable or application setting with the key name `Exceptionless:ApiKey` and your `YOUR_API_KEY` as the value. + +### Using Web.config + +Exceptionless can be configured using a config section in your web.config or app.config depending on what kind of project you have. Installing the correct NuGet package should automatically add the necessary configuration elements. It should look like this: + +```xml + + + +
+ + + + ... + + + + + + ... + + +``` + +Now, before you can fully configure your Exceptionless client, it's important to know what options are available for you to configure. We'll cover that below. + +### Available Configuration Options + +When initializing the Exceptionless client, you can set any of the following values: + +* ServerUrl +* IncludePrivateInformation +* DefaultTags +* DefaultData + +### ServerUrl + +The `ServerUrl` is used when you are self-hosting Exceptionless and need to point your client to your self-hosted server. This one is pretty self-explanatory. + +### IncludePrivateInformation + +This is a boolean value that will automatically strip private info like credit card numbers and passwords from being sent in event handling. The default is `true`. However, you can set this value like this: + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.IncludePrivateInformation = false; +``` + +You can also set it in a global configuration file like this: + +```xml + +``` + +### Extended Data + +The next two properties that can be set when configuring the Exceptionless client can be considered features that extend your data. If you want to apply additional information to every single event that is fired, you would use one of these two settings. + +### Default Tags + +Just as you are able to apply tags to individual events, you can set default tags that will apply to all events you submit. Configuring this is simple. Here's a quick example: + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.DefaultTags.Add("Tag1"); +``` + +You can also set this up globally with a configuration file like this: + +```xml + +``` + +### Default Data + +When viewing your stacks and individual events, you can see additional information about the events on the Extended Data tab. Data found there is usually passed in by adding info to the data object in the event payload. Here's an example of how you might do that: + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.DefaultData["Data1"] = "Exceptionless"; +``` + +You can also configure this with a configuration file like this: + +```xml + + + + + + + + +``` + +## Versioning + +By specifying an application version you can [enable additional functionality](/docs/versioning). By default, an application version will try to be resolved from assembly attributes. However, it's a good practice to specify an application version if possible using the code below. + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.SetVersion("1.2.3"); +``` + +## Offline storage + +By default, Exceptionless keeps events in memory. This means if the application exits before the event can be sent to the server, the event will not be sent on restart. This can be overcome by persisting events to disk. + +To persist events to disk for offline scenarios or to ensure no events are lost between application restarts, you will need to configure your Exceptionless client to know to store the events on disk and to know where to store them. You can simply pass in a configuration value that includes the storage path. When selecting a folder path, make sure that the identity the application is running under has full permissions to that folder. + +Please note that this adds a bit of overhead as events need to be serialized to disk on submission and is not recommended for high throughput logging scenarios. + +### Configuration File + +```xml + + +``` + +### Code + +```csharp +// Use folder storage +ExceptionlessClient.Default.Configuration.UseFolderStorage("PATH OR FOLDER NAME"); +// Use isolated storage +ExceptionlessClient.Default.Configuration.UseIsolatedStorage(); +``` + +## Disabling Exceptionless + +You can disable Exceptionless from reporting events during testing using the `Enabled` setting. + +### Configuration File + +```xml + +``` + +### Attribute + +```csharp +using Exceptionless.Configuration; +[assembly: Exceptionless("YOUR_API_KEY", Enabled=false)] +``` + +## Self Hosted Options + +The Exceptionless client can also be configured to send data to your [self hosted instance](/docs/self-hosting/). This is configured by setting the `serverUrl` setting to point to your Exceptionless instance. + +### Configuration file + +```csharp + +``` + +### Attribute + +```csharp +using Exceptionless.Configuration; +[assembly: Exceptionless("YOUR_API_KEY", ServerUrl = "http://localhost")] +``` + +--- +[Next > Client Configuration Values](/docs/clients/dotnet/client-configuration-values) diff --git a/docs/docs/clients/dotnet/guides/console-apps-example.md b/docs/docs/clients/dotnet/guides/console-apps-example.md new file mode 100644 index 0000000000..c26a16d19d --- /dev/null +++ b/docs/docs/clients/dotnet/guides/console-apps-example.md @@ -0,0 +1,55 @@ +--- +title: "Console Apps Example" +--- + +# Console Apps Example + +Exceptionless runs in all types of .NET aplications. Let's take a look at how to get started with Exceptionless in a console application. First, we'll some configuration out of the way. + +To use Exceptionless, add the Exceptionless namespace like this: `using Exceptionless;` + +Once you've done that, be sure to define the Exceptionless client: + +`var client = new ExceptionlessClient("YOUR API KEY");` + +Now you can send events to Exceptionless like this: + +`client.SubmitLog("Hello World!");` + +Or you can capture exceptions like this: + +```csharp +try { + throw new Exception("MyApp error"); +} catch (Exception ex) { + // submit the exception to the Exceptionless server + client.SubmitException(ex); +} +``` + +Because Exceptionless is designed to process events asynchronously in the background via a queue, you may need to make sure the event is processed before the app exits. If this is a requirement for your app, you can handle this situation by telling Exceptionless about it up front with `client.Startup();`, which means Exceptionless knows to force process any events in the queue before allowing the app to exit, or by calling `await client.ProcessQueueAsync();` before your application exists. + +There's one additional configuration option that doesn't require defining the client first. If you use the Exceptionless default client, it takes care of of most things for you. Simply load up the Exceptionless default client by calling `Startup` with your API Key, and you're ready to go: + +`ExceptionlessClient.Default.Startup("Your API Key");` + +When you go this route, you can send exceptions to Exceptionless just by calling a `ToExceptionless()` method on the default Exceptionless client. It looks like this: + +```csharp +// configure the default instance +ExceptionlessClient.Default.Startup("Your API Key"); + +try { + throw new Exception("MyApp ToExceptionless error"); +} catch (Exception ex) { + // use ToExceptionless extension method. Uses ExceptionlessClient.Default and requires it to be configured. + ex.ToExceptionless().Submit(); + // don't forget to call Submit. +} +``` + +Exceptionless supports a wide range of platforms. For a full list, see the [supported platforms page here](/docs/clients/dotnet/supported-platforms). + +--- + +[Next > Web Server Example](/docs/clients/dotnet/guides/web-server-example) diff --git a/docs/docs/clients/dotnet/guides/index.md b/docs/docs/clients/dotnet/guides/index.md new file mode 100644 index 0000000000..ecaaf70de7 --- /dev/null +++ b/docs/docs/clients/dotnet/guides/index.md @@ -0,0 +1,19 @@ +--- +title: ".NET Platform Guides" +order: 3 +--- + +# .NET Platform Guides + +This section will provide you with specific guides for setting up and configuring Exceptionless with the most used and current .NET platforms Exceptionless supports. To see the full list of supported platforms, see our [Supported Platforms documentation](/docs/clients/dotnet/supported-platforms). + +Exceptionless tries to provide support for platforms as long as Microsoft supports them. As such, you will be able to utilize any of our packages for your applications, but this documentation will focus on our core packages for .NET. + +### Platform Guides + +* [Console Apps & Services Apps](/docs/clients/dotnet/guides/console-apps-example) +* [Web Server](/docs/clients/dotnet/guides/web-server-example) + +--- + +[Next > Console App Guide](/docs/clients/dotnet/guides/console-apps-example) diff --git a/docs/docs/clients/dotnet/guides/logging-with-generic-host.md b/docs/docs/clients/dotnet/guides/logging-with-generic-host.md new file mode 100644 index 0000000000..1507ab1a52 --- /dev/null +++ b/docs/docs/clients/dotnet/guides/logging-with-generic-host.md @@ -0,0 +1,96 @@ +--- +title: "Logging With Generic Host" +--- + +# Logging With Generic Host + +Microsoft provides a useful tool for logging events called `Microsoft.Extensions.Logging`. You can read up on [how logging works with .NET Core here](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0), but we'll cover how to set up Exceptionless as a logging provider to be used as a generic host. + +To get started, you'll need to make sure you update your `appsettings.json` file for your project. Here's an example configuration that will allow you to use Exceptionless with .NET Core's generic host: + +```json + "Exceptionless": { + "ApiKey": "YOUR API KEY" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +``` + +With that added, you can add the Exceptionless namespace to any file in your project with `using Exceptionless;`. This then allows you to utilize Exceptionless with dependency injection, or as we're covering here, as a generic host. + +In your `Startup` method, you can read in your configuration file like this: + +```csharp +var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); +``` + +This tells .NET Core to use whatever settings you've provided in the `appsettings.json` file for the logger (it also sets up some other configurations). To ensure Exceptionless is used for logging, you will need to update the `ConfigureServices` method to this: + +```csharp +services.AddLogging(b => b + .AddConfiguration(Configuration.GetSection("Logging")) + .AddDebug() + .AddConsole() + .AddExceptionless()); +``` + +This is adding debugging capabilities, console logging, and Exceptionless to your generic host logging configuration. + +If you are using a generic host in a web server application, you may want to capture more information about HTTP requests automatically. To do this, you'll need to edit the `ConfigureServices` method to include the following line: + +`services.AddHttpContextAccessor();` + +Finally, you'll need to tell the app itself to use Exceptionless. You can do this in your `Configure` method liket his: + +`app.useExceptionless(Configuration);` + +Now, you have access to send logs, exceptions, and messages to Exceptionless automatically through the generic host configuration. If you'd like to see a full, detailed example, [we have that here](https://github.com/exceptionless/Exceptionless.Net/blob/9e91a51c36d03fcc3bee79a8b6eaee3034ac78b4/samples/Exceptionless.SampleAspNetCore/Startup.cs). + +### Exceptionless Configuration Options + +One of the nice things about configuring Exceptionless through `appsettings.json` is you can set up some defaults that will apply to all events sent through to Exceptionless. Let's explore what that might look like. In your `appsettings.json` file, you can add the following to your `Exceptionless` property: + +```json +"DefaultData": { + "JSON_OBJECT": "{ \"Name\": \"John Doe\" }", + "Boolean": true, + "Number": 1, + "Array": "1,2,3" +} +``` + +This is a very simple object that encapsulates default data that will be sent to Exceptionless with every event. The `DefaultData` property can take in any property keys you'd like to pass in. The property values must be strings, booleans, numbers, or arrays. As you can see in the example, a JSON object can simply be stringified. + +In addition to the `DefaultData` property, you can include `DefaultTags` and `Settings`. To include `DefaultTags`, add the following: + +```json +"DefaultTags": [ "MySpecialTag" ] +``` + +As you can probably tell, you can pass in as many tags as you'd like as an array of strings. + +To add custom settings, you would do something like this: + +```json +"Settings": { + "FeatureXYZEnabled": false +} +``` + +The `Settings` property can take any keys you'd like. The values associated with those keys must be strings, numbers, or booleans. + +You can, of course, customize the default logging, but that is outside the Exceptionless configuration. If you'd like to customize the way things are logged when using the generic host, [follow this guide](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0#configure-logging). + +--- + +[Next > Sending Events](/docs/clients/dotnet/sending-events) \ No newline at end of file diff --git a/docs/docs/clients/dotnet/guides/web-server-example.md b/docs/docs/clients/dotnet/guides/web-server-example.md new file mode 100644 index 0000000000..08071556a5 --- /dev/null +++ b/docs/docs/clients/dotnet/guides/web-server-example.md @@ -0,0 +1,82 @@ +--- +title: "Web Server Example" +--- + +# Web Server Example + +Exceptionless runs great in all sorts of environments. Let's take a look at how you might set up Exceptionless to work with your .NET web server. + +To get started, be sure to include the Exceptionless namespace wherever you plan to use it. You can do that like this: `using Exceptionless;` + +The simplest example of using Exceptionless in your web server is to include a try/catch block that leverages Exceptionless in the catch. It might look something like this: + +```csharp +[HttpGet("{id}")] +public ActionResult GetUser(string id) +{ + try { + var user = userService.GetUser(id); + return Ok(user); + } catch (Exception ex) { + ex.ToExceptionless().SetProperty("UserId", id).Submit(); + return NotFound(); + } +} +``` + +Should the request to `FetchUser()`, or whatever your method is, happen to throw, the Exceptionless client will pick it up and send the exception to your dashboard. + +Of course, Exceptionless is more than just error handling. You can leverage any of the Exceptionless event methods [documented here](/docs/clients/dotnet/sending-events) through the client interface. + +Exceptionless can be configured as a generic host for your web server. In your `Startup.cs` file, you would include the following within the `ConfigureServices` method: + +```csharp +services.AddHttpContextAccessor(); +``` + +By adding this helper method, Exceptionless is able to gather more information about the request including the API endpoint that threw the error, user-agent information, and more. + +Then in your `Configure` method, you would add: + +```csharp +app.UseExceptionless(Configuration); +``` + +To get access to your Exceptionless configuration (which we'll explain next), you'll need to do create a `builder` variable in your `Startup` method and build the configuration like this: + +```csharp +var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddEnvironmentVariables(); +Configuration = builder.Build(); +``` + +This gives your server application access to any configuration you've set in your `appsettings.json` file. And that's exactly where we will configure Exceptionless. So, go ahead and open that file and we can create some configuration for your Exceptionless client: + +```json + "Exceptionless": { + "ApiKey": "YOUR API KEY", + "ServerUrl": "http://localhost:5200", + "DefaultData": { + "JSON_OBJECT": "{ \"Name\": \"Alice\" }", + "Boolean": true, + "Number": 1, + "Array": "1,2,3" + }, + "DefaultTags": [ "SOME_TAG" ], + "Settings": { + "FeatureXYZEnabled": false + } +}, +``` + +You will only pass in the `ServerUrl` if you are self-hosting Exceptionless. You'll use this to point to your correct URL. The `DefaultData` is metadata you'd like associated with every event you send to Exceptionless. + +With this configured, you can now call the Exceptionless client from anywhere in your server application without first defining the client. + +This is just one example of one platform Exceptionless supports. But Exceptionless supports a wide range of platforms. For a full list, see the [supported platforms page here](/docs/clients/dotnet/supported-platforms). + +--- + +[Next > Logging With Generic Host](/docs/clients/dotnet/guides/logging-with-generic-host) diff --git a/docs/docs/clients/dotnet/index.md b/docs/docs/clients/dotnet/index.md new file mode 100644 index 0000000000..698c1bf436 --- /dev/null +++ b/docs/docs/clients/dotnet/index.md @@ -0,0 +1,81 @@ +--- +title: ".NET Client" +--- + +# .NET Client + +Exceptionless provides a simple-to-use .NET client for your convenience. To get started, you'll need to install the client. There are a variety of ways to install, but for brevity we'll focus on the dotnet cli. If you don't have that installed, [follow the guide here](https://docs.microsoft.com/en-us/dotnet/core/sdk). + +Exceptionless provides packages for specific platform (listed toward the bottom of this page), but to get started quickly, you can install the root version of Exceptionless like so: + +`dotnet add package Exceptionless` + +If you want to install a specific version, you can pass in the `--version` flag like this: + +`dotnet add package Exceptionless --version 4.5.0` + +For more specific packages for your particular target platform, we have provided the following packages: + +## [Exceptionless.Mvc](https://www.nuget.org/packages/Exceptionless.Mvc/) + +Exceptionless client for ASP.NET MVC 3+ applications. + +## [Exceptionless.WebApi](https://www.nuget.org/packages/Exceptionless.WebApi/) + +Exceptionless client for ASP.NET Web API applications. + +## [Exceptionless.Web](https://www.nuget.org/packages/Exceptionless.Web/) + +Exceptionless client for ASP.NET WebForms applications. + +## [Exceptionless.AspNetCore](https://www.nuget.org/packages/Exceptionless.AspNetCore/) + +Exceptionless client for ASP.NET Core applications. + +## [Exceptionless.Nancy](https://www.nuget.org/packages/Exceptionless.Nancy/) + +Exceptionless client for [Nancy](http://nancyfx.org/) applications. + +## [Exceptionless.Wpf](https://www.nuget.org/packages/Exceptionless.Wpf/) + +Exceptionless client for WPF applications. + +## [Exceptionless.Windows](https://www.nuget.org/packages/Exceptionless.Windows/) + +Exceptionless client for Windows Forms applications. + +## [Exceptionless.NLog](https://www.nuget.org/packages/Exceptionless.NLog/) + +NLog target that sends log entries to Exceptionless. + +## [Exceptionless.Log4net](https://www.nuget.org/packages/Exceptionless.Log4net/) + +Log4net appender that sends log entries to Exceptionless. + +## [Serilog.Sinks.ExceptionLess](https://www.nuget.org/packages/Serilog.Sinks.ExceptionLess/) + +Serilog sink that sends log entries to Exceptionless. + + + +--- + +[Next > Platform Guides](/docs/clients/dotnet/guides/) diff --git a/docs/docs/clients/dotnet/plugins.md b/docs/docs/clients/dotnet/plugins.md new file mode 100644 index 0000000000..fb53083c78 --- /dev/null +++ b/docs/docs/clients/dotnet/plugins.md @@ -0,0 +1,121 @@ +--- +title: "Plugins" +order: 8 +--- + +# Plugins + +A plugin is a client-side add-in that is run **every time** you submit an event. + +- [Create a New Plugin](#create-a-new-plugin) +- [Add System Uptime to Feature Usages](#add-system-uptime-to-feature-usages) + - [Output](#output) +- [Plugin Priority](#plugin-priority) +- [Adding the Plugin to Your App](#adding-the-plugin-to-your-app) +- [Removing an Existing Plugin](#removing-an-existing-plugin) + +## Create a New Plugin + +Specify a `System.Action<EventPluginContext>` or create a class that derives from [IEventPlugin](https://github.com/exceptionless/Exceptionless.Net/blob/master/src/Exceptionless/Plugins/IEventPlugin.cs) to create a plugin. + +Every plugin is passed an [EventPluginContext](https://github.com/exceptionless/Exceptionless.Net/blob/master/src/Exceptionless/Plugins/EventPluginContext.cs), which contains all the valuable contextual information that your plugin may need via the following properties: + +- Client +- Event +- ContextData +- Log +- Resolver + +## Add System Uptime to Feature Usages + +```csharp +using System; +using System.Diagnostics; +using Exceptionless.Plugins; +using Exceptionless.Models; + +namespace Exceptionless.SampleConsole.Plugins { + [Priority(100)] + public class SystemUptimePlugin : IEventPlugin { + public void Run(EventPluginContext context) { + // Only update feature usage events. + if (context.Event.Type != Event.KnownTypes.FeatureUsage) + return; + + // Get the system uptime + using (var pc = new PerformanceCounter("System", "System Up Time")) { + pc.NextValue(); + + var uptime = TimeSpan.FromSeconds(pc.NextValue()); + + // Store the system uptime as an extended property. + context.Event.SetProperty("System Uptime", String.Format("{0} Days {1} Hours {2} Minutes {3} Seconds", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds)); + } + } + } +} +``` + +### Output + +![Exceptionless Plugin Screenshot](/assets/img/news/exceptionless-plugin-system-uptime.png) + +## Plugin Priority + +The plugin priority determines the order the plugin runs (lowest to highest, then by order added). All plugins shipped with the client have a starting priority of 10 and increment by multiples of 10. For your addin to run first, give it a priority lower than 10 (e.g., 0-5). To have it run last, give it a priority higher than 100. **If a priority is not specified, it defaults to 0.** + +## Adding the Plugin to Your App + +Start by calling one of the `Exceptionless.ExceptionlessClient.Default.Configuration.AddPlugin()` overloads. This will typically be the following: + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.AddPlugin(); +``` + +Passing a `System.Action<EventPluginContext>` to AddPlugin can also be used to add a plugin. _Note we specify a key so we can remove the plugin later. If you won't be removing the plugin, you can omit the first argument._ + +**AddPlugin is passed three arguments:** + +- Unique Plugin Key (to remove later, if applicable) +- Priority +- Action (logic) + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.AddPlugin("system-uptime", 100, context => { + // Only update feature usage events. + if (context.Event.Type != Event.KnownTypes.FeatureUsage) + return; + + // Get the system uptime + using (var pc = new PerformanceCounter("System", "System Up Time")) { + pc.NextValue(); + var uptime = TimeSpan.FromSeconds(pc.NextValue()); + + // Store the system uptime as an extended property. + context.Event.SetProperty("System Uptime", String.Format("{0} Days {1} Hours {2} Minutes {3} Seconds", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds)); + + } +}); +``` + +## Removing an Existing Plugin + +Call one of the `Exceptionless.ExceptionlessClient.Default.Configuration.RemovePlugin` overloads to remove a plugin. + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.RemovePlugin(); +``` + +If it was registered via an action, you have to remove it via the key you added it with. + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.RemovePlugin("system-uptime"); +``` + +--- + +[Next > Private Information](/docs/clients/dotnet/private-information) diff --git a/docs/docs/clients/dotnet/private-information.md b/docs/docs/clients/dotnet/private-information.md new file mode 100644 index 0000000000..6eee955e92 --- /dev/null +++ b/docs/docs/clients/dotnet/private-information.md @@ -0,0 +1,45 @@ +--- +title: "Private Information" +order: 9 +--- + +# Private Information + +By default the Exceptionless Client will report all available metadata which could include potentially private data. There are various ways to limit the scope of data collection. For example, one could use [Data Exclusions](/docs/security) to remove sensitive values but it only applies to specific collection points such as `Cookie Keys`, `Form Data Keys`, `Query String Keys` and `Extra Exception properties`. Additional data may need to be removed like the collection of user names and IP Addresses. Shown below is several examples of how you can configure the client to remove this additional data. + +You have the option of finely tuning what is collected via individual setting options or you can disable the collection of all private data by setting the `IncludePrivateInformation` to `false`. + +## Configuration File + +```xml + +``` + +## Code + +```csharp +ExceptionlessClient.Default.Configuration.IncludePrivateInformation = false; +``` + +If you wish to have a finer grained approach which allows you to use Data Exclusions while removing specific meta data collection you can do so via code. Please note if the below doesn't meet your needs you can always [write a plugin](/docs/clients/dotnet/plugins). + +## Configuration + +```csharp +// Include the username if available (E.G., Environment.UserName or IIdentity.Name) +ExceptionlessClient.Default.Configuration.IncludeUserName = false; +// Include the MachineName in MachineInfo. +ExceptionlessClient.Default.Configuration.IncludeMachineName = false; +// Include Ip Addresses in MachineInfo and RequestInfo. +ExceptionlessClient.Default.Configuration.IncludeIpAddress = false; +// Include Cookies, please note that DataExclusions are applied to all Cookie keys when enabled. +ExceptionlessClient.Default.Configuration.IncludeCookies = false; +// Include Form/POST Data, please note that DataExclusions are only applied to Form data keys when enabled. +ExceptionlessClient.Default.Configuration.IncludePostData = false; +// Include Query String information, please note that DataExclusions are applied to all Query String keys when enabled. +ExceptionlessClient.Default.Configuration.IncludeQueryString = false; +``` + +--- + +[Next > Troubleshooting](/docs/clients/dotnet/troubleshooting) diff --git a/docs/docs/clients/dotnet/sending-events.md b/docs/docs/clients/dotnet/sending-events.md new file mode 100644 index 0000000000..b2ad5c2819 --- /dev/null +++ b/docs/docs/clients/dotnet/sending-events.md @@ -0,0 +1,150 @@ +--- +title: "Sending Events" +order: 4 +--- + +# Sending Events + +Once [configured](/docs/clients/dotnet/configuration), Exceptionless will automatically send any unhandled exceptions that happen in your application. The sections below will show you how to send us different event types as well as customize the data that is sent in. + +You may also want to send us **log messages**, **feature usages** or other kinds of events. You can do this very easily with our fluent api. Find examples, below. + +- [Log Messages, Feature Usages, 404, and Custom Event Types](#log-messages-feature-usages-404-and-custom-event-types) +- [Manually Sending Errors](#manually-sending-errors) +- [Sending Additional Information](#sending-additional-information) +- [Modifying Unhandled Exception Reports](#modifying-unhandled-exception-reports) +- [Using NLog or Log4net Targets](#using-nlog-or-log4net-targets) + +*** + +## Log Messages, Feature Usages, 404, and Custom Event Types + +```csharp +// Import the exceptionless namespace. +using Exceptionless; + +// Submit logs +ExceptionlessClient.Default.SubmitLog("Logging made easy"); + +// You can also specify the log source and log level. +// We recommend specifying one of the following log levels: Trace, Debug, Info, Warn, Error +ExceptionlessClient.Default.SubmitLog(typeof(Program).FullName, "This is so easy", "Info"); +ExceptionlessClient.Default.CreateLog(typeof(Program).FullName, "This is so easy", "Info").AddTags("Exceptionless").Submit(); + +// Submit feature usages +ExceptionlessClient.Default.SubmitFeatureUsage("MyFeature"); +ExceptionlessClient.Default.CreateFeatureUsage("MyFeature").AddTags("Exceptionless").Submit(); + +// Submit a 404 +ExceptionlessClient.Default.SubmitNotFound("/somepage"); +ExceptionlessClient.Default.CreateNotFound("/somepage").AddTags("Exceptionless").Submit(); + +// Submit a custom event type +ExceptionlessClient.Default.SubmitEvent(new Event { Message = "Low Fuel", Type = "racecar", Source = "Fuel System" }); +``` + +## Manually Sending Errors + +In addition to automatically sending all unhandled exceptions, you may want to manually send exceptions to the service. You can do so by importing the Exceptionless namespace and using code like this: + +```csharp +try { + throw new ApplicationException(Guid.NewGuid().ToString()); +} catch (Exception ex) { + ex.ToExceptionless().Submit(); +} +``` + +## Sending Additional Information + +You can easily include additional information in your error reports using our fluent event builder API. + +```csharp +try { + throw new ApplicationException("Unable to create order from quote."); +} catch (Exception ex) { + ex.ToExceptionless() + // Set the reference id of the event so we can search for it later (reference:id). + // This will automatically be populated if you call ExceptionlessClient.Default.Configuration.UseReferenceIds(); + .SetReferenceId(Guid.NewGuid().ToString("N")) + // Add the order object but exclude the credit number property. + .AddObject(order, "Order", excludedPropertyNames: new [] { "CreditCardNumber" }, maxDepth: 2) + // Set the quote number. + .SetProperty("Quote", 123) + // Add an order tag. + .AddTags("Order") + // Mark critical. + .MarkAsCritical() + // Set the coordinates of the end user. + .SetGeo(43.595089, -88.444602) + // Set the user id that is in our system and provide a friendly name. + .SetUserIdentity(user.Id, user.FullName) + // Set the users description of the error. + .SetUserDescription(user.EmailAddress, "I tried creating an order from my saved quote.") + // Submit the event. + .Submit(); +} +``` + +## Modifying Unhandled Exception Reports + +You can get notified, add additional information or ignore unhandled exceptions by wiring up to the `SubmittingEvent` event. + +```csharp +// Wire up to this event in somewhere in your application's startup code. +ExceptionlessClient.Default.SubmittingEvent += OnSubmittingEvent; + +private void OnSubmittingEvent(object sender, EventSubmittingEventArgs e) { + // Only handle unhandled exceptions. + if (!e.IsUnhandledError) + return; + + // Ignore 404s + if (e.Event.IsNotFound()) { + e.Cancel = true; + return; + } + + // Get the error object. + var error = e.Event.GetError(); + if (error == null) + return; + + // Ignore 401 (Unauthorized) and request validation errors. + if (error.Code == "401" || error.Type == "System.Web.HttpRequestValidationException") { + e.Cancel = true; + return; + } + + // Ignore any exceptions that were not thrown by our code. + var handledNamespaces = new List { "Exceptionless" }; + if (!error.StackTrace.Select(s => s.DeclaringNamespace).Distinct().Any(ns => handledNamespaces.Any(ns.Contains))) { + e.Cancel = true; + return; + } + + // Add some additional data to the report. + e.Event.AddObject(order, "Order", excludedPropertyNames: new [] { "CreditCardNumber" }, maxDepth: 2); + e.Event.Tags.Add("Order"); + e.Event.MarkAsCritical(); + e.Event.SetUserIdentity(user.EmailAddress); +} +``` + +## Using NLog or Log4net Targets + +Using major logging frameworks like NLog or Log4net gives you more granular control over what's logged. + +To use the [NLog](https://www.nuget.org/packages/exceptionless.nlog) or [Log4net](https://www.nuget.org/packages/exceptionless.log4net) clients, bring down the NuGet package and follow the detailed readme. You can also take a look at our [sample app](https://github.com/exceptionless/Exceptionless.Net/tree/master/samples/Exceptionless.SampleConsole), which uses both frameworks. + +**Performance Note** +If you are logging thousands of messages a minute, you should use the in-memory event storage (below). This way, the client won't serialize the log events to disk, thus is much faster. This does mean, however, that if the application dies you will lose unsent events in memory. When you use the NLog or Log4net targets and specify the API key as part of the target configuration, we will automatically create a second client instance that uses in-memory storage only for log messages. This way, any logged exceptions or feature usages still use disk storage, while log messages use in-memory storage, allowing maximum performance. + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.UseInMemoryStorage(); +``` + +--- + +[Next > Supported Platforms](/docs/clients/dotnet/supported-platforms) diff --git a/docs/docs/clients/dotnet/settings.md b/docs/docs/clients/dotnet/settings.md new file mode 100644 index 0000000000..e75e53aafa --- /dev/null +++ b/docs/docs/clients/dotnet/settings.md @@ -0,0 +1,179 @@ +--- +title: "Settings" +order: 7 +--- + +# Settings + +- [About](#about) +- [Usage Example](#usage-example) +- [Typed Helpers](#typed-helpers) +- [Updating Client Configuration settings](#updating-client-configuration-settings) +- [Subscribing to Client Configuration Setting changes](#subscribing-to-client-configuration-setting-changes) +- [Custom Config Settings](#custom-config-settings) + - [Configuration file](#configuration-file) + - [Attribute](#attribute) +- [Adding Static Extended Data Values with Every Report](#adding-static-extended-data-values-with-every-report) + - [Configuration file](#configuration-file-1) + - [Code](#code) +- [Adding Custom Tags with Every Report](#adding-custom-tags-with-every-report) + - [Configuration File](#configuration-file-2) + - [Code](#code-1) + +## About + +[Read about client configuration and view in-depth examples](/docs/project-settings) + +## Usage Example + +The below example demonstrates **how we would turn on or off log event submissions at runtime** without redeploying the app or changing server config settings. + +First, we add a (completely arbitrary for this example) `enableLogSubmission` client configuration value key with value `true` in the Project's Settings in the Exceptionless dashboard. + +![Exceptionless Client Configuration Value](/assets/img/docs/client-configuration.png) + +Then, we register a new client side plugin that runs each time an event is created. If our key (`enableLogSubmission`) is set to false and the event type is set to log, we will discard the event. + +```csharp +ExceptionlessClient.Default.Configuration.AddPlugin("Conditionally cancel log submission", 100, context => { + var enableLogSubmission = context.Client.Configuration.Settings.GetBoolean("enableLogSubmission", true); + + // only cancel event submission if it's a log event and enableLogSubmission is false + if (context.Event.Type == Event.KnownTypes.Log && !enableLogSubmission) { + context.Cancel = true; + } +}); +``` + +## Typed Helpers + +The `GetBoolean` method checks the `enableLogSubmission` key. This helper method makes it easy to consume saved client configuration values. The first parameter defines the settings key (name). The second parameter is optional and allows you to set a default value if the key doesn't exist in the settings or was unable to be converted to the proper type (e.g., a boolean). + +We have a few helpers to convert string configuration values to different system types. These methods also contain overloads that allow you to specify default values. + +- `GetString` +- `GetBoolean` +- `GetInt32` +- `GetInt64` +- `GetDouble` +- `GetDateTime` +- `GetDateTimeOffset` +- `GetGuid` +- `GetStringCollection` (breaks a comma delimited list into an IEnumerable of strings) + +## Updating Client Configuration settings + +![Exceptionless Client Configuration Settings](/assets/img/docs/client-configuration.png) + +All project settings are synced to the client in almost real time. When an event is submitted to Exceptionless we send down a response header with the current configuration version. If a newer version is available we will immediately retrieve and apply the latest configuration. + +By default the client will check after `5 seconds` on client startup (*if no events are submitted on startup*) and then every `2 minutes` after the last event submission for updated configuration settings. + +- Checking for updated settings doesn't count towards plan limits. +- Only the current configuration version is sent when checking for updated settings (no user information will ever be sent). +- If the settings haven't changed, then no settings will be retrieved. + +You can also **turn off the automatic updating of configuration settings when idle** using the code below. + +```csharp +ExceptionlessClient.Default.Configuration.UpdateSettingsWhenIdleInterval = TimeSpan.Zero; +``` + +You can also manually update the configuration settings using the code below. + +```csharp +await Exceptionless.Configuration.SettingsManager.UpdateSettingsAsync(ExceptionlessClient.Default.Configuration); +``` + +## Subscribing to Client Configuration Setting changes + +To be notified when client configuration settings change, subscribe to them using the below code. + +```csharp +ExceptionlessClient.Default.Configuration.Settings.Changed += SettingsOnChanged; + +private void SettingsOnChanged(object sender, ChangedEventArgs> args) { + Console.WriteLine("The key {0} was {1}", args.Item.Key, args.Action); +} +``` + +## Custom Config Settings + +Exceptionless allows you to add custom config values to your Exceptionless clients that can be set through the client config section, attributes or remotely on the project settings. These config values can be accessed and used within your app to control things like wether or not to send custom data with your reports. For example, you could have a `IncludeOrderData` flag in your config that you use to control wether or not you add a custom order object to your Exceptionless report data. You can even remotely turn the setting on or off from your project settings. Here is an example of doing that: + +### Configuration file + +```csharp + + + + + +``` + +### Attribute + +```csharp +using Exceptionless.Configuration; +[assembly: ExceptionlessSetting("IncludeOrderData", "true")] +``` + +Then in your app, you can check the setting and determine if you should include the order data or not: + +```csharp +using Exceptionless; + +try { + ... +} catch (Exception ex) { + var report = ex.ToExceptionless(); + if (ExceptionlessClient.Default.Configuration.Settings["IncludeOrderData"] == "true") + report.AddObject(order); + report.Submit(); +} +``` + +## Adding Static Extended Data Values with Every Report + +You can have the Exceptionless client automatically add extended data values to every report that it submits like this: + +### Configuration file + +```csharp + + + + + + + + +``` + +### Code + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.DefaultData["Data1"] = "Exceptionless"; +``` + +## Adding Custom Tags with Every Report + +You can have the Exceptionless client automatically add specific tags to every report that it submits like this: + +### Configuration File + +```csharp + +``` + +### Code + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.DefaultTags.Add("Tag1"); +``` + +--- + +[Next > Plugins](/docs/clients/dotnet/plugins) diff --git a/docs/docs/clients/dotnet/supported-platforms.md b/docs/docs/clients/dotnet/supported-platforms.md new file mode 100644 index 0000000000..422ed1d212 --- /dev/null +++ b/docs/docs/clients/dotnet/supported-platforms.md @@ -0,0 +1,54 @@ +--- +title: "Supported Platforms" +order: 5 +--- + +# Supported Platforms + +## [Exceptionless](https://www.nuget.org/packages/Exceptionless/) + +Exceptionless client for non-visual (ie. Console and Services) applications. Use this package if you are not using any other platform specific packages. + +## [Exceptionless.Mvc](https://www.nuget.org/packages/Exceptionless.Mvc/) + +Exceptionless client for ASP.NET MVC 3+ applications. + +## [Exceptionless.WebApi](https://www.nuget.org/packages/Exceptionless.WebApi/) + +Exceptionless client for ASP.NET Web API applications. + +## [Exceptionless.Web](https://www.nuget.org/packages/Exceptionless.Web/) + +Exceptionless client for ASP.NET WebForms applications. + +## [Exceptionless.AspNetCore](https://www.nuget.org/packages/Exceptionless.AspNetCore/) + +Exceptionless client for ASP.NET Core applications. + +## [Exceptionless.Nancy](https://www.nuget.org/packages/Exceptionless.Nancy/) + +Exceptionless client for [Nancy](http://nancyfx.org/) applications. + +## [Exceptionless.Wpf](https://www.nuget.org/packages/Exceptionless.Wpf/) + +Exceptionless client for WPF applications. + +## [Exceptionless.Windows](https://www.nuget.org/packages/Exceptionless.Windows/) + +Exceptionless client for Windows Forms applications. + +## [Exceptionless.NLog](https://www.nuget.org/packages/Exceptionless.NLog/) + +NLog target that sends log entries to Exceptionless. + +## [Exceptionless.Log4net](https://www.nuget.org/packages/Exceptionless.Log4net/) + +Log4net appender that sends log entries to Exceptionless. + +## [Serilog.Sinks.ExceptionLess](https://www.nuget.org/packages/Serilog.Sinks.ExceptionLess/) + +Serilog sink that sends log entries to Exceptionless. + +--- + +[Next > Settings](/docs/clients/dotnet/settings) diff --git a/docs/docs/clients/dotnet/troubleshooting.md b/docs/docs/clients/dotnet/troubleshooting.md new file mode 100644 index 0000000000..956494ea14 --- /dev/null +++ b/docs/docs/clients/dotnet/troubleshooting.md @@ -0,0 +1,79 @@ +--- +title: "Troubleshooting" +order: 10 +--- + +# Troubleshooting + +If your events aren't being sent to the server there are a few things that you can try to diagnose the issue. + +## Update Your Client + +Please make sure that you are using the [latest version of the client](/docs/clients/dotnet/upgrading). + +## Ensure the Queue has Time to Process + +If you are using Exceptionless in a scenario where an event is submitted and the process is immediately terminated, then you will need to make sure that the queue is processed before the application ends. Please note that this will happen automatically if your runtime supports it _(portable profiles do not currently support this)_. + +Events are queued to disk and sent in the background, if the application isn't running then the events cannot be sent. You can manually force the queue to be processed by calling the following line of code before before the process ends: + +```csharp +await ExceptionlessClient.Default.ProcessQueueAsync(); +``` + +This will cause the event queue to be processed synchronously and the events to be reported. If this doesn't solve the issue then please enable client logging and send us the log file. + +## How to Locate the Default Isolated Storage Queue Folder + +By default, Exceptionless stores errors in an isolated storage folder. You can find this folder using the 1st 8 characters of your API key. So if your API key is `a7aa250fce7e4e36a22a7031cf2337c8`, then you would search in the `C:\ProgramData\IsolatedStorage` folder for a folder named `a7aa250f`. + +## Firewall / Proxy + +If you are behind a proxy or firewall, please ensure that you can connect to and . + +Your proxy settings should be picked up automatically by the Exceptionless client, but you can also try manually configuring the settings by adding a section to your app/web.config file. + +::: info +Some clients may not support proxies. Proxies are not supported in Portable Class Libraries (PCL). If you are only using the `Exceptionless` portable class library package, then proxies will not work.** +::: + +```xml + + + + + + + + + +``` + +You also have the option of specifying the proxy in code by setting the `ExceptionlessClient.Configuration.Proxy` property. + +## Enable Client Logging + +The Exceptionless client can be configured to write diagnostic messages to a log file to help diagnose any issues with the client. You can enable logging via configuration using one of the following methods: + +_Make sure you have write access to the file you specify for the log path._ + +## Configuration File + +```csharp + +``` + +## Code + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.UseFileLogger("C:\\exceptionless.log"); +``` + +## Debugging Source Code + +You can also debug the Exceptionless NuGet packages by configuring the Visual Studio source server integration. Please follow the [Symbol Source documentation](http://tripleemcoder.com/2015/10/04/moving-to-the-new-symbolsource-engine/) on configuring Visual Studio. + +--- + +[Next > Upgrading](/docs/clients/dotnet/upgrading) diff --git a/docs/docs/clients/dotnet/upgrading.md b/docs/docs/clients/dotnet/upgrading.md new file mode 100644 index 0000000000..5e6bde2b59 --- /dev/null +++ b/docs/docs/clients/dotnet/upgrading.md @@ -0,0 +1,105 @@ +--- +title: "Upgrading" +order: 11 +--- + +# Upgrading + +- [Upgrading from Exceptionless 5.x](#upgrading-from-exceptionless-5x) +- [Upgrading from Exceptionless 4.x](#upgrading-from-exceptionless-4x) + - [ProcessQueueAsync IAsyncDisposable pattern](#processqueueasync-iasyncdisposable-pattern) +- [Upgrading from Exceptionless 3.x](#upgrading-from-exceptionless-3x) +- [Upgrading from Exceptionless 2.x](#upgrading-from-exceptionless-2x) + +## Upgrading from Exceptionless 5.x + +We bumped the major version due to serialization changes we made under the hood. +We now only apply snake case naming strategy to known exceptionless models. Any +extra data like custom exception properties or user defined data is preserved +exactly as is. We also made changes to ensure that empty collections and +dictionaries are now serialized as they were previously excluded. + +## Upgrading from Exceptionless 4.x + +Here is a breakdown of the breaking changes in each package + +- Exceptionless Package + - `ExceptionlessClient` + - renamed `UpdateUserEmailAndDescription` to `UpdateUserEmailAndDescriptionAsync` and made it async. + - removed `ProcessQueue`, replace this call with the async version `ProcessQueueAsync`. + - removed `ProcessQueueDeferred`, we recommend calling `ProcessQueueAsync` in `IAsyncDisposable` pattern. The section [below](#processqueueasync-iasyncdisposable-pattern) contains more information. + - renamed `Shutdown` extension method to `ShutdownAsync` and made it async. + - renamed `SubmitSessionEnd` extension method to `SubmitSessionEndAsync` and made it async. + - renamed `SubmitSessionHeartbeat` extension method to `SubmitSessionHeartbeatAsync` and made it async. + - `SettingsManager` + - renamed `CheckVersion` to `CheckVersionAsync` and made it async. + - renamed `UpdateSettings` to `UpdateSettingsAsync` and made it async. + - `DefaultEventQueue` + - removed `Process`, replace this call with the async version `ProcessAsync`. + - `ProcessQueueScope` + - removed this class, we recommend calling `await client.ProcessQueueAsync` in `IAsyncDisposable` pattern. The section [below](#processqueueasync-iasyncdisposable-pattern) contains more information. + - `ISubmissionClient` + - removed `PostEvents`, replace this call with the async version `PostEventsAsync`. + - removed `PostUserDescription`, replace this call with the async version `PostUserDescriptionAsync`. + - removed `GetSettings`, replace this call with the async version `GetSettingsAsync`. + - removed `SendHeartbeat`, replace this call with the async version `SendHeartbeatAsync`. +- Exceptionless.WebApi Package + - `ExceptionlessClient extension methods` + - renamed `UnregisterWebApi` to `UnregisterWebApiAsync` and made it async. +- Exceptionless.Windows Package + - `ExceptionlessClient extension methods` + - renamed `Unregister` to `UnregisterAsync` and made it async. +- Exceptionless.Wpf Package + - `ExceptionlessClient extension methods` + - renamed `Unregister` to `UnregisterAsync` and made it async. + +### ProcessQueueAsync IAsyncDisposable pattern + +We removed `ProcessQueueDeferred` as it was doing asynchronous work inside of a synchronous dispose. The following pattern solves this issue. + +> We may introduce a this pattern in the core library at a later date targeting +> .NET Core, we just didn't want to take on extra package dependencies, of +> which could become a diamond dependency. + +The change is pretty simple, just upgrade existing code calling `ProcessQueueDeferred` + +```csharp +using var _ = client.ProcessQueueDeferred(); +``` + +and replace it with the following: + +```csharp +await using var _ = new ProcessQueueScope(client); + +internal class ProcessQueueScope : IAsyncDisposable { + private readonly ExceptionlessClient _exceptionlessClient; + + public ProcessQueueScope(ExceptionlessClient exceptionlessClient) { + _exceptionlessClient = exceptionlessClient; + } + + public async ValueTask DisposeAsync() { + await _exceptionlessClient.ProcessQueueAsync(); + } +} + +``` + +We recommend creating a `ProcessQueueScope` as a reusable utility class and feel free to rename it! + +## Upgrading from Exceptionless 3.x + +- The `Exceptionless.Portable` package and `Exceptionless.Extras` assembly was merged into the `Exceptionless` package. + +## Upgrading from Exceptionless 2.x + +- `IEventEnrichment` has been renamed to `IEventPlugin` +- `IEventPlugin.Enrich(context, event)` signature has been changed to `IEventPlugin.Run(context)`. The event has been moved to the context +- `client.Configuration.AddEnrichment<IEventEnrichment>();` has been renamed to `client.Configuration.AddPlugin<IEventPlugin>();` +- `EventPluginContext.Data` property has been renamed to `EventPluginContext.ContextData` +- `EventSubmittingEventArgs.EnrichmentContextData` property has been renamed to `EventSubmittingEventArgs.PluginContextData` + +--- + +[Next > JavaScript Client](/docs/clients/javascript/) diff --git a/docs/docs/clients/index.md b/docs/docs/clients/index.md new file mode 100644 index 0000000000..c39d05ef26 --- /dev/null +++ b/docs/docs/clients/index.md @@ -0,0 +1,8 @@ +--- +title: "Clients" +--- + +# Clients + +- [.NET](/docs/clients/dotnet/) +- [JavaScript](/docs/clients/javascript/) diff --git a/docs/docs/clients/javascript/client-configuration-values.md b/docs/docs/clients/javascript/client-configuration-values.md new file mode 100644 index 0000000000..1c7d4c5756 --- /dev/null +++ b/docs/docs/clients/javascript/client-configuration-values.md @@ -0,0 +1,91 @@ +--- +title: "Client Configuration Values" +order: 2 +--- + +# Client Configuration Values + +- [About](#about) +- [Usage Example](#usage-example) +- [Updating Client Configuration settings](#updating-client-configuration-settings) +- [Subscribing to Client Configuration Setting changes](#subscribing-to-client-configuration-setting-changes) + +## About + +[Read about client configuration and view in-depth examples](/docs/project-settings) + +## Usage Example + +The below example demonstrates **how we would turn on or off log event submissions at runtime** without redeploying the app or changing server config settings. + +First, we add a (completely arbitrary for this example) `enableLogSubmission` client configuration value key with value `true` in the Project's Settings in the Exceptionless dashboard. + +![Exceptionless Client Configuration Value](/assets/img/docs/client-configuration.png) + +Then, we register a new client side plugin that runs each time an event is created. If our key (`enableLogSubmission`) is set to false and the event type is set to log, we will discard the event. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.addPlugin('Conditionally cancel log submission', 100, (context) => { + var enableLogSubmission = context.client.config.settings['enableLogSubmission']; + + // only cancel event submission if it’s a log event and + // enableLogSubmission is set to a value and the value is not true. + if (context.event.type === 'log' && (!!enableLogSubmission && enableLogSubmission !== 'true')) { + context.cancelled = true; + } + }); +}); +``` + +*** + +## Updating Client Configuration settings + +![Exceptionless Client Configuration Settings](/assets/img/docs/client-configuration.png) + +All project settings are synced to the client in almost real time. When an event is submitted to Exceptionless we send down a response header with the current configuration version. If a newer version is available we will immediately retrieve and apply the latest configuration. + +By default the client will check after `5 seconds` on client startup (*if no events are submitted on startup*) and then every `2 minutes` after the last event submission for updated configuration settings. + +- Checking for updated settings doesn't count towards plan limits. +- Only the current configuration version is sent when checking for updated settings (no user information will ever be sent). +- If the settings haven't changed, then no settings will be retrieved. + +You can also **turn off the automatic updating of configuration settings when idle** using the code below. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.updateSettingsWhenIdleInterval = -1; +}); +``` + +You can also manually update the configuration settings using the code below. + +```js +import { Exceptionless, SettingsManager } from "@exceptionless/browser"; + +await SettingsManager.updateSettings(Exceptionless.config); +``` + +## Subscribing to Client Configuration Setting changes + +To be notified when client configuration settings change, subscribe to them using the below code. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.subscribeServerSettingsChange((configuration) => { + // configuration.settings contains the new settings + }); +}); +``` + +*** + +[Next > Sending Events](/docs/clients/javascript/sending-events) diff --git a/docs/docs/clients/javascript/client-configuration.md b/docs/docs/clients/javascript/client-configuration.md new file mode 100644 index 0000000000..0db6e31181 --- /dev/null +++ b/docs/docs/clients/javascript/client-configuration.md @@ -0,0 +1,187 @@ +--- +title: "Configuration" +order: 1 +--- + +# Configuration + +- [Installation](#installation) + - [Browser](#browser) + - [Node.js](#nodejs) +- [Configuration](#configuration) + - [Offline Storage](#offline-storage) + - [API Key](#api-key) + - [Extended Data](#extended-data) + - [Default Tags](#default-tags) + - [Default Data](#default-data) + - [General Data Protection Regulation](#general-data-protection-regulation) +- [Versioning](#versioning) +- [Self Hosted Options](#self-hosted-options) + +*** + +## Installation + +### Browser + +1. Install the package by running `npm install @exceptionless/browser` +2. Add the Exceptionless client to your app: + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup((c) => { + c.apiKey = "API_KEY_HERE"; +}); +``` + +### Node.js + +1. Install the package by running `npm install @exceptionless/node`. +2. Add the Exceptionless client to your app: + +```js +import { Exceptionless } from "@exceptionless/node"; + +await Exceptionless.startup(c => { + c.apiKey = "API_KEY_HERE"; +}); +``` + +*** + +## Configuration + +_NOTE: The only required setting that you need to configure is the client's `apiKey`._ However, many values may be important for your application. Specifically, you may want to consider persisting events to disk. + +### Offline Storage + +By default, Exceptionless keeps events in memory and stores server configuration to local storage if available. This means if the application exits before the event can be sent to the server, the event will not be sent on restart. This can be overcome by persisting events to disk as well. + +This can be done by setting the configuration value like this: + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.usePersistedQueueStorage = true; +}); +``` + +### API Key + +You can set the `apiKey` two different ways. The first is by passing it to the +startup function. This is the recommended way if you have no other client +configuration settings to configure. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup("API_KEY_HERE"); +``` + +The second way is to set it on the configuration instance passed to startup. +This is the recommended way when configuring multiple settings. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.apiKey: 'API_KEY_HERE', + c.serverUrl: 'http://localhost:5200' +}); +``` + +**NOTE**: creating new instances is good for sending custom events. **Automatic catching of errors uses default client**. Make sure you setup default client as well if you need automatic catching of unhandled errors. + +### Extended Data + +You can include information that is set globally and provided with every event you send. There are two types of data that can be provided this way: Default Tags and Default Data. + +#### Default Tags + +To add default tags to every request, you can configure your client like this: + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.defaultTags.push("Tag1", "Tag2"); +}); +``` + +#### Default Data + +You can set up default data to be sent with every request very similarly to how you send default tags. You would do it like this: + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.defaultData["data"] = "My custom data"; +}); +``` + +### General Data Protection Regulation + +By default the Exceptionless Client will report all available metadata which could include potential PII data. There are various ways to limit the scope of PII data collection. For example, one could use [Data Exclusions](/docs/security#data-exclusions) to remove sensitive values but it only applies to specific collection points such as `Cookie Keys`, `Form Data Keys`, `Query String Keys` and `Extra Exception properties`. Additional data may need to be removed for the GDPR like the collection of user names and IP Addresses. Shown below is several examples of how you can configure the client to remove this additional metadata. + +You have the option of finely tuning what is collected via individual setting options or you can disable the collection of all PII data by setting the `includePrivateInformation` to `false`. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.includePrivateInformation = false; +}); +``` + +If you wish to have a finer grained approach which allows you to use Data Exclusions while removing specific meta data collection you can do so via code. Please note if the below doesn't meet your needs you can always write a plugin. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + // Include the username if available. + c.includeUserName = false; + // Include the MachineName in MachineInfo. + c.includeMachineName = false; + // Include Ip Addresses in MachineInfo and RequestInfo. + c.includeIpAddress = false; + // Include Cookies, please note that DataExclusions are applied to all Cookie keys when enabled. + c.includeCookies = false; + // Include Form/POST Data, please note that DataExclusions are only applied to Form data keys when enabled. + c.includePostData = false; + // Include Query String information, please note that DataExclusions are applied to all Query String keys when enabled. + c.includeQueryString = false; +}); +``` + +## Versioning + +By specifying an application version you can [enable additional functionality](/docs/versioning). It's a good practice to specify an application version if possible using the code below. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.version = "1.2.3"; +}); +``` + +## Self Hosted Options + +The Exceptionless client can also be configured to send data to your [self hosted instance](/docs/self-hosting/). This is configured by setting the `serverUrl` setting to point to your Exceptionless instance. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.apiKey: 'API_KEY_HERE', + c.serverUrl: 'http://localhost:5200' +}); +``` + +*** + +[Next > Client Configuration Values](/docs/clients/javascript/client-configuration-values) diff --git a/docs/docs/clients/javascript/express-example.md b/docs/docs/clients/javascript/express-example.md new file mode 100644 index 0000000000..ed73bbe96c --- /dev/null +++ b/docs/docs/clients/javascript/express-example.md @@ -0,0 +1,55 @@ +--- +title: "Express Example" +--- + +# Express Example + +Add Exceptionless to your Express.js project and start collecting unhandled errors and 404s quickly. + +To start, just add the following middleware to the bottom of your middleware definitions. + +```js +import { Exceptionless } from "@exceptionless/node"; + +// This middleware processes any unhandled errors that may occur in your middleware. +app.use(async (err, req, res, next) => { + if (res.headersSent) { + return next(err) + } + + await Exceptionless.createUnhandledException(err, "express") + .addRequestInfo(req) + .submit(); + + res.status(500).send("Something broke!"); +}); + +// This middleware processes 404’s. +app.use(async (req, res) => { + await Exceptionless.createNotFound(req.originalUrl).addRequestInfo(req).submit(); + res.status(404).send("Sorry cant find that!"); +}); +``` + +## Sample Express.js App + +We have built a quick [Express.js sample app](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example/express/app.js) you can play around with. + +**Run the sample app by following the steps below:** + +1. Install [Node.js](https://nodejs.org/) +2. [Clone or download our repository from GitHub](https://github.com/exceptionless/Exceptionless.JavaScript). +3. Run `npm install`. This steps is required because we reference the exceptionless package from the root dist folder. +4. Navigate to the `example\express` folder via the command line (e.g., cd example\express) +5. Open app.js in your favorite text editor and set the [`apiKey`](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example/express/app.js#L7). You may need to remove the `serverUrl` setting if you are not self hosting. +6. Run node app.js. +7. Navigate to in your browser to view the express app. +8. To create an error, navigate to + +### Troubleshooting + +We recommend enabling debug logging by calling `Exceptionless.config.useDebugLogger();`. This will output messages to the console regarding what the client is doing. Please contact us by creating an issue on GitHub if you need assistance or have any feedback for the project. + +--- + +[Next > Angular Example](/docs/clients/javascript/react-example) diff --git a/docs/docs/clients/javascript/guides/angular.md b/docs/docs/clients/javascript/guides/angular.md new file mode 100644 index 0000000000..31d73b080d --- /dev/null +++ b/docs/docs/clients/javascript/guides/angular.md @@ -0,0 +1,72 @@ +--- +title: "Angular" +order: 3 +--- + +# Angular + +Exceptionless can be configured in just about any JavaScript environment, but this section is dedicated to set up and use within the Angular framework. + +### Install + +To install exceptionless, you can use npm or yarn: + +npm - `npm install @exceptionless/browser` + +yarn - `yarn add @exceptionless/browser` + +### Initializing the Client + +Exceptionless provides a default singleton client instance. While we recommend +using the default client instance for most use cases, you can also create +custom instances (though that's beyond the scope of this guide). + +```javascript +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; +}); +``` + +You can see an additional parameter passed into the configuration object as an +example. To see all the available options, take a look at our +[configuration values here](/docs/clients/javascript/client-configuration-values). + +### Using Exceptionless in an Angular Component + +To make use of Exceptionless within a component, you'll import the package like +described above. Your set up will vary depending on your needs, but this is a +quick example of using Exceptionless within the `app` component of a default +Angular project. + +```js +import { Component } from '@angular/core'; +import { Exceptionless } from "@exceptionless/browser"; + +Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; +}); + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'my-app'; + public handleClick(event) { + try { + throw new Error("Whoops!"); + } catch (error) { + Exceptionless.submitException(error); + } + } +} +``` + +In the `app` component's html, clicking a button that calls `handleClick` will immediately throw an error and report it to Exceptionless. + +--- + +[Next > Express](/docs/clients/javascript/guides/express) diff --git a/docs/docs/clients/javascript/guides/express.md b/docs/docs/clients/javascript/guides/express.md new file mode 100644 index 0000000000..2333338e5f --- /dev/null +++ b/docs/docs/clients/javascript/guides/express.md @@ -0,0 +1,79 @@ +--- +title: "Express" +order: 4 +--- + +# Express + +Perhaps the most popular NodeJS server-side framework, Express is used in thousands of projects. Exceptionless provides dedicated NodeJS support, and configuring your Exceptionless client in Express is easy. + +### Install + +To install exceptionless, you can use npm or yarn: + +npm - `npm install @exceptionless/node` + +yarn - `yarn add @exceptionless/node` + +### Initializing the Client + +Exceptionless provides a default singleton client instance. While we recommend +using the default client instance for most use cases, you can also create +custom instances (though that's beyond the scope of this guide). + +```javascript +import { Exceptionless } from "@exceptionless/node"; + +await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; +}); +``` + +You can see an additional parameter passed into the configuration object as an +example. To see all the available options, take a look at our +[configuration values here](/docs/clients/javascript/client-configuration-values). + +### Using Exceptionless in a Express App + +In this example, we're just making use of the Exceptionless client in a file +that handles one of our API routes. We will also show off how to handle errors +and 404s in Express. + +```js +import { Exceptionless, KnownEventDataKeys } from "@exceptionless/node"; +import express from "express"; + +await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; +}); + +const app = express(); +app.get("/", async (req, res) => { + await Exceptionless.submitLog("Hello World!"); + res.send("Hello World!"); +}); + +app.use(async (err, req, res, next) => { + if (res.headersSent) { + return next(err); + } + + await Exceptionless.createUnhandledException(err, "express").setContextProperty(KnownEventDataKeys.RequestInfo, req).submit(); + res.status(500).send("Something broke!"); +}); + +app.use(async (req, res) => { + await Exceptionless.createNotFound(req.originalUrl).setContextProperty(KnownEventDataKeys.RequestInfo, req).submit(); + res.status(404).send("Sorry cant find that!"); +}); + +const server = app.listen(3000, async () => { + var host = server.address().address; + var port = server.address().port; + + var message = "Example app listening at http://" + host + port; + await Exceptionless.submitLog("app", message, "Info"); +}); +``` + +With that set up, you can use the Exceptionless client anywhere in your app. diff --git a/docs/docs/clients/javascript/guides/index.md b/docs/docs/clients/javascript/guides/index.md new file mode 100644 index 0000000000..d89b924820 --- /dev/null +++ b/docs/docs/clients/javascript/guides/index.md @@ -0,0 +1,19 @@ +--- +title: "JavaScript Framework Guides" +order: 3 +--- + +# JavaScript Framework Guides + +Exceptionless works with all popular JavaScript frameworks on both the front end and the backend including React, Angular, Typescript, Express, and Svelte. Below, you will find our guides for those frameworks. + +* [React](/docs/clients/javascript/guides/react) +* [Angular](/docs/clients/javascript/guides/angular) +* [Vue](/docs/clients/javascript/guides/vue) +* [Express](/docs/clients/javascript/guides/express) + +Exceptionless should work anywhere JavaScript runs, but if you have specific frameworks you'd like to see covered, let us know or submit a pull request. Our documentation is [open-source and editable](https://github.com/exceptionless/Website/tree/master/content/docs). + +--- + +[Next > React Guide](/docs/clients/javascript/guides/react) diff --git a/docs/docs/clients/javascript/guides/more-guides.md b/docs/docs/clients/javascript/guides/more-guides.md new file mode 100644 index 0000000000..435f253547 --- /dev/null +++ b/docs/docs/clients/javascript/guides/more-guides.md @@ -0,0 +1,12 @@ +--- +title: "More Guides" +order: 5 +--- + +# More Guides + +In addition to the quick start guides we've provided here, there are full app examples located in our Github repository. Take a look and feel free to let us know if you'd like to see other tutorials and guides included. + +[JavaScript Example Repository](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example) + +[Next > Sending Events](/docs/clients/javascript/sending-events) diff --git a/docs/docs/clients/javascript/guides/react.md b/docs/docs/clients/javascript/guides/react.md new file mode 100644 index 0000000000..43f8073477 --- /dev/null +++ b/docs/docs/clients/javascript/guides/react.md @@ -0,0 +1,66 @@ +--- +title: "React" +order: 1 +--- + +# React + +Exceptionless can be configured in just about any JavaScript environment, but this section is dedicated to set up and use within the React framework. + +### Install + +To install exceptionless, you can use npm or yarn: + +npm - `npm install @exceptionless/react` + +yarn - `yarn add @exceptionless/react` + +### Initializing the Client + +Exceptionless provides a default singleton client instance. While we recommend +using the default client instance for most use cases, you can also create +custom instances (though that's beyond the scope of this guide). + +```javascript +import { Exceptionless } from "@exceptionless/react"; + +await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; +}); +``` + +You can see an additional parameter passed into the configuration object as an +example. To see all the available options, take a look at our +[configuration values here](/docs/clients/javascript/client-configuration-values). + +### Using Exceptionless in a React App + +```javascript +import { Exceptionless, ExceptionlessErrorBoundary } from "@exceptionless/react"; + +class App extends Component {1 + async componentDidMount() { + await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; + }); + } + + render() { + return ( + + +// YOUR APP COMPONENTS HERE + + + ); + } +} + +export default App; +``` + +With that set up, you can use the Exceptionless client anywhere in your app. + +--- + +[Next > Vue](/docs/clients/javascript/guides/vue) diff --git a/docs/docs/clients/javascript/guides/vue.md b/docs/docs/clients/javascript/guides/vue.md new file mode 100644 index 0000000000..1aa4677a2b --- /dev/null +++ b/docs/docs/clients/javascript/guides/vue.md @@ -0,0 +1,57 @@ +--- +title: "Vue" +order: 2 +--- + +# Vue + +Vue is one of the more popular JavaScript frameworks out there, and Exceptionless has your back if you're working with it. Getting started is simple. + +### Install + +To install exceptionless, you can use npm or yarn: + +npm - `npm install @exceptionless/vue` + +yarn - `yarn add @exceptionless/vue` + +### Initializing the Client + +Exceptionless provides a default singleton client instance. While we recommend +using the default client instance for most use cases, you can also create +custom instances (though that's beyond the scope of this guide). + +```javascript +import { Exceptionless } from "@exceptionless/vue"; + +await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; +}); +``` + +You can see an additional parameter passed into the configuration object as an +example. To see all the available options, take a look at our +[configuration values here](/docs/clients/javascript/client-configuration-values). + +### Using Exceptionless in a Vue App + +```javascript +import { createApp } from "vue"; +import App from "./App.vue"; +import { Exceptionless, ExceptionlessErrorHandler } from "@exceptionless/vue"; + +Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; +}); + +const app = createApp(App); +// Set the global vue error handler. +app.config.errorHandler = ExceptionlessErrorHandler; +app.mount("#app"); +``` + +With that set up, you can use the Exceptionless client anywhere in your app. + +--- + +[Next > Angular](/docs/clients/javascript/guides/angular) diff --git a/docs/docs/clients/javascript/index.md b/docs/docs/clients/javascript/index.md new file mode 100644 index 0000000000..73b4507efb --- /dev/null +++ b/docs/docs/clients/javascript/index.md @@ -0,0 +1,60 @@ +--- +title: "JavaScript Client" +--- + +# JavaScript Client + +The Exceptionless JavaScript client SDK makes it easy to report errors, log details, track feature usage and more. Be sure you have an Exceptionless account ([you can sign up here](/)) or that you are self-hosting a running instance of Exceptionless. + +--- + +Full guides can be found below: + +* [React](/docs/clients/javascript/guides/react) +* [Vue](/docs/clients/javascript/guides/vue) +* [Angular](/docs/clients/javascript/guides/angular) +* [Node](/docs/clients/javascript/node-example) +* [Express](/docs/clients/javascript/guides/express) + +--- + +This quickstart focuses on the vanilla JavaScript implementation of Exceptionless. + +## npm + +To install with npm, run: `npm install @exceptionless/browser` + +Next, you just need to call startup during your apps startup to automatically capture unhandled errors. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup("API KEY HERE"); + +try { + throw new Error("test"); +} catch (error) { + await Exceptionless.submitException(error); +} +``` + +## CDN + +To install via a script tag referencing Exceptionless over a CDN, add the following before your closing `` tag and call startup like so: + +```html +`` +``` + +--- + +[Next > Configuration](/docs/clients/javascript/client-configuration) diff --git a/docs/docs/clients/javascript/javascript-example.md b/docs/docs/clients/javascript/javascript-example.md new file mode 100644 index 0000000000..5e86954a13 --- /dev/null +++ b/docs/docs/clients/javascript/javascript-example.md @@ -0,0 +1,12 @@ +--- +title: "JavaScript Example" +--- + +# JavaScript Example + +We have put together an example for a few JavaScript-based frameworks and the browser to help you get started. You can find those [here in the GitHub Repo](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example). You can clone the repository and run the code as is or you can use the repository example as a starting point. + +For framework specific details, continue on to the next page or select a specific framework on the left. +--- + +[Next > React Example](/docs/clients/javascript/react-example) diff --git a/docs/docs/clients/javascript/node-example.md b/docs/docs/clients/javascript/node-example.md new file mode 100644 index 0000000000..9396b49a1f --- /dev/null +++ b/docs/docs/clients/javascript/node-example.md @@ -0,0 +1,25 @@ +--- +title: "Node.js Example" +--- + +# Node.js Example + +Here is a very simple example using a Node.js script. + +```js +import { Exceptionless } from "@exceptionless/node"; + +await Exceptionless.startup("YOUR API KEY"); + +const forceError = async () => { + try { + throw new Error("Whoops, I did it again.") + } catch(e) { + await Exceptionless.submitException(e); + } +} +``` + +--- + +[Next > Express Example](/docs/clients/javascript/express-example) {.text-right } diff --git a/docs/docs/clients/javascript/react-example.md b/docs/docs/clients/javascript/react-example.md new file mode 100644 index 0000000000..f86dc4bf6f --- /dev/null +++ b/docs/docs/clients/javascript/react-example.md @@ -0,0 +1,58 @@ +--- +title: "React Example" +--- + +# React Example + +The React Client from Exceptionless includes all of the functionality from the browser client, but with some extra React-specific helpers. + +The one thing you'll specifically notice in the React client is the addition of an `ExceptionlessErrorBoundary` class component. This is a wrapper component that can be used to ensure all errors in the presentational layer of your app are reported. + +It works exactly as Error Boundaries in React work, but it's pre-wired to report to Exceptionless. Here's a very simple example: + +```js +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 () => { + await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; + c.useDebugLogger(); + + c.defaultTags.push("Example", "React"); + }); +}; + +startExceptionless(); + +ReactDOM.render( + + + + + + + , + document.getElementById('root') +); + +reportWebVitals(); +``` + +As you can see, we wrap the root `App` component first in the `ExceptionlessErrorBoundary` and then if you want to present your own fallback UI, you can create a custom `ErrorBoundary` component that will make sure that UI is served. + +We have a detailed [blog post about this here](https://exceptionless.com/news/2021/2021-08-16-how-to-use-error-boundaries-in-react/). + +[The full example / sample can be found here](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example/react). + +--- + +[Next > Node.js Example](/docs/clients/javascript/node-example) {.text-right } diff --git a/docs/docs/clients/javascript/sending-events.md b/docs/docs/clients/javascript/sending-events.md new file mode 100644 index 0000000000..a185d88308 --- /dev/null +++ b/docs/docs/clients/javascript/sending-events.md @@ -0,0 +1,81 @@ +--- +title: "Sending Events" +order: 4 +--- + +# Sending Events + +Once configured, Exceptionless automatically sends unhandled exceptions that happen in your application. To send different event types, as well as customize the data that is sent, continue reading. + +You can send us log messages, feature usages, or other kinds of events easily with our fluent api. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.submitLog('Logging made easy'); + +// You can also specify the log source and log level. +// We recommend specifying one of the following log levels: Trace, Debug, Info, Warn, Error +await Exceptionless.submitLog('app.logger', 'This is so easy', 'Info'); +await Exceptionless.createLog('app.logger', 'This is so easy', 'Info').addTags('Exceptionless').submit(); + +// Submit feature usages +await Exceptionless.submitFeatureUsage('MyFeature'); +await Exceptionless.createFeatureUsage('MyFeature').addTags('Exceptionless').submit(); + +// Submit a 404 +await Exceptionless.submitNotFound('/somepage'); +await Exceptionless.createNotFound('/somepage').addTags('Exceptionless').submit(); + +// Submit a custom event type +await Exceptionless.submitEvent({ message = 'Low Fuel', type = 'racecar', source = 'Fuel System' }); +``` + +### Manually Sending Errors + +In addition to automatically sending all unhandled exceptions, you may want to manually send exceptions to the service. You can do so by using code like this: + +```javascript +import { Exceptionless } from "@exceptionless/browser"; + +try { + throw new Error('test'); +} catch (error) { + await Exceptionless.submitException(error); +} +``` + +### Sending Additional Information + +You can easily include additional information in your error reports using our fluent [event builder API](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/packages/core/src/EventBuilder.ts). + +```javascript +import { Exceptionless } from "@exceptionless/node"; + +try { + throw new Error('Unable to create order from quote.'); +} catch (error) { + await Exceptionless.createException(error) + // Set the reference id of the event so we can search for it later (reference:id). + // This will automatically be populated by default with a unique id; + .setReferenceId('random guid') + // Add the order object (the ability to exclude specific fields will be coming in a future version). + .setProperty("Order", order) + // Set the quote number. + .setProperty("Quote", 123) + // Add an order tag. + .addTags("Order") + // Mark critical. + .markAsCritical() + // Set the coordinates of the end user. + .setGeo(43.595089, -88.444602) + // Set the user id that is in our system and provide a friendly name. + .setUserIdentity(user.Id, user.FullName) + // Submit the event. + .submit(); +} +``` + +--- + +[Next > Troubleshooting](/docs/clients/javascript/troubleshooting) diff --git a/docs/docs/clients/javascript/troubleshooting.md b/docs/docs/clients/javascript/troubleshooting.md new file mode 100644 index 0000000000..d81d6c6a6f --- /dev/null +++ b/docs/docs/clients/javascript/troubleshooting.md @@ -0,0 +1,49 @@ +--- +title: "Troubleshooting" +order: 6 +--- + +# Troubleshooting + +If your events aren't being sent to the server there are a few things that you can try to diagnose the issue. + +## Update Your Client + +Please make sure that you are using the latest version of the client. + +## Ensure the Queue has Time to Process + +If you are using Exceptionless in a scenario where an event is submitted and the process is immediately terminated, then you will need to make sure that the queue is processed before the application ends. Please note that the client will try to do this automatically. + +Events are queued and sent in the background, if the application isn't running then the events cannot be sent. You can manually force the queue to be processed by calling the following line of code before before the process ends: + +```js +import { Exceptionless } from "@exceptionless/browser"; +await Exceptionless.processQueue(); +``` + +This will cause the event queue to be processed asynchronously and the events to be reported. If this doesn’t solve the issue then please enable client logging and send us the log file. You can also attempt to pass true to `process(true)` to try and process the queue synchronously. _Please note that sending synchronously depends on specific api's that may not be available, so it may not send synchronously._ + +## Enable Client Logging + +The Exceptionless client can be configured to write diagnostic messages to the console to help diagnose any issues with the client. + +```js +import { Exceptionless } from "@exceptionless/browser"; + +await Exceptionless.startup(c => { + c.useDebugLogger(); +}); +``` + +## Check Your API Key + +By design, an invalid API key provided to the Exceptionless client is not going to crash your application. Be sure to check the log outputs as this information will tell you if you have provided an invalid key. + +## Debugging Source Code + +You can also debug the Exceptionless source code by using the unmagnified version and set breakpoints in your browsers developer tools. + +--- + +[Next > JavaScript Example](/docs/clients/javascript/javascript-example) diff --git a/docs/docs/clients/javascript/vue-example.md b/docs/docs/clients/javascript/vue-example.md new file mode 100644 index 0000000000..99ed3598a5 --- /dev/null +++ b/docs/docs/clients/javascript/vue-example.md @@ -0,0 +1,11 @@ +--- +title: "Vue Example" +--- + +# Vue Example + +[Example / Sample can be found here](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example/vue). + +--- + +[Next > Self-Hosting](/docs/self-hosting/) diff --git a/docs/docs/comparison.md b/docs/docs/comparison.md new file mode 100644 index 0000000000..e22d97cdec --- /dev/null +++ b/docs/docs/comparison.md @@ -0,0 +1,44 @@ +--- +title: "Comparison" +--- + +# Comparison + +| Feature | Exceptionless | Application Insights | Elmah | Raygun | +| :----------------------------- | :-----------: | :------------------: | :---: | :----: | +| Open Source | X | | X | | +| Free Self Hosting | X | | X | | +| Detailed error reports | X | X | | X | +| Email Notifications | X | X | X | X | +| Export Events | | X | X | | +| Filtering | X | X | | X | +| Send Custom Data [^1] | X | | | X | +| Real-time Client Configuration | X | | | | +| Real-time Dashboards | X | | | | +| Complete Rest API | X | | | | +| Search | X | X | | X | +| Search Custom Fields | X | | | | +| Intelligent Stacking | X | X | | X | +| Custom Stacking | X | | | X | +| Mark Fixed | X | | | X | +| Mark Hidden | X | | | X | +| Comment on Events | | | | X | +| Support Multiple Platforms | X | X | | X | +| User Sessions [^2] | X | | | X | +| User % [^3] | X | | | ? | +| Broken Links | X | X | X | X | +| Releases | | | | X | +| Feature Usages | X | | | | +| Log Messages | X | | | | +| Custom Event Types | X | X | | | +| Webhooks | X | X | | X | + +- **X** = has feature, **empty box** does not have feature, **?** = unknown + +[^1]: Send custom data on any event and promote it to a first class tab. +[^2]: Automatically tracks users sessions. Please note that this is a paid add on for Raygun Pulse (**$149/mo**). +[^3]: Ability to see how many users are affected by an error or are using a specific feature. + +--- + +[Next > Security](/docs/security) diff --git a/docs/docs/deduplication.md b/docs/docs/deduplication.md new file mode 100644 index 0000000000..9e5f7d6853 --- /dev/null +++ b/docs/docs/deduplication.md @@ -0,0 +1,15 @@ +--- +title: "Event De-Duplication" +--- + +# Event De-Duplication + +Have you ever run into an error where the event that triggers the error happens rapidly in a short amount of time? Infinite loops combined with errors? Ugh. If that happens, we don't think you should have to worry about your event quotas and plan limits. + +That's why we built automatic de-duplication. + +If we get two events that are exactly the same within a minute, we send the first, cancel the second and hold onto it for 60 seconds. If that same exact event comes in again, we cancel it and increment the count on the one we were holding. Once 60 seconds is released we submit that event and now you get a sampling of events during that period with the exact account that occurred. We only do this if the event is an exactly the same minus date occurred. + +--- + +[Next > Integrations](/docs/integrations) diff --git a/docs/docs/demo-formatting.md b/docs/docs/demo-formatting.md new file mode 100644 index 0000000000..a7e08d96fa --- /dev/null +++ b/docs/docs/demo-formatting.md @@ -0,0 +1,73 @@ +--- +title: "Markdown Formatting Demo" +hidden: true +url: false +--- + +# Markdown Formatting Demo + +Shows all the different markdown formatting options available for writing docs and blog posts + +General markdown-it formatting: + +- [Footnote](#footnote) +- [Anchor Links](#anchor-links) +- [Attrs {.text-center}](#attrs-text-center) +- [Bracketed Spans](#bracketed-spans) +- [Alerts](#alerts) +- [Abbreviations](#abbreviations) +- [Tables](#tables) + +## Footnote + + + +Here is a footnote reference,[^1] and another.[^longnote] + +[^1]: Here is the footnote. + +[^longnote]: Here's one with multiple blocks. + + Subsequent paragraphs are indented to show that they belong to the previous footnote. + +## Anchor Links + + + +[Link to footnote section](#footnote) + +## Attrs {.text-center} + + + +paragraph {.text-center} + +## Bracketed Spans + + + +paragraph with [a warning span]{.text-warning} + +## Alerts + + + +::: danger Danger danger danger! [Link](#). ::: + +::: info Information information information! [Link](#). ::: + +::: success Success success success! [Link](#). ::: + +## Abbreviations + + + +*[HTML]: Hyper Text Markup Language *[W3C]: World Wide Web Consortium The HTML specification is maintained by the W3C. + +## Tables + +| Feature | Exceptionless | Application Insights | Elmah | Raygun | +| :--------------------- | :-----------: | :------------------: | :---: | :----: | +| Open Source | X | | X | | +| Free Self Hosting | X | | X | | +| Detailed error reports | X | X | | X | diff --git a/docs/docs/filtering-and-searching.md b/docs/docs/filtering-and-searching.md new file mode 100644 index 0000000000..d0ba2f1a50 --- /dev/null +++ b/docs/docs/filtering-and-searching.md @@ -0,0 +1,135 @@ +--- +title: "Filtering & Searching" +--- + +# Filtering & Searching + +- [Filter by Organization \& Project](#filter-by-organization--project) +- [Filter by Time Frame](#filter-by-time-frame) +- [Filter / Search by Specific Criteria](#filter--search-by-specific-criteria) +- [Searchable Fields \& Requirements](#searchable-fields--requirements) +- [Multiple Queries](#multiple-queries) +- [Wild Cards](#wild-cards) +- [Exclusions](#exclusions) +- [Set and Unset Fields](#set-and-unset-fields) +- [Ranges](#ranges) +- [Custom Extended Data](#custom-extended-data) +- [Demo Video](#demo-video) + +## Filter by Organization & Project + +The dashboard loads up with all projects selected by default. + +Click on the “All Projects” drop down in the top left of the dashboard and select your organization or project to filter the data to your liking. + +![Exceptionless Filter Project Organization](img/filter-by-project-organization.png) + +## Filter by Time Frame + +Click on the calendar icon in the header to select from multiple preset time frame filters, or click "Custom" and select your own. + +![Exceptionless Filter Time Frame](img/filter-by-timeframe.png) + +## Filter / Search by Specific Criteria + +Click the magnifying glass to search by specific criteria. + +You can filter by tag, ID, organization, project, stack, type, value, IP, architecture, user, and much more. + +Some searches, such as ID, require a prefix (“id:”) on the search, but others, such as error.message, can be entered as strings (“A NullReferenceException occurred”). + +View a complete list of searchable terms, examples, and FAQs below. + +![Exceptionless Filter Search Criteria Field](img/filter-by-search-filter-criteria.png) + +## Searchable Fields & Requirements + +| TERM | EXAMPLE | FIELD REQUIRED? (field:term) | DESCRIPTION | +| ------------------ | -------------------------------------------------------------------------------------------------------------------- | ---------------------------- | --------------------------------------------- | +| `*` | `*` | false | Shows all events (including hidden and fixed) | +| id | `id:54d8315ce6bb2d0500bcc7b4` | true | Documents id | +| organization | `organization:54d8315ce6bb2d0500bcc7b4` | true | Organization id | +| project | `project:54d8315ce6bb2d0500bcc7b4` | true | Project id | +| stack | `stack:54d8315ce6bb2d0500bcc7b4` | true | Stack id | +| reference | `reference:12345678` | true | Reference id | +| session | `session:12345678` | true | Session id | +| type | `type:error` | true | Event type | +| source | `source:"my log source"` or `"my log source"` | false | Event source | +| level | `level:Error` | true | Log level | +| date | `date:"2020-10-16T12:00:00.000"` | true | Occurrence date | +| first | `first:true` | true | True if first occurrence of event | +| message | `message:"My error message"` or `"My error message"` | false | Event message | +| tag | `tag:"Blake Niemyjski"` or `tag:Blake` or `blake` | false | Tags | +| value | `value:1` | true | Value of event (used in charts) | +| geo | `geo:75044~75mi` or `geo:[geohash1..geohash2]` | true | Geo Location | +| status | `status:open` or `status:discarded` or `status:fixed` or `status:regressed` or `status:snoozed` or `status:ignored` | true | Stack status | +| version | `version:1` or `version:1.0` or `version:1.0.0` | true | Application version | +| machine | `machine:Server` or `Server` | false | Machine name | +| ip | `ip:127.0.0.1` or `127.0.0.1` | false | IP address | +| architecture | `architecture:x64` | true | Machine architecture | +| useragent | `useragent:IE` or `useragent:"Mozilla/5.0"` | true | User Agent | +| path | `path:"/cart"` or `"/cart"` | false | URL path | +| browser | `browser:Chrome` | true | Browser | +| browser.version | `browser.version:50.0` | true | Browser version | +| browser.major | `browser.major:50` | true | Browser major version | +| device | `device:iPhone` | true | Device | +| os | `os:iOS` | true | Operating System | +| os.version | `os.version:8.0` | true | Operating System version | +| os.major | `os.major:8` | true | Operating System major version | +| bot | `bot:true` | true | bot | +| error.code | `error.code:500` or `500` | false | Error code | +| error.message | `error.message:"A NullReferenceException occurred"` or `"A NullReferenceException occurred"` | false | Error message | +| error.type | `error.type:"System.NullReferenceException"` or `"System.NullReferenceException"` | false | Error type | +| error.targettype | `error.targettype:"System.NullReferenceException"` or `"System.NullReferenceException"` | false | Error target type | +| error.targetmethod | `error.targetmethod:AssociateWithCurrentThread` or `AssociateWithCurrentThread` | false | Error target method | +| user | `user:"random user identifier"` or `"random user identifier"` | false | Uniquely identifies user | +| user.name | `user:"Exceptionless User"` or `"Exceptionless User"` | false | Friendly name of user | +| user.description | `user.description:"I clicked the button"` or `"I clicked the button"` | false | User Description | +| user.email | `user.email:"support@exceptionless.io"` or `"support@exceptionless.io"` | false | User Email Address | + +## Multiple Queries + +All queries separated by a space will be an `AND` operation. If you wish to `OR` queries you’ll need to use an `OR` statement. We recommend wrapping conditional statements with parentheses. + +**Example:** Lets assume we want to return all events that have a `blue` or `red` tag. To search for these events our query would be `(tag:blue OR tag:red)`. + +## Wild Cards + +Suffix your query with `*` for wild card searches. + +## Exclusions + +Prefix the field name with `-` for exclusions. + +**Example:** Lets assume that we want to return all events that are not marked as a bot. To search for these events our query would be `-bot:true`. +*NOTE: In some cases searching with `-bot:true` is more accurate than searching with `bot:false`. This happens because the first query returns all records where `bot` field is `not set` or `not equal to true`. The second query returns results only where the `bot` field is set to `false`. + +## Set and Unset Fields + +Prefix the field name with `_missing_` or `_exists_`. + +**Example:** Lets assume that we want to return all events that do not contain any tags. To search for these events our query would be `_missing_:tag`. + +## Ranges + +Specify a `date` or `numeric` range as part of the term. + +**Date Range Example:** Lets assume that we want to return all events that occurred in 2020. To search for these events our query would be `date:[2020-01-01 TO 2020-12-31]`. + +**Numeric Range Example:** Lets assume that we want to return all events that contain contain a `value` between 1 and 10. To search for these events our query would be `value:(>0 AND <=10)`. + +## Custom Extended Data + +All simple data types (`string`, `boolean`, `date`, `number`) that are stored in extended data will be indexed. _NOTE_: Field names will be lowercased and escaped. Any field name that is not a valid identifier (containing only letter and digits) or is longer than 25 characters will be ignored. + +**Example:** Lets assume that our events extended data contains a property called `Age` with a value of `18`. To search for this value our query would be `data.age:18`. + +*** + +## Demo Video + + + +--- + +[Next > Bulk Actions](/docs/bulk-actions) diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md new file mode 100644 index 0000000000..3cc9232ab3 --- /dev/null +++ b/docs/docs/getting-started.md @@ -0,0 +1,41 @@ +--- +title: "Getting Started" +--- + +# Getting Started + +Exceptionless provides you the tools to track errors, logs, and events while guiding you toward actionable solutions. To get started, you'll want to decide if you are self-hosting Exceptionless or using our hosted version. If you choose to use our hosted version, you can get started for free. + +## Hosted Option + +1. [Create an account](https://be.exceptionless.io/signup) +2. When you sign-up, you will be prompted to create your first project. +3. [Configure your application](https://be.exceptionless.io/project/list) by clicking the Download & Configure Client action button on the project list page. +4. Select your project type and follow the instructions. +5. Your application will now automatically send all unhandled errors to the Exceptionless service. +6. You can also send handled errors, feature usage or log messages along with additional information ([see documentation for your specific client](/docs/clients/)). + +## Self-Hosted Option + +We have put together comprehensive documentation to help you get started with a self-hosted Exceptionless instance. You can [find that documentation here](/docs/self-hosting/). + +## Sending Your First Event + +Once you've singed up for an account and created a project, you can start receiving events. Let's take a look at sending a simple event to Exceptionless. + +POST `api/v2/events` + +```shell +curl --location --request POST "https://api.exceptionless.com/api/v2/events" \ +--header 'Authorization: Bearer YOUR_PROJECT_TOKEN' \ +--header 'Content-Type: application/json' \ +--data-raw '{ "type": "error", "date":"2030-01-01T12:00:00.0000000-05:00", "@simple_error": { "message": "Simple Exception", "type": "System.Exception", "stack_trace": " at Client.Tests.ExceptionlessClientTests.CanSubmitSimpleException() in ExceptionlessClientTests.cs:line 77" } }' +``` + +--- + +You've got your account created, now what? Let's get a better understanding of how you manage events in Exceptionless and then we can dive into some best practice and ways to enhance your use. + +--- + +[Next > Managing Stacks](/docs/managing-stacks) diff --git a/docs/docs/img/DataExclusions.png b/docs/docs/img/DataExclusions.png new file mode 100644 index 0000000000..2088dab39e Binary files /dev/null and b/docs/docs/img/DataExclusions.png differ diff --git a/docs/docs/img/Manual_Key.png b/docs/docs/img/Manual_Key.png new file mode 100644 index 0000000000..a0c3f5fc0c Binary files /dev/null and b/docs/docs/img/Manual_Key.png differ diff --git a/docs/docs/img/Most_Frequent.png b/docs/docs/img/Most_Frequent.png new file mode 100644 index 0000000000..738d45739d Binary files /dev/null and b/docs/docs/img/Most_Frequent.png differ diff --git a/docs/docs/img/Options.png b/docs/docs/img/Options.png new file mode 100644 index 0000000000..53194f564e Binary files /dev/null and b/docs/docs/img/Options.png differ diff --git a/docs/docs/img/Spam_Detection.png b/docs/docs/img/Spam_Detection.png new file mode 100644 index 0000000000..ca6e8d0a7f Binary files /dev/null and b/docs/docs/img/Spam_Detection.png differ diff --git a/docs/docs/img/Stack_Details.png b/docs/docs/img/Stack_Details.png new file mode 100644 index 0000000000..c278da8c06 Binary files /dev/null and b/docs/docs/img/Stack_Details.png differ diff --git a/docs/docs/img/Status_Options.png b/docs/docs/img/Status_Options.png new file mode 100644 index 0000000000..15dc3eed04 Binary files /dev/null and b/docs/docs/img/Status_Options.png differ diff --git a/docs/docs/img/apiKeyGeneration.png b/docs/docs/img/apiKeyGeneration.png new file mode 100644 index 0000000000..d78561ffbb Binary files /dev/null and b/docs/docs/img/apiKeyGeneration.png differ diff --git a/docs/docs/img/apikeys.png b/docs/docs/img/apikeys.png new file mode 100644 index 0000000000..003b106ca0 Binary files /dev/null and b/docs/docs/img/apikeys.png differ diff --git a/docs/docs/img/bulk-actions-video-screenshot.png b/docs/docs/img/bulk-actions-video-screenshot.png new file mode 100644 index 0000000000..a7a0a9a2ba Binary files /dev/null and b/docs/docs/img/bulk-actions-video-screenshot.png differ diff --git a/docs/docs/img/dashboard-nav.jpg b/docs/docs/img/dashboard-nav.jpg new file mode 100644 index 0000000000..ed651db3ca Binary files /dev/null and b/docs/docs/img/dashboard-nav.jpg differ diff --git a/docs/docs/img/default_log_levels.png b/docs/docs/img/default_log_levels.png new file mode 100644 index 0000000000..308506fb5e Binary files /dev/null and b/docs/docs/img/default_log_levels.png differ diff --git a/docs/docs/img/email-notification-settings.png b/docs/docs/img/email-notification-settings.png new file mode 100644 index 0000000000..3f8565737a Binary files /dev/null and b/docs/docs/img/email-notification-settings.png differ diff --git a/docs/docs/img/exceptionless-bulk-actions.gif b/docs/docs/img/exceptionless-bulk-actions.gif new file mode 100644 index 0000000000..1be04ada8b Binary files /dev/null and b/docs/docs/img/exceptionless-bulk-actions.gif differ diff --git a/docs/docs/img/exceptionless-slack-settings.png b/docs/docs/img/exceptionless-slack-settings.png new file mode 100644 index 0000000000..7f46387e9e Binary files /dev/null and b/docs/docs/img/exceptionless-slack-settings.png differ diff --git a/docs/docs/img/exceptionless_webhooks.png b/docs/docs/img/exceptionless_webhooks.png new file mode 100644 index 0000000000..02a6e39840 Binary files /dev/null and b/docs/docs/img/exceptionless_webhooks.png differ diff --git a/docs/docs/img/exceptionless_zapier.png b/docs/docs/img/exceptionless_zapier.png new file mode 100644 index 0000000000..711c0ca976 Binary files /dev/null and b/docs/docs/img/exceptionless_zapier.png differ diff --git a/docs/docs/img/filter-by-project-organization.png b/docs/docs/img/filter-by-project-organization.png new file mode 100644 index 0000000000..6670514be1 Binary files /dev/null and b/docs/docs/img/filter-by-project-organization.png differ diff --git a/docs/docs/img/filter-by-search-filter-criteria.png b/docs/docs/img/filter-by-search-filter-criteria.png new file mode 100644 index 0000000000..a682dcb6d1 Binary files /dev/null and b/docs/docs/img/filter-by-search-filter-criteria.png differ diff --git a/docs/docs/img/filter-by-timeframe.png b/docs/docs/img/filter-by-timeframe.png new file mode 100644 index 0000000000..e8e5e29c5b Binary files /dev/null and b/docs/docs/img/filter-by-timeframe.png differ diff --git a/docs/docs/img/integrations.png b/docs/docs/img/integrations.png new file mode 100644 index 0000000000..814e4cb786 Binary files /dev/null and b/docs/docs/img/integrations.png differ diff --git a/docs/docs/img/logdetails.png b/docs/docs/img/logdetails.png new file mode 100644 index 0000000000..2291a22afb Binary files /dev/null and b/docs/docs/img/logdetails.png differ diff --git a/docs/docs/img/logleveldashboard.png b/docs/docs/img/logleveldashboard.png new file mode 100644 index 0000000000..afc9c68638 Binary files /dev/null and b/docs/docs/img/logleveldashboard.png differ diff --git a/docs/docs/img/logmessageevents.png b/docs/docs/img/logmessageevents.png new file mode 100644 index 0000000000..dba3d7f130 Binary files /dev/null and b/docs/docs/img/logmessageevents.png differ diff --git a/docs/docs/img/logstack.png b/docs/docs/img/logstack.png new file mode 100644 index 0000000000..58c06c4c1f Binary files /dev/null and b/docs/docs/img/logstack.png differ diff --git a/docs/docs/img/newstacks.png b/docs/docs/img/newstacks.png new file mode 100644 index 0000000000..26897405a9 Binary files /dev/null and b/docs/docs/img/newstacks.png differ diff --git a/docs/docs/img/override.png b/docs/docs/img/override.png new file mode 100644 index 0000000000..6a2d429cbf Binary files /dev/null and b/docs/docs/img/override.png differ diff --git a/docs/docs/img/project-settings.png b/docs/docs/img/project-settings.png new file mode 100644 index 0000000000..ed1f086e1d Binary files /dev/null and b/docs/docs/img/project-settings.png differ diff --git a/docs/docs/img/sessions-event-tab-user-footsteps.jpg b/docs/docs/img/sessions-event-tab-user-footsteps.jpg new file mode 100644 index 0000000000..383d443344 Binary files /dev/null and b/docs/docs/img/sessions-event-tab-user-footsteps.jpg differ diff --git a/docs/docs/img/versioning.png b/docs/docs/img/versioning.png new file mode 100644 index 0000000000..e8a359522f Binary files /dev/null and b/docs/docs/img/versioning.png differ diff --git a/docs/docs/index.md b/docs/docs/index.md new file mode 100644 index 0000000000..f6b90ebc51 --- /dev/null +++ b/docs/docs/index.md @@ -0,0 +1,29 @@ +--- +title: "Overview" +--- + +# Index + +The definition of the word exceptionless is: to be without exception. Exceptionless provides real-time error reporting for your JavaScript, Node, .NET Core, ASP.NET, Web API, WebForms, WPF, Console, and MVC apps. It organizes the gathered information into simple actionable data that will help your app become exceptionless! + +Exceptionless focuses on real-time configurability which sets it apart from other error monitoring services. Where others might require a configuration change in your code and a re-deployment of your app, Exceptionless allows you to make changes without ever changing your deployed code. + +--- + +## Who is using us? + +Companies from around the world trust Exceptionless to help them deliver an improved experience for their customers. + +![Customers](/assets/img/codesmith-client-logo-bar-left.png) {.text-center} + +## Want to Learn More? + +Browse the [news archive](/news/) for release notes, engineering updates, and articles about error monitoring, .NET, JavaScript, and development. + +--- + +## Ready to Dive in? + +Let's jump right into the documentation and get you up and running. Navigate at your leisure on the left, or click through each section and read the entirety of our docs (if you're an over-achiever). + +[Getting Started](/docs/getting-started) diff --git a/docs/docs/integrations.md b/docs/docs/integrations.md new file mode 100644 index 0000000000..5e43c46485 --- /dev/null +++ b/docs/docs/integrations.md @@ -0,0 +1,67 @@ +--- +title: "Integrations" +--- + +# Integrations + +To make managing events from your application easier, Exceptionless provides some useful integrations. You can access these integrations by clicking the Project dropdown menu, clicking the settings icon next to the project name, then clicking on the Integrations tab on the Settings page. + +![Integrations Page Screenshot](./img/integrations.png) + +We provide three integrations: + +1. Zapier +2. Slack +3. Webhooks + +## Zapier + +Exceptionless has built a [first-class Zapier application](https://zapier.com/apps/exceptionless/integrations) that allows you to connect your Exceptionless account to over 3,000 other apps. To use this, simply sign into your Zapier account and search for Exceptionless. + +![Zapier page for Exceptionless](./img/exceptionless_zapier.png) + +## Slack + +Connecting to Slack is as simple as clicking the Slack integration button. You'll be prompted to sign into your Slack workspace. Once signed in, you can choose the channel for your notifications to be sent to. Then, back on the Settings page, you can configure what types of notifications are sent. + +![Slack integration example](./img/exceptionless-slack-settings.png) + +## Webhooks + +By configuring a webhook, you are telling Exceptionless to post data to the specified endpoint whenever specific events happen. This is useful in creating custom, bespoke integrations for your Exceptionless account. Configuring a webhook is simple. Click the Add Webhook button on the Settins page and provide the information requested in the modal. + +![Webhooks example](./img/exceptionless_webhooks.png) + +Here's an example of the event payload (this applies to v2 of the Exceptionless API): + +```json +{ + "id": "22cd0826e447a44e78877a22", + "url": "http://localhost:5200/event/22cd0826e447a44e78877a22", + "occurrence_date": "2014-01-17T14:37:02.739-06:00", + "type": "error", + "message": "A potentially dangerous Request.Path value was detected from the client (&).", + "project_id": "537650f3b77efe23a47914f4", + "project_name": "Disintegrating Pistol", + "organization_id": "537650f3b77efe23a47914f3", + "organization_name": "Acme", + "stack_id": "1ecd0826e447a44e78877ab1", + "stack_url": "http://localhost:5200/stack/1ecd0826e447a44e78877ab1", + "stack_title": "A potentially dangerous Request.Path value was detected from the client (&).", + "stack_tags": [ + "Test" + ], + "total_occurrences": 0, + "first_occurrence": "2014-01-17T20:37:02.739Z", + "last_occurrence": "2014-01-17T20:37:02.739Z", + "is_new": false, + "is_regression": false, + "is_critical": false +} +``` + +To see both v1 and v2 models for events and stacks, [see this link](https://github.com/exceptionless/Exceptionless/tree/master/tests/Exceptionless.Tests/Plugins/WebHookData). + +--- + +[Next > FAQ](/docs/FAQ) diff --git a/docs/docs/managing-stacks.md b/docs/docs/managing-stacks.md new file mode 100644 index 0000000000..f448d33ee3 --- /dev/null +++ b/docs/docs/managing-stacks.md @@ -0,0 +1,63 @@ +--- +title: "Managing Stacks" +--- + +# Managing Stacks + +Perhaps the most important thing you'll do in Exceptionless is manage your stacks. Think of stacks as your todo list for error management. And like any good todo list, you can drill into a task for more details, mark the task complete, or set the task aside for a later date. + +But what is a stack, exactly? It's pretty simple, actually. A stack is an automatically ([or manually](/docs/manual-stacking)) grouped list of events. Events can be errors, messages, or logs. Exceptionless will try to automatically group the same events together while gathering as much information about them as possible (i.e. number of users affected, frequency of the event, last occurrence). + +### Viewing Stacks + +Now, let's take a look at how you manage these stacks. When you first sign in, you'll be taken to your dashboard on the Most Frequent view. + +![Most Frequent view of stacks on dashboard](img/Most_Frequent.png) + +Click on a stack you'd like to manage (We recommend you start with the most frequent event because that's probably pretty annoying for your customers 😉). Clicking on a stack will take you to a detailed view that includes important information such as how many times the event occurred, the number of users impacted, and the first and last occurrences of the event. + +![Stack Details Example](img/Stack_Details.png) + +### Applying Statuses + +To apply a status on a stack, click the dropdown in the top-right and apply the appropriate selection. Selection options include: + +* Open +* Fixed +* Snoozed +* Ignored +* Discarded + +![Status Options Example](img/Status_Options.png) + +Marking the status of a stack will control your [filtering](/docs/filtering-and-searching) options, but it can also drive your workflow. Ignored stacks may be stacks you have no plans of addressing. Discarded stacks (which do not count against your plan quota) may be stacks that you can't easily prevent from coming through but you don't want to see and don't care about. Snoozing stacks allows you to be reminded at a future point to address the stack in question. + +Let's take a look at each status in detail: + +**Open** - This status indicates that the error is new or actively occurring. You will receive email notifications for these issues. + +**Fixed** - Well, this one means you fixed it. If you look at Exceptionless as your todo list for errors, marking a stack as "Fixed" is like checking an item off your todo list. To be more specific, you won't get notifications if you have marked events as fixed. You will have the opportunity to provide your software's version number in which the fix was introduced. If another error comes through of the same kind and it matches the version number that was supposed to fix the issue, your stacks will be marked as "Regressed" instead of "Fixed". Additionally, if you mark a stack as Fixed but do not supply a version number in which it was fixed, should the event happen again, the stack will be marked as "Regressed". + +**Snoozed** - Marking a stack as snoozed means you will not get email notifications for whatever period of time you indicate. This is like your alarm clock in the morning. You know you need to take action (like wake up or fix the bug), but you really don't want to yet. Snooze has your back. After the specified period of time, the stacks will once again start alerting you. + +**Ignored** - When you ignore a stack, you will no longer receive email notifications unless you change the status. You may choose to do this when you have no intentions of resolving the issue but still want to collect information from the stacks. + +**Discarded** - You should use this status when you do not care about the event at all. If "Ignored" is turning your back on an event and trying not to see it, "Discarded" is putting its feet in cement and dropping it into the middle of a lake. And since these events are sleeping with the fishes, they don't count against your plan quota. + +Beyond statuses, you have options to further control your stacks. + +### Additional Options + +![Options Examples](img/Options.png) + +Marking a stack with "Future Occurrences are Critical" will automatically tag all subsequent events that come into that stack with the critical tag and will make them more prominent for you to review. + +The "Promote to External" option allows you to send the stack details to an external source that you've configured through webhooks in the [Integrations](/docs/integrations) section. This can help you automate issue tracking and project management. For example, you can use this functionality to connect to [Zapier](https://zapier.com), a no-code automation tool. By doing so, you can automatically funnel events from Exceptionless to issues on Github or Jira. You can send text alerts to your devops team (just be smart about this one because those folks need sleep too!), or you can use the data from Exceptionless to build custom dashboards for your entire organization. + +Adding a "Reference Link" allows you to supply to a link from an external source. This is helpful when a customer files a Github issue, for example. You can link to Github or to a Slack conversation, or anywhere, really. + +Managing your stacks is the core focus within Exceptionless, and we try to automate as much as possible for you. However, it is possible to manually stack events, allowing you some of the same management tools outlined here. + +--- + +[Next > Manual Stacking](/docs/manual-stacking) diff --git a/docs/docs/manual-stacking.md b/docs/docs/manual-stacking.md new file mode 100644 index 0000000000..24fb8b5e3a --- /dev/null +++ b/docs/docs/manual-stacking.md @@ -0,0 +1,76 @@ +--- +title: "Manual Stacking" +--- + +# Manual Stacking + +We try to group events into intuitive stacks, but sometimes you might want to create your own for organization, reporting, troubleshooting, etc. A good example use case might be when you are introducing a new feature. The errors or events you send to Exceptionless may ultimately look like or be the same as events linked to other features in your applications. However, you might want to see the events triggered by use of this new feature stacked together. + +How might we do this? You can use the `SetManualStackingKey` method to facilitate this need. + +## Creating Custom Stacks + +In the below examples, we use `SetManualStackingKey` and are naming the custom stack "MyCustomStackingKey" and setting the value to "ANOTHER FEATURE. What this does is it ensures that any events, regardless of the type or reason for the event, will be grouped together. + +![Example manual stacking on dashboard](img/Manual_Key.png) + +In the example above, the events grouped under "My stack title" use custom stacking keys to group them together. Let's see how you would do this in practice. + +## cURL Example + +```shell +curl --location --request POST 'https://api.exceptionless.com/api/v2/events' \ +--header 'Authorization: Bearer XUlBBdgFxAlmCsAZHDFTIacXpzYuZDuqDzzFYMlR' \ +--header 'Content-Type: application/json' \ +--data-raw '{ "type": "error", + "date":"2030-01-01T12:00:00.0000000-05:00", + "title": "NEW FEATURE WORK", + "@simple_error": { + "message": "Weird Exception", + "type": "System.Exception", + "stack_trace": " at Client.Tests.ExceptionlessClientTests.CanSubmitSimpleException() in ExceptionlessClientTests cs:line 99" + }, + "@stack": { "title": "My stack title", "signature_data": { "mystackingkey": "ANOTHER FEATURE" }} +``` + +## C# Example + +```csharp +try { + throw new ApplicationException("Unable to create order from quote."); +} catch (Exception ex) { + ex.ToExceptionless().SetManualStackingKey("MyCustomStackingKey").Submit(); +} +``` + +Or, you can set the stacking directly on an event (e.g., inside a plugin). + +```csharp +event.SetManualStackingKey("MyCustomStackingKey"); +``` + +## JavaScript Example + +```javascript +var client = exceptionless.ExceptionlessClient.default; +// Node.Js +// var client = require('exceptionless').ExceptionlessClient.default; + +try { + throw new Error('Unable to create order from quote.'); +} catch (error) { + client.createException(error).setManualStackingKey('MyCustomStackingKey').submit(); +} +``` + +## When Should You Use This + +Custom, manual stacking is certainly an advanced feature. We have tried to make your experience fantastic without needing this functionality, but sometimes, there's no avoiding it. So, let's think about some times when you might want to use manual stacking: + +* Critical Functionality - if you have a piece of your app that you need see all errors for quickly, manual stacking would be perfect. +* Logs - we tend to think of stacks as errors, but they don't have to be, and you can easily use manual stacking to group logs for other purposes. +* Notifications - manual stacking makes it easy to set up [notifications](/docs/notifications) for errors or events that happen from a specific source that you define. + +--- + +[Next > Filtering & Searching](/docs/filtering-and-searching) diff --git a/docs/docs/notifications.md b/docs/docs/notifications.md new file mode 100644 index 0000000000..baee42f4ed --- /dev/null +++ b/docs/docs/notifications.md @@ -0,0 +1,15 @@ +--- +title: "Notifications" +--- + +# Notifications + +To turn on email notifications, go to "My Account" in your dashboard, then click on the "Notifications" tab. + +Once you're in there, you can select the project you want to edit notifications to, and then select which notifications you want to receive for that selected project. + +![Email Notifications](img/email-notification-settings.png) + +--- + +[Next > Log Levels](/docs/setting-log-levels) diff --git a/docs/docs/project-settings.md b/docs/docs/project-settings.md new file mode 100644 index 0000000000..47ca72a7dd --- /dev/null +++ b/docs/docs/project-settings.md @@ -0,0 +1,158 @@ +--- +title: "Project Settings" +--- + +# Project Settings + +Exceptionless is different from most error monitoring services in that it provides you with real-time updates. That includes updates from your Exceptionless project settings to your client. What does that mean? + +All project settings are synced to the client in almost real time, so when an event is submitted to Exceptionless we send down a response header with the current configuration version. If a newer version is available we will immediately retrieve and apply the latest configuration. We will also periodically check for newer configuration when the client is idle. + +By default the client will check after `5 seconds` on client startup (*if no events are submitted on startup*) and then every `2 minutes` after the last event submission for updated configuration settings. + +- Checking for updated settings doesn't count towards plan limits. +- Only the current configuration version is sent when checking for updated settings (no user information will ever be sent). +- If the settings haven't changed, then no settings will be retrieved. + +You can also **turn off the automatic updating of configuration settings when idle** in each client respectively. Please see the [client specific documentation](#client-configuration). + +Now, let's take a look at the available settings for your projects. There are quite a few, so feel free to jump to the section that interests you below: + + +- [API Keys](#api-keys) +- [Data Exclusions](#data-exclusions) + - [Example usage](#example-usage) +- [Error Stacking](#error-stacking) + - [User Namespaces](#user-namespaces) + - [Common Methods](#common-methods) +- [Spam Detection](#spam-detection) + - [Automatic Spam Detection](#automatic-spam-detection) +- [Client Configuration](#client-configuration) +- [Event Exclusions](#event-exclusions) + - [Example](#example) +- [Using Client Configuration Settings](#using-client-configuration-settings) + +--- + + + +## API Keys + +Before doing anything, you want to create an API Key for your project. This protects you and your team by ensuring you are using a revokable key. Instead of using a user-scoped key that would provide access to everything, a project-scoped key is limited to—you guessed it—a single project. + +To generate an API Key, go to your project settings page and click on the API Keys tab. There, you can click the New API Key button. + +![exceptionless api keys](../docs/img/apikeys.png) + +## Data Exclusions + +Data can be excluded from your error reports by specifying the information you'd like excluded. This is especially important when you are dealing with sensitive information. For example, an error on log in might, by default, send a user's password to our server. You probably don't want that, so you can exclude that type of data from being sent. For more on how we handle security issues, check out our [security page](/docs/security). + +To get started, go to your project settings page, click the Settings tab. + +![Settings](img/DataExclusions.png) + +A comma delimited list of field names that should be removed from any error report data (e.g., extended data properties, form fields, cookies and query parameters). Data Exclusions can be configured on the project settings page. You can also specify a field name with wildcards `*` to specify starts with, ends with, or contains just to be extra safe. + +### Example usage + +- Entering `Password` will remove any field **named** `Password` from the report. +- Entering `Password*` will remove any field that **starts with** `Password` from the report. +- Entering `*Password` will remove any field that **ends with** `Password` from the report. +- Entering `*Password*` will remove any field that **contains** `Password` from the report. + +--- + +## Error Stacking + +You can also control how errors are stacked by specifying user namespaces (if you application code utilizes namespaces) or common methods (in all apps) to ignore. Let's take a look at how each works. + +### User Namespaces + +If your app runs on .NET or other languages that support namespaces, you can define what namespaces your code runs in. This allows Exceptionless to pick a stacking target within your code. + +You can set this up on the project settings page in the Settings tab. You simply need to provide, a comma delimited list of the namespace names that your applications code belongs to. If this value is set, only methods inside of these namespaces will be considered as stacking targets. + +### Common Methods + +Slightly different from your namespace definitions above, defining common methods here will *exclude* stacks from building up for specified methods. This is important as you may have catch-all methods in your code or specific methods that you expect to have frequent errors you'd rather not pass to Exceptionless. + +You can set this up on the project settings page in the Settings tab. Simply supply a comma delimited list of common method names that should not be used as stacking targets. + +--- + +## Spam Detection + +Spam detection allows you to prevent noise from being tracked. Bots crawling your site or app can contribute to stacks that you simply do not want to see or track. We make it easy to filter these out. + +On your project settings page, click the Settings tab and scroll down to the Spam Detection section. There, you can also specify a comma delimited list of user agents that should be ignored client side. This list supports wildcards and by default covers a vast major of bots. + +### Automatic Spam Detection + +![Automatic Spam Filtering](img/Spam_Detection.png) + +We also provide you with a simple tool to automatically detect spam from a single IP address sending in a high volume of activity. Click the checkbox, and we will do the rest. + +--- + +## Client Configuration + +Custom client configuration values allow you to control the behavior of your app in real time. They are a dictionary of key value pairs (string key, string value). Usage examples include controlling data exclusions to protecting sensitive data and or enabling/disabling features. + +To set up custom client configurations, click the All Projects drop down in the navigation header when you are signed into Exceptionless. Then, hover over your project name and you'll see a gear icon. Click that icon. This will take you to your project settings screen where you can click the tab called Client Configuration. + +![Exceptionless Project Settings](img/project-settings.png) + +Once you have made changes to your Project Settings, the configuration values will only be read by your client if your client is aware of the configuration. This happens out of the box with the [Exceptionless .NET Client](/docs/clients/dotnet/) and the [Exceptionless JS Client](/docs/clients/javascript/). If you are building your own client or simply wrapping our API, you can still make use of these configuration values by reading them in periodically via a `GET` request to `/api/v2/projects/{id}/config`. + +## Event Exclusions + +The Exceptionless clients have the ability to automatically discard events based on client configuration settings. We have a plugin that looks at the client configuration settings using a simple key name convention. + +To help us understand this consider that every event has a `Type` and `Source` property. The `Type` can be anything but we have a few first class types like [`error`, `usage`, `log`, `404`, `session`](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Models/Event.cs#L92-L100). `Source` is usually set to the exception type when dealing with `error` events or the `log` source. + +With that said, you can exclude any event type and source by adding a new client configuration key `@@EVENT_TYPE:SOURCE` by replacing the `EVENT_TYPE` and `SOURCE` respectively and specify a configuration value of `false`. *You can also specify a wild card `*` as part of the `SOURCE`.* + +### Example + +- To discard all errors of type `System.ArgumentNullException`: + - **KEY:** `@@error:System.ArgumentNullException` + - **VALUE:** `false` + +- To discard all errors in general you would use a wildcard `*`: + - **KEY:** `@@error:*` + - **VALUE:** `false` + +- To discard all 404s in general you would use a wildcard `*`: + - **KEY:** `@@404:*` + - **VALUE:** `false` + +- To discard all 404s for a specific resource, use the resource's event source as the key. + - **KEY:** `@@404:/invalid-file-path.jpg` + - **VALUE:** `false` + +We have also added some additional known values to support **minimum log levels**. The known values are: `Trace`, `Debug`, `Info`, `Warn`, `Error`, `Fatal`, `Off`. + +- Sets a minimum log level of `Info` for my application: + - **KEY:** `@@log:*` + - **VALUE:** `Info` + +- You can also set a log level on a per log source basis. This will override any general minimum log level (e.g., `@@log:*` you have defined! + - **KEY:** `@@log:*AuthController` + - **VALUE:** `Trace` + +## Using Client Configuration Settings + +- [.NET](/docs/clients/dotnet/client-configuration-values) +- [JavaScript / Node.js](/docs/clients/javascript/client-configuration-values) + +--- + +[Next > Versioning](/docs/versioning) diff --git a/docs/docs/references-ids.md b/docs/docs/references-ids.md new file mode 100644 index 0000000000..cbdede6123 --- /dev/null +++ b/docs/docs/references-ids.md @@ -0,0 +1,115 @@ +--- +title: "Reference Ids" +--- + +# Reference Ids + +Reference Ids are unique identifiers that let you look up a submitted event. This is important because _event Ids are not created until after an event is processed, so there's no other way to look up an event_. + +Reference Ids are also used to help deduplicate events on the server side. + +## Uses + +One example of using Reference Ids is to help support your users. For instance, we always include a Reference Id with every error message for our users, allowing them to contact us with that Reference Id and receive help faster because we can easily track it down. + +## Reference Id Example + +To attach Reference Ids to our errors in Exceptionless, we register a default Reference Id plugin that sets a Reference Id when the event is submitted and stores the Id in an implementation of ILastReferenceIdManager. With the default plugin, we enable this behavior by calling `UseReferenceIds()` on the configuration object. + +## C# Example + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.UseReferenceIds(); +``` + +## JavaScript Example + +The JavaScript client will automatically manage reference ids. + +You can also create your own plugin to create your own Reference Ids. + +## Get Last Used Reference Id + +Call `GetLastReferenceId()` on the `ExceptionlessClient` instance. + +### C# Last Reference Id Example + +```csharp +using Exceptionless; +// Get the last created Reference Id +ExceptionlessClient.Default.GetLastReferenceId(); +``` + +### JavaScript Last Reference Id Example + +```javascript +// Get the last created Reference Id +exceptionless.ExceptionlessClient.default.getLastReferenceId(); +``` + +## Displaying Reference Ids to End Users + +We do this for our end users because it allows them to better support their app users. + +To do so, we add a custom `IExceptionHandler` and return a new error response to include the Reference Id as shown below: + +```csharp +public class ExceptionlessReferenceIdExceptionHandler : IExceptionHandler { + public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken) { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + var exceptionContext = context.ExceptionContext; + var request = exceptionContext.Request; + if (request == null) + throw new ArgumentException($"{typeof(ExceptionContext).Name}.{"Request"} must not be null", nameof(context)); + + context.Result = new ResponseMessageResult(CreateErrorResponse(request, exceptionContext.Exception, HttpStatusCode.InternalServerError)); + return TaskHelper.Completed(); + } + + private HttpResponseMessage CreateErrorResponse(HttpRequestMessage request, Exception ex, HttpStatusCode statusCode) { + HttpConfiguration configuration = request.GetConfiguration(); + HttpError error = new HttpError(ex, request.ShouldIncludeErrorDetail()); + + string lastId = ExceptionlessClient.Default.GetLastReferenceId(); + if (!String.IsNullOrEmpty(lastId)) + error.Add("Reference", lastId); + + // CreateErrorResponse should never fail, even if there is no configuration associated with the request + // In that case, use the default HttpConfiguration to con-neg the response media type + if (configuration == null) { + using (HttpConfiguration defaultConfig = new HttpConfiguration()) { + return request.CreateResponse(statusCode, error, defaultConfig); + } + } + + return request.CreateResponse(statusCode, error, configuration); + } +} +``` + +Then we replace the existing `IExceptionFilter` + +```csharp +Config.Services.Replace(typeof(IExceptionHandler), new ExceptionlessReferenceIdExceptionHandler()); +``` + +Now you'll get a user friendly error response that contains a Reference Id, like: + +`{ + "message": "An error has occurred.", + “reference”: “411085622e” +}` + +## Looking up Events by Reference Id + +Link directly to an event by outputting a link in your UI or log files, like +`https://be.exceptionless.io/event/by-ref/YOUR_REFERENCE_ID)` + +Or you can search via the api/ui with `reference:YOUR_REFERENCE_ID` + +--- + +[Next > User Sessions](/docs/user-sessions) diff --git a/docs/docs/security.md b/docs/docs/security.md new file mode 100644 index 0000000000..5b3947e261 --- /dev/null +++ b/docs/docs/security.md @@ -0,0 +1,24 @@ +--- +title: "Security" +--- + +# Security + +Exceptionless follows industry best practices and uses SSL out of the box to be as secure as possible. We also provide you with the tools to take your information security to the next level. These tools include Data Exclusions. To accommodate various data protection laws, Exceptionless allows you to prevent the transmission of specified pieces of information through Data Exclusions. + +### Data Exclusions + +These exclusions are simply a comma delimited list of field names that should be removed from any error report data (e.g., extended data properties, form fields, cookies and query parameters). Data Exclusions can be configured on the project settings page. You can also specify a field name with wildcards `*` to specify starts with, ends with, or contains just to be extra safe. + +#### Example usage: + +Entering `Password` will remove any field **named** `Password` from the report. +Entering `Password*` will remove any field that **starts with** `Password` from the report. +Entering `*Password` will remove any field that **ends with** `Password` from the report. +Entering `*Password*` will remove any field that **contains** `Password` from the report. + +[See more on data exclusions here](/docs/project-settings#data-exclusions). + +--- + +[Next > API Usage](/docs/api/) diff --git a/docs/docs/self-hosting/docker.md b/docs/docs/self-hosting/docker.md new file mode 100644 index 0000000000..32f839afc2 --- /dev/null +++ b/docs/docs/self-hosting/docker.md @@ -0,0 +1,75 @@ +--- +title: "Docker" +--- + +# Docker + +If you would like to test Exceptionless locally, please follow this section. + +## Requirements + +* [Docker](https://www.docker.com) + +## Testing Setup + +Runs Exceptionless without persisting data between runs. Good for checking out Exceptionless for the first time and testing. + +```bash +docker run --rm -it -p 5200:8080 exceptionless/exceptionless:latest +``` + +## Simple Setup + +Runs a very simple non-production setup for Exceptionless with data persisted between runs in a sub-directory of the current directory called `esdata`. It uses an embedded single node Elasticsearch cluster and does not have backups. It is recommended that you create your own Elasticsearch cluster for production deployments of Exceptionless. + +On Linux: + +```bash +docker run --rm -it -p 5200:8080 \ + -v $(pwd)/esdata:/usr/share/elasticsearch/data \ + exceptionless/exceptionless:latest +``` + +On PowerShell: + +```powershell +docker run --rm -it -p 5200:8080 ` + -v ${PWD}/esdata:/usr/share/elasticsearch/data ` + exceptionless/exceptionless:latest +``` + +## Simple Setup w/SSL Support and SMTP + +Runs a very simple non-production setup for Exceptionless with data persisted between runs in a sub-directory of the current directory called `esdata`. It uses an embedded single node Elasticsearch cluster and does not have backups. It is recommended that you create your own Elasticsearch cluster for production deployments of Exceptionless. In the SMTP password characters disallowed or reserved according to RFC-2396 (e.g. @:#/?+) need to be percent-encoded (e.g. # => %23). + +On Linux: + +```bash +docker run --rm -it -p 5200:8080 -p 5089:443 \ + -e EX_ConnectionStrings__Email=smtps://user:password@smtp.host.com:587 \ + -e ASPNETCORE_URLS="https://+;http://+" \ + -e ASPNETCORE_HTTPS_PORT=5001 \ + -e ASPNETCORE_Kestrel__Certificates__Default__Password="password" \ + -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx \ + -v ~/.aspnet/https:/https/ \ + -v $(PWD)/esdata:/usr/share/elasticsearch/data \ + exceptionless/exceptionless:latest +``` + +On PowerShell: + +```powershell +docker run --rm -it -p 5200:8080 -p 5089:443 ` + -e EX_ConnectionStrings__Email=smtps://user:password@smtp.host.com:587 ` + -e ASPNETCORE_URLS="https://+;http://+" ` + -e ASPNETCORE_HTTPS_PORT=5001 ` + -e ASPNETCORE_Kestrel__Certificates__Default__Password="password" ` + -e ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx ` + -v ~/.aspnet/https:/https/ ` + -v ${PWD}/esdata:/usr/share/elasticsearch/data ` + exceptionless/exceptionless:latest +``` + +--- + +[Next > Kubernetes](/docs/self-hosting/kubernetes) diff --git a/docs/docs/self-hosting/index.md b/docs/docs/self-hosting/index.md new file mode 100644 index 0000000000..829ae550b0 --- /dev/null +++ b/docs/docs/self-hosting/index.md @@ -0,0 +1,17 @@ +--- +title: "Self Hosting" +--- + +# Self Hosting + +Exceptionless can be self-hosted by either manually running the source code for the server and the frontend or by using our simply Docker image. + +You can also use Kubernetes while self-hosting Exceptionless. We'll cover both topics in the following pages. + +* [Docker](/docs/self-hosting/docker) +* [Kubernetes](/docs/self-hosting/kubernetes) +* [Upgrading](/docs/self-hosting/upgrading-self-hosted-instance) + +--- + +[Next > Docker](/docs/self-hosting/docker) diff --git a/docs/docs/self-hosting/kubernetes.md b/docs/docs/self-hosting/kubernetes.md new file mode 100644 index 0000000000..667ab9a4de --- /dev/null +++ b/docs/docs/self-hosting/kubernetes.md @@ -0,0 +1,92 @@ +--- +title: "Kubernetes" +--- + +Please follow this section to set up Exceptionless in a Kubernetes environment. Please note this section is a work in progress, any contributions is greatly appreciated. + +## Requirements + +* [Kubernetes](https://kubernetes.io) +* [Helm](https://helm.sh) + +## Instructions + +Please note that we recommend you use Kubernetes for running in production. + +1. Follow the steps [here](https://github.com/exceptionless/Exceptionless/blob/master/k8s/ex-setup.ps1) for how to create it in AKS +2. View the configuration settings below for more information on configuring Exceptionless. +3. [Configure your clients](/docs/clients/) to send errors to your website. + +Now, you can create a local account, organization, and project and send events to it. + +## Configuration + +The following section will cover how to configure exceptionless inside of a Kubernetes instance using the `exceptionless-config` config map. All exceptionless configuration keys are prefixed with `EX_`. Please note that these instructions also apply to docker using environment variables. + +All configuration options and settings can be found in the various option classes located [here](https://github.com/exceptionless/Exceptionless/tree/master/src/Exceptionless.Core/Configuration). + +_Please note that if you are specifying configuration via `docker-compose`, then you will need to drop the `EX_` and `EX_ConnectionStrings__` prefixes._ + +## ConnectionStrings + +```yaml +# connection string used for any provider specifying Redis. +EX_ConnectionStrings__Redis: localhost:6379,abortConnect=false + +EX_ConnectionStrings__Cache: provider=redis; +EX_ConnectionStrings__Elasticsearch: server=http://10.0.0.4:9200; +EX_ConnectionStrings__Email: smtps://user%40domain.com:password@smtp.domain.com:465 +EX_ConnectionStrings__MessageBus: provider=redis; +EX_ConnectionStrings__Metrics: provider=statsd;server=localhost +EX_ConnectionStrings__Queue: provider=redis; +EX_ConnectionStrings__Storage: provider=azurestorage; +``` + +You can append values to any connection string using a `;`. For example, you can control many shards and replicas each Elasticsearch index should be created with by appending to the `EX_ConnectionStrings__Elasticsearch` connection string. For a Elasticsearch cluster (3 nodes, two masters), you would append `shards=3;replicas=1`. + +The `provider` value determines what implementations to use for the various abstractions. We've made it easier to reuse a single connection string by automatically looking up a connection string by the provider name and adding any key value pairs to the current connection string (as shown above with redis). + +## General Configuration + +1. You'll want to set the `EX_ApiUrl` key to your external url of the api. +2. You'll want to set the `EX_BaseUrl` key to your external url of the website. If you are not following the clean urls optional section below, please make sure you also add the hashbang (`/#!`) to the base url. +3. `EX_AppMode` should be set to `Production` if you want to send unrestricted emails. +4. Please take a quick look at all the configuration options and settings that can be found in the various option classes located [here](https://github.com/exceptionless/Exceptionless/tree/master/src/Exceptionless.Core/Configuration). + +## Active Directory Authentication + +To enable Active Directory authentication, update the Update the `exceptionless-config` config map to include the `EX_ConnectionStrings__LDAP` connection string. The value should be your domain's LDAP URI (e.g. `LDAP://ad.domain.com/` or `LDAP://ad.domain.com/DC=domain,DC=com`). + +Please note the following: + +1. Users must still go through the registration process using their AD credentials. This allows account setup to proceed as normal. AD credentials are **not** stored. +2. Exceptionless relies on the following properties being available in AD: + * `mail`: user's email address + * `givenName`: user's first name + * `sn`: user's last name + * `sAMAccountName`: user's username +3. To ensure the correct account information is retrieved for a user, consider using a more specific connection string to narrow down the LDAP account type. For example: `LDAP://ad.domain.com/OU=Standard Users,OU=User Accounts,DC=domain,DC=com` + +## Enabling Slack Integrations + +1. Create a Slack app for your workspace + * __Please do not distribute your app outside of your organization.__ +2. Go to the `OAuth & Permissions` feature. Add a new redirect URL. The redirect URL should be your Exceptionless base URL. +3. On the *basic info* page of your Slack App, you will need to find the Client ID and Client Secret +4. Update the `exceptionless-config` config map `ConnectionStrings__OAuth` value to include `SlackId=YOUR_ID;SlackSecret=YOUR_SECRET;` and restart the associated pods. +5. If you've already loaded a page in Exceptionless, you will need to do a hard refresh for the config changes to apply. + +## Upgrading + +Please see the [Upgrading](/docs/self-hosting/upgrading-self-hosted-instance) for details on how to upgrade to the current version. + +## Troubleshooting + +If you are having issues please try the following to resolve the issues. If this doesn't work please open an issue or contact us on [Discord](https://discord.gg/xv3sjurVwA). + +* Make sure you are running the latest release by visiting our [releases page](https://github.com/exceptionless/Exceptionless/releases). You can verify the version you are currently running by accessing the status page [`http://localhost/api/v2/about`](http://localhost/api/v2/about). +* You can also enable detailed logging by updating the `Serilog__MinimumLevel__Default` config map value to `Debug`. + +--- + +[Next > Upgrading](/docs/self-hosting/upgrading-self-hosted-instance) diff --git a/docs/docs/self-hosting/upgrading-self-hosted-instance.md b/docs/docs/self-hosting/upgrading-self-hosted-instance.md new file mode 100644 index 0000000000..dd0974989f --- /dev/null +++ b/docs/docs/self-hosting/upgrading-self-hosted-instance.md @@ -0,0 +1,1111 @@ +--- +title: "Upgrading" +--- + +# Upgrading + +**Please ensure that you have created backups before upgrading!** + +**If you are upgrading from v1 or [v2](https://github.com/exceptionless/Exceptionless/releases/tag/v2.0.0) you will need to upgrade to [v3.0](https://github.com/exceptionless/Exceptionless/releases/tag/v3.0.0) before upgrading to the latest release.** + +## Upgrading from v7.1 to v8 + +We simplified the self hosting process by integrating the UI into the existing app images. As such `exceptionless/ui` docker images are deprecated and we recommend using `exceptionless/app`. + +We also upgraded to Elasticsearch 8 in the base images. One requirement of upgrading with existing data is the Elasticsearch data is loaded with the latest Elasticsearch 7.x release. If you are using the all in one image, first use `exceptionless/exceptionless:8.0.0-elasticsearch7` and wait for the app to startup and give it some time. Then turn off the app and then use `exceptionless/exceptionless:8.0.0` image. We will be deprecating the `exceptionless/exceptionless:8.0.0-elasticsearch7` image in the future, this is only there to help with the upgrade process. + +You may also need to update the connection strings. In v8.2.7 we updated the Redis Connection String to remove the `server=` prefix. + +## Upgrading from v7 to v7.1 + +We made some changes to email configuration. Yoy wukk now be required to set the `EX_SmtpFrom` config map/environment variable in order to send email. The value should be in the following format: `"Exceptionless "` + +## Upgrading from v6 to v7 + +A migration job will need to be run as there are several in place data migrations that need to be applied. The migrations will add new index mappings for soft delete support as well as stack status and populate various stack fields with data. + +1. You'll need to run an out of process `Migration` job. In order to do this you'll need to update configuration to ensure it's pointing to your Elasticsearch (e.g., `EX_ConnectionStrings__Elasticsearch` environment variable/connection string) and Redis instances. +2. Scale down existing Exceptionless apps and jobs. +3. Start the `Migration` job. + 1. For docker, you just need to pass the `Migration` argument to the `exceptionless/job` container image (e.g., `docker run exceptionless/job:latest Migration`). Please remember to pass any configuration settings (e.g., connection strings) to the migration job. + 2. For Kubernetes, you can run [`kubectl apply -f manual-migration-job.yaml`](https://github.com/exceptionless/Exceptionless/blob/master/k8s/manual-migration-job.yaml). Please note that you may have to tweak namespaces and container image version. +4. Scale back up and you should be good to go. + +## Upgrading from v5 to v6 + +Version 6 added support for Elasticsearch 7, which requires a complete data migration from Elasticsearch 5.x. This tutorial assumes you have docker/Kubernetes installed and have followed the [setup guide](/docs/self-hosting/). + +1. Create a new Elasticsearch 7 cluster or modify your existing `docker-compose` file to also include our Elasticsearch 7.x image (There will need to be two Elasticsearch docker instances (5.x and 7.x). Please note that we've included the Elasticsearch major version number in the data path of the docker data path, this allows you to run two versions side by side without losing the data. +2. Add a new environment variable or config map setting for `EX_ElasticsearchToMigrate` with the value of the `EX_Elasticsearch` 5.x connection string. +3. Add your existing Elasticsearch instance to `reindex.remote.whitelist` in Elasticsearch 7's `elasticsearch.yml`. Make sure you include the port as well, for example `reindex.remote.whitelist: 127.0.0.1:9200`. +4. Update the existing `EX_Elasticsearch` environment variable or config map entry to point to the Elasticsearch 7.x Cluster. +5. Scale down existing Exceptionless apps and jobs. +6. Start the Data Migration by running the `DataMigration` job. You can run it by opening the CLI and executing `dotnet Exceptionless.Job.dll DataMigration`. If you receive a warning that the port is already used, you need to change `ASPNETCORE_URLS` first, for example `ASPNETCORE_URLS=http://+:8080`. You can also run an incremental reindex by setting the `EX_ReindexCutOffDate` with a date value (E.G., `2022-01-28T18:00:00.00Z`., environment variable or config map entry and rerunning the Migration Job. +7. Scale up the rest of the app! + +## Upgrading from v4 to v5 + +We now only provide official docker images as release artifacts. This tutorial assumes you have docker/Kubernetes installed and have followed the [setup guide](/docs/self-hosting/). + +1. We now can run on linux or windows as we are running on ASP.NET Core! As a result we've completely redone the configuration. For the most part we've prefixed configuration with `EX_` and simplified it as much as possible. I'd recommend taking a look at your previous configuration settings and then read over the following [configuration document](/docs/self-hosting/kubernetes#configuration) to migrate your settings. +2. Please note that no Elasticsearch changes are required. You can continue to use your existing Elasticsearch cluster. You just need to update the connection string by following step 1. +3. Please note that the UI and API no longer run on the same port as they are now two different docker images. You may need to update your server url accordingly in your client applications. + +## Upgrading from v3 to v4 + +This process requires you to setup and configure a new Elasticsearch 5 instance and reindex your existing Elasticsearch 1.x data into the Elasticsearch 5 instance using [external reindexing](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html). This tutorial assumes you have Elasticsearch 5 Kibana instance installed and configured. + +1. Edit the Elasticsearch 5's `elasticsearch.yml` configuration file. + 1. Add the `reindex.remote.whitelist: 10.0.0.9:9200` setting with a value that contains the IP address or hostname of the 1.x server. This allows you to reindex the 1.x data into your new 5.x instance. + 2. Temporarily comment out (with a leading `#`) the following line: `#action.auto_create_index: .security,.monitoring*,.watches,.triggered_watches,.watcher-history*` + 3. Restart the elasticsearch service. +2. Open Kibana (E.G., [http://localhost:5601](http://localhost:5601)) and execute the following scripts to reindex your data. + +### Create Organization Index with the correct mappings: + +```json +PUT organizations-v1 +{ + "settings": { + "index.number_of_replicas": 1, + "index.number_of_shards": 3, + "analysis": { + "analyzer": { + "keyword_lowercase": { + "type": "custom", + "filter": [ + "lowercase" + ], + "tokenizer": "keyword" + } + } + } + }, + "aliases": { + "organizations": {} + }, + "mappings": { + "organization": { + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + }, + "created_utc": { + "type": "date" + }, + "updated_utc": { + "type": "date" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "stripe_customer_id": { + "type": "keyword" + }, + "has_premium_features": { + "type": "boolean" + }, + "plan_id": { + "type": "keyword" + }, + "plan_name": { + "type": "keyword", + "ignore_above": 256 + }, + "subscribe_date": { + "type": "date" + }, + "billing_status": { + "type": "float" + }, + "billing_price": { + "type": "double" + }, + "is_suspended": { + "type": "boolean" + }, + "retention_days": { + "type": "integer" + }, + "invites": { + "type": "object", + "properties": { + "token": { + "type": "keyword" + }, + "email_address": { + "type": "text", + "analyzer": "keyword_lowercase" + } + } + }, + "usage": { + "type": "object", + "properties": { + "date": { + "type": "date" + }, + "total": { + "type": "float" + }, + "blocked": { + "type": "float" + }, + "limit": { + "type": "float" + }, + "too_big": { + "type": "float" + } + } + }, + "overage_hours": { + "type": "object", + "properties": { + "date": { + "type": "date" + }, + "total": { + "type": "float" + }, + "blocked": { + "type": "float" + }, + "limit": { + "type": "float" + }, + "too_big": { + "type": "float" + } + } + } + } + }, + "project": { + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + }, + "created_utc": { + "type": "date" + }, + "updated_utc": { + "type": "date" + }, + "organization_id": { + "type": "keyword" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "next_summary_end_of_day_ticks": { + "type": "long" + } + } + }, + "token": { + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + }, + "created_utc": { + "type": "date" + }, + "updated_utc": { + "type": "date" + }, + "expires_utc": { + "type": "date" + }, + "organization_id": { + "type": "keyword" + }, + "project_id": { + "type": "keyword" + }, + "default_project_id": { + "type": "keyword" + }, + "user_id": { + "type": "keyword" + }, + "refresh": { + "type": "keyword" + }, + "scopes": { + "type": "keyword" + }, + "type": { + "type": "byte" + } + } + }, + "user": { + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + }, + "created_utc": { + "type": "date" + }, + "updated_utc": { + "type": "date" + }, + "organization_ids": { + "type": "keyword" + }, + "full_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "email_address": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "analyzer": "keyword_lowercase" + }, + "verify_email_address_token": { + "type": "keyword" + }, + "password_reset_token": { + "type": "keyword" + }, + "roles": { + "type": "keyword" + }, + "o_auth_accounts": { + "type": "object", + "properties": { + "provider": { + "type": "keyword" + }, + "provider_user_id": { + "type": "keyword" + }, + "username": { + "type": "keyword" + } + } + } + } + }, + "webhook": { + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + }, + "created_utc": { + "type": "date" + }, + "organization_id": { + "type": "keyword" + }, + "project_id": { + "type": "keyword" + }, + "url": { + "type": "keyword" + }, + "event_types": { + "type": "keyword" + } + } + } + } +} +``` + +### Reindex Organization data from 1.x into 5.x **Please make sure you update the host name**: + +```json +POST _reindex +{ + "source": { + "remote": { + "host": "http://10.0.0.9:9200" + }, + "index": "organizations-v1" + }, + "dest": { + "index": "organizations-v1", + "op_type": "create" + }, + "script": { + "inline": "if (ctx._source.modified_utc != null) { ctx._source.updated_utc = ctx._source.remove('modified_utc'); }", + "lang": "painless" + } +} +``` + +### Create Stack Index with the correct mappings: + +```json +PUT stacks-v1 +{ + "settings": { + "index.number_of_replicas": 1, + "index.number_of_shards": 3 + }, + "aliases": { + "stacks": {} + }, + "mappings": { + "stacks": { + "include_in_all": false, + "dynamic": false, + "properties": { + "id": { + "type": "keyword" + }, + "organization_id": { + "type": "keyword" + }, + "project_id": { + "type": "keyword" + }, + "signature_hash": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "first_occurrence": { + "type": "date" + }, + "last_occurrence": { + "type": "date" + }, + "title": { + "type": "text", + "boost": 1.1, + "include_in_all": true + }, + "description": { + "type": "text", + "include_in_all": true + }, + "tags": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "boost": 1.2, + "include_in_all": true + }, + "references": { + "type": "text", + "include_in_all": true + }, + "date_fixed": { + "type": "date" + }, + "fixed": { + "type": "boolean" + }, + "fixed_in_version": { + "type": "keyword" + }, + "is_hidden": { + "type": "boolean" + }, + "is_regressed": { + "type": "boolean" + }, + "occurrences_are_critical": { + "type": "boolean" + }, + "total_occurrences": { + "type": "integer" + } + } + } + } +} +``` + +### Reindex Stack data from 1.x into 5.x **Please make sure you update the host name**: + +```json +POST _reindex +{ + "source": { + "remote": { + "host": "http://10.0.0.9:9200" + }, + "index": "stacks-v1" + }, + "dest": { + "index": "stacks-v1", + "op_type": "create" + } +} +``` + +### Create Event Template so daily indexes can be created with the correct mappings: + +```json +PUT _template/events-v1 +{ + "template": "events-v1-*", + "settings": { + "number_of_shards": 1, + "number_of_replicas": 1, + "analysis": { + "analyzer": { + "comma_whitespace": { + "type": "pattern", + "pattern": "[,\\s]+" + }, + "email": { + "type": "custom", + "filter": [ + "email", + "lowercase", + "unique" + ], + "tokenizer": "keyword" + }, + "version_index": { + "type": "custom", + "filter": [ + "version_pad1", + "version_pad2", + "version_pad3", + "version_pad4", + "version", + "lowercase", + "unique" + ], + "tokenizer": "whitespace" + }, + "version_search": { + "type": "custom", + "filter": [ + "version_pad1", + "version_pad2", + "version_pad3", + "version_pad4", + "lowercase" + ], + "tokenizer": "whitespace" + }, + "whitespace_lower": { + "type": "custom", + "filter": [ + "lowercase" + ], + "tokenizer": "whitespace" + }, + "typename": { + "type": "custom", + "filter": [ + "typename", + "lowercase", + "unique" + ], + "tokenizer": "typename_hierarchy" + }, + "standardplus": { + "type": "custom", + "filter": [ + "standard", + "typename", + "lowercase", + "stop", + "unique" + ], + "tokenizer": "comma_whitespace" + } + }, + "filter": { + "email": { + "type": "pattern_capture", + "patterns": [ + "(\\w+)", + "(\\p{L}+)", + "(\\d+)", + "(.+)@", + "@(.+)" + ] + }, + "typename": { + "type": "pattern_capture", + "patterns": [ + "\\.(\\w+)", + "([^\\()]+)" + ] + }, + "version": { + "type": "pattern_capture", + "patterns": [ + "^(\\d+)\\.", + "^(\\d+\\.\\d+)", + "^(\\d+\\.\\d+\\.\\d+)" + ] + }, + "version_pad1": { + "type": "pattern_replace", + "pattern": "(\\.|^)(\\d{1})(?=\\.|-|$)", + "replacement": "$10000$2" + }, + "version_pad2": { + "type": "pattern_replace", + "pattern": "(\\.|^)(\\d{2})(?=\\.|-|$)", + "replacement": "$1000$2" + }, + "version_pad3": { + "type": "pattern_replace", + "pattern": "(\\.|^)(\\d{3})(?=\\.|-|$)", + "replacement": "$100$2" + }, + "version_pad4": { + "type": "pattern_replace", + "pattern": "(\\.|^)(\\d{4})(?=\\.|-|$)", + "replacement": "$10$2" + } + }, + "tokenizer": { + "comma_whitespace": { + "type": "pattern", + "pattern": "[,\\s]+" + }, + "typename_hierarchy": { + "type": "path_hierarchy", + "delimiter": "." + } + } + } + }, + "mappings": { + "events": { + "dynamic": "false", + "include_in_all": false, + "_all": { + "analyzer": "standardplus", + "search_analyzer": "whitespace_lower" + }, + "_size": { + "enabled": true + }, + "dynamic_templates": [ + { + "idx_reference": { + "match": "*-r", + "mapping": { + "ignore_above": 256, + "type": "keyword" + } + } + } + ], + "properties": { + "count": { + "type": "integer" + }, + "created_utc": { + "type": "date" + }, + "data": { + "properties": { + "@environment": { + "properties": { + "architecture": { + "type": "keyword" + }, + "ip_address": { + "type": "text", + "index": false, + "copy_to": [ + "ip" + ], + "include_in_all": true + }, + "machine_name": { + "type": "text", + "boost": 1.1, + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "include_in_all": true + }, + "o_s_name": { + "type": "text", + "copy_to": [ + "os" + ] + } + } + }, + "@error": { + "properties": { + "data": { + "properties": { + "@target": { + "properties": { + "ExceptionType": { + "type": "text", + "index": false, + "copy_to": [ + "error.targettype" + ], + "include_in_all": true + }, + "Method": { + "type": "text", + "index": false, + "copy_to": [ + "error.targetmethod" + ], + "include_in_all": true + } + } + } + } + } + } + }, + "@level": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "@location": { + "properties": { + "country": { + "type": "keyword" + }, + "level1": { + "type": "keyword" + }, + "level2": { + "type": "keyword" + }, + "locality": { + "type": "keyword" + } + } + }, + "@request": { + "properties": { + "client_ip_address": { + "type": "text", + "index": false, + "copy_to": [ + "ip" + ], + "include_in_all": true + }, + "data": { + "properties": { + "@browser": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "@browser_major_version": { + "type": "text" + }, + "@browser_version": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "@device": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "@is_bot": { + "type": "boolean" + }, + "@os": { + "type": "text", + "index": false, + "copy_to": [ + "os" + ] + }, + "@os_major_version": { + "type": "text" + }, + "@os_version": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "path": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "include_in_all": true + }, + "user_agent": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "@simple_error": { + "properties": { + "data": { + "properties": { + "@target": { + "properties": { + "ExceptionType": { + "type": "text", + "index": false, + "copy_to": [ + "error.targettype" + ], + "include_in_all": true + } + } + } + } + } + } + }, + "@submission_method": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "@user": { + "properties": { + "identity": { + "type": "text", + "boost": 1.1, + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "analyzer": "email", + "search_analyzer": "whitespace_lower", + "include_in_all": true + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "include_in_all": true + } + } + }, + "@user_description": { + "properties": { + "description": { + "type": "text", + "include_in_all": true + }, + "email_address": { + "type": "text", + "boost": 1.1, + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "analyzer": "email", + "search_analyzer": "simple", + "include_in_all": true + } + } + }, + "@version": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "analyzer": "version_index", + "search_analyzer": "version_search" + } + } + }, + "date": { + "type": "date" + }, + "error": { + "include_in_all": true, + "properties": { + "code": { + "type": "keyword", + "boost": 1.1 + }, + "message": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "targetmethod": { + "type": "text", + "boost": 1.2, + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "analyzer": "typename", + "search_analyzer": "whitespace_lower" + }, + "targettype": { + "type": "text", + "boost": 1.2, + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "analyzer": "typename", + "search_analyzer": "whitespace_lower" + }, + "type": { + "type": "text", + "boost": 1.1, + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "analyzer": "typename", + "search_analyzer": "whitespace_lower" + } + } + }, + "geo": { + "type": "geo_point" + }, + "id": { + "type": "keyword", + "include_in_all": true + }, + "idx": { + "type": "object", + "dynamic": "true" + }, + "ip": { + "type": "text", + "analyzer": "comma_whitespace" + }, + "is_deleted": { + "type": "boolean" + }, + "is_first_occurrence": { + "type": "boolean" + }, + "is_fixed": { + "type": "boolean" + }, + "is_hidden": { + "type": "boolean" + }, + "message": { + "type": "text", + "include_in_all": true + }, + "organization_id": { + "type": "keyword" + }, + "os": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "project_id": { + "type": "keyword" + }, + "reference_id": { + "type": "keyword" + }, + "source": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "include_in_all": true + }, + "stack_id": { + "type": "keyword" + }, + "tags": { + "type": "text", + "boost": 1.2, + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + }, + "include_in_all": true + }, + "type": { + "type": "keyword" + }, + "updated_utc": { + "type": "date" + }, + "value": { + "type": "double" + } + } + } + } +} +``` + +### Reindex Event data from 1.x into 5.x **Please make sure you update the host name**: + +```json +POST _reindex +{ + "source": { + "remote": { + "host": "http://10.0.0.9:9200" + }, + "index": "events-v1-*", + "size": 200 + }, + "dest": { + "index": "events-v1-error" + }, + "script": { + "lang": "painless", + "inline": "ctx._index = 'events-v1-' + DateTimeFormatter.ofPattern('yyyy.MM.dd').format(OffsetDateTime.parse(ctx._source.date).toInstant().atZone(ZoneOffset.UTC)); if (ctx._source.updated_utc == null) { ctx._source.updated_utc = ctx._source.created_utc; } if (ctx._source.is_deleted == null) { ctx._source.is_deleted = false; } if (!ctx.containsKey('data') || !(ctx.data.containsKey('@error') || ctx.data.containsKey('@simple_error'))) return null;def types = [];def messages = [];def codes = [];def err = ctx.data.containsKey('@error') ? ctx.data['@error'] : ctx.data['@simple_error'];def curr = err;while (curr != null) { if (curr.containsKey('type')) types.add(curr.type); if (curr.containsKey('message')) messages.add(curr.message); if (curr.containsKey('code')) codes.add(curr.code); curr = curr.inner;}if (ctx.error == null) ctx.error = new HashMap();ctx.error.type = types;ctx.error.message = messages;ctx.error.code = codes;" + } +} +``` + +### Delete the previous Event Template: + +```json +DELETE _template/events-v1 +``` + +## Upgrading from v2 to v3 + +_Please note that upgrading from [v2](https://github.com/exceptionless/Exceptionless/releases/tag/v2.0.0) to [v3](https://github.com/exceptionless/Exceptionless/releases/tag/v3.0.0) requires that `Redis` is installed and configured._ + +1. Download and extract the [v3](https://github.com/exceptionless/Exceptionless/releases/tag/v3.0.0) release to a temp folder. +2. Update the connection strings in the `App_Data\JobRunner\Job.exe.config` config file. + 1. You'll also need to add a `Migration:MongoConnectionString` connection string for the migration jobs to run. + + ```xml + + ``` + +3. Open the terminal and run the following jobs to migrate data from previous major versions of Exceptionless. `Jobs.exe` can be found in the `\wwwroot\App_Data\JobRunner\` folder. + +```powershell +Job.exe -t "Exceptionless.EventMigration.OrganizationMigrationJob, Exceptionless.EventMigration" -s "Exceptionless.Core.Jobs.JobBootstrapper, Exceptionless.Core" +``` + +## Upgrading from v1 to v3 + +_Please note that upgrading from v1 to [v3](https://github.com/exceptionless/Exceptionless/releases/tag/v3.0.0) requires that `Redis` is installed and configured._ + +1. Download and extract the [v3](https://github.com/exceptionless/Exceptionless/releases/tag/v3.0.0) release to a temp folder. +2. Update the connection strings in the `App_Data\JobRunner\Job.exe.config` config file. + 1. You'll also need to add a `Migration:MongoConnectionString` connection string for the migration jobs to run. + + ```xml + + ``` + +3. Open the terminal and run the following jobs to migrate data from previous major versions of Exceptionless. `Jobs.exe` can be found in the `\wwwroot\App_Data\JobRunner\` folder. + +```powershell +Job.exe -t "Exceptionless.EventMigration.StackMigrationJob, Exceptionless.EventMigration" -s "Exceptionless.Core.Jobs.JobBootstrapper, Exceptionless.Core" +Job.exe -t "Exceptionless.EventMigration.QueueEventMigrationsJob, Exceptionless.EventMigration" -s "Exceptionless.Core.Jobs.JobBootstrapper, Exceptionless.Core" +Job.exe -t "Exceptionless.EventMigration.EventMigrationJob, Exceptionless.EventMigration" -c -s "Exceptionless.Core.Jobs.JobBootstrapper, Exceptionless.Core" +Job.exe -t "Exceptionless.EventMigration.OrganizationMigrationJob, Exceptionless.EventMigration" -s "Exceptionless.Core.Jobs.JobBootstrapper, Exceptionless.Core" +``` diff --git a/docs/docs/setting-log-levels.md b/docs/docs/setting-log-levels.md new file mode 100644 index 0000000000..3f8858944e --- /dev/null +++ b/docs/docs/setting-log-levels.md @@ -0,0 +1,49 @@ +--- +title: "Log Levels" +--- + +# Log Levels + +Setting log levels allows you to control the flow of data into your Exceptionless account. This is important when you are trying to filter the signal from the noise. In most error monitoring services, you would need to manually configure what log levels are used to send events by customizing your code. With Exceptionless, you can update the log levels used right in the Exceptionless UI. + +To configure your default log levels, go to your project settings page by clicking the project name dropdown in the top left of the header. Hover over your project name, then click the gear icon. Once on the project settings page, click the Settings tab. Here, you will see the default log level options. + +![Log Level Settings](img/default_log_levels.png) + +You can change this at the project level or override the setting on the Stacks page. To override the global log level, click on "Log Messages" on the left side of your screen: + +![Log Levels](./img/logleveldashboard.png) + +Next, you'll want to do one of two things: + +### 1. Click on "New Stacks" and then click on the log stack you'd like to change. + +The new stacks tab is on the left under Log Messages: + +![new stacks](./img/newstacks.png) + +When you click that link, you can click on the log stack and it will take you to this page: + +![log stack](./img/logstack.png) + +### 2. You can click on a log message event from the Log Messages -> Events dashboard or the All -> Events dashboard, then you can click on a particular log message and click Go To Stack. + +If you click Events, you'll see all log events (or all events depending on the dashboard you've chosen): + +![log message events](./img/logmessageevents.png) + +Then, click on the event and you'll be taken to a details page for that event where you will see a "Go To Stack" button: + +![log details](./img/logdetails.png) + +### Overriding Global Log Levels + +Now, you can override the global log levels for your account. Simply click the log level dropdown, select the new log level setting you'd like to capture in your stacks, and events of the same type or above will be captured, but any log levels below the type selected will no longer be captured. + +![override](./img/override.png) + +As with Data Exclusions, updates to project level and global log level settings will be passed down to the Exceptionless client in near real-time. While the Exceptionless server will catch event that should not be included in your dashboard, the client will catch them based on your configuration and prevent them from ever being sent to the server. Read more about [Project Settings](/docs/project-settings) here. + +--- + +[Next > De-Duplication](/docs/deduplication) diff --git a/docs/docs/user-sessions.md b/docs/docs/user-sessions.md new file mode 100644 index 0000000000..f2f827cf3a --- /dev/null +++ b/docs/docs/user-sessions.md @@ -0,0 +1,80 @@ +--- +title: "User Sessions" +--- + +# User Sessions + +With user session tracking, you can easily see what a user is doing that leads up to an event occurrence, or just see how they are using your app. + +Each session has a list of events (feature usages, exceptions, log messages, etc) that the user triggered. Each can be clicked on to drill down. + +![Exceptionless User Session Events](img/sessions-event-tab-user-footsteps.jpg) + +Browser and environment information, along with any other data that persists throughout the user session is stored as well. + +Once you set up session tracking, you can find the report under Reports > Sessions, or click on the unique session id in any event's overview tab. + +![Exceptionless Sessions Report](img/dashboard-nav.jpg) + +## Turn On Session Tracking + +Set a default user identity via the following client methods to send the user ID for each event. Once set, it will be applied for all future events. + +### C# Set User Identity Example + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.SetUserIdentity("UNIQUE_ID_OR_EMAIL_ADDRESS", "Display Name"); +``` + +### JavaScript Set User Identity Example + +```javascript +exceptionless.ExceptionlessClient.default.config.setUserIdentity('UNIQUE_ID_OR_EMAIL_ADDRESS', 'Display Name'); +``` + +**Please Note: In WinForms and WPF applications**, a plugin will automatically set the default user to the `Environment.UserName` if the default user hasn’t been already set. Likewise, if you are in a web environment, we will set the default user to the request principal’s identity if the default user hasn’t already been set. + +**If you are using WinForms, WPF, or a Browser App**, you can enable sessions by calling the `UseSessions` extension method. + +### C# Use Sessions Example + +```csharp +using Exceptionless; +ExceptionlessClient.Default.Configuration.UseSessions(); +``` + +### JavaScript Use Sessions Example + +```javascript +exceptionless.ExceptionlessClient.default.config.useSessions(); +``` + +## Manually Send SessionStart, SessionEnd, and heartbeat Events + +You can use our client API to start, update, or end a session. Just remember, a user identity must be set. + +### C# Submit Session Events Example + +```csharp +using Exceptionless; +ExceptionlessClient.Default.SubmitSessionStart(); +await ExceptionlessClient.Default.SubmitSessionHeartbeatAsync(); +await ExceptionlessClient.Default.SubmitSessionEndAsync(); +``` + +### JavaScript Submit Session Events Example + +```javascript +exceptionless.ExceptionlessClient.default.submitSessionStart(); +exceptionless.ExceptionlessClient.default.submitSessionHeartbeat(); +exceptionless.ExceptionlessClient.default.submitSessionEnd(); +``` + +## Disable Heartbeat + +If you would like to disable the near real-time session tracking heartbeat that goes out ever 30 seconds, you can pass `false` as an argument to the `UseSessions()` method. + +--- + +[Next > Notifications](/docs/notifications) diff --git a/docs/docs/versioning.md b/docs/docs/versioning.md new file mode 100644 index 0000000000..033b1aaada --- /dev/null +++ b/docs/docs/versioning.md @@ -0,0 +1,42 @@ +--- +title: "Versioning" +--- + +# Versioning + +You can mark error stacks fixed and they won't show up or notify you until they regress! + +## How does this work? + +When an event comes into Exceptionless, we figure out what makes it unique and place it into a stack of similar events. This means that an error comes in, it will be placed in a stack of similar error events. All events may contain an application version, this can be used to track what versions of an application are causing errors or being actively used. + +## How do I specify an application version? + +An application version will try and be resolved if possible, but it's a good idea to specify a version if you can. Please view the client specific documentation below to learn more about setting an app version. + +## Choose your Client + +* [.NET](/docs/clients/dotnet/) +* [JavaScript / Node.js](/docs/clients/javascript/client-configuration) + +## What does mark fixed do? + +![Exceptionless Mark Fixed](img/versioning.png) + +When you mark a stack as fixed, the following meta data is recorded on the stack: + +* when the stack was fixed +* and **optionally** the semantic version that you fixed this behavior in. + +> **NOTE:** If you are using a **four-part version number** (E.G., `1.2.3.4`), you'll need to enter it as `1.2.3-4`. We will automatically handle this conversion when processing events. + +Next, all stack event occurrences are marked as fixed and will be hidden from all dashboards. You can show fixed events in dashboards by updating the search box with `*` or `fixed:true`. + +This meta data is then inspected when an matching event is processed to determine if the stack and all occurrences should be regressed (_marked not fixed_). There are two scenarios where a stack will be marked as regressed: + +1. If no fixed in version is specified, any occurrence with a date newer than the date the stack was marked as fixed. +2. If a fixed in version is specified, any occurrence that has a newer version specified (Example: `1.0.0` > `1.0.0-beta`). + +--- + +[Next > Reference Ids](/docs/references-ids) diff --git a/docs/index.vto b/docs/index.vto new file mode 100644 index 0000000000..ed07bafa08 --- /dev/null +++ b/docs/index.vto @@ -0,0 +1,206 @@ +--- +title: Home +layout: layouts/base.vto +description: Real-time exception reporting for ASP.NET, Web API, WebForms, WPF, Console, and MVC applications. Includes event organization, notifications, and more. +extraStyles: + - /assets/cyclone-slider-pro/templates/standard/style.css +--- +
+
+
+
+
+
Exceptionless Dashboard
+
+

Don't let your users walk away in frustration

+

Discover errors in your app you never knew were happening and use detailed error reports to + squash them with ease. Make your app Exceptionless!

Sign up for FREE!
+
+
+
+

Exceptionless makes error reporting a breeze

+

Simply install the client and begin collecting unhandled exceptions right away. Use our fluent + API to send additional details about critical errors and be notified immediately.

Take the Tour
+
+
Exceptionless submission code sample
+
+
+
+
+
+
Exceptionless logs tracking
+
+

Report Logs, Feature Usages, and more!

+

You can send any type of event to your Exceptionless dashboard. Create tags for organization, and + you've got a robust event logging system!

Sign up for + FREE!
+
+
+
+

Fork Us! Exceptionless is Open Source

+

Join the community and help us make the software world a better place. Collaborate, give + feedback, report bugs, and host Exceptionless yourself - for free.

Fork Us on GitHub!
+
+
Exceptionless on GitHub
+
+
+
+
+ +
+
+ + + +
+
+
+ +
Exceptionless Customers & Users
+
Exceptionless Users & Customers
+

What Is Exceptionless?

+
+

The definition of the word exceptionless is: to be without exception. Our product provides real-time error, feature, and log reporting for your ASP.NET, Web API, WebForms, WPF, Console, and MVC apps. It organizes the gathered information into simple actionable data that will help your app become exceptionless. Best of all, it’s open source!

+
    +
  • +
    +
    Error notifications, including critical and regressions
    +
  • +
  • +
    +
    Easily see top errors and prioritize them
    +
  • +
  • + +
    Intelligent grouping of exceptions, logs, and features
    +
  • +
  • +
    +
    Dashboard with event stats and trends
    +
  • +
  • +
    +
    Detailed error reports, including stacktrace
    +
  • +
  • +
    +
    Add any custom objects to your events
    +
  • +
  • +
    +
    Unlimited users per organization
    +
  • +
  • +
    +
    Mark exceptions as fixed, monitor for regressions
    +
  • +
  • +
    +
    Real-time view of events as they happen
    +
  • +
  • +
    +
    Ability to mark events as being critical
    +
  • +
  • +
    +
    Supports offline and occasionally connected scenarios
    +
  • +
  • +
    +
    Easy setup in less than 5 minutes
    +
  • +
+
+

How Does It Work?

+
+
+

1. Create a free account

+

Signup in seconds – No credit card required

+
+
+
+

2. Install the client

+

Install the Exceptionless client from NuGet

+
+
+
+

3. See your exceptions

+

Done – Start tracking & fixing those exceptions!

+
+
+
+ + +
+ +
+
diff --git a/docs/news/2013/2013-08-06-exceptionless-1-1-0-released.md b/docs/news/2013/2013-08-06-exceptionless-1-1-0-released.md new file mode 100644 index 0000000000..2467e91e1c --- /dev/null +++ b/docs/news/2013/2013-08-06-exceptionless-1-1-0-released.md @@ -0,0 +1,18 @@ +--- +title: "Exceptionless 1.1.0 Released" +--- + +# Exceptionless 1.1.0 Released + +## Features + +* Added ability to visually select a custom date range, giving you the ability to investigate spikes. +* Added ability to add reference links to error stacks. +* Added web hook and Zapier support. +* Added daily summary notification. +* Added ability to filter out hidden and 404 errors. +* Added ability to promote stacks to external services. +* Added ability to add reference links to stacks. +* Added ExceptionlessWcfHandleErrorAttribute to Exceptionless.Web package. +* Minor visual improvements and fixes for mobile and desktop layouts. +* Numerous bug fixes and other enhancements. diff --git a/docs/news/2013/2013-08-06-introducing-exceptionless.md b/docs/news/2013/2013-08-06-introducing-exceptionless.md new file mode 100644 index 0000000000..3371681bb3 --- /dev/null +++ b/docs/news/2013/2013-08-06-introducing-exceptionless.md @@ -0,0 +1,32 @@ +--- +title: "Introducing Exceptionless" +date: 2013-08-06 +--- + +# Introducing Exceptionless + +**[Exceptionless](/ "What is Exceptionless?")** is a new error reporting service that helps you answer important questions about the software that you build. + +* Do you know when and how your app is failing? +* Are my users running into issues and walking away? +* What are the top issues that I should be fixing? +* What issues are affecting the most people and would give me the highest ROI when fixed? +* Is my app getting more or less stable with each release over time? + +The definition of the word exceptionless is: **to be without exception**. Our product provides real-time error reporting for your apps. It organizes the gathered information into simple actionable data that will help your app become exceptionless! + +![Exceptionless Dashboard](/assets/img/news/dashboard1.png) + +You can integrate **Exceptionless** into your application in a matter of seconds and start getting the answer to all these questions right now! It’s simply a matter of adding our library and setting your sAPI key. + +**Exceptionless** gives you a look at your application health and allows you to take a closer look at how oftern errors occur. You can dive into a specific error stack to get detailed information about an error. You can also mark an error as fixed or hide an error completely. + +![Exceptionless Error Stack](/assets/img/news/stack.png) + +We believe that all app developers should strive to be **Exceptionless** and that’s why we are offering a FREE plan! It’s easy to get started, so what are you waiting for?? + + + + [Sign Up For **FREE** Now!](https://be.exceptionless.io/signup) + + diff --git a/docs/news/2013/2013-12-19-exceptionless-1-2-0-released.md b/docs/news/2013/2013-12-19-exceptionless-1-2-0-released.md new file mode 100644 index 0000000000..87e2d38b23 --- /dev/null +++ b/docs/news/2013/2013-12-19-exceptionless-1-2-0-released.md @@ -0,0 +1,29 @@ +--- +title: "Exceptionless 1.2.0 Released" +--- + +# Exceptionless 1.2.0 Released + +## Server Features + +* Added ability to copy extended data to the clipboard. +* Added ability to copy stack traces to the clipboard. This is very useful when you have an obfuscated stack trace and wish to decode it. +* Added ability to purchase yearly billing plans. +* Added the ability to consume the rest api with an `apikey` query string parameter. +* We now show friendly error messages when an error occurs while downgrading or upgrading billing plans. +* Numerous improvements to the project configuration page. +* Numerous bug fixes and performance enhancements. + +## Client Features + +Update your NuGet packages to take advantage of these improvements! + +* Added support for MVC5 and Web API 2.0. +* Improved the detection and ignoring of duplicate errors to prevent them from being reported. +* The client now excludes dynamic assemblies from the modules error report section. +* AddObject now serializes objects to a depth of 5 by default. +* Fixed a couple bugs that may occur when multiple client instances are running on the same machine concurrently. +* Fixed a bug with the ExceptionlessWcfHandleErrorAttribute where it wouldn't catch errors when aspNetCompatibilityEnabled was set to false. +* The client now submits errors to [collector.exceptionless.com/api/v1/error](https://collector.exceptionless.com/api/v1/error). +* Fixed a bug that would prevent the Windows Form client from showing the Crash Report dialog. +* Fixed a bug where multiple HttpModule sections could be added by the NuGet installer. diff --git a/docs/news/2013/2013-12-19-find-customer-facing-bugs-with-exceptionless-case-study.md b/docs/news/2013/2013-12-19-find-customer-facing-bugs-with-exceptionless-case-study.md new file mode 100644 index 0000000000..f30edda416 --- /dev/null +++ b/docs/news/2013/2013-12-19-find-customer-facing-bugs-with-exceptionless-case-study.md @@ -0,0 +1,28 @@ +--- +title: "Find Customer Facing Bugs with Exceptionless - Case Study" +date: 2013-12-19 +--- + +# Find Customer Facing Bugs with Exceptionless - Case Study + +## The Power of .NET Error Reporting + +![ApexCCTV Logo](/assets/img/news/header-logoNew.png) One of our long time customers, ApexCCTV, recently described how Exceptionless' .NET error reporting allowed them to find and squash a bug that was causing their website to be completely unusable by some customers. + +Because of the e-commerce development environment being used, this issue would not have been brought to their attention without the implementation of Exceptionless, making this a prime example of how powerful the tool is and what it can mean for all types of .NET web applications. + +### What customers were experiencing + +> "After a site upgrade, **every page** of the site was crashing if the customer had been previously logged in." - ApexCCTV + +So, if a user had selected the "keep me logged in" box the last time they logged in, prior to the update, nothing was working for them. + +### The cause + +When a customer logs in, a secure cookie for that user is created behind the scenes. The code update had changed the format of the cookie, but not the name, so when a user visited the site with the old cookie, the authentication was breaking. This was throwing errors and crashing the site for the customer, but because the development team clears cookies regularly, and no one had reported any issues, the exceptions were flying under the radar. + +### The fix + +Exceptionless logged and reported the error, and the fix was easy - simply change the cookie name so that users were forced to get a fresh cookie the next time they visited the site. Bam, done! Users could then happly log in and buy [security cameras](http://www.apexcctv.com) without any issues. + +There could be, and a lot of the times are, errors like this in any .NET project, and using a real-time exception reporting tool like Exceptionless can really be an asset, saving time, money, and customers. diff --git a/docs/news/2013/2013-12-24-net-exception-reporting-why-you-need-it.md b/docs/news/2013/2013-12-24-net-exception-reporting-why-you-need-it.md new file mode 100644 index 0000000000..70b6bec328 --- /dev/null +++ b/docs/news/2013/2013-12-24-net-exception-reporting-why-you-need-it.md @@ -0,0 +1,55 @@ +--- +title: ".NET Exception Reporting and Why You Need It" +date: 2013-12-24 +--- + +# .NET Exception Reporting and Why You Need It + +We have all worked on projects, large and small, where tiny, one-off bugs went unnoticed for _a while_ before they were finally reported by a user or discovered by a developer. In some instances, these bugs probably affected the end-user's ability to use the service, purchase an item, etc, meaning that there was a direct impact on the bottom line. + +What if you didn't have to worry about .NET exceptions going unnoticed anymore? + +## Enter real-time .NET exception reporting + +![Exceptionless ASP.NET Error Reporting](/assets/img/news/toexceptionless1-300x150.png) + +What .NET developers needed was a tool that focused on error reporting by logging, grouping, and sending notifications. They needed flexibility through custom objects and a fluent API. They needed every error detail presented in a organized, readable manner. The even needed charts that clearly showed their progress in squashing the tens, hundreds, or thousands of daily exceptions that they didn't know they were occurring. + +We needed all that, too, so **we built a tool that does it all for us!** + +### What a .NET exception reporting tool has up its sleeves + +When we set out to build Exceptionless, we went through hundreds of possible features, and even toyed with building a larger product that including other functionality, but in the end we decided we wanted it to do the following things really well. + +* Send error **notifications** +* **Group exceptions** intelligently into stacks +* **Show top errors** and allow them to be **prioritized** +* Provide **detailed error reports**, including **stacktrace** +* Have a **dashboard** with an immediate view of error statistics and trends +* Allow **custom objects** to be added to reports +* Allow **unlimited users** per organization +* Give developers a way to **mark exceptions critical, fixed, or ****monitor for regressions** +* Provide **real-time updates**, as exceptions happen +* **Support offline usability** in scenarios where the developer is traveling, etc +* Be able to be **installed in less than 5 minutes** + +### Why Exceptionless is a must-try for .NET developers + +**You should give it a shot if:** + +* Finding that bug 2 weeks sooner could have saved you or your company a lot of money +* Customers were lost because of a bug on production that you couldn't see locally or in the development environment +* You fixed a bug in one spot, only to find out that it was happening in several other places as well +* There might be errors here or there, but they probably aren't affecting very many users _(hint: they probably are)_. +* You or your team are making a lot of changes in the next sprint, and you really want to make sure you know when a bug gets introduced +* _and the list goes on..._ + +#### And of course, we're here to help! + +If you have any issues or questions, just let us know! You can [contact us here on the website](/contact/ "Contact Us"), or via the support button on your Exceptionless dashboard. + + + + [Try It for **FREE**](https://be.exceptionless.io/signup) + + diff --git a/docs/news/2014/2014-01-04-find-leaking-exceptions-eliminate-empty-catch-block.md b/docs/news/2014/2014-01-04-find-leaking-exceptions-eliminate-empty-catch-block.md new file mode 100644 index 0000000000..6c76b4277d --- /dev/null +++ b/docs/news/2014/2014-01-04-find-leaking-exceptions-eliminate-empty-catch-block.md @@ -0,0 +1,47 @@ +--- +title: "Find Leaking Exceptions by Eliminating Empty Catch Blocks - Case Study" +date: 2014-01-04 +--- + +# Find Leaking Exceptions by Eliminating Empty Catch Blocks - Case Study + +## How a client eliminated 50+ exceptions/hour + +Recently, a client contacted us and gave us a pretty incredible case study. He found a huge number of "leaking" exceptions by eliminating all of the empty catch statements in his ASP.NET code and sending an exception to Exceptionless instead. By doing so, he was able to track down about **12 individual bugs** and get rid of **over 50 exceptions per hour** by fixing them. That's **1200+ exceptions per day** - gone! + +> "This gave us a picture of just how many poorly written methods were leaking exceptions. The answer was, A LOT. So, even though these weren't customer facing, they were expensive and a good indicator of code quality. In just a couple of days, we were able to eliminate the majority of them completely." - Eric Burcham + +After speaking with Mr. Burcham further, he explained that while there were only about 12 individual bugs, the number of times that those bugs were occurring in different areas throughout the code (an ASP.NET eCommerce solution) was numerous. Luckily, he was able to use several multi-line find and replace actions to make all the changes relatively quickly and get things back on track. + +## A brief code example + +### Empty .NET catch blocks + +Before using Exceptionless to generated exceptions, the catch blocks were empty. + +```cs +try +{ + // Do Something +} +catch { } +``` + +### Using Exceptionless to generate an exception in the catch block + +By submitting an exception in the catch block, instead, their eyes were opened to thousands of daily exceptions. + +```cs +try +{ + // Do Something +} +catch(Exception ex) +{ + ex.ToExceptionless().Submit(); +} +``` + +### But I can already throw an exception in my catch block... + +While you can throw an exception in a catch block normally with .NET, Eric was able to utilize Exceptionless' intelligent error grouping, notifications, and detailed reporting to pinpoint the problems and deal with them accordingly. Then, he was able to monitor the decline of occurrences and make sure that there were no regressions. That's pretty powerful, we think. diff --git a/docs/news/2014/2014-01-15-project-portal-tour.md b/docs/news/2014/2014-01-15-project-portal-tour.md new file mode 100644 index 0000000000..0e71b9d7e7 --- /dev/null +++ b/docs/news/2014/2014-01-15-project-portal-tour.md @@ -0,0 +1,130 @@ +--- +title: "An In-Depth Look at the Exceptionless Project Portal" +date: 2014-01-15 +--- + +# An In-Depth Look at the Exceptionless Project Portal + +We cover the basic features of the Exceptionless platform on our [feature tour page](/tour "Exceptionless Feature Tour"), but we wanted to give everyone a deeper look into all the information available via the web-based, real-time .NET error reporting admin area. + +Continue reading to learn more. + +## The Dashboard + +![Visual .NET Exception Graph](/assets/img/news/graph.jpg) + +The Exceptionless Dashboard features a quick overview of the exceptions for the currently selected project. It also updates in real-time, so you can watch exceptions roll in. + +This is a great place to glimpse your exceptions by total, unique, new, or per hour. The most frequent and most recent exceptions are also displayed here, along with a graph representing your total and unique exceptions. You can go directly to an error's details by clicking on it. + +**At the top of the page, throughout the admin, you can:** + +* Change the project you are currently viewing +* Go to that projects settings +* Adjust the date range +* Show/Hide hidden errors +* Show/Hide fixed errors +* Show/Hide "Not Found" errors + + +![Exceptionless Date Range Selector](/assets/img/news/date-range-150x150.jpg) +_Show/Hide Errors & Select Date Range_ + + + + + + + + +## View Most Recent, Most Frequent, and New Exceptions + +On the left side of the dashboard, you can select to view your Most Recent, Most Frequent, or New (first time) .NET exceptions. + + +![New .NET Exceptions](/assets/img/news/new-150x150.jpg) +_New Errors_ + + + + + + + + +### Most Recent + +The most recent report lists your errors individually with the one that occurred last at the top. It also tells you exactly how long ago the error occurred. You can click into the exception to view details. + +### Most Frequent and New Exceptions + +Each of these reports lists the respective error type with a summary, the count, when the error first happened, and the last occurrence. Most frequent is ordered by count, and new is ordered by most recent. + +## Lets Take a Look at Exception Details + +### Error Stack Page + + +![Error Stack Options](/assets/img/news/exception-options-150x150.jpg) + + + + + + +If you click into any error, Exceptionless will show you the error stack, which includes the number of occurrences, when it first happened, and the latest re-occurrence. You can adjust the date range on this page, like the rest, and you also get a nice graph of that error's occurrences over time. Each individual time the error triggered is listed below the graph, and you can click into each instance separately. + +**Before we do that, though,** I'd like to point out another major feature of the error stack page.. + +Above and to the right of the graph are two buttons: "Mark Fixed" and "Options". Mark fixed is exactly what it sounds like, and if you click on the "Options" button it drops down with the following choices: + +* Hide from reports +* Promote to external +* Add reference link +* Disable notifications +* Future occurrences are critical +* Reset stats + +### Individual Error Details + +After you click into an individual error instance, you will see the following tabs. + +![.NET Exception Environment Details](/assets/img/news/exception-details-environment-150x150.jpg) + + + + + + +#### Error Overview + +This page shows you a quick overview of the error, including the stack trace. It includes the date and time, type, message, platform, URL, and referrer. You can also go to the previous or next occurrence. + +#### Exception + +This tab displays a few overview details, then gives you a list of loaded modules related to the error. + +#### Request + +The request view gives you the request details, including date and time, http method, url, referrer, client IP, user agent, browser, browser OS, device, and whether or not it's a known bot. You also get Post Data. + +#### Environment + +Because you needed **all** the data, the environment tab displays time and date, machine name, ip address, processor count, total, available, and process memory, OS name, OS version, architecture, runtime version, process ID, process name, and command line details. It also has client information, such as install date, version, platform, submission method, application starts, and errors submitted. + +## What Else Can I Do from the Admin? + +Naturally, you can manager your projects, organizations, and account, but we also have pretty handy feedback and support tools so you can let us know how we're doing! Your feedback and comments are important and provide direction to the code. + +![Exceptionless Support](/assets/img/news/support-150x150.jpg) + + + + + + +In short, the tool offers extremely helpful insights into the world of your web application's bugs. Whether internal or customer-facing, knowing when, where, and how many exceptions are being generated makes it easier for you to track them down and squash them. And when you've fixed it, regression notifications are there to let you know if it rears its ugly head again. + +Still not convinced? Give it a try - [sign up today, for free](https://be.exceptionless.io/signup "Sign up for Exceptionless"). + + diff --git a/docs/news/2014/2014-01-24-server-browser-cookie-error.md b/docs/news/2014/2014-01-24-server-browser-cookie-error.md new file mode 100644 index 0000000000..592ff70f4f --- /dev/null +++ b/docs/news/2014/2014-01-24-server-browser-cookie-error.md @@ -0,0 +1,36 @@ +--- +title: "Catching a Server-Side Browser Cookie Support Error - Case Study" +date: 2014-01-24 +--- + +# Catching a Server-Side Browser Cookie Support Error - Case Study + +Internet Explorer CookiesAs with every new release of software, things change. And, like we all expected, there wasn't an exception to that rule when Microsoft introduced Internet Explorer 10 into the mix. + +Everyone coding for the web had the normal things to worry about, of course, like design formatting, speed, and support, but one of our clients experienced something that would have taken a long time to catch if they hadn't been using Exceptionless' **real-time error reporting**. + +### Who Adopts New Versions of IE Right Away, Anyway? + +Like many, the client's web team doesn't necessarily adopt the latest version of IE right away, much less use it as their main browser. Unfortunately, that leads to little immediate exposure to potential bugs. + +Lets explore how this came back to bite them, and how Exceptionless helped them treat the wound quickly. + +#### A nasty customer-facing error + +Users of the client's eCommerce platform that were already using IE10 were able to view and use the website fine, until they logged in. At that point, everything broke. They couldn't checkout, browse, or submit contact forms. + +Because the team wasn't using IE10 regularly yet for testing actual logged-in user transactions, **they were clueless**! + +Luckily, Exceptionless reported the customers' errors and the team was able to take notice of the recurring bug within days, rather than weeks or months. + +#### Turns out... the problem was server-side! + +After the error was reported in the Exceptionless Dashboard, the team was able to use the attached details to trace the root of the issue back to the server's definitions of which browsers support modern cookie encryption. + +All the server needed was a **routine update** that had not been performed! Bam - fixed. + +#### Another bug bites the dust + +We love to hear stories like this. Something so simple, yet so easy to overlook and cause serious customer-facing problems! + +Errors like this happen every day to hundreds, if not thousands, of small, medium, and large software teams across the world. We just want to help squash as many of them as we can! diff --git a/docs/news/2014/2014-02-03-app-error-notifications.md b/docs/news/2014/2014-02-03-app-error-notifications.md new file mode 100644 index 0000000000..607cee414c --- /dev/null +++ b/docs/news/2014/2014-02-03-app-error-notifications.md @@ -0,0 +1,59 @@ +--- +title: "Receive Error Notifications from Your App via Email" +date: 2014-02-03 +--- + +# Receive Error Notifications from Your App via Email + +Maybe you've got this awesome new web app that you're ready to go live with, or maybe you're working on a project that is already customer facing but you've got major new features rolling out and want to make sure all goes well. + +We both know there's going to be _something_ that isn't completely right after launch. It might be a big bug stopping certain users from placing orders on your site, or it might be something that won't even affect your customers. It might be highly visible, or completely hidden from your view. Either way, you want to know when that error occurs and what the details are. That's where Exceptionless comes in. + +## Real-Time Error Notifications via Email + +![ASP.NET Error Notifications](/assets/img/news/notification.png) + +The Exceptionless platform provides a great [real-time dashboard](/project-portal-tour/ "Error Reporting Dashboard") view of your errors, but our email notifications allow you to be absolutely in touch with any errors that may be occurring within your application. + + + + [Try It Out for **FREE**](https://be.exceptionless.io/signup) + + + +### Notification options + +There are several email notification options for your app's exceptions. + +To receive notifications, you need to turn them on under the "My Account" section, in the "Profile Information" tab. This option should be on by default. Then, you can view the below options under the individual project settings by clicking on the cog/gear icon next to the project name at the top of your dashboard. + +![Email Notification Settings](/assets/img/news/email-notification-settings.png) + +#### Lets take a look at the different options: + + 1. **Daily Project Summary** + This is simply a summary of your project, including error counts, etc, that you can receive each day. + 2. **Critical Errors** + You can mark an individual error as critical, and then check this box to receive email notifications each time that error occurs. + 3. **Error Regressions** + If you have marked an error as fixed, you can check this to get an email notification if it ever rears it's ugly head again. + 4. **Error Occurrence Notification Frequency** + These are fairly self-explanatory. How often would you like to receive emails? + + 1. All Occurrences + 2. New Only + 3. Never + +_**Note:** _You can also turn notifications off for individual errors by going to Options>>Disable Notifications while inside a specific error. + +### Sit back and relax + +... until an error notification comes in, that is. Then you should probably fix it. + + + + [Try It Out for **FREE**](https://be.exceptionless.io/signup) + + + + diff --git a/docs/news/2014/2014-02-07-xml-parsing-exception-caught-fixed-case-study.md b/docs/news/2014/2014-02-07-xml-parsing-exception-caught-fixed-case-study.md new file mode 100644 index 0000000000..5702868735 --- /dev/null +++ b/docs/news/2014/2014-02-07-xml-parsing-exception-caught-fixed-case-study.md @@ -0,0 +1,40 @@ +--- +title: "XML Parsing Exception Caught and Fixed - Case Study" +date: 2014-02-07 +--- + +# XML Parsing Exception Caught and Fixed - Case Study + +This is yet another story of an elusive bug that, without a proper error reporting service, would have gone un-noticed for a very long time. + +When third-party software and services interact with your code, in any way, you have to be wary that their data may be different from yours. In this instance, our client was parsing some XML that included an unfriendly cookie name. Lets see what happened next... + +![.NET Exception Dashboard](/assets/img/news/apexExceptionsRandom.png) + +## Killer Cookies + +[Listrak](http://www.listrak.com/) is a pretty cool company that provides, among other things, a robust email marketing, shopping cart abandonment, and welcome series suite of tools. + +One of their cookies uses a "$" in it's name ($ListrakFoo or similar). When the client's XML Config packages were executed, that $ was causing an XML parsing exception. + +### That's not customer facing. What's the big deal? + +#### 37,000 + +While not directly customer facing, it was happening on almost every page of the website and occurred something like 37,000 times in the span of it's existence. + +#### Sluggish + +Along with the sheer number of occurrences, it was also noticeably slowing the site down. + +### The fix + +The fix was relatively simple. The client now checks for "$" in cookie names within the affected method and just doesn't handle them. + +**Tracking errors like this is what we're all about.** There are hundreds of thousands, probably even millions, of bugs out there _right now_ that throw exceptions every day but manage to remain hidden in the shadows of code written by professional developers. + +It's not a sign of poor programming, it simply comes with the territory. You will have bugs, big and small, in every project you work on. The difference is, with Exceptionless, you can actually be aware of, and fix, them! + +Another bug bites the dust, thanks to help of Exceptionless' [real-time exception reporting](https://exceptionless.com "Real Time Exception Reporting")! + +Do you have a story where our software helped you track down and squash an elusive error? Let us know! We'll publish the details and link back to your app, if you like. diff --git a/docs/news/2014/2014-02-13-exceptionless-1-3-released.md b/docs/news/2014/2014-02-13-exceptionless-1-3-released.md new file mode 100644 index 0000000000..ef41ddb22c --- /dev/null +++ b/docs/news/2014/2014-02-13-exceptionless-1-3-released.md @@ -0,0 +1,27 @@ +--- +title: "Exceptionless 1.3 Released" +date: 2014-02-13 +--- + +# Exceptionless 1.3 Released + +Exceptionless 1.3 brings with it both server and client changes, including [open sourcing the project](/fork-us-exceptionless-goes-open-source/ "Exceptionless Goes Open Source!") (which we're super excited about!), some minor updates, and a few bug fixes. Check out the changelog items below, and let us know if you have any questions. + +## Server + +* Open sourced the server under the [GNU Affero General Public License, Version 3.0](http://www.gnu.org/licenses/agpl-3.0.html)! +* Extended data key names are now shown with friendly formatted name. +* Summary notification emails that were not sent out and are older than two days will be ignored by the email job. This will help prevent users from being spammed in some circumstances. +* Fixed a major application start up performance bug that had to do with dependency injection. +* Fixed a bug that was causing the key-up event to be cancelled on every page that had a chart. This affected modals from working properly in some scenarios. +* The following improvements were made specifically to make local development and internal deployments easier: + * Added the ability to add or remove a user from the admin role. + * When you are running exceptionless in development mode and you are the first user to signup for an account, a new sample project with a sample api key will be created. + * When billing is not configured, all new organizations will be placed in an unlimited plan. + +## Client + +* Open sourced the client under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)! +* Symbols are now available on [http://www.symbolsource.org/](http://www.symbolsource.org/). Documentation on configuring visual studio can be found [here](http://www.symbolsource.org/Public/Home/VisualStudio). +* Adding binding redirects to the right version. +* Data Exclusions now [support wildcards](/docs/security). \ No newline at end of file diff --git a/docs/news/2014/2014-02-18-fork-us-exceptionless-goes-open-source.md b/docs/news/2014/2014-02-18-fork-us-exceptionless-goes-open-source.md new file mode 100644 index 0000000000..9320df2989 --- /dev/null +++ b/docs/news/2014/2014-02-18-fork-us-exceptionless-goes-open-source.md @@ -0,0 +1,55 @@ +--- +title: "Fork Us! Exceptionless Goes Open Source" +date: 2014-02-18 +--- + +# Fork Us! Exceptionless Goes Open Source + +**![GitHub Octocat](/assets/img/news/Octocat-300x249.png)It's a big day at Exceptionless.** + +We are super excited to announce that we are [open sourcing the Exceptionless code](https://github.com/exceptionless/Exceptionless)! That's right, now you can hack on our real-time error reporting tool yourself. + +Too many apps are throwing too many errors out there, resulting in confused users, lost business, and endless frustration. + +We believe Exceptionless can help the development community become more in-tune with their code by making those errors more transparent, trackable, and squashable. More importantly, we want to support developers building and shipping better code for their **users**. + + + +## Cool, Where Do I Start? + +Check out the [Exceptionless Github Repository](https://github.com/exceptionless/Exceptionless), and make sure to [read about contributing](https://github.com/exceptionless/Exceptionless/blob/master/CONTRIBUTING.md) if you plan on helping us improve the project. + +You'll find instructions on getting started there, including setting up your hosting environment if you want to host things yourself. If you would rather host with us, we offer [easy and affordable plans](/pricing). + +If you have a feature request or issue, let us know on the [issue tracker](https://github.com/exceptionless/Exceptionless/issues). We are **100% committed** to supporting the project. + +## Why Open Source? + +In short, we want to see what the community can do with our baby, which we consider a great development tool. The open source movement has provided innovation throughout the industry, and we cannot tell you how excited we are to be a part of it. + +We hope you will take it, add to it, suggest great new features, and report bugs, but most of all we hope you will use it to **build better apps for the world**. + +The Exceptionless Team will continue to work on a road map of features and improvements, all while providing support to developers that want to contribute. + +### Planned features/enhancements + +* Refactor client so that the base client is a PCL library thus supporting WinRT and Mono. +* Implement search features using ElasticSearch. +* JavaScript client for reporting client side errors. +* Refactor the API and UI to be completely separate layers and rewrite the UI as a SPA app using AngularJS. +* Add a server side plugin system that allows new functionality to be easily added like HipChat notifications. + +### Ideas for the community + +These include just a few of feature requests, etc, that aren't in the team's immediate pipeline that you might consider tackling. + +* Clients for Ruby, Java, Python, PHP, etc +* Ability to log non-exception data +* Teams within organizations +* Bookmarks + +### Lets make something awesome + +We have spent a lot of time on Exceptionless, but together with the community we can take it to the next level. Check out the [GitHub repo](https://github.com/exceptionless/Exceptionless) today, and happy coding! + +**Watch out, exceptions!** diff --git a/docs/news/2014/2014-02-25-installing-excteptionless-github.md b/docs/news/2014/2014-02-25-installing-excteptionless-github.md new file mode 100644 index 0000000000..7e9a15382f --- /dev/null +++ b/docs/news/2014/2014-02-25-installing-excteptionless-github.md @@ -0,0 +1,47 @@ +--- +title: "Installing Exceptionless from GitHub" +date: 2014-02-25 +--- + +# Installing Exceptionless from GitHub + +Since we officially announced that Exceptionless was going open source last week, we wanted to provide everyone with a quick and easy video walkthrough of how to get up and running locally. + +It's really quick, as you can see from the below video. Below the video is also a textual walkthrough. Please take a look and let us know if you have any questions. + +Please note that before contributing to the Exceptionless project, you must read and sign the Exceptionless [Contribution License Agreement](http://www.clahub.com/agreements/exceptionless/Exceptionless). Pull requests will not be accepted otherwise. + +### GitHub Exceptionless Getting Started Video + +https://www.youtube.com/watch?v=wROzlVuBoDs + +### Text Guide + +1. Log in to github +2. Install the [GitHub Windows client](https://windows.github.com/), if you want to use the GUI. If not, you can do the rest of the steps from command line. +3. Fork the [Exceptionless repository](https://github.com/exceptionless/Exceptionless) +4. Clone the repo to your machine (Clone to Desktop) +5. Open your local repository you just cloned +6. Follow the "[Getting Started](https://github.com/exceptionless/Exceptionless#getting-started)" section of github readme. +7. Start StartBackendServers.bat file to start redis and mongodb +8. Open the Exceptionles solution in Visual Studio +9. Right click solution and select select "set startup projects" +10. Click on "Multiple startup projects" +11. Locate Exceptionless.app and Exceptionless.SampleConsole and change them to "Start" +12. Rebuild the solution to pull down the NuGet packages +13. Start Debugging +14. A console app and Internet explorer instance will start +15. Go to the browser and create a (sample) account. This will create a sample organization and project. +16. You will be redirected to the dashboard for the new project +17. Go back to the console app and hit 1. A new error will be generated and your Exceptionless dashboard should reflect the error in real-time. +18. Now, after you make any changes or updates, you will want to do a pull request. +19. To do so, commit working, tested changes to the project. +20. Then, sync the changes +21. Go back to github and click on the green compare, review, or create a pull request icon. +22. Review the updates and make sure the pull request includes the proper changes. +23. Click "Create a Pull Request" +24. Add any comments relevant to the pull request. Details are great! +25. Click "Send Pull Request" +26. The Exceptionless Team will review the request and merge it into the project, provide feedback, etc. + +Please let us know if you have any questions. Happy coding! diff --git a/docs/news/2014/2014-03-05-new-support-nancyfx-thanks-luisrudge.md b/docs/news/2014/2014-03-05-new-support-nancyfx-thanks-luisrudge.md new file mode 100644 index 0000000000..9074f81f56 --- /dev/null +++ b/docs/news/2014/2014-03-05-new-support-nancyfx-thanks-luisrudge.md @@ -0,0 +1,42 @@ +--- +title: "New Support for NancyFX - Thanks Luisrudge!" +date: 2014-03-05 +--- + +# New Support for NancyFX - Thanks Luisrudge! + +**NancyFX LogoWe've had our first substantial pull request!** + +Luisrudge has become the first non-trivial contributor to the Exceptionless real-time error reporting project on GitHub, with his NancyFX integration. + +If you're a NancyFX user, you can find the [Nancy package](http://www.nuget.org/packages/Exceptionless.Nancy/) in our NuGet gallery. + +As a token of our appreciation, Luis received a free year of hosting! Thanks again Luis! Read more about contributing and getting free hosting below. + +### What's NancyFX? + +> "Nancy is a lightweight, low-ceremony, framework for building HTTP based services on .Net and Mono. The goal of the framework is to stay out of the way as much as possible and provide a super-duper-happy-path to all interactions." + +* Built from the ground up (not simply a DSL on another framework) +* Removed underlying framework limitations and feature hacks +* Removed need to reference assemblies you don't need, keeping things light +* Ability to run anywhere, including ASP.NET/IIS, WCF, self hosted, and any OWIN out of the box +* Super lightweight action declarations for GET, HEAD, PUT, POST, DELETE, OPTIONS and PATCH requests +* View engine integration for Spark, Razor, dotLiquid, SuperSimpleViewEngine, and others +* Request path matching with advanced parameter capabilities, plus the ability to replace the path matching strategy with custom implementations for your needs +* Easy response syntax, enabling you to return things like int, string, HttpStatusCode and Action elements without having to explicitly cast or wrap your response - you just return it and Nancy will do the work for you +* A powerful, light-weight, testing framework to help you verify the behavior of your application +* Content negotiation +* And more... + +Visit the [website](http://nancyfx.org/) or check out the [GitHub Repo](https://github.com/NancyFx/Nancy) for more information. + +### Contribute & Get Free Hosting + +We love pull requests! + +Anyone that contributes a non-trivial enhancement or feature to the Exceptionless project will receive one free year of our small hosting plan. + +If you are interested, please read the [contributing documentation](https://github.com/exceptionless/Exceptionless/blob/master/CONTRIBUTING.md) for more details regarding contributing, standards, etc. + +We welcome everyone to participate in helping us build a better coding community with better apps for users everywhere. diff --git a/docs/news/2014/2014-03-10-achievement-unlocked-1000-accounts-8-million-errors.md b/docs/news/2014/2014-03-10-achievement-unlocked-1000-accounts-8-million-errors.md new file mode 100644 index 0000000000..b2c2a309ec --- /dev/null +++ b/docs/news/2014/2014-03-10-achievement-unlocked-1000-accounts-8-million-errors.md @@ -0,0 +1,36 @@ +--- +title: "Achievement Unlocked - 1000 Accounts and Over 8,000,000 Errors Reported!" +date: 2014-03-10 +--- + +# Achievement Unlocked - 1000 Accounts and Over 8,000,000 Errors Reported! + +![8 million errors reported](/assets/img/news/8-million-errors.png)Just over six months ago, we launched Exceptionless with a mission to impact the coding community in a positive way. The goal was, and still is, to help developers find, track, and squash errors, ultimately creating better code for users. + +A few days ago we officially hit **1000 accounts**, and as of today Exceptionless has reported **8,562,499 errors**! We couldn't be more excited! + +Sure, we're busier than ever now, answering emails, conversing with open source contributors on new features, and working on new features ourselves, but seeing something grow this quickly, that we've put so much work into, leaves us with little room to complain. The only real thing we can do is say thank you. + +## Thanks + +We'd like to thank all of our users for using the service, providing feedback, asking the hard questions that make us realize we need to make tweaks here and there, and providing us with direction. + +Also, we would specifically like to thank our beta testers that were with us from the beginning. You know who you are, and without you Exceptionless simply would not be the tool it is today. + +And, of course, we have to thank everyone that has contributed to and forked the project since [we went open source](/fork-us-exceptionless-goes-open-source/ "Exceptionless Goes Open Source") a few weeks ago. 39 forks, 124 [GitHub](https://github.com/exceptionless/Exceptionless)stars, and a NancyFX client so far - not bad! + +## But Wait, There's More! + +They say there's no sleep for the wicked, so we're feverishly working on a few major things that will have big long-term benefits for the app. + +* Moving to Azure for faster, more robust, scaleable hosting +* Simplifying the API to make it easier for new clients to be implemented and improve metric reporting +* JavaScript client + +That's just the tip of the iceberg, of course. The to-do list is ever-growing, but we've got to start somewhere. + +### Let us know what you think + +If you are just now joining the Exceptionless community, let us know what you think. Love it or hate it, we want to know why and how to improve. + +Happy bug hunting! diff --git a/docs/news/2014/2014-03-17-exceptionless-1-4-released.md b/docs/news/2014/2014-03-17-exceptionless-1-4-released.md new file mode 100644 index 0000000000..5412551229 --- /dev/null +++ b/docs/news/2014/2014-03-17-exceptionless-1-4-released.md @@ -0,0 +1,45 @@ +--- +title: "Exceptionless 1.4 Released" +date: 2014-03-17 +--- + +# Exceptionless 1.4 Released + +![Exceptionless Version 1.4](/assets/img/news/version1.4.png)Exceptionless 1.4 brings with it both server and client changes, a new client integration, some minor updates, and lots of bug fixes. Check out the changelog items below, and let us know if you have any questions. + +We want to extend our thanks again to the developers that have worked on the project since we [went open source](/fork-us-exceptionless-goes-open-source/ "Exceptionless Goes Open Source") a few weeks ago. See their contributions below, along with links to their GitHub profiles. + + +## Server + +* The app will now be displayed in full screen mode on iOS devices (via Add to Home Screen). +* Added the ability to view the status page while in maintenance mode. +* Added the ability disable error processing on the error controller. +* Various usability improvements dealing with chart date-range selection. +* Added documentation link on the sidebar. +* Added checks to limit the number of max results returned from various API methods. +* Add new indexes to help performance and fix some inefficient queries. +* Changed the way we are filtering fixed and hidden errors to be more efficient. +* Updated all indexes to be created in the background if they don't already exist. +* Switched the JavaScriptEngineSwitcher to use JurassicJsEngine. Jurassic has no external dependencies on IE or Windows specific libraries. +* Fixed a race condition that would throw an exception when updating stats. +* Fixed a bug where the EnforceRetentionLimitsAction was returning all the query results and then paging them. +* The upgrade script now upgrades the database in a background thread. +* Fixed a bug where an error with no stack trace wouldn't be processed. +* Fixed a bug where the list loading indicators could spin non-stop. +* Fixed a bug where errors could be stored with the incorrect DateTimeOffset. This caused inconsistencies between charts and list data. +* Fixed a bug where the error stack's tags were not being synced with the error instances. +* Fixed a bug where the terms and privacy links could point to the wrong domain. +* Fixed a bug where a UriFormatException could be thrown when viewing an error occurrence. This could be caused by third party obfuscators that create a new pdb file. +* Updated the UpgradableJsonMediaTypeFormatter to handle errors gracefully. +* Fixed a bug where the EncodingDelegatingHandler could throw an exception when there was no request content. +* Fixed a bug that could [prevent an error from being processed](https://jira.mongodb.org/browse/CSHARP-893). + +## Client + +* Added support for [Nancy](http://nancyfx.org/)(Contrib: [luisrudge](https://github.com/luisrudge)). +* Better support for low trust environments (Contrib: [obsbne](https://github.com/obsbne)). +* Fixed a bug where the MVC integration could interfere with custom error pages. +* Fixed a bug where a batch of errors wouldn't be sent if an error occurred while sending a previous error in the same batch. +* The client will now attempt to delete an already sent error when ProcessQueue is called. +* Fixed a bug where an exception would occur while deleting the manifest file that was saved by a different or elevated user. diff --git a/docs/news/2014/2014-03-26-whats-included-exceptionless-detailed-error-reports.md b/docs/news/2014/2014-03-26-whats-included-exceptionless-detailed-error-reports.md new file mode 100644 index 0000000000..f2a451e6b1 --- /dev/null +++ b/docs/news/2014/2014-03-26-whats-included-exceptionless-detailed-error-reports.md @@ -0,0 +1,105 @@ +--- +title: "Detailed Error Reports - What's Included?" +--- + +# Detailed Error Reports - What's Included? + +When an error occurs in your app, you need to know the critical details, fast, so you can drill down and fix it. We get it - we're developers too - that's why we built Exceptionless. + +The trick was organizing the data so it didn't overwhelm our users, while still providing all the important stuff so developers wouldn't have to spend extra time tracking down versions, requesting stack traces, or pulling teeth to get environment information. + +Lets take a look at the **default** information included with every error. We say default because you can easily **add your own** information with custom objects. + +## Each Error Occurrence + +Every single error occurrence has the following tabs: + +* Overview +* Exception +* Request +* Environment + +On each of these, you can go to the previous or next occurrence for easy comparison. + +Lets take a closer look at each tab. + +### Error Overview + +![Exception Reporting Overview](/assets/img/news/error-overview-tab-248x300.jpg) + +The overview tab holds general information for that occurrence, including the variables below. Sometimes this is all you'll need to track down the bug. Sometimes you'll need to dig deeper. + +* Occurred On +* Error Type +* Message +* Platform +* URL +* Referrer +* Browser +* Browser OS +* User Name +* Stack Trace + +### Exception Tab + +![Exceptionless Exception Details](/assets/img/news/error-exception-tab.jpg) + + + + On the exception tab, we reference the timestamp, error type, message, and stack trace, while also providing you with all of the loaded modules, including versions. + + + + +### Request Tab + + +![Exceptionless Request Details](/assets/img/news/error-request-tab-225x300.jpg) + +Here we have tons of important request info: + +* Occurred On +* HTTP Method +* URL +* Referrer +* Client IP +* User Agent +* Browser +* Browser OS +* Device +* Is Known Bot +* Cookie Values + + +### Environment Tab + + +![Exceptionless Environment Details](/assets/img/news/error-environment-tab.jpg) + +Environment isn't something that we always think about, but in some cases it can tell us a lot about the exception. We've got you covered! + +* Occurred On +* Machine Name +* IP Address +* Processor Count +* Total Memory +* Available Memory +* Process Memory +* OS Name +* OS Version +* Architecture +* Runtime Version +* Process ID +* Process Name +* Command Line +* Client Information + * Install Date + * Version + * Platform + * Submission Method + * Application Starts + * Errors Submitted + +## How Did We Do? + +We have done our best to include all the important information in an organized, easy to read, intuitive interface. Think we're missing something? Think we can organize it differently? Let us know! We love feedback. diff --git a/docs/news/2014/2014-04-04-exceptionless-now-hosted-azure.md b/docs/news/2014/2014-04-04-exceptionless-now-hosted-azure.md new file mode 100644 index 0000000000..b70c329c3f --- /dev/null +++ b/docs/news/2014/2014-04-04-exceptionless-now-hosted-azure.md @@ -0,0 +1,32 @@ +--- +title: "Exceptionless Now Hosted on Azure" +date: 2014-04-04 +--- + +# Exceptionless Now Hosted on Azure + +[![Microsoft Azure](/assets/img/news/logo1.png)](/assets/img/news/logo1.png)As usual, we've been working on ways to improve the Exceptionless service. + +Due to growing demand for our hosted error reporting plans, we decided to move everything to the Microsoft Azure Cloud platform. + +We completed the move last week and, except for a few small hiccups that were quickly resolved, everything is already running faster across the board! + + + +## Benefits of Azure + +### Bring on the errors! + +As our user base continues to expand, the first priority is to continue providing the best service possible. Azure allows us to guarantee scalability, and has already proven to be **much** faster and more responsive. We're ready for whatever you can throw at us. + +### Focus + +Developing infrastructure takes time, and we would rather be developing the code behind Exceptionless. The move to Azure allows us to do just that, taking a lot off our plate in terms of hosting. It's pretty awesome. + +### Future Azure partner + +In the future, we would like to become an Azure partner and be listed as one of the approved store add-ons. We're not there yet, because we've got to go through the application process, etc, etc, but it's in the works! + +> "Azure is an open and flexible cloud platform that enables you to quickly build, deploy and manage applications across a global network of Microsoft-managed datacenters. You can build applications using any language, tool or framework. And you can integrate your public cloud applications with your existing IT environment." - Microsoft Azure + +We are happy with the move and think it means great things for the future of Exceptionless. We hope our users appreciate the speed and responsiveness, and can see the improvements in service. diff --git a/docs/news/2014/2014-04-11-intelligent-app-error-grouping-helps-organize-exceptions.md b/docs/news/2014/2014-04-11-intelligent-app-error-grouping-helps-organize-exceptions.md new file mode 100644 index 0000000000..c0b909aaae --- /dev/null +++ b/docs/news/2014/2014-04-11-intelligent-app-error-grouping-helps-organize-exceptions.md @@ -0,0 +1,59 @@ +--- +title: "Intelligent App Error Grouping Helps Organize Your Exceptions" +date: 2014-04-11 +--- + +# Intelligent App Error Grouping Helps Organize Your Exceptions + +![Exception Grouping Totals](/assets/img/news/thumbnail.png)Having a tool like Exceptionless to report and log your software's errors is great, but many of our clients experience thousands of instances of each error over various lengths of time, which can become overwhelming quickly. + +We couldn't just leave them with a huge list of individual error occurrences to drudge through, so we went through several different potential options until we devised the best way to group them. + +## Grouping Errors Intelligently + +### What's there to group by? + + 1. The details we provide on each error give us countless ways to group them. While some wouldn't make sense, we considered everything. + +* Date +* Type +* Message +* Platform +* Location +* Browser information +* User information +* Environment information +* Request details +* and more... + +### Drill down fast + +Since we use Exceptionless to report and track down our own bugs, it was easy to put ourselves in our own shoes and think about what would allow us to drill down and fix errors quickly. + +With that mindset, we decided that there were two important error details that should be used for grouping. + + 1. **Where the error occurred** + We felt that, first and foremost, we wanted to know where the error was occurring. Even though there is a possibility it might be occurring in multiple locations, we felt that each location represented its own importance in our grouping scheme. + 2. **Type of error** + The type of error is also very important, and we felt that when you combine type with location, you get a set of errors that holds enough significant explicit data to be recognized as a group. + +## What Grouping Allows Us to Do + +When we group app errors by location and type, it allows us to report error instance counts, first occurrences, frequency of occurrence, and most recent occurrence on the dashboard. + + +[![Error Group Details](/assets/img/news/dashboard-home-150x150.png)](/assets/img/news/group-details.png) +_Error Group Details_ + + + + + + + + +This seemingly basic grouping forms the basis for the different Exceptionless dashboard tabs and pages, thus becoming a major cornerstone for the platform. Click into a group, and you see the title, exception type, and location, along with a graph of occurrences and the most recent occurrences. + +From there, you can drill down into each occurrence and scrutinize all of the [error's details](/whats-included-exceptionless-detailed-error-reports/ "Error Report Details"). + +That's how we do it! Any questions? Let us know. diff --git a/docs/news/2014/2014-04-18-net-error-exception-handling-wpf-mvc.md b/docs/news/2014/2014-04-18-net-error-exception-handling-wpf-mvc.md new file mode 100644 index 0000000000..7f2d339b7b --- /dev/null +++ b/docs/news/2014/2014-04-18-net-error-exception-handling-wpf-mvc.md @@ -0,0 +1,38 @@ +--- +title: "Exception Handling & Logging Tool for ASP.NET, Web API, WebForms, WPF, Console, MVC, and more" +date: 2014-04-18 +--- + +# Exception Handling & Logging Tool for ASP.NET, Web API, WebForms, WPF, Console, MVC, and more + +![Visual .NET Exception Graph](/assets/img/news/graph-300x122.jpg)Having a handle on your code's errors is important. Thousands, if not millions, of exceptions are thrown every day **in production code** without anyone knowing. These errors might be affecting the bottom line, or they could be negligible - either way, it's important to know that they exist, how often they are occurring, and what parts of the app are affected. + +Are you looking for a comprehensive tool that handles logging, reporting, grouping, and notifications for exceptions in your ASP.NET, Web API, WebForms, WPF, Console, MVC, or NancyFX app? Exceptionless does all that, and more. Lets take a look. + +## Who is Exceptionless for? + +Exceptionless is for developers and dev teams that want to have enhanced visibility of errors, track down bugs faster, tighten up code, and produce a better overall product for the end user. + +Currently, the platform is .NET based and has client support for ASP.NET, Web API, WebForms, WPF, Console, MFC, and NancyFX. Soon, we will support clients for JavaScript, PHP, Ruby on Rails, Java, Python, and more. Developers are welcome to [work on supporting other technologies](https://github.com/exceptionless/Exceptionless), as well. **Contributors receive free hosting credits!** + +## Take the Tour + +[![Grouping Error Dashboard](/assets/img/news/dashboard-home-300x198.png)](/assets/img/news/dashboard-home.png)In a nutshell, Exceptionless provides a dashboard, detailed error reports, custom object handling, intelligent error grouping, email notifications, and a fluent API for sending manual error reports. + +[Take a look at the tour page](/tour) for more details on each feature, and follow the the links at the end of each section to read even more about each. Specifically, make sure to check out the [in-depth look at the Exceptionless project portal](/project-portal-tour/)blog post. It has screenshots and explanations for each feature. + +Feel free to [contact us](/contact/) with any questions, or [sign up and take it for a test drive](https://be.exceptionless.io/signup) - implementation takes minutes! + +## Open Source - Host it Yourself or with Us + +Back in February, we [went open source](/fork-us-exceptionless-goes-open-source/), allowing developers that have the resources and infrastructure to host Exceptionless for free. Since then, we've had several contributors to the project and more than 50 forks. Pretty exciting stuff! + +We offer **extremely reasonable hosting services** for those that would prefer we handle that side of things. The single user, single project hosting account is free, then the small team account starts at $15 per month. Pricing scales from there. Check out the [Pricing Plans page](/pricing) for full pricing details and frequently asked questions. + + + + [Sign Up For **FREE**!](https://be.exceptionless.io/signup) + + + + diff --git a/docs/news/2014/2014-04-29-recent-exceptionless-case-studies.md b/docs/news/2014/2014-04-29-recent-exceptionless-case-studies.md new file mode 100644 index 0000000000..7956c1e704 --- /dev/null +++ b/docs/news/2014/2014-04-29-recent-exceptionless-case-studies.md @@ -0,0 +1,45 @@ +--- +title: "A Few Recent Exceptionless Case Studies" +date: 2014-04-29 +--- + +# A Few Recent Exceptionless Case Studies + +[![Error Stack Dashboard](/assets/img/news/error-stack-300x264.jpg)](/assets/img/news/error-stack.jpg) + +We like to know how Exceptionless is helping its users, and we love it when we get feedback! Every once in a while, we like to share a story or two so we can drive home the benefits of having a real-time exception logging service tied into code projects. + +Surveys are sometimes sent out to users, and we wanted to share a few recent responses. + +## Exceptionless Case Study Questions + +* What is the **number one customer-facing bug** that Exceptionless has helped you track down? Can you give us a brief description of the bug and how you solved it? + +* **User 1:** "Missing DLLs in the client environment, due to required 3rd party apps not being installed (eg: Crystal Reports runtime). [Exceptionless] enabled me to create a list of missing DLLs and computers for relay to the client." +* **User 2:** They were previously handling their own exception logging well and don't have any serious customer-facing errors coming in. + +* When you first started using Exceptionless, were you surprised by the number of errors that were being reported? Approximately **how many were you seeing per day**? + +* **User 1:** "Not really, but just because I had written a similar tool that logged these before, they just were not as accessible (database table on web service)." The user reported that the above bug was appearing 10-15 times each day. +* **User 2:** They were already handling their error logging and already had errors down to a minimum, around 50 per month. "The primary reasons that we switched to Exceptionless from our own code is that Exceptionless captures additional detail (including code line numbers), Exceptionless has a better interface and design for reviewing and managing errors and bugs (including summary views that we didn’t previously have), and we no longer need to maintain our own error-logging code." + +* What is the **number one internal bug** that Exceptionless has helped you track down? Can you give us a brief description of the bug and how you solved it? + +* **User 1:** N/A +* **User 2:** "...a small number of situations where our code doesn’t correctly handle empty record sets (that is, where, based on the specific query string parameters in the URL, no corresponding records are found in the database and the page is expecting that there will always be records to display)." + +* What is the **number one feature request** or change that you would like to see the Exceptionless Team tackle? + +* **User 1:** "More options to filter dashboard by tags/versions/environment variables. Custom reporting, exporting to CSV file etc or other way to import them into TFS or similar." +* **User 2:** "...my number one request is probably for additional information in daily summary emails and for a combined daily summary. Notification defaults and moving notification settings out of the project setup is probably a close second; or perhaps the ability to add comments when marking an issue as fixed would be my second highest feature request." + +* If you have any other other **examples of Exceptionless helping you squash bugs**, please share them below - we would love to hear them! + +* **User 1:** N/A +* **User 2:** "...in our small team, the additional information from Exceptionless (as well as the process of converting to Exceptionless) has prompted us to review and solve a few ongoing bugs that we were aware of..." + +## What has Exceptionless Done for You? + +If you use Exceptionless to log, report, organize, and squash errors in your code, we want to hear how it helps, what kind of crazy errors you are eliminating, and your general thoughts on the project! Don't be shy, we won't bite. + +_Thanks to Philip with the [Beth Israel Deaconess Medical Center](http://bidmc.org/) and Michael with [Customer Logic](http://www.customerlogic.com.au/) for their case study contributions. We appreciate it guys!_ diff --git a/docs/news/2014/2014-05-04-web-application-errors-80-20-rule.md b/docs/news/2014/2014-05-04-web-application-errors-80-20-rule.md new file mode 100644 index 0000000000..a5dc9af99c --- /dev/null +++ b/docs/news/2014/2014-05-04-web-application-errors-80-20-rule.md @@ -0,0 +1,31 @@ +--- +title: "Web Application Errors and the 80-20 Rule" +--- + +# Web Application Errors and the 80-20 Rule + +[![Most Frequent Errors](/assets/img/news/most-frequent-300x262.png)](/assets/img/news/most-frequent.png)You know the 80-20 rule. The one marketers, managers, bigwigs, writers, speakers, and everyone else references to tell you what to focus on or why the widgets aren't selling like they should. + +Well, as painful as it might be to hear the rule applied to yet another scenario, we're here today to let you know that 80-20 can be applied, in many cases, to your code's exceptions as well.  + +## 20% of Errors Cause 80% of Exception Instances + +That's not so bad, is it? + +All we're trying to point out is that when you start tracking and organizing the errors in your code, inevitably you'll start to realize that a small percentage of bugs are causing the majority of your total errors. + +### What we did about it + +We realized this ourselves, so we built the "Most Frequent Errors" report right into the Exceptionless dashboard. + +When you log into your account, you immediately see which errors are causing the largest number of exceptions, how many instances of each there is, when the first occurrence was, and when the last occurrence was. + +From there, you can click in, view there error's details, and hopefully find a quick resolution to the problem. + +## Most Frequent <> Most Important + +While it's great to chip away at the most frequent errors, it's worth pointing out that most frequent doesn't always mean most important, so be sure to focus on bottom line, customer facing, and major functionality issues first! + +## Have You Observed the 80-20 in the Wild? + +In your coding adventures, have you found the 80-20 rule to apply to your exceptions? Was it something you found quickly, or did you track down numerous instances of the same error before realizing it? diff --git a/docs/news/2014/2014-05-20-exceptionless-2-in-the-making.md b/docs/news/2014/2014-05-20-exceptionless-2-in-the-making.md new file mode 100644 index 0000000000..39d7c50e8f --- /dev/null +++ b/docs/news/2014/2014-05-20-exceptionless-2-in-the-making.md @@ -0,0 +1,32 @@ +--- +title: "Exceptionless 2.0 - In the Making" +date: 2014-05-20 +--- + +# Exceptionless 2.0 - In the Making + +Exceptionless Version 2.0 Sneak PeekIt may seem quiet in Exceptionless land, but the truth is we've been writing, and re-writing, more code than you can point a cursor at. If it weren't a labor of love, our fingers would have mutinied long ago, but luckily they are in it for the long haul and are churning out some seriously **sweet new features and rewrites**. + +Exceptionless 2.0 will include many of the feature requests that have come in since we launched, and will drastically expand on the current functionality. We know you'll love it, so continue reading for a high level view of what's coming in the near future. + +### Event Based System + +Many users have asked for ways to use Exceptionless to report additional types of events, rather than just errors. With 2.0, we are moving to an event based system that will accommodate this. + +

API Simplified

+ +Since [going open source](/fork-us-exceptionless-goes-open-source/ "Fork Us! Exceptionless Goes Open Source"), we've wanted to simplify the API and make it easier to work with. We're taking the time to do it now, and it's going to be **awesome.** Watch out! + +

Pluggable System

+ +Plugins will allow customization and translation throughout the Exceptionless platform, including integration with third-party services and more. + +### Client Rewrite + +The client is being re-written be highly simplified and extensible, opening up platform support and ease of functionality additions. + +### Coming Soon + +Version 2.0 is coming soon. In the mean time, look for more details and sneak peeks containing examples of functionality and usage. We can't wait to show the world! + +Don't forget to [follow along with the development on GitHub](https://github.com/exceptionless/Exceptionless) and watch Exceptionless 2.0 while it's being built! diff --git a/docs/news/2014/2014-05-28-event-based-reporting-system-coming-version-2-0.md b/docs/news/2014/2014-05-28-event-based-reporting-system-coming-version-2-0.md new file mode 100644 index 0000000000..1c3477d433 --- /dev/null +++ b/docs/news/2014/2014-05-28-event-based-reporting-system-coming-version-2-0.md @@ -0,0 +1,26 @@ +--- +title: "Event Based Reporting System Coming in Version 2.0" +--- + +# Event Based Reporting System Coming in Version 2.0 + +[![Event Based Reporting System](/assets/img/news/errors-only.png)](/assets/img/news/errors-only.png)We [hinted](/exceptionless-2-in-the-making/)that more details on the upcoming Exceptionless 2.0 release would get announced soon, and here we are! Lets dive in a bit further, shall we? + +Many users have asked for ways to use Exceptionless to report additional types of events, rather than just errors. With version 2.0, we are moving to an event based system that will accommodate such requests. + +## What's an Event Based Real-Time Reporting Tool Look Like? + +* The new system allows us to receive literally any data people want to send us instead of only allowing errors. +* Event posts can be as simple as this: + [![Post Event Exceptionless](/assets/img/news/ex-curl.png)](/assets/img/news/ex-curl.png) +* You can send log messages or even entire log files. +* Log messages can contain extended data objects just like errors can now. +* You can post random JSON objects and the data within them will be treated as extended data. +* You can post batches of events instead of only being able to send one at a time. +* You can send feature usage events that let you see how often features of your application are being used. Think about how useful that will be! +* You can send session start and end events that will enable you to know what percentage of users are affected by errors and enable you to better know what your priorities should be. +* We will be gathering enough data to make it easy for us to begin putting together some **very** useful analytic reports. + +We're pretty excited about the switch from error-only to send-us-any-event-you-can-think-of real-time reporting, logging, and notifications. We think it's going to be awesome, and it's almost scary how much of a playground Exceptionless is going to turn into for some of our customers. We're not pushing the limits, we're pushing for **no limits**! + +Ideas? Concerns? Let us know. We're working hard to wrap up Exceptionless 2.0, but there's still a lot more bells and whistles we're polishing before launch! Keep an eye out for still more sneak peek material in the coming weeks! diff --git a/docs/news/2014/2014-06-03-exceptionless-1-5-released.md b/docs/news/2014/2014-06-03-exceptionless-1-5-released.md new file mode 100644 index 0000000000..0ab5175bfb --- /dev/null +++ b/docs/news/2014/2014-06-03-exceptionless-1-5-released.md @@ -0,0 +1,45 @@ +--- +title: "Exceptionless 1.5 Released!" +date: 2014-06-03 +--- + +# Exceptionless 1.5 Released! + +![Exceptionless Version 1.5](/assets/img/news/version1.5.png)While we're [on the march to Exceptionless 2.0](/exceptionless-2-in-the-making/ "Exceptionless 2.0 – In the Making"), we're still making updates and fixing bugs on version 1. Today, we'd like to announce that Exceptionless 1.5 has been released, which includes several server changes and bug fixes, as well as major client code base optimization. + +Please **update your client to version 1.5** and take a look at the other changes and bug fixes, below. We've done quite a bit of work to notifications, added throttling to improve coverage on small and free plans, and improved performance in a few places. + +## Server Changes + +* Added **throttling to accounts that are over their usage limits**. If an account is sending a high number of errors, the errors will be throttled on an hourly basis so that the entire plan limit won’t be used up immediately. This allows for a distributed sampling of the errors instead of only capturing everything in a short period of time. +* Added a site notification that shows you when error submissions are being throttled or if you are over your monthly plan limits. +* Removed total count from most recent errors list as it was a very expensive to calculate while providing little value. +* Fixed a bug with notifications that could cause some users to get spammed. Now notifications only send a maximum of 10 notifications per project every 30 minutes. +* **Greatly simplified the authentication logic** for the web api pipeline. +* Added the ability to **print all content on the error occurrence page**. +* The pager will no longer scroll to the top of the current list when changing pages. +* Updated the paged lists to only refresh the list data via push notifications when you are on the first page. +* The list data will only be updated in real time if the data matches the current filter criteria. +* Fixed a bug where the loading indicators would appear on the suspended and manage organization pages. +* Fixed a bug where the save button on the manage organization page would have improper styling. +* Fixed a bug where a HttpAntiForgeryException could be thrown when accessing the website. +* Fixed a bug where a ArgumentException would be thrown if multiple model validation errors occurred on a single page. +* Fixed a bug where a NullReferenceException could be thrown when signing up. +* Added some additional checks to try and resolve the user profile when an invited user signs up. +* Fixed a bug where an updated organization notification could be sent before the user was authorized to access the organization. +* Fixed a bug where empty OS Name and Version values were being shown in the errors environment section even if they didn't exist. This could happen if the client was reporting from an azure website instance. +* Changed billing plans to use per month error limits. +* Fixed a bug where the BillingManager could throw a NullReferenceException for a newly added organization. This could happen because the primary node had not replicated the content to the secondary nodes or the data wasn't cached on creation. +* Updated various MongoDB collections to not persist empty array fields. +* Fixed a bug where some cache entries were not automatically expiring. + +## Client Changes + +It's **highly recommend that you update your clients** to 1.5 as we did major optimizations to the client code base. + +* Greatly simplified how the client processes and sends errors. The client now properly handles the various status codes that can be returned from the service. +* Added an event that allows you to customize the request object before it is sent to the service. + +**As always, please let us know if you have any questions!** + + diff --git a/docs/news/2014/2014-06-12-upcoming-exceptionless-2-0-simplified-api.md b/docs/news/2014/2014-06-12-upcoming-exceptionless-2-0-simplified-api.md new file mode 100644 index 0000000000..91ecd95eea --- /dev/null +++ b/docs/news/2014/2014-06-12-upcoming-exceptionless-2-0-simplified-api.md @@ -0,0 +1,33 @@ +--- +title: "More from the Upcoming Exceptionless 2.0: Simplified API" +date: 2014-06-12 +--- + +# More from the Upcoming Exceptionless 2.0: Simplified API + +![Exceptionless 2.0 API Simplified](/assets/img/news/v2-api.png)Since [going open source](/fork-us-exceptionless-goes-open-source/ "Fork Us! Exceptionless Goes Open Source"), we've wanted to simplify the API and make it easier to work with. + +We're taking the time to do it now, and it's going to be **awesome!** + +Exceptionless 2.0, [coming soon](/exceptionless-2-in-the-making/ "Exceptionless 2.0 – In the Making"), will have a new, manageable API with tons of great documentation and examples. Take a look at the preliminary documentation at the below link, and make sure to give us any feedback you might have. + +### API Simplified + +
    +
  • New REST API documentation and samples site.
    Take a look and let us know what you thinkExceptionless API Documentation
  • +
  • Event POSTs take the raw data and use a plugin system to interpret that data and translate them into events. +
      +
    • This allows us to take literally any data and turn it into events in the system.
    • +
    • The POST data is captured as a raw bytes and added immediately added to a queue for processing.
    • +
    • Plugins can easily be created to support new data formats like system logs.
    • +
    +
  • +
  • This simplified API will make creating libraries for other platforms dead simple.
  • +
  • The API lives in a separate project and can be hosted on high-performance systems like the new Helios IIS host.
  • +
  • Makes it easy for us to migrate the UI to a SPA app.
  • +
  • Now uses OAuth 2.0 in addition to supporting API tokens.
  • +
  • Highly consistent REST API modeled after GitHub and Stripe.
  • +
  • It's so simple you can just use CURL as a client.
  • +
+ +We hope you're as excited as we are to have this new, improved, more complete, and more usable documentation. Stay tuned for more details on the upcoming Exceptionless 2.0, and don't forget to leave a comment letting us know what you think. diff --git a/docs/news/2014/2014-06-25-coming-exceptionless-2-0-pluggable-system.md b/docs/news/2014/2014-06-25-coming-exceptionless-2-0-pluggable-system.md new file mode 100644 index 0000000000..ef59d70df5 --- /dev/null +++ b/docs/news/2014/2014-06-25-coming-exceptionless-2-0-pluggable-system.md @@ -0,0 +1,47 @@ +--- +title: "Coming in Exceptionless 2.0 - A Pluggable System" +--- + +# Coming in Exceptionless 2.0 - A Pluggable System + +![Pluggable System](/assets/img/news/pluggable-system.jpg) + +In the last Exceptionless 2.0 article, we announced the upcoming [simplified API](/upcoming-exceptionless-2-0-simplified-api/). Today, we want to introduce another major piece of V2.0 - the **pluggable system**. + +Plugins will allow customization and translation throughout the Exceptionless platform, including integration with third-party services and more. Read on for more details about pluggable details such as event parsing, event pipeline, and formatting. + +## Event Parsing + +* Has access to the raw POST data as well as the content type and submission client info. +* Used to translate that raw data into events. +* Can easily create new plugins to support new data formats like system logs. +* Can be used to support other JSON formats like adding support for clients made for other systems. + +[Source](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Plugins/EventParser/IEventParserPlugin.cs) + +## Event Processor + +* Can be used to add new functionality to the system. +* Gets called on startup, when an event is starting to be processed and when an event is done being processed. +* Has access to settings from both the org and project level. +* Can be used to create integrations for 3rd party services like HipChat, Trello, GitHub, Slack, etc. + +[Source](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Plugins/EventProcessor/IEventProcessorPlugin.cs) + +## Formatting + +* Used to control how events are displayed in the system. +* Controls the summary view of an event. +* Controls the stack title. +* Controls what notification emails look like. +* Controls which view is used to display the details of an event. + +[Source](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Plugins/Formatting/IFormattingPlugin.cs) + +We believe building a pluggable exception reporting system and allowing third-party service and app access will create one of the most flexible, usable, and friendly solutions on the market. + +### Coming Soon + +We're anxious to get Exceptionless 2.0 wrapped up, but we do not have an ETA currently. We are working hard and making good progress, so keep an eye out for more sneak peeks, feature announcements, and progress reports! + +As always, please let us know if you have any feedback or questions. diff --git a/docs/news/2014/2014-07-03-exceptionless-2-0-client-rewrite-sneak-peek-usage-example.md b/docs/news/2014/2014-07-03-exceptionless-2-0-client-rewrite-sneak-peek-usage-example.md new file mode 100644 index 0000000000..746b6dd8da --- /dev/null +++ b/docs/news/2014/2014-07-03-exceptionless-2-0-client-rewrite-sneak-peek-usage-example.md @@ -0,0 +1,198 @@ +--- +title: "Exceptionless 2.0 Client Rewrite Sneak Peek Usage Example" +date: 2014-07-03 +--- + +# Exceptionless 2.0 Client Rewrite Sneak Peek Usage Example + +![new-client-header](/assets/img/news/new-client-header.jpg) + +As Exceptionless 2.0 continues to become a reality, we thought we would give everyone a little taste of what you will be able to do with the new, rewritten client. Continue reading for a glimpse at the primary features, along with a complete usage example for adding extra data to events. + +After you check it out, let us know if you have questions or suggestions. We're listening! + +## New Client Features + +* The Exceptionless client has been completely rewritten to be highly simplified and extensible. +* Will work with Mono and Project K. +* The base client is [PCL](https://www.nuget.org/packages/exceptionless.portable), and we will have platform specific clients that add additional functionality for each platform. +* Adding extra data to events is extremely easy. + +**[View Client Source](https://github.com/exceptionless/Exceptionless.net)** + +### Extended event data usage example + +![Exceptionless Code Example](/assets/img/news/ex-client-1024x420.png)client source</a> if you want to take a look at the complete code. + +**First, set your API key.** + +```cs +var client = new ExceptionlessClient(config => { +config.ApiKey = "API_KEY_HERE"; +``` + +* * * + +Then, send events to your own free Exceptionless server install. + +```cs +config.ServerUrl = "https://exceptionless.myorg.com"; +``` + +* * * + +Now, read config settings from attributes. + +```cs +config.ReadFromAttributes(); +``` + +* * * + +Read config settings from a config section in your app/web.config. + +```cs +config.ReadFromConfigSection(); +``` + +* * * + +Store all client data including the offline queue in the store folder, by default isolated storage is used. + +```cs +config.UseFolderStorage("store"); +``` + +* * * + +Exclude any form fields, cookies, query string parameters, and custom data properties containing "CreditCard". + +```cs +config.AddDataExclusions("CreditCard"); +``` + +* * * + +Add the "SomeTag" to all events. + +```cs +config.DefaultTags.Add("SomeTag"); +``` + +* * * + +Add the "MyObject" custom data object to every event. + +```cs +config.DefaultData.Add("MyObject", new { MyProperty = "Value1" }); +``` + +* * * + +Add a custom event enrichment that will add a tag called "MyTag" to every event. + +```cs +config.AddEnrichment(ev => ev.Tags.Add("MyTag")); +``` + +* * * + +Register a custom log implementation that uses NLog. + +```cs +config.Resolver.Register(new NLogExceptionlessLog()); +``` + +* * * + +The Startup method is specific for each platform and wires up to all relevant unhandled exception events so that they will be automatically sent to the server. + +```cs +client.Startup(); +``` + +* * * + +Manually catch and report an error with a custom tag on it. + +```cs +try { + throw new ApplicationException("Boom!"); +} catch (Exception ex) { + ex.ToExceptionless().AddTags("MyTag").Submit(); +} +``` + +* * * + +Let users add their email address and a description of the error. + +```cs +await client.UpdateUserEmailAndDescriptionAsync(client.GetLastReferenceId(), "me@me.com", "It broke!"); +``` + +* * * + +Create and submit a log message and add an extra "Order" object to the event. + +```cs +client.CreateLog("Order", "New order created.") + .AddObject(new { Total = 14.95 }, name: "Order") + .Submit(); +``` + +* * * + +Submit a feature usage event that will let you see how much certain features of your app are being used. + +```cs +client.SubmitFeatureUsage("FeatureA"); +``` + +* * * + +Submit a page not found event so you can keep track of your broken links and fix them. + +```cs +client.SubmitNotFound("/badpage"); +``` + +* * * + +Listen to all events being sent and cancel any errors that are "IgnoredType". + +```cs +client.SubmittingEvent += (sender, args) => +args.Cancel = args.Event.IsError() && args.Event.GetError().Type.Contains("IgnoredType"); +``` + +* * * + +Settings data is synced in real-time with the project settings in your Exceptionless project on the server. + +```cs +client.Configuration.Settings.Changed += (sender, args) => +Trace.WriteLine(String.Format("Action: {0} Key: {1} Value: {2}", args.Action, args.Item.Key, args.Item.Value)); +``` + +* * * + +You can use those settings to control behavior in your app. + +```cs +if (client.Configuration.Settings.GetBoolean("IncludeMyCustomData", false)) + Trace.WriteLine("Should include my custom data"); +``` + +## That's All There Is To It! + +After checking out the above example, we hope you agree that we've drastically simplified and improved the process of adding data to events, allowing for much more flexibility. + +As always, if you have any questions, comments, suggestions, or concerns, let us know! + +### Read more about Exceptionless 2.0 + +* [Exceptionless 2.0 - In the Making](/exceptionless-2-in-the-making/ "Exceptionless 2.0 – In the Making") +* [Event Based Reporting System](/event-based-reporting-system-coming-version-2-0/ "Event Based Reporting System Coming in Version 2.0") +* [Simplified API](/upcoming-exceptionless-2-0-simplified-api/ "More from the Upcoming Exceptionless 2.0: Simplified API") +* [A Pluggable System](/coming-exceptionless-2-0-pluggable-system/ "Coming in Exceptionless 2.0 – A Pluggable System") diff --git a/docs/news/2014/2014-07-17-version-2-0s-new-message-bus-queueing-systems.md b/docs/news/2014/2014-07-17-version-2-0s-new-message-bus-queueing-systems.md new file mode 100644 index 0000000000..be0241f9c3 --- /dev/null +++ b/docs/news/2014/2014-07-17-version-2-0s-new-message-bus-queueing-systems.md @@ -0,0 +1,33 @@ +--- +title: "Version 2.0's New Message Bus and Queueing Systems" +--- + +# Version 2.0's New Message Bus and Queueing Systems + +In an effort to improve scalability, allow for new functionality to easily be added to Exceptionless, make the system less coupled, process things more efficiently, go fully Async, and further support Azure, we've been working hard on a new message bus and queueing system. + +Lets take a look at a few of the details surrounding these new systems we're building for Exceptionless 2.0. Take a look and let us know what you think. If you've got questions or comments, we'd love to hear them! + +## Message Bus + +The new message bus allows us to publish and subscribe to messages across all our resources. We [subscribe to different types of messages to send SignalR notifications](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Web/Hubs/MessageBusBroker.cs) to the client. + +## Queueing + +The new queueing system allows us to enqueue expensive tasks that can be handled at a later time. This lets us greatly reduce the processing and latency times of the api. + +* We stream event data that is posted to the event controller directly into the queue without taking the IO or Memory hit of processing it. This means that we can process more errors, faster, with less resources. + +The system also supports retrying and discarding of data. + +* We queue emails that need to be sent, as well as user defined webhooks that need to be called with data. Email servers on the sending and receiving can go offline or error out while sending, but by queuing the notification emails we can ensure you always get them by re-sending in the future, after a failure occurs. In the event that we can't send you an email after a few retries, we can discard the notification. + +## More on Version 2.0 + +If you're just now learning about the upcoming Exceptionless 2.0, make sure to catch up on previous feature announcements and examples by reading the below articles. + +* [Exceptionless 2.0 – In the Making](/exceptionless-2-in-the-making/ "Exceptionless 2.0 – In the Making") +* [Event Based Reporting System](/event-based-reporting-system-coming-version-2-0/ "Event Based Reporting System Coming in Version 2.0") +* [Simplified API](/upcoming-exceptionless-2-0-simplified-api/ "More from the Upcoming Exceptionless 2.0: Simplified API") +* [A Pluggable System](/coming-exceptionless-2-0-pluggable-system/ "Coming in Exceptionless 2.0 – A Pluggable System") +* [Exceptionless 2.0 Client Rewrite Sneak Peak and Example](/exceptionless-2-0-client-rewrite-sneak-peek-usage-example/ "Exceptionless 2.0 Client Rewrite Sneak Peek Usage Example") diff --git a/docs/news/2014/2014-07-29-job-system-enhancements-version-2s-got-em.md b/docs/news/2014/2014-07-29-job-system-enhancements-version-2s-got-em.md new file mode 100644 index 0000000000..5048db9876 --- /dev/null +++ b/docs/news/2014/2014-07-29-job-system-enhancements-version-2s-got-em.md @@ -0,0 +1,40 @@ +--- +title: "Job System Enhancements - Version 2's Got Em!" +date: 2014-07-29 +--- + +# Job System Enhancements - Version 2's Got Em! + +Summer means vacations and pool time, but we haven't stopped working on Exceptionless 2.0. Things are coming along nicely, and today we're here to talk about the job system and the code being written to enhance it. + +**After you read this article**, check out the previous V2.0 feature and detail articles, if you haven't already. Good stuff in there! + + 1. [Exceptionless 2.0 – In the Making](/exceptionless-2-in-the-making/ "Exceptionless 2.0 – In the Making") + 2. [Event Based Reporting System](/event-based-reporting-system-coming-version-2-0/ "Event Based Reporting System Coming in Version 2.0") + 3. [Simplified API](/upcoming-exceptionless-2-0-simplified-api/ "More from the Upcoming Exceptionless 2.0: Simplified API") + 4. [A Pluggable System](/coming-exceptionless-2-0-pluggable-system/ "Coming in Exceptionless 2.0 – A Pluggable System") + 5. [Exceptionless 2.0 Client Rewrite Sneak Peak and Example](/exceptionless-2-0-client-rewrite-sneak-peek-usage-example/ "Exceptionless 2.0 Client Rewrite Sneak Peek Usage Example") + 6. [New Message Bus and Queuing System](/version-2-0s-new-message-bus-queueing-systems/) + 7. [Job System Enhancements](/job-system-enhancements-version-2s-got-em/ "Job System Enhancements – Version 2′s Got Em!") + + + +## Job System Enhancements + +### Standalone + +Jobs can easily be run standalone now, which makes it much easier to test the system. You won't have to worry about your application pool shutting down prematurely and killing your job half way through it's long-running work item. + +### More Ways to Run + +With 2.0, you'll be able to run jobs in process, as a service, as a standalone exe, or as Azure WebJobs. Cool, huh? + +### Need More? Run More! + +If you need to process more tasks, simply fire up more jobs. This will save resources and money when using Azure WebJobs, as you can auto-scale jobs based on resource constraints. + +We use jobs to send emails, call web hooks, process events, and much more, so these enhancements will allow for better resource control when scaling, and in general. + +## Questions? + +We've thrown out a lot of information about Exceptionless 2.0 and all the new features, enhancements, and tweaks that it's going to get. We'd love to hear from some of the regulars out there and see if we've missed anything obvious. Check out the links to the other articles at the top of the page and let us know. Thanks! diff --git a/docs/news/2014/2014-08-07-new-price-plans-medium-large-teamsprojects.md b/docs/news/2014/2014-08-07-new-price-plans-medium-large-teamsprojects.md new file mode 100644 index 0000000000..8ae65635b4 --- /dev/null +++ b/docs/news/2014/2014-08-07-new-price-plans-medium-large-teamsprojects.md @@ -0,0 +1,48 @@ +--- +title: "New Price Plans for Medium to Large Teams/Projects" +date: 2014-08-07 +--- + +# New Price Plans for Medium to Large Teams/Projects + +We've had quite a few requests for pricing plans that support users, retention, and errors somewhere between our old medium and enterprise plans, so we crunched the numbers and came up with new large and extra large plans that find a happy medium. + +Both plans include more users, more retention, and more errors. Check out the details on each package below or [view the Pricing Page](/pricing "Pricing Plans") for a quick summary. + +## Free + +The free plan, which is great for trying things out or super small personal projects, includes provisions for **one project, one user, three days of error retention, and three thousand errors per month**. + +It does not include premium features such as advanced notifications, web hooks, and other future premium features. + +## Small - $15 + +For $15 per month, you get **five projects, ten users, thirty days of retention, 15,000 errors per month**, and premium features. + +## Medium - $49 + +The medium Exceptionless plan offers **fifteen projects and twenty-five users**. You get **ninety days of retention, 75,000 errors per month**, and premium features. + +## Large Plan - $99 _(new)_ + +The large plan is new, and includes **unlimited projects and users, 180 days of error retention, 250,000 errors per month**, and premium features. + +This is quickly becoming a popular plan and makes sense for a lot of medium to medium-large teams and projects. + +## Extra Large - $199 _(new)_ + +The extra large plan was created to bridge the gap between large and enterprise by quadrupling the **number of errors per month to 1,000,000**. You still get unlimited projects and users, as well as 180 days of retention and premium features. + +## Enterprise - $499 + +For those businesses and enterprise-level teams that have several large projects and need to handle huge numbers of errors, the Enterprise plan offers everything that the Extra Large plan offers, with **3,000,000 errors per month**. + +## Custom + +And, of course, should you need to customize a plan to handle even more errors, we can always get you taken care of, just let us know! + + + + [Sign Up Now!](https://be.exceptionless.io/signup) + + diff --git a/docs/news/2014/2014-08-13-upcoming-exceptionless-version-2-0-overview-review.md b/docs/news/2014/2014-08-13-upcoming-exceptionless-version-2-0-overview-review.md new file mode 100644 index 0000000000..6fb8c8cff2 --- /dev/null +++ b/docs/news/2014/2014-08-13-upcoming-exceptionless-version-2-0-overview-review.md @@ -0,0 +1,52 @@ +--- +title: "Upcoming Exceptionless Version 2.0 Overview & Review" +date: 2014-08-13 +--- + +# Upcoming Exceptionless Version 2.0 Overview & Review + +Many of you guys have been following along in previous posts as we went through the details of the new features and enhancements coming with the next version of Exceptionless, V2.0. + +To make things easier for everyone, we thought we'd do an overview post as well, so all the new features can be found in one location and people can click to read more on the specific ones they are interested in. + +## Exceptionless 2.0 Features & Enhancements + +### Event Based Reporting System + +[![Post Event Exceptionless](/assets/img/news/ex-curl-150x150.png)](/assets/img/news/ex-curl.png)Many users have asked for ways to use Exceptionless to report additional types of events, rather than just errors. With version 2.0, we are moving to an event based system that will accommodate such requests. + +[Read full article...](/event-based-reporting-system-coming-version-2-0/ "Event Based Reporting System Coming in Version 2.0") + +### Simplified API + +[![Exceptionless API Documentation](/assets/img/news/Screen-shot-2014-06-11-at-5.20.44-PM-150x150.png)](/assets/img/news/Screen-shot-2014-06-11-at-5.20.44-PM.png)2.0 will have a new, manageable API with tons of great documentation and examples. Take a look at the preliminary documentation at the below link, and make sure to give us any feedback you might have. + +[Read full article...](/upcoming-exceptionless-2-0-simplified-api/ "More from the Upcoming Exceptionless 2.0: Simplified API") + +### A Pluggable System + +[![Pluggable System](/assets/img/news/pluggable-system-150x150.jpg)](/assets/img/news/pluggable-system.jpg)The new pluggable system will allow customization and translation throughout the Exceptionless platform, including integration with third-party services and more. Read on for more details and source code about event parsing, the event pipeline, and formatting. + +[Read full article...](/coming-exceptionless-2-0-pluggable-system/ "Coming in Exceptionless 2.0 – A Pluggable System") + +### Client Rewrite + +[![new-client-header](/assets/img/news/new-client-header-150x150.jpg)](/assets/img/news/new-client-header.jpg)The Exceptionless client has been completely rewritten to be highly simplified and extensible, work with Mono and Project K, include additional platform specific clients, and much more. Take a look at an extended event data usage example at the link below. + +[Read full article...](/exceptionless-2-0-client-rewrite-sneak-peek-usage-example/ "Exceptionless 2.0 Client Rewrite Sneak Peek Usage Example") + +### New Message Bus & Queueing + +In an effort to improve scalability, allow for new functionality to easily be added to Exceptionless, make the system less coupled, process things more efficiently, go fully Async, and further support Azure, we’ve been working hard on a new message bus and queueing system. + +[Read full article...](/version-2-0s-new-message-bus-queueing-systems/ "Version 2.0′s New Message Bus and Queueing Systems") + +### Job System Enhancements + +A lot of time has been spent on enhancing the job system behind Exceptionless. From the ability to run jobs standalone, making testing easier, to more ways to run jobs and the ability to auto-scale jobs based on resource constraints, lots of great changes are coming! + +[Ready full article...](/job-system-enhancements-version-2s-got-em/ "Job System Enhancements – Version 2′s Got Em!") + +## Feedback Welcome! + +If you've taken a look at the upcoming features and have any comments, please let us know! We're working on everything as fast and hard as we can, and will hopefully have an ETA to have everything finished soon. diff --git a/docs/news/2014/2014-08-21-case-study-server-expiration-error-pre-alpha-game-release.md b/docs/news/2014/2014-08-21-case-study-server-expiration-error-pre-alpha-game-release.md new file mode 100644 index 0000000000..157ca591aa --- /dev/null +++ b/docs/news/2014/2014-08-21-case-study-server-expiration-error-pre-alpha-game-release.md @@ -0,0 +1,62 @@ +--- +title: "Case Study: Server Expiration Error for Pre-Alpha Game Release" +date: 2014-08-21 +--- + +# Case Study: Server Expiration Error for Pre-Alpha Game Release + +![game-post](/assets/img/news/game-post.jpg)Today we've got a pretty cool case study that comes to us from a game development studio! + +We love to see Exceptionless being used by companies with interesting projects and development pipelines, and what's more interesting than gaming, multi-server, and multi-player environments? + +These guys also gave us some good feedback, which we'll address. + +Check it out! + +## Project + +This user is working on a pre-alpha game that is, at the time of the feedback, only available to the in-house team. The game environment requires multiple servers that are deployed via script. When an old version of a server comes down and a new one is deployed, there is cleanup that must happen, etc. + +> "I like your product! I've previously written an exception-reporting system that did the same type of thing as Exceptionless but used a mail-server as the exception repository. Since that system was something I had to leave behind at my last company, I wanted to find a solution for my current company, and after comparing alternatives liked what your team had built, so that's what we're using now." + +## How Exceptionless Helped + +Because the game had such limited players, servers, and testing, it's tough to catch all the little bugs. Fortunately, Exceptionless was able to catch a potentially huge bug that would cause old versions of the servers that were still running to crash because of files being deleted by the new server development clean up scripts. + +> "If an old version was still running it would crash because its data-files got deleted. Since we're still in development mode there aren't enough people playing on our game servers to notice this exception - but we would have when going into alpha or beta test! Fortunately Exceptionless did notice and report this problem." + +We think that's pretty awesome, and not just because we're huge nerds! + +## Feature Requests & Thoughts + +We were lucky enough to get some great feedback from these guys, as well. + +### Bug Ownership + +> +"We'd like a feature that allows our developers to claim ownership of bugs so that they're not seen by others in the Dashboard view by default." + + +With multiple developers on multiple projects, bugs can stack up and things can get messy. John doesn't need to see Billy's bugs from project A when he's working on his own bugs for project B. + +We definitely agree here and understand, but  +there is a fine line between us being an error reporting service and getting into [bug tracking](/bug-tracking/) type features. We had a previous product that tried to do too much and turned people off so we really wanted to try and keep Exceptionless simple. That being said, **we want to make Exceptionless integrate with other apps** much more in the future and make it really easy to create new integrations. We're working on this now with [Exceptionless 2.0, coming soon](/upcoming-exceptionless-version-2-0-overview-review/)! + + +### Multiple Services on Single Server + +> " +One other thing that was painful for me personally: we run multiple services of the same type on a single server (e.g. multiple instances of "game-server.exe"). In order to ensure that each server has its own queue folder and logfile, I had to write a chunk of custom code." + + +Again, we totally agree!  +The [client in Exceptionless 2.0](/exceptionless-2-0-client-rewrite-sneak-peek-usage-example/) will be MUCH simpler and will make things much easier. You will be able to easily use in-memory storage and be able to plug in different storage implementations. + + +## We Love Feedback! + +If you're a current user, we'd love to hear how you've used Exceptionless to cut down on bugs and build better apps. If you've got any criticisms or feature feedback/requests, keep those coming as well - they help us improve! + +Have an awesome day! + + diff --git a/docs/news/2014/2014-09-03-making-move-elastic-search-exceptionless-2-0.md b/docs/news/2014/2014-09-03-making-move-elastic-search-exceptionless-2-0.md new file mode 100644 index 0000000000..5cdacd95ae --- /dev/null +++ b/docs/news/2014/2014-09-03-making-move-elastic-search-exceptionless-2-0.md @@ -0,0 +1,38 @@ +--- +title: "Making the Move to Elasticsearch for Exceptionless 2.0" +date: 2014-09-03 +--- + +# Making the Move to Elasticsearch for Exceptionless 2.0 + +![Screenshot 2014-09-03 15.03.16](/assets/img/news/Screenshot-2014-09-03-15.03.16.png)We know you've thought about it when using Exceptionless, and many developers have submitted formal requests. **Search**. + +You need it, and we want to provide it. That's why we've decided to integrate Elasticsearch into 2.0, and it's going to be awesome! + +Check out a few of the cool things we're going to be able to do with it, below, and let us know what you think! + +## What Elasticsearch Brings to the Table + +### Simple scaleability + +Moving to [Elasticsearch](http://www.elasticsearch.org/) for event and stack storage will enable us to simplify many areas of the system, like stats, and also enable us to easily scale the service as it continues to grow. + +### Search ALL the things + +The new system will allow users to search by tags, date range, keywords, error type, and more, all while providing full statistics at the same time. This, specifically, has been our most requested feature, and we're glad to finally be able to say it's coming soon! + +### Faster, too! + +Elasticsearch removes the need for us to do stats incrementing for every type of view that we want to show. This simplifies the system, further increases performance, and improves throughput for the event collector. + +### Statistics everywhere + +You're not just going to get more accurate stats within Exceptionless, you're going to get them in real time, and we'll be able to display them in multiple time zones, too. + +### Future-proofing + +Instead of having to think of everything up front while we're building Exceptionless 2.0, Elasticsearch will enable us to provide new insights in the future, something every developer dreams of! + +## We Hope You're as Stoked as We Are + +Search has been a long time coming for Exceptionless, and we're super excited to be able to provide a robust, thorough, scaleable solution that will cover 99.99% of possible use cases. Hang in there - we're coding it in as fast as we can! diff --git a/docs/news/2014/2014-09-26-server-side-technology-exceptionless-team-uses.md b/docs/news/2014/2014-09-26-server-side-technology-exceptionless-team-uses.md new file mode 100644 index 0000000000..2146d0a4cf --- /dev/null +++ b/docs/news/2014/2014-09-26-server-side-technology-exceptionless-team-uses.md @@ -0,0 +1,87 @@ +--- +title: "Server Side Technology the Exceptionless Team Uses" +--- + +# Server Side Technology the Exceptionless Team Uses + +![Server Technology](/assets/img/news/servers.jpg)As it turns out, building technology and web applications takes a **lot** of other technology. We were reflecting the other day and decided it would be cool if we did a blog series that went over all the different "stuff" we use to make and maintain Exceptionless. + +For the first part in the series, we decided to look at all the **server-side products and services**. They are listed below, along with a short description of what they are used for. See something you've never used? Check it out! Have something we should try out instead? Let us know by commenting! + +## The Server Tech + +### TeamCity + +**Continuous integration and deployment triggering** + +[TeamCity](http://www.jetbrains.com/teamcity/) from JetBrains is a popular continuous integration server that supports a variety of different version control systems and build runners. + +### Octopus Deploy + +**Automated deployment** + +[Octopus Deploy](http://octopusdeploy.com/) works with, not against your build server. This ensures reliable, secure, automated releases of ASP.NET applications and Windows Services into test, staging and production environments, whether they are in the cloud or on-premises. The Octopus Deploy dashboard can tell you quickly which versions of your application are deployed to specific environments. . + +### ElasticSearch + +**Event storage, filtering, stats and search** + +[Elasticsearch](http://www.elasticsearch.com/) is a search server. is a distributed, multitenant-capable full-text search engine with a RESTful web interface and schema-free JSON documents. It has scalable search, real-time search, multi tenancy and can be used to search all kinds of documents. + +### MongoDB + +**Account and billing info storage** + +[MongoDB](http://www.mongodb.org/) makes integration of data in certain types of applications easier and faster. It is a cross-platform document-oriented database that is classified as a NoSQL database. It favors JSON-like documents with dynamic schemas over the traditional table-based relational database structure. + +### Redis + +**Caching** + +[Redis](http://redis.io/) is often referred to as a data structure server. Keys can contain strings, hashes, lists, sets, sorted sets, bitmaps and hyperloglogs. It is open source and licensed under BSD. + +### Resharper + +**Makes Visual Studio awesome!** + +[ReSharper](http://www.jetbrains.com/resharper/) is a productivity tool that makes Microsoft Visual Studio a much better IDE. It includes features such as code inspections, automated code refactorings, blazing fast navigation, and coding assistance. + +### Postman + +**For testing our REST API** + +[Postman](http://www.getpostman.com/) allows you to construct simple as well as complex requests quickly. You can save them for later use and analyze the response sent by the API. It dramatically cuts down the time required to test and develop APIs. It can easily scale and be used for your small team, or larger organizations. + +### Simple Injector + +**Dependency Injection** + +[Simple Injector](https://simpleinjector.codeplex.com/) is an easy-to-use Dependency Injection (DI) library for .NET 4+. It supports Silverlight 4+, Windows Phone 8, Windows 8 including Universal apps and Mono. It can be easily integrated with popular frameworks such as Web API, MVC, WCF and many others. It also provides a carefully selected set of features in its core library to support many advanced scenarios. + +### SignalR + +**Real time notifications** + +[SignalR](http://signalr.net/) is a library for ASP.NET developers that assists with developing real-time web functionality. SignalR allows bi-directional communication between server and client. It allows pushing content to connected clients instantly as it becomes available. SignalR supports Web Sockets, and falls back to other compatible techniques for older browsers easily as well as includes APIs for connection management, grouping connections, and authorization. + +### AutoMapper + +**Easy mapping of data models from one form to another** + +[AutoMapper](https://github.com/AutoMapper/AutoMapper) is a convention-based object-object mapper. It provides useful conventions to take the tedious work out of figuring out how to map type A to type B. As long as you follow a few simple standards, almost zero configuration is needed to map two types. + +### FluentValidation + +**Validating business rules in our data model** + +A small validation library for .NET, [FluentValidation](http://fluentvalidation.codeplex.com/) uses an easy-to-use interface and lambda expressions for building validation rules for your business objects quickly and efficiently. + +### ApprovalTests + +**Easy verification of test outputs** + +[ApprovalTests](http://approvaltests.sourceforge.net/) is an open source assertion/verification library to assist with unit testing. It is compatible with many .NET unit testing frameworks such as Nunit, MsTest, Xunit, and MBUni. It can be used for verifying objects that require more than the simplest of asserts. + +## What Did We Miss? + +We know you've got some cool toys you use on your projects. Spit it out! What other technology should we give a try. We're always looking for the best, fastest, coolest stuff to try out. diff --git a/docs/news/2014/2014-10-02-client-side-technology-exceptionless-team-uses.md b/docs/news/2014/2014-10-02-client-side-technology-exceptionless-team-uses.md new file mode 100644 index 0000000000..3145d86ba0 --- /dev/null +++ b/docs/news/2014/2014-10-02-client-side-technology-exceptionless-team-uses.md @@ -0,0 +1,71 @@ +--- +title: "Client Side Technology the Exceptionless Team Uses" +--- + +# Client Side Technology the Exceptionless Team Uses + +![colored-swoosh](/assets/img/news/colored-swoosh.png)Last week we wrote up a whole list of [server side technologies](/server-side-technology-exceptionless-team-uses/) that we use to build and maintain Exceptionless. This week, we're going to look at client side tools and services. + +We're all about function around here, but we like to think that the app looks and feels pretty good, too! We hope you agree, and maybe you'll come across a thing or two you could use in the future to jazz up the user side of your projects. + +Most of these are **free** services, so check them out! + + + +## Client Side Tech + +### AngularJS + +**JavaScript framework for building dynamic, awesome apps** + +[AngularJS](https://angularjs.org/)is a structural framework for dynamic web apps. It lets you use HTML as your UI language and lets you extend HTML's syntax to define your application’s structure efficiently. Angular's data binding and dependency injection eliminates much of the "fluff" code needed and does this all in the browser. + +### Bootstrap + +**Mobile first front-end framework** + +[Bootstrap](http://getbootstrap.com/)is a free collection of tools for creating websites and web applications that was created by a developer and a designer at Twitter. It contains libraries of HTML,CSS, and JavaScript components to give your project a head start. + +### Font Awesome + +**Scalable vector based icons via CSS** + +[Font Awesome](http://fortawesome.github.io/Font-Awesome/) gives you scalable vector icons that can instantly and easily be customized and extended with the power of CSS. + +### Restangular + +**AngularJS service for handling Restful Resource** + +[Restangular](https://github.com/mgonto/restangular)is an AngularJS service that simplifies the most common GET, POST, DELETE, and UPDATE requests with a minimum amount of client code. It is a perfect fit for any application that uses data from a RESTful API. + +### AngularJS Batarang + +**Debugging and inspecting Angular apps in Chrome** + +The [AngularJS Batarang](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk)Chrome extension includes tools and utilities to assist in finding and addressing performance bottlenecks, and visualize and debug applications using AngularJS. + +### Emmet Re:View + +**Easily test responsive layouts** + +[Emmet Re:View](https://chrome.google.com/webstore/detail/emmet-review/epejoicbhllgiimigokgjdoijnpaphdp) is a small Google Chrome extension that finds responsive design breakpoints on your page and creates view for each breakpoint. This allows you to easily debug your code to perfect and create the perfect UI. + +### WebStorm + +**Awesome JavaScript IDE for front end dev** + +[JetBrains WebStorm](http://www.jetbrains.com/webstorm/) is a commercial IDE for JavaScript, CSS & HTML. It includes JavaScript plugins (such as for Node.js) as well as provides automatic code completion, on-the-fly code analysis, refactoring support and VCS integration. + +### Grunt + +**JavaScript task runner** + +[Grunt](http://gruntjs.com/) provides an easy way of managing the large number of build tasks required to maintain a sophisticated web application. It also has a vast library of plugins to further extend its functionality. + +### npm / Bower + +**Package managing** + +[Npm](https://www.npmjs.org/)is most commonly used for managing Node.js modules, but it works for the front-end too when combined with Browserify and/or $ npm dedupe. + +[Bower](http://bower.io/)is created solely for the front-end and is optimized with that in mind. The biggest difference is that npm does nested dependency tree (size heavy) while Bower requires a flat dependency tree (puts the burden of dependency resolution on the user). diff --git a/docs/news/2014/2014-10-13-services-technologies-exceptionless-team-uses.md b/docs/news/2014/2014-10-13-services-technologies-exceptionless-team-uses.md new file mode 100644 index 0000000000..836bb186ac --- /dev/null +++ b/docs/news/2014/2014-10-13-services-technologies-exceptionless-team-uses.md @@ -0,0 +1,75 @@ +--- +title: "Services and Other Technologies the Exceptionless Team Uses" +--- + +# Services and Other Technologies the Exceptionless Team Uses + +![Exceptionless Services & Technology](/assets/img/news/services-and-tech.png)Over the past couple of weeks, we have been writing about the tools and technologies that the Exceptionless Team uses to create, support, and maintain Exceptionless. In part three of the series, we want to take a look at the services used. + +Most projects need project organization, time management, tracking, the ability to easily communicate with team members, version control, etc - the list goes on. Exceptionless is no different. Here are some of our favorite tools that provide those services to help keep Exceptionless, well, Exceptionless. + +## Services & Technologies + +### Azure + +**Hosts our infrastructure** +Microsoft [Azure](https://azure.microsoft.com) lets you build, deploy, and manage applications any way you like for exceptional productivity. It is a major cloud platform and is an industry leader for both infrastructure-as-a-service (IaaS) and platform-as-a-service (PaaS). + +### GitHub + + **Source control, issue tracking, wiki, and static site hosting** +[GitHub](https://www.github.com) provides access control ,version control, issue tracking and several collaboration features such as wikis, task management, [bug tracking](/bug-tracking/), and feature requests for any project. It is a web-based graphical interface tool that also includes desktop and mobile integration. + +### HipChat + +**Team chat and notifications** +[HipChat](https://www.hipchat.com) allows users to create and participate in chat rooms and send one-on-one messages with other people in a group-centric format. It is an excellent tool to keep your team organized and on task, no matter how small or large. + +### Pingdom + +**Awesome uptime monitoring** +[Pingdom](https://www.pingdom.com/) is a service that tracks the uptime, downtime, and performance of your websites from multiple locations globally so that it can distinguish genuine downtime from routing and access problems. An excellent tool to stay on top of your website’s downtime and to assist with issues that arise. + +### Trello + +**Task management** +[Trello](https://trello.com/) is a collaboration tool that organizes your projects into boards. In one glance, it tells you what's being worked on, who's working on what, and where something is in a process. You can easily sort your projects by tasks, to-do lists, and to stay on top of those time sensitive projects. + +### Librato + +**Monitoring real time system metrics** +[Librato](https://metrics.librato.com/) provides a solution for monitoring, analyzing, and understanding the system metrics that impact your business at all levels. It provides everything you need to visualize, analyze, and actively alert on the metrics that matter to you. + +### Mandrill + +**Awesome and inexpensive way to send emails** +[Mandrill](https://www.mandrill.com/) is a transactional email product that apps can use to send automated one-to-one email, like password reminders, shopping-cart receipts, and personalized notifications. It is highly customizable and can help assist with all aspects of email for your business. + +### Intercom + +**Integrated app messaging and user communication** +[Intercom](https://www.intercom.io/in-app-messaging) shows you who is using your product and makes it easy to personally communicate with them through behavior-driven email and in-app messages to help with feedback and suggestions to help you develop your product further. + +### Stripe + +**Awesome payment processing** +[Stripe](https://stripe.com/) is a developer-friendly way to accept payments online on your website, or in your mobile app. It can be used in any size business and scales perfectly. + +### Apiary + +**Api documentation** +[Apiary](http://apiary.io/) allows you to easily write a custom API blueprint for your project. Once created, you can share it with your teammates or customers to test. Once you have the perfect API mock, let your developers get to work. Check out the upcoming [Exceptionless 2.0 documentation](https://api.exceptionless.io/docs/index.html). + +### Google Apps for Work + +**Cloud based email and documents** +[Google Apps for Work](http://www.google.com/enterprise/apps/business/) is a service from Google that provides independently customizable versions of several Google products. It uses your personal domain name and features several Web applications with similar functionality to traditional office suites, including Gmail, Hangouts, Google Calendar, Drive, Docs, Sheets, Slides, Groups, News, Play, Sites, and Vault + +### Skype + +**Video conferencing** +[Skype](http://www.skype.com) is the most popular voice communication service in the world. Skype can be used to instant message, VoIP, Send files, or collaborate with your friends, family, or team members. They provide desktop applications as well as mobile applications. + +## What did we miss? + +As always, if you use other services and tools that are worth checking out, let us know. We know they're out there! diff --git a/docs/news/2014/2014-10-23-angularjs-exceptionless-2-0.md b/docs/news/2014/2014-10-23-angularjs-exceptionless-2-0.md new file mode 100644 index 0000000000..c9296fd027 --- /dev/null +++ b/docs/news/2014/2014-10-23-angularjs-exceptionless-2-0.md @@ -0,0 +1,36 @@ +--- +title: "AngularJS and Exceptionless 2.0" +date: 2014-10-23 +--- + +# AngularJS and Exceptionless 2.0 + +![Angular JS](/assets/img/news/AngularJS-large-300x84.png)As we plug away at Exceptionless 2.0, perfecting and future-proofing it, we wanted to stop and take the time to talk about AngularJS, how we are using it in version two, and what benefits we're going to get out of it. + +Naturally, we want to maintain all current functionality while supporting planned V2.0 features like search and filtering. We also want it to be static and use the REST API for everything. We're pretty determined to not cheat on that point. Then, thinking ahead, building it to support easily adding new features in the future is a huge priority. + +Lets look at these points in a bit more detail. + +## Static UI + +Using our fully documented REST API, the new Exceptionless 2.0 UI will be static, with no server side logic. What this allows us to do is host the UI on a content delivery network (CDN), guaranteeing faster load times for users anywhere in the world. **Everyone** loves fast load times! + +## Much, Much Faster + +Being a single page application (SPA), the new version of the app eliminates page loads. The only thing being loaded is the JSON data, and we can pre-load other content as users navigate the site. That, along with the static UI mentioned above, means we can deliver an app that responds almost instantaneously to the user's input. What a time to be alive. + +## Maintainable Modularity + +Version 1 taught us a lot. We gained valuable feedback from users, beat our head against several complex problems, and made countless wish lists for the future. Most of that lead to the desire for a more modular, easily maintainable system that new features could be added to with minimal reinvention. + +AngularJS has helped us fulfill those dreams. We can now add new features very easily, without breaking other sections of the site, and our code based has been greatly simplified. And, even with all the modularity, we are still able to run tests on the UI. Pretty snazzy! + +Event type support is handled via pluggable view modules, and we'll be able to add new ones that we haven't even conceived of with relative ease. + +## Do You Angular? + +Making the choice to go with AngularJS wasn't easy or quick, but be believe it was the right path to take. + +Do you Angular? What apps have you used it on? If not, what other frameworks do you use for this type of app, and why? + + diff --git a/docs/news/2014/2014-11-26-exceptionless-2-0-user-interface-first-look.md b/docs/news/2014/2014-11-26-exceptionless-2-0-user-interface-first-look.md new file mode 100644 index 0000000000..68c65c0104 --- /dev/null +++ b/docs/news/2014/2014-11-26-exceptionless-2-0-user-interface-first-look.md @@ -0,0 +1,46 @@ +--- +title: "Exceptionless 2.0 User Interface FIRST LOOK" +date: 2014-11-26 +--- + +# Exceptionless 2.0 User Interface FIRST LOOK + +We can prove it! Exceptionless 2.0 is real, and we've got evidence! + +We've been wanting to give everyone a sneak peak for a long time, and today we are excited to finally be able to. Watch the video above to see a high level overview of the new UI and features. + +There are still quite a few small things to take care of before we release it, but we are happy to say that we are around the 85% mark as far as being finished. Once we get closer, we will be putting up a live demo/preview site for everyone to play with and give feedback on. + +Please don't hesitate to give us any feedback you may have after watching the video or reading the transcript below. We want to hear it! + + + +## **Video Transcript** + +![Exceptionless 2.0](/assets/img/news/v2VideoThumbnail-300x179.png) Lets take a quick look around, shall we? + +Everything is built on angularJS and talking to the REST api, so the UI itself is static, with no more server-rendered views. + +There are a few upfront differences - mainly the fact that we're using all the screen real estate now and everything is mobile responsive + +### Navigation & Exception Types + +On the left navigation bar, we have the 4 default event types, exceptions, log messages, broken links, and feature usages. Each has a dashboard, most recent, most frequent, and new view, which generates a page very similar to what you're used to seeing. + +As promised with version 2.0, we also have an all events section, which you can send literally any event to. We'll go into more detail on that in future posts and videos. + +### Cross Project Views & Filtering + +If we move to the top navigation bar, we see that you can now view data across all projects or by individual projects - a highly requested feature. We then have a quick time period selector, and finally the new filtering system, which allows you to quickly filter your exceptions. We'll show off that feature in it's own video soon. + +### Bulk Actions! + +Moving down into the data portion of the view, one feature that actually isn't new is that you can click and drag to select a period of time on the graph. Just a quick pointer there. Something that is new is the ability to select multiple exceptions or instances of an exception and perform bulk actions on it, such as Mark Fixed, Mark Hidden, or Delete. Again, more on that soon. + +### Anywhere. Anytime. + +One last quick feature that we thought we would highlight today is that all times are now translated to the user's timezone, so your team members can always be working in their specific time no matter where they are. + +That's about it for today, but keep an eye out for more updates as we close in on a release date for Exceptionless 2.0. We know some of these features and enhancements have been on your request list, and we're really excited to be this close to shipping them for you guys. + +Until next time, take care! diff --git a/docs/news/2014/2014-12-07-filter-your-exceptions-video-demo.md b/docs/news/2014/2014-12-07-filter-your-exceptions-video-demo.md new file mode 100644 index 0000000000..6a9b2d71b2 --- /dev/null +++ b/docs/news/2014/2014-12-07-filter-your-exceptions-video-demo.md @@ -0,0 +1,35 @@ +--- +title: "Filter Your Exceptions in Version 2.0 - Video Demo" +--- + +# Filter Your Exceptions in Version 2.0 - Video Demo + +![ElasticSearch Exceptionless Filter Demo](/assets/img/news/tag-filter2-resized.gif)If you've used Exceptionless, chances are a **search or filter system** would have helped you out more than once. We know, and we agree! That's why we've made it a priority with Exceptionless 2.0, which is coming very soon. + +To expand on our previous "[Exceptionless 2.0 User Interface FIRST LOOK](/exceptionless-2-0-user-interface-first-look/ "Exceptionless 2.0 User Interface FIRST LOOK")" article, we want to give everyone a little bit more of a look at the filtering system. This demo isn't anything super fancy, but it gives you a good idea of how easy and fast it will be to filter and search through your event data. + +As always, we are looking for feedback on the platform as we continue to draw nearer to launch, so feel free to leave us a comment or contact us and let us know what you think. We hope you like it! + +https://youtu.be/jIyAYeqHKAM + +## Filter Demo Transcript + +Hi there. Today we want to quickly demonstrate the use of the new filtering system in Exceptionless 2.0. + +Let's check out a quick example. + +With our new tagging system, you can add any tag you like to an exception - so maybe you want to tag various exceptions to be related to a specific feature or issue - you can do that now. + +As you can see in our dummy data here, we've introduced Tag 1 through Tag 5 on various exceptions. + +If we go back out to the main dashboard and click up here on our filter/search icon, we can give it a quick test. + +Lets say I want to see all exceptions tagged "tag4". OK Great. How about tag5? And tag 3? Cool. + +Now, we can also do that within a group of exceptions... Let's look at this one. Again, all we do is filter by the different tags to see their frequency, look at individual instances, and more. Let me run through the different tags real quick. + +And that's a quick look at the Exceptionless 2.0 Filtering system, which gives you even more control over sorting and finding the information you need. + +## Looking forward to filtering your Exceptionless events? + +Great! That's what we like to hear. We think it's going to be super easy, super fast, and even fun for some of you data junkies. Again, if you have any questions or comments, please let us know. diff --git a/docs/news/2014/2014-12-12-bulk-actions-sneak-peak-exceptionless-2-0-video.md b/docs/news/2014/2014-12-12-bulk-actions-sneak-peak-exceptionless-2-0-video.md new file mode 100644 index 0000000000..6bac4f3596 --- /dev/null +++ b/docs/news/2014/2014-12-12-bulk-actions-sneak-peak-exceptionless-2-0-video.md @@ -0,0 +1,29 @@ +--- +title: "Bulk Actions Sneak Peak in Exceptionless 2.0 - Video" +--- + +# Bulk Actions Sneak Peak in Exceptionless 2.0 - Video + +![Exceptionless Bulk Actions](/assets/img/news/exceptionless-bulk-actions.gif)You know you want it! Bulk edit actions, that is. The ability to select multiple exceptions or occurrences of a single exception and do with them as you please, all at once. Well, they're coming, and today we've got a sneak peak! + +We're not changing the world here, but we're making yours a little more efficient. Maybe you want to remove sensitive instances of an error that contains certain data, or maybe you you've got some test errors that you don't want included in the total count, either way the new feature should help. Check it out and let us know what you think! + +https://youtu.be/pQXk3ayK8P8 + +## Exceptionless Bulk Actions Video Transcript + +Welcome to another sneak peak video for the upcoming Exceptionless 2.0. Today we'll be looking at the new bulk edit feature, one of many highly requested features we wanted to make sure we got into version 2. + +If we log in to our Exceptionless 2.0 dashboard, which you've hopefully checked out the overview of in a [previous blog post and video](/exceptionless-2-0-user-interface-first-look/ "Exceptionless 2.0 First Look Video"), we can see that there are now check boxes next to each exception, and if you click in to an individual exception, there is also a check box next to each occurrence of that exception. + +Going back to the dashboard, you can select one, multiple, or all visible exceptions. Then, after you've made your selections, you can mark all of them fixed or hidden, or you can delete them. + +Now, if we go into a specific exception, we can make all of the same selections, and then we can delete those specific occurrences of that exception. + +And that's a quick look at the new bulk edit feature of the soon-to-be Exceptionless 2.0. Please leave a comment on this video or blog post and let us know what you think or any questions you may have. Thanks for watching. + +## Thoughts? + +Lets hear em! Thanks for watching. + +Check out the [Exceptionless 2.0 First Look Video](/exceptionless-2-0-user-interface-first-look/ "Exceptionless 2.0 First Look") and the [new filtering system demo video](/filter-your-exceptions-video-demo/ "Exceptionless 2.0 Filtering Demo"), if you haven't already. diff --git a/docs/news/2015/2015-01-12-exceptionless-2-0-update-close.md b/docs/news/2015/2015-01-12-exceptionless-2-0-update-close.md new file mode 100644 index 0000000000..5918bbb0f6 --- /dev/null +++ b/docs/news/2015/2015-01-12-exceptionless-2-0-update-close.md @@ -0,0 +1,51 @@ +--- +title: "Exceptionless 2.0 Update - SO CLOSE!" +date: 2015-01-12 +--- + +# Exceptionless 2.0 Update - SO CLOSE! + +![Exceptionless Error Logging Service](/assets/img/news/exceptionless-2.0-screenshot-300x171.png)We know, we know... It's been a while since our last update. As so often is the case, the holidays took their toll on work and waists here at Exceptionless over the past few months. However, we're not slacking too bad. In fact, we've got a small update on Exceptionless 2.0 that proves it's hasn't been all turkey and naps! + +In general, the primary features and functionality of the new version are complete and we are in the testing, bug fix, and tweaking phase before we officially launch a production environment and begin orchestrating the process of data migration and rolling users over into the new system. + +## Recent Changes & Progress + +We thought we would throw out some of the most recent stuff we've been working on. We're sure you'll approve! + +### Filter / Search + +One of the main things we've been working hard to get right is the new filtering system. Since we put together our [filter demo video](/filter-your-exceptions-video-demo/ "Exceptionless Search Filter Feature"), we've added in the following searchable items: + +* Exception Type +* IP Address +* Messages +* Machine Name +* User +* Codes +* URL Path +* and more! + +### Documentation + +Another major feature we want to make sure is ready to go when we launch is the documentation. We aren't quite finished with the user documentation, but the [API documentation](/upcoming-exceptionless-2-0-simplified-api/ "Exceptionless API Documentation") has been updated and is current. Of course, we'll keep updating everything as development continues and will field any support related questions you may have. + +### Queue Processor + +We've been bragging about how fast Exceptionless 2.0 will be, and we're not joking. We've been putting a lot of time recently into optimizing the queue processor so that it's not just fast, but _**really**_ fast. You'll see! + +### Bots + +Another little feature we've added is the ability to specify custom user agent strings to treat as bots. We're sure a few of you guys will find that handy. + +## Coming Soon. Not Tomorrow, but Soon. + +As mentioned above, we're still working out some bugs and preparing to enter the production and migration phase. We'll be sure to keep everyone updated via the blog, social media, email, and in-app as we get closer to launch. + +Until next time, we hope everyone had a great holiday season and is enjoying a happy new year! + +### Previously, Re: Exceptionless 2.0 + +* [Version 2.0 First Look](/exceptionless-2-0-user-interface-first-look/ "Exceptionless 2.0 First Look") +* [Filtering Demo](/filter-your-exceptions-video-demo/ "Exceptionless 2.0 Filtering and Search Demo") +* [Bulk Actions Demo](/bulk-actions-sneak-peak-exceptionless-2-0-video/ "Exceptionless Bulk Actions Demo") diff --git a/docs/news/2015/2015-02-11-exceptionless-2-0-live-preview-want-build-sandbox.md b/docs/news/2015/2015-02-11-exceptionless-2-0-live-preview-want-build-sandbox.md new file mode 100644 index 0000000000..11f60eeffc --- /dev/null +++ b/docs/news/2015/2015-02-11-exceptionless-2-0-live-preview-want-build-sandbox.md @@ -0,0 +1,89 @@ +--- +title: "Exceptionless 2.0 Live Preview! Do You Want to Build a Sandbox?" +--- + +# Exceptionless 2.0 Live Preview! Do You Want to Build a Sandbox? + +![exceptionless-sandbox](/assets/img/news/exceptionless-sandbox.png)Oh boy! We're ready for you guys to beat on Exceptionless 2.0 in a sandbox environment! + +We've made you wait, and everyone has done so quite patiently, but now it's officially time to check out V2.0 for yourself. + +We're super excited, but we also  +**need your help!** + At this point, we are asking for any and all  +**feedback** +to help us tweak and refine and get things launched. Check out the details and instructions below, and make sure to send us thoughts, critiques, praise, and (of course) bug reports via [GitHub Issues](https://github.com/exceptionless/Exceptionless/issues/new). + +## You Can Be.Exceptionless + + +![Exceptionless 2.0 Dashboard Preview](/assets/img/news/sandbox-preview-300x183.jpg) +_Exceptionless 2.0 Dashboard Preview_ + + + +**Simply...** + + 1. Go to [https://be.exceptionless.io](https://be.exceptionless.io) + 2. Log in with your **existing** Exceptionless account + _Some very recent accounts may not allow you to log in. If this is the case, please create new account for testing purposes._ + + 1. View your current data in the new system - play around with it! + 2. (Optional, but Encouraged) Upgrade your client and start sending events to Exceptionless 2.0! + +**Notice:** All new data sent to this sandbox preview will be lost when the final version of Exceptionless 2.0 goes live. You will have a gap in historical data. Also, existing clients (1.x) will still work against the 2.0 API when we go live. + + + 1. Open the NuGet Package Manager dialog. + 2. Click on the Updates tab. + 3. Select "Include Prerelease" from the dropdown. + 4. Select the Exceptionless NuGet packages and click the Update button. + 5. **You should be good to go! +** If you need more info, view our [upgrading documentation](/docs/self-hosting/upgrading-self-hosted-instance) or contact us via in-app support. + 3. Provide feedback via [GitHub Issues](https://github.com/exceptionless/Exceptionless/issues/new). (good, bad, or ugly - we want it all) + 4. Be Exceptionless! + +### Documentation + +* [How to Upgrade 1.x client to 2.0](/docs/self-hosting/upgrading-self-hosted-instance) +* [Search Terms](/docs/filtering-and-searching) +* [Fully Documented API](https://api.exceptionless.io/docs/index.html) + +### Notes + + +All events submitted to the 2.0 system may be reset at any time and will be reset before we go live (sandboxed). New events that are submitted, and any changes that happen in the 2.0 preview, will not be available in the 1.x system and will be lost once 2.0 goes live. Existing clients (1.x) will still work against the 2.0 API when we go live. + + +## What Exceptionless 2.0 Offers + +We have covered many of these new features in previous update posts, but there are a few new additions and tweaks we've thrown in since then, along with links to previous discussions. + +* **Searching / Filtering** + We've implemented Elasticsearch and you can search/filter ALL the things! Read more [here](/making-move-elastic-search-exceptionless-2-0/) and watch a quick demo video [here](/filter-your-exceptions-video-demo/). + +* **Cross Organization Views** + You now have the ability to view all events across all organizations, a single organization, or a project. + +* **PCL Support** + We've built in client support for [portable class libraries](https://www.nuget.org/packages/exceptionless.portable)! + +* ****New Clients! +**** Including: [Exceptionless.Portable](https://www.nuget.org/packages/exceptionless.portable) for console apps and [Exceptionless.NLog](http://www.nuget.org/packages/exceptionless.nlog), an nlog target that reports to Exceptionless + +* **Fully Documented API** + For all your API needs, check out the [API Documentation](https://api.exceptionless.io/docs/index.html) +* **Bulk Actions +** Select multiple events or instances of events and do with them as you please! [Watch the preview demo.](/bulk-actions-sneak-peak-exceptionless-2-0-video/) + +* **Faster than Ever! +** Exceptionless 2.0 is a single page app (SPA) and is lightning fast. [We're using AngularJS](/angularjs-exceptionless-2-0/) and we're stoked to give our users a super quick experience! + +* **And more... +** Check out more new features, including source links, in our [Exceptionless 2.0 Overview article](/upcoming-exceptionless-version-2-0-overview-review/). Includes details on: Event Based Reporting System, Simplified API, The Pluggable System, Client Rewrite, New Message Bus & Queuing, and Job System Enhancement. + +## Help Us Make Exceptionless 2.0 Even Better + +We've asked a few times already in this post, but we have to ask, once again, for your [feedback](https://github.com/exceptionless/Exceptionless/issues/new)on the V2.0 platform. Our users define Exceptionless, and to make it the absolute best we can, we rely on **you** to let us know what's good, what's bad, and what we shouldn't have even wasted the bytes on. So please, give it a go and use [GitHub Issues](https://github.com/exceptionless/Exceptionless/issues/new) to give us your thoughts. We appreciate it more than you know. Thanks! + + diff --git a/docs/news/2015/2015-03-12-its-go-time-exceptionless-2-0-launched.md b/docs/news/2015/2015-03-12-its-go-time-exceptionless-2-0-launched.md new file mode 100644 index 0000000000..5968320f5b --- /dev/null +++ b/docs/news/2015/2015-03-12-its-go-time-exceptionless-2-0-launched.md @@ -0,0 +1,81 @@ +--- +title: "IT'S GO TIME - Exceptionless 2.0 Launched!" +--- + +# IT'S GO TIME - Exceptionless 2.0 Launched! + +![version-2.0-launched](/assets/img/news/version-2.0-launched.png)Today, after much development and [weeks of live user testing and feedback](#and-more), we have officially released Exceptionless 2.0 into the wild! + +Users will notice a completely new interface and experience **numerous new features and improvements**, highlighted below. Existing users that [update their clients](/docs/self-hosting/upgrading-self-hosted-instance) (not required) will experience improved client efficiency, the ability to send us logs, and more. We believe 2.0 will usher in a new era in event reporting and logging, becoming a true asset to developers everywhere. + +Shipping 2.0 out to our amazing customers has us **overwhelmed with excitement**, and we can't wait to see all the new ways in which Exceptionless will be used to squash bugs and improve apps everywhere. Read on for more details on updating existing clients and all the new features and changes. **We know you'll love it.** + + + + [Check Out Exceptionless 2.0 Now!](https://be.exceptionless.io/) + + + + + +## Updating Clients for Existing Users + +Follow these quick and easy steps below to update your Exceptionless client to 2.0. + + 1. Open the NuGet Package Manager dialog. + 2. Click on the Updates tab. + 3. Select the Exceptionless NuGet packages and click the Update button. + 4. **You should be good to go! +** If you need more info, view our [updating documentation](/docs/self-hosting/upgrading-self-hosted-instance) or contact us via in-app support. We're always here to help if you have any questions! + +## Exceptionless 2.0 Feature Recap + +### Check out these awesome new and improved features + + +![Exceptionless 2.0 Screenshot](/assets/img/news/version-2-launch-screenshot-150x150.jpg) + +Exceptionless 2.0 is faster, sleeker, mobile-friendly, more functional, includes all the below major improvements, and has countless smaller tweaks and changes we poured our heart and soul into. It's a whole new system - check it out! + +* **Searching / Filtering** + We’ve implemented Elasticsearch and you can search/filter ALL the things! Read more [here](/making-move-elastic-search-exceptionless-2-0/) and watch a quick demo video [here](/filter-your-exceptions-video-demo/). + +* **Cross Organization Views** + You now have the ability to view all events across all organizations, a single organization, or a project. + +* **PCL Support** + We’ve built in client support for [portable class libraries](https://www.nuget.org/packages/exceptionless.portable)! + +* ****New Clients! +**** Including: [Exceptionless.Portable](https://www.nuget.org/packages/exceptionless.portable) for console apps and [Exceptionless.NLog](http://www.nuget.org/packages/exceptionless.nlog), an nlog target that reports to Exceptionless + +* **Fully Documented API** + For all your API needs, check out the [API Documentation](https://api.exceptionless.io/docs/index.html) + +* **Bulk Actions +** Select multiple events or instances of events and do with them as you please! [Watch the preview demo.](/news/2014/2014-12-12-bulk-actions-sneak-peak-exceptionless-2-0-video) + +* **Faster than Ever! +** Exceptionless 2.0 is a single page app (SPA) and is lightning fast. [We’re using AngularJS](/news/2014/2014-10-23-angularjs-exceptionless-2-0) and we’re stoked to give our users a super quick experience! + +### And more... + +Check out more new features, including source links, in our [Exceptionless 2.0 Overview article](/news/2014/2014-08-13-upcoming-exceptionless-version-2-0-overview-review). Includes details on: Event Based Reporting System, Simplified API, The Pluggable System, Client Rewrite, New Message Bus & Queuing, and Job System Enhancement. + +## Live User Testing Review & Notes + +**Our live preview went great! Thank you EVERYONE that sent feedback and comments.** + +We received some awesome feedback from many of our customers, made some UI/usability tweaks and improvements, and fixed a few minor bugs. We also added the ability to search custom fields, which is a pretty big deal for some. + +Naturally, we used Exceptionless 2.0 to log, report on, and gather data for the preview - and it worked amazingly! (shameless, but true, promotion) + +On average, we traced **200,000+ anonymous log messages** within the app **each day** from preview activity. That data allowed us to learn a lot more about the behavior of Exceptionless 2.0 in areas such as jobs and gave us additional insight into what was going on. We were able to use a combination of errors, logs, and feature usage metrics to track down and fix an issue with external logins, as well. Awesome! + +The system also helped us track down and identify a performance issue that we were able to fix and improve. + +Overall, we had no major surprises and were able to tweak and improve several pieces of the app that we think will make it even more awesome. + +## Keep The Feedback Coming + +No software application is ever "done," so make sure to keep the feedback coming. We've made a huge leap from Exceptionless 1.x, but we want to keep improving the system in all areas. **We love hearing from our users**, and respond to each email, in-app message, website form submission, etc. So, please, let us know what you think! diff --git a/docs/news/2015/2015-03-25-logging-feature-usages-with-exceptionless.md b/docs/news/2015/2015-03-25-logging-feature-usages-with-exceptionless.md new file mode 100644 index 0000000000..8b3bddcb85 --- /dev/null +++ b/docs/news/2015/2015-03-25-logging-feature-usages-with-exceptionless.md @@ -0,0 +1,104 @@ +--- +title: "Logging Feature Usages with Exceptionless" +--- + +# Logging Feature Usages with Exceptionless + +![Exceptionless Feature Usage](/assets/img/news/feature-usage.png)The ability to log feature usages is one of the many [new... features... of Exceptionless 2.0](/its-go-time-exceptionless-2-0-launched/). + +If you want to know when a button is being clicked, or what users are doing certain tasks, feature usage logging will help you track and visualize each occurrence. + +What you learn from logging these types of feature usages might surprise you, and at the very least you'll know more about how users interact with your system. + +## How to Submit a Feature Usage + +### Using the client + +For this example, we are assuming that you have already created an account and installed and [configured](/docs/clients/dotnet/configuration) the Exceptionless 2.0 client. If you are still using the 1.x client, you will need to [upgrade](/docs/clients/dotnet/upgrading) to send us feature usage events. Please contact support via an in-app support message or our [contact page](/contact/) if you have any questions or need assistance in this area. + +#### Example 1 - Signup + +In the example below, we are going to submit a feature usage when any user signs up. + +**To submit the feature occurrence, you just need to call our api as follows:** + +```cs +using Exceptionless; +ExceptionlessClient.Default.SubmitFeatureUsage("Signup"); +``` + +SubmitFeatureUsage creates a simple feature usage and submits it. To include more information, please use CreateFeatureUsage (example below). + +#### More detailed examples + +You can also submit additional information with a feature usage using our fluent api. This is nice when you want to add contextual information, contact information, or a tag. + +#### Example 2 - Signup with tags + +If, for instance, you wanted to indicate how a user signs up, you can add a tag to the feature usage occurrence. In the below example, we are tagging a feature usage that uses GitHub to sign up. + +```cs +using Exceptionless; +ExceptionlessClient.Default.CreateFeatureUsage("Signup").AddTags("GitHub").Submit(); +``` + +#### Example 3 - Who's Searching? + +As another example, maybe we want to log a feature usage when users search, and then set their identity. + +```cs +using Exceptionless; +ExceptionlessClient.Default.CreateFeatureUsage("Searching").SetUserIdentity("John Smith"); +``` + +#### What else can I add to a submission? + +There are a number of additional pieces of data you can use for your event. The below bullets include the current EventBuilder list, but we are always adding more that can be found on [GitHub](https://github.com/exceptionless/Exceptionless.Net/blob/master/src/Exceptionless/EventBuilder.cs). Also, view more examples here on our [Sending Events](/docs/clients/dotnet/sending-events) page. + +* AddTags +* SetProperty +* AddObject +* MarkAsCritical +* SetUserIdentity +* SetUserDescription +* SetVersion +* SetSource +* SetSessionId +* SetReferenceId +* SetMessage +* SetGeo +* SetValue +* And more, depending on your client + +### Using the REST API + +You can also submit a feature usage by posting JSON to our API. See details in our [API Documentation](https://api.exceptionless.io/docs/index.html#!/Event/Event_Post). If you need an API key for simply posting events, you can find it in your [project settings](https://be.exceptionless.io). Otherwise, please refer to the [auth login documentation](https://api.exceptionless.io/docs/index.html#!/Auth/Auth_Login) to get a user scoped api key. + +```json +{ + "type": "usage", + "source": "Signup" +} +``` + +## The Dashboard + +Feature usage logging makes it very easy to see how often a feature, such as logging into an account, is used over time. If usage of one type of login, for instances, is never used, there might be an issue or you could consider removing it (less code debt). Or, if one is used the majority of the time, maybe it should be first in the list. There are almost unlimited ways you can use feature usage data to improve user experience. + +![Exceptionless Feature Usage Dashboard](/assets/img/news/feature-usage-dashboard-1024x603.png) + +If we click on the stack for the signup feature, it shows the tag list of the providers that have been used to signup (GitHub and Google, in this instance). + +![Exceptionless Feature Usage Stack](/assets/img/news/feature-usage-stack-tags.png) + +You can even go further and filter by a tag to see exactly how people are logging into your system using the search filter. Example: "tag:GitHub" + +![Exceptionless Feature Usage Filtering Searching](/assets/img/news/feature-usage-tag-github.png) + +Regarding the SetUserIdentity example above, we can see that user information being appended to a feature usage occurrence if we visit the "Search" feature and view an occurrence. + +![Exceptionless Feature Usage User Info](/assets/img/news/feature-usage-searching-userID.png) + +## Cool Stuff, Right? + +We think so, and we hope you do too. Either way, we're always looking for feedback, so let us know what you think via the comments below, an in app support message, or via the [contact page](/contact/ "Contact Exceptionless"). diff --git a/docs/news/2015/2015-03-31-sending-log-messages-to-exceptionless.md b/docs/news/2015/2015-03-31-sending-log-messages-to-exceptionless.md new file mode 100644 index 0000000000..60bd6ca4cb --- /dev/null +++ b/docs/news/2015/2015-03-31-sending-log-messages-to-exceptionless.md @@ -0,0 +1,145 @@ +--- +title: "Sending Log Messages to Exceptionless" +--- + +# Sending Log Messages to Exceptionless + +![Exceptionless Log Message Events](/assets/img/news/log-messages.png)We're all about exceptions, but sometimes, as developers, we run into bugs that don't throw them but still cause major havoc in the system. There are also times we just need to record an event with a custom message to help track down bottlenecks, etc. + +That's where Exceptionless meets log messages. + +In Exceptionless 2.0, you can now send custom log messages to a Log Messages dashboard where they can be tracked and view just like exceptions and other events. + +Lets take a closer look... + +## How to Submit a Log Message to Exceptionless + +### Using the Client + +For this example, we are assuming that you have already created an account and installed and [configured](/docs/clients/dotnet/configuration) the Exceptionless 2.0 client. If you are still using the 1.x client, you will need to [upgrade](/docs/self-hosting/upgrading-self-hosted-instance) to send us log messages. Please contact support via an in-app support message or our [contact page](/contact/) if you have any questions or need assistance in this area. + +#### Let's submit a log message + +```cs +using Exceptionless; +ExceptionlessClient.Default.SubmitLog("Application starting up"); +``` + +That's your basic log message. + +#### **Getting fancier**, you can also specify the log source and log level. + +In the below example, "_typeof(MainWindow)__.FullName_" specifies the log source, and "_Info_" specifies the log level. If no log source is specified, the log messages will be stacked under a global log stack. + +We recommend specifying one of the following log levels, all of which add a visual indicator to each log message (see below screenshot). + +* Trace +* Debug +* Info +* Warn +* Error + +```cs +ExceptionlessClient.Default.SubmitLog(typeof(MainWindow).FullName, "Info log example", "Info"); +``` + +Here's a screenshot of what the visual indicators for the different types of log levels look like. + +![Exceptionless Log Message Preview](/assets/img/news/log-messages-log-level.png) + +#### You can also add additional information using our fluent API. + +This is helpful wen you want to add contextual information, contact information, or a tag. + +In the below example, we will use the "_CreateLog_" method to add a tag to the log message. + +```cs +using Exceptionless; +ExceptionlessClient.Default.CreateLog(typeof(MainWindow).FullName, "Info log example", "Info").AddTags("Wpf").Submit(); +``` + +There are a number of additional pieces of data you can use for your event. The below bullets include the current EventBuilder list, but we are always adding more that can be found on [GitHub](https://github.com/exceptionless/Exceptionless.Net/blob/master/src/Exceptionless/EventBuilder.cs). Also, view more examples here on our [Sending Events](/docs/api/posting-events) page. + +* AddTags +* SetProperty +* AddObject +* MarkAsCritical +* SetUserIdentity +* SetUserDescription +* SetVersion +* SetSource +* SetSessionId +* SetReferenceId +* SetMessage +* SetGeo +* SetValue +* And more, depending on your client + +### Using the REST API + +You can also submit a log message with an HTTP post to our [events endpoint](https://api.exceptionless.io/docs/index.html#!/Event/Event_Post). + +``` +My log message +My second log message. +``` + +By default, any content that is submitted to the API post is a log message. The above example will be broken into two log messages because it automatically splits text content by the new line. + +#### You can submit a log message via JSON, too. + +See details in our [API Documentation](https://api.exceptionless.io/docs/index.html#!/Event/Event_Post). If you need an API key for simply posting events, you can find it in your [project settings](https://be.exceptionless.io/). Otherwise, please refer to the [auth login documentation](https://api.exceptionless.io/docs/index.html#!/Auth/Auth_Login) to get a user scoped api key. + +Below is a JSON example of a log message, with source, message, and log level. + +```json +{ + "type": "log", + "source": "WpfApplication3.MainWindow", + "message": "Application started", + "data": { + "@level": "Info", + } +} +``` + +### Using NLog or Log4net Targets + +We also have integrations with major logging frameworks. The benefits of using a logging framework is finer, more granular control over what is logged. + +For example, you can log only warnings or errors project-wide, but then enable trace level messages for a specific class. We do this to keep our system from getting filled up with noise that doesn't add any value unless there is an issue. + +This also allows you to quickly change what you want to log to. Maybe you want to turn off logging to Exceptionless, or log to Exceptionless and to disk. + +#### NLog or Log4net Usage + +To use the [NLog](https://www.nuget.org/packages/exceptionless.nlog)or [Log4net](https://www.nuget.org/packages/exceptionless.log4net) clients, you’ll just need to bring down the NuGet package and follow the detailed readme. + +_ +**Note on performance: Use in-memory event storage for high volumes** +_ + +_There are some performance considerations you should be aware of when you are logging very high numbers of log events and using our client. We've spent a lot of time to ensure Exceptionless doesn't degrade your applications performance. However, if you are logging thousands of messages a minute, you should use the in-memory event storage._ + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.UseInMemoryStorage(); +``` + +This tells the client not to serialize the log events to disk before sending and thus is much faster (the client doesn't need to serialize the event to disk and read it from disk before sending). This comes at the expense that if the application dies, you will lose any unsent events that were in memory. When you use the NLog or Log4net targets and specify the API key as part of the target configuration, we will automatically create a second client instance that uses in-memory storage only for log messages. This way, any logged exceptions or feature usages still use disk storage, while log messages use in-memory storage, allowing maximum performance. + +**Another Note:** We are also working on updating the [Serilog implementation](https://github.com/serilog/serilog/issues/381). + +## Log Messages Dashboard + +The Log Messages Dashboard makes it easy to see log occurrences. You can keep track of how active a component is, or how long code takes to execute using existing metrics. + +For metrics, we have created an [open source metrics library called Foundatio](https://github.com/FoundatioFx/Foundatio). We use it for Exceptionless, and think you will find it extremely helpful as well. Check it out! We'll be posting an article on Foundatio soon, so check back. + +## ![log-messages-dashboard](/assets/img/news/log-messages-dashboard.png) + +How Are You Liking Exceptionless 2.0? + +We think we've added some pretty cool features to Exceptionless 2.0, including logging, but you are the ultimate judge. What's good? What's bad? What's missing? Let us know via a comment on the blog, social media, in-app, or however else you want to get in touch! + +If you're new to Exceptionless 2.0, make sure to [check out the launch article](/news/2015/2015-03-12-its-go-time-exceptionless-2-0-launched) for more details on the new features and enhancements. diff --git a/docs/news/2015/2015-04-06-how-to-add-a-plugin-to-affect-events-in-exceptionless.md b/docs/news/2015/2015-04-06-how-to-add-a-plugin-to-affect-events-in-exceptionless.md new file mode 100644 index 0000000000..3ce71c83ed --- /dev/null +++ b/docs/news/2015/2015-04-06-how-to-add-a-plugin-to-affect-events-in-exceptionless.md @@ -0,0 +1,150 @@ +--- +title: "How to Add a Plugin to Affect Events in Exceptionless" +--- + +# How to Add a Plugin to Affect Events in Exceptionless + +![Exceptionless Plugins](/assets/img/news/plugins-code-featured1.jpg)A plugin is a client-side addin that is run every time you submit an event. + +Plugins can be used to add or remove data from an event, or even allow you to cancel an event submission. + +Each client-specific implementation registers a plugin to provide client-specific information like request info, environmental info, etc. These abilities make plugins very powerful. + +Let's take a more in-depth look at Exceptionless Plugins and how they are used. + + + +## Pre-Reqs + +First, we are assuming that you have already created an account and installed and [configured](/docs/clients/dotnet/configuration) the latest version of the Exceptionless client (plugins require client v3 - released 4/6/2015). If you are still using the 1.x client, you will need to [upgrade](/docs/self-hosting/upgrading-self-hosted-instance) to use plugins.  Please contact support via an in-app support message or our [contact page](/contact/) if you have any questions or need assistance in this area. + +## Creating a New Plugin + +Before we create our first plugin, it’s important to keep in mind that **each plugin will run every time an event is submitted**. As such, you should ensure your plugins are fast and not super resource-intensive so your app remains as quick as possible. + +To create a plugin, you have to specify a System.Action<EventPluginContext>, or create a class that derives from [IEventPlugin](https://github.com/exceptionless/Exceptionless.Net/blob/master/src/Exceptionless/Plugins/IEventPlugin.cs). + +Every plugin is passed an [EventPluginContext](https://github.com/exceptionless/Exceptionless.Net/blob/master/src/Exceptionless/Plugins/EventPluginContext.cs), which contains all the valuable contextual information that your plugin may need via the following properties: + +* **Client +** The ExceptionlessClient that created the event. +* **Event +** The target event. +* **ContextData +** Allows plugins to access additional contextual data to allow them to add additional data to events. +* **Log +** An ExceptionlessLog implementation that lets you write to the internal logger. This internal logger is used only when debugging the client. +* ****Resolver +**** The ExceptionlessClient\`s dependency resolver. This is useful for resolving other dependencies at runtime that were not requested via constructor injection. + +### Exceptionless Plugin Example - Add System Uptime to Feature Usages + +The following system uptime plugin derives from IEventPlugin and places the system uptime into every feature usage event as extended data when the plugin’s Run(context) method is called. + +```cs +using System; +using System.Diagnostics; +using Exceptionless.Plugins; +using Exceptionless.Models; + +namespace Exceptionless.SampleConsole.Plugins { + [Priority(100)] + public class SystemUptimePlugin : IEventPlugin { + public void Run(EventPluginContext context) { + // Only update feature usage events. + if (context.Event.Type != Event.KnownTypes.FeatureUsage) + return; + + // Get the system uptime + using (var pc = new PerformanceCounter("System", "System Up Time")) { + pc.NextValue(); + + var uptime = TimeSpan.FromSeconds(pc.NextValue()); + + // Store the system uptime as an extended property. + context.Event.SetProperty("System Uptime", String.Format("{0} Days {1} Hours {2} Minutes {3} Seconds", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds)); + } + } + } +} +``` + +**Output in Exceptionless:** + +#### [![Exceptionless Plugin System Uptime](/assets/img/news/exceptionless-plugin-system-uptime.png)](/assets/img/news/exceptionless-plugin-system-uptime.png) + +_Note:_ We kept the formatting of the uptime simple for the sake of this example, but we recommend using our [open source DateTimeExtensions library](https://github.com/exceptionless/Exceptionless.DateTimeExtensions) if you wish to format it in a really pretty manner. + +#### Plugin Priority + +You might have noticed that there is a priority attribute with a value of 100. The priority of a plugin determines the order that the plugin will run in (runs in order of lowest to highest, and then by order added). All plugins that ship as part of the client start with a priority of 10 and increment by multiples of 10. If you want your addin to run first, give it a low priority (e.g., 0, 1, 2, 3, 4, 5). If you want it to run last, give it a high priority (>100). By default, if you don’t specify a priority, 0 will be used. + +To make sure your plugin runs first (if required), you can inspect the configuration's plugin property in Visual Studio while debugging. + +```cs +foreach (var plugin in Exceptionless.ExceptionlessClient.Default.Configuration.Plugins) + Console.WriteLine(plugin); +``` + +![Exceptionless Plugin Priority](/assets/img/news/exceptionless-plugin-priority.png) + +## Adding the Plugin to Your App + +Now that we've created the plugin, we’ll add it when our application starts up by calling one of the Exceptionless.ExceptionlessClient.Default.Configuration.AddPlugin() overloads. + +In most cases, we use the following overload to register plugins: + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.AddPlugin(); +``` + +When you add a plugin by specifying the type, we inspect the type and try to find a PriorityAttribute. If we can’t find one, the default value of 0 will be used. + +You can also add a plugin by passing a System.Action<EventPluginContext> to AddPlugin. +_Please note that we are specifying a key when adding the action plugin so we can remove it later. If you are not going to be removing your plugin, then you can omit the first argument._ + +**We pass AddPlugin three arguments:** + +* **A unique plugin key** (which can be used to remove the plugin later) +* **Priority** +* **An action** that contains all of our logic to add the system uptime (or whatever your plugin does). + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.AddPlugin("system-uptime", 100, context => { + // Only update feature usage events. + if (context.Event.Type != Event.KnownTypes.FeatureUsage) + return; + + // Get the system uptime + using (var pc = new PerformanceCounter("System", "System Up Time")) { + pc.NextValue(); + var uptime = TimeSpan.FromSeconds(pc.NextValue()); + + // Store the system uptime as an extended property. + context.Event.SetProperty("System Uptime", String.Format("{0} Days {1} Hours {2} Minutes {3} Seconds", uptime.Days, uptime.Hours, uptime.Minutes, uptime.Seconds)); + + } +}); +``` + +## Removing an Existing Plugin + +To remove a previously added plugin, you need to call one of the Exceptionless.ExceptionlessClient.Default.Configuration.RemovePlugin overloads. + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.RemovePlugin(); +``` + +If you registered your plugin via an action, you will need to remove the plugin with the key it was added with. + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.RemovePlugin("system-uptime"); +``` + +## How Can You Use Plugins? + +Can you think of ways that plugins can help your app? Are you already building some? Let us know what they are and how they help! Eventually, we plan on building a library of useful and common plugins that other developers can easily implement. The more help we've got, the faster that library will grow! diff --git a/docs/news/2015/2015-04-16-an-exceptionless-nuget-package-tour.md b/docs/news/2015/2015-04-16-an-exceptionless-nuget-package-tour.md new file mode 100644 index 0000000000..131605ee70 --- /dev/null +++ b/docs/news/2015/2015-04-16-an-exceptionless-nuget-package-tour.md @@ -0,0 +1,101 @@ +--- +title: "An Exceptionless NuGet Package Tour" +date: 2015-04-16 +--- + +# An Exceptionless NuGet Package Tour + +![Exceptionless NuGet Packages](/assets/img/news/nugetlogo.png)Giving back to the development community is important to us over here at Exceptionless. [We love open source!](https://github.com/exceptionless) + +As such, the Exceptionless [NuGet assembly library](https://www.nuget.org/profiles/exceptionless?showAllPackages=True), with 31 assemblies and over 176,000 package downloads, is ever growing and expanding right along with our [GitHub repos](https://github.com/exceptionless). + +We thought we would give everyone a quick tour, and at the same time perhaps provide a good resource and reference page. + +Don't forget, though - this page may be out-dated by the time you view it, so please [view our full library on NuGet](https://www.nuget.org/profiles/exceptionless?showAllPackages=True). + +## Exceptionless NuGet Clients + +Exceptionless, our primary [open source](https://github.com/exceptionless/Exceptionless.net) application, provides real-time error, feature, and log reporting for ASP.NET, Web API, WebForms, WPF, Console, and MVC apps (and more, soon!). + +Below you will find the NuGet assemblies for all the platforms we currently support. + +[Exceptionless.Portable](https://www.nuget.org/packages/Exceptionless.Portable/) +Exceptionless client for portable (PCL) applications. This is the base library all the other implementations build on top of. It contains all the basic functionality that powers the Exceptionless clients! This library can be used on many different platforms. It’s worth noting that this is a very basic client and as such you won’t get all the bells and whistles as described [here](/docs/clients/dotnet/configuration) in the PCL configuration section. For those bells and whistles, see the Exceptionless package, below. +Frameworks: .NET 4, .NET 4.5, Silverlight 5, Windows 8, Windows Phone 8.1, Windows Phone Silverlight 8 + +[Exceptionless](https://www.nuget.org/packages/Exceptionless/)Exceptionless client for non visual (ie. Console and Services) applications.** **We recommend using this package if you are not using any other platform specific packages (E.G., Exceptionless.Mvc), as it provides all the bells and whistles that are missing in the portable package. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.Mvc](https://www.nuget.org/packages/Exceptionless.Mvc/)Exceptionless client for ASP.NET MVC 3+ applications. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.WebApi](https://www.nuget.org/packages/Exceptionless.WebApi/)Exceptionless client for ASP.NET Web API applications. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.Web](https://www.nuget.org/packages/Exceptionless.Web/)Exceptionless client for ASP.NET WebForms applications. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.Nancy](https://www.nuget.org/packages/Exceptionless.Nancy/)Exceptionless client for [Nancy](http://nancyfx.org/) applications. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.Wpf](https://www.nuget.org/packages/Exceptionless.Wpf/) +Exceptionless client for WPF applications. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.Windows](https://www.nuget.org/packages/Exceptionless.Windows/)Exceptionless client for Windows Forms applications. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.NLog](https://www.nuget.org/packages/Exceptionless.NLog/)NLog target that sends log entries to Exceptionless. +Frameworks: .NET 4.0, .NET 4.5 + +[Exceptionless.Log4net](https://www.nuget.org/packages/Exceptionless.Log4net/)Log4net appender that sends log entries to Exceptionless. +Frameworks: .NET 4.0, .NET 4.5 + +[Serilog.Sinks.ExceptionLess](https://www.nuget.org/packages/Serilog.Sinks.ExceptionLess/)Serilog sink that sends log entries to Exceptionless. +Frameworks: .NET 4.0, .NET 4.5 +[View Source](https://github.com/serilog/serilog-sinks-exceptionless) + +### Signed Assemblies + +We also have signed versions of most assemblies on our [NuGet Profile](https://www.nuget.org/profiles/exceptionless?showAllPackages=True). See MSDN for additional info on signing assemblies ([Strong-Named Assemblies](https://msdn.microsoft.com/en-us/library/wd40t7ad%28v=vs.110%29.aspx)). + +## Foundatio by Exceptionless + +Foundatio (Requires .NET 4.5) is an open source library for building distributed applications that we built, use, and think you will find helpful. Foundatio provides in memory, redis, and azure implementations. This allows you to do development or testing using in-memory versions and switch them out for redis or azure implementations in production. This saves you time (setup and maintaining) and money (not paying for cloud resources) during development and testing! Foundatio source code can be found at [https://github.com/FoundatioFx/Foundatio](https://github.com/FoundatioFx/Foundatio). + +Exceptionless was built using Foundatio and utilizes implementations for caching, queues, locks, messaging, jobs, file storage, and metrics. + +[Foundatio](https://www.nuget.org/packages/Foundatio/) +Foundatio consists of pluggable foundation blocks for building distributed apps, including caching, queues, locks, messaging, jobs, file storage, and metrics. + +[Foundatio Redis Implementations](https://www.nuget.org/packages/Foundatio.Redis/) +Contains the redis implementations of caching, queues, locks, messaging, jobs, file storage. + +[Foundatio Azure ServiceBus Implementations](https://www.nuget.org/packages/Foundatio.AzureServiceBus/) +Contains the redis implementations of queues and messaging. The azure packages are split into different packages so you don't have to take extra azure dependencies on things you don't need. + +[Foundatio Azure Storage Implementations](https://www.nuget.org/packages/Foundatio.AzureStorage/) +Contains the redis implementations of file storage. The azure packages are split into different packages so you don't have to take extra azure dependencies on things you don't need. + +## Other + +[Exceptionless LuceneQueryParser](https://www.nuget.org/packages/Foundatio.Parsers.LuceneQueries/) +Lucene Query Parser is a lucene style query parser that is extensible and allows additional syntax features. We use this in [Exceptionless](https://github.com/exceptionless/Exceptionless) to [ensure the query is valid before executing it, check to see if you are trying to a basic or premium search query and much more](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Repositories/Queries/Validation/PersistentEventQueryValidator.cs)! +Frameworks: .NET 4.5 +[View Source](https://github.com/FoundatioFx/Foundatio.Parsers) + +[Exceptionless RandomData](https://www.nuget.org/packages/Exceptionless.RandomData/) +RandomData is a utility class for easily generating random data, making the creation of good unit test data a breeze. +Frameworks: .NET 4.0, .NET 4.5 +[View Source](https://github.com/exceptionless/Exceptionless.RandomData) + +[Exceptionless DateTimeExtensions](https://www.nuget.org/packages/Exceptionless.DateTimeExtensions/) +This package includes DateTimeRange, Business Day, and various DateTime, DateTimeOffset, and TimeSpan extension methods. +Frameworks: .NET 4.0, .NET 4.5, Windows 8, Windows Phone 8.1 +[View Source](https://github.com/exceptionless/Exceptionless.DateTimeExtensions) + +## We'll Keep Building! + +We don't plan on stopping anytime soon, and will continue writing assemblies to make life easier for developers everywhere. Naturally, we could always use your help, so [fork us on GitHub](https://github.com/exceptionless) if you feel like chipping in. We always appreciate our contributors! + +Otherwise, let us know what you think of Exceptionless, Foundatio, and all our other projects. Feedback is always welcomed and appreciated. diff --git a/docs/news/2015/2015-04-30-filter-and-searching-tutorial-video-exceptionless.md b/docs/news/2015/2015-04-30-filter-and-searching-tutorial-video-exceptionless.md new file mode 100644 index 0000000000..80f8897bad --- /dev/null +++ b/docs/news/2015/2015-04-30-filter-and-searching-tutorial-video-exceptionless.md @@ -0,0 +1,56 @@ +--- +title: "Filter and Searching Tutorial Video - Exceptionless" +--- + +# Filter and Searching Tutorial Video - Exceptionless + +![Exceptionless Search Filtering](/assets/img/news/filter-search.png)One of the most requested features from the beginning of Exceptionless 1.0 was a filtering and searching system. When we started developing Exceptionless 2.0, we knew it was one of the major features we wanted to include. + +We couldn't just throw in a string search and hope for the best. We had to build it in a way that let users perform basic and advanced filtering, easily, with fast and streamlined results. + +**Enter Exceptionless filtering and searching.** You can filter by organization, project, multiple time frame selectors, and specific event variables (with modifiers). + +Watch the video below for a quick test drive, and read further down the page for more details and links! + +## Exceptionless Filtering and Search Demo Video + + +## Filter by Organization & Project + +![Exceptionless Organizations and Projects](/assets/img/news/filter-by-project-organization-300x208.png) + +By default, the dashboard loads up with all projects selected. + +To show only data from a specific organization or project within an organization, simply click on the "All Projects" drop down in the top left of the dashboard and select your organization or project. + +Whatever view you are in will then be transformed to display only data from that organization/project. + +To change it back to all projects, simply select the drop down again and click on "All Projects." + +## Filter by Time Frame + +![Exceptionles Time Frame Filters](/assets/img/news/filter-by-timeframe-300x205.png) + +Exceptionless offers multiple preset time frame options, as well as the ability to customize the time frame down to the second. + +To select your time frame of choice, click on the calendar icon next to the project drop down on the top navigation bar of your dashboard. + +Once there, you can select "Last Hour," "Last 24 Hours," "Last Week," "Last 30 Days," "All Time," or "Custom." + +Most of these options are pretty self explanatory, but if you click on "Custom," a popup will appear that lets you select the start and end date, as well as start and end hours, minutes, and seconds of those dates. + +Another way to control the data time frame is to simply select a period of time on the history graph itself by clicking, dragging, and releasing. This will automatically update the custom time frame points and refresh the data to match that period. + +## Filter and Search by Specific Criteria + +![Exceptionless Search Filter Feature](/assets/img/news/filter-by-search-filter-criteria-300x203.png) + +Being able to search your errors and events by specific criteria is, perhaps, the largest improvement for version 2.0. + +By selecting the magnifying glass icon next to the calendar icon in the top navigation, you can enter [search criteria](/docs/filtering-and-searching) and select whether you want the results to include fixed and/or hidden events/errors. + +You can filter by tag, ID, organization, project, stack, type, value, IP, architecture, user, and much much more. Some searches, such as ID, require a prefix ("id:") on the search, but others, such as error.message, can be entered as strings ("A NullReferenceException occurred"). View a complete list of searchable terms, examples, and FAQs on our [Searching Documentation Page](/docs/filtering-and-searching). + +## We're Always Improving - What Could be Better? + +Please let us know what you think of the filtering and searching abilities by commenting here on the blog, sending us an in-app support message, or filling out our [contact form](/contact/ "Exceptionless Contact Form"). We're always looking for feedback, and genuinely want to know what you think! diff --git a/docs/news/2015/2015-05-06-exceptionless-api-usage-and-overview.md b/docs/news/2015/2015-05-06-exceptionless-api-usage-and-overview.md new file mode 100644 index 0000000000..910445cd3f --- /dev/null +++ b/docs/news/2015/2015-05-06-exceptionless-api-usage-and-overview.md @@ -0,0 +1,131 @@ +--- +title: "Exceptionless API Usage and Overview" +--- + +# THESE DOCS HAVE BEEN UPDATED. SEE THE [NEW DOCS HERE](/docs/api/). + +![Exceptionless API](/assets/img/news/Screenshot-2015-05-06-16.26.42-300x220.png) + +So you've been using Exceptionless for a while, but you wish you had a different dashboard, or maybe you'd like to integrate event data into one of your apps. No problem, **just use the API!** + +Through our adventures while building Exceptionless, we've kept open source, automation, and ease of use in mind. With that, we think our API, which utilizes [Swagger](http://swagger.io/) and [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle) to automatically generate, update, and display documentation (which means it works automatically on self-hosted environments), is a great resource for our users that want to get their hands dirty and use Exceptionless data to roll their own tools, dashboards, etc. + +Lets take a closer look at the API, how to use it, and some quick examples of what can be done. + +## Start Using the Exceptionless API + +### Accessing the API + +To access the Exceptionless API, visit [https://api.exceptionless.io](https://api.exceptionless.io) and click on the "API Documentation" link to be taken to the API documentation. + +### Get Your User Scoped Token + +Tokens are used to access the api and have roles (scopes). When you authenticate via the login controller action, you are getting a token that impersonates your user so it has the same roles as your user account (e.g., client and user). + +#### +[Go to Auth controller action](https://api.exceptionless.io/docs/index.html#!/Auth/Auth_Login) + and enter your login credentials. + +You can enter JSON into the model field, or you an click the yellow box on the right to pre-populate the field with acceptable JSON fields. Just replace the values that you want to specify and remove the fields you don't need, like invite token. + +![Exceptionless API Get User Scoped Token](/assets/img/news/01get-user-scope-token1-300x218.png) + +Click "Try it out!" and generate your token. Take note of the response messages section above the button, as it details the possible codes that would be returned in the event of an error (e.g. 401 if the user name or email address was incorrect). + +![Retrieve Exceptionless User Scoped Token](/assets/img/news/01get-user-scope-token2-300x105.png) + +You can see from the response that it returned our token from the request url above. Take your generated token and put it in the "api_key" field at the top of the page and click "Explore." This authorizes you via bearer authentication, authenticates you to the rest api, and allows you to call controller actions. + +![Add Exceptionless User Scoped Token ](/assets/img/news/02add-token-refresh-page-300x50.png) + +### Get a New Token + +Now, we’ll get a new token for the project we want to work on and assign it a user role (scope) of "user." We want to get a new user scoped token because we want to do more than just post events (client scoped tokens only allow you to post events), we want to retrieve them. Creating a new token also allows us to revoke the token later. + +First, get your project ID from the Exceptionless Dashboard. It can be found in the URL of that project’s dashboard. + +![Get Exceptionless Project ID](/assets/img/news/03get-project-ID-300x141.png) + +Now, we’ll navigate to [Tokens > POST /api/v2/projects/{projectId}/tokens](https://api.exceptionless.io/docs/index.html#!/Token/Token_PostByProject), enter our Project ID, and set up our token to include the user scope and a quick note. + +![Create Exceptionless Token](/assets/img/news/04get-new-token1-300x220.png) + +Next, we'll click "Try it out!" and generate our new token id. + +![Get new Exceptionless Token ID](/assets/img/news/04get-new-token2-300x146.png) + +Now, once again, copy this new token and place it in the "api_key" field at the top of the page and click "Explore." Now everything we do will be authenticated to this new user token you’ve just created. + +### Posting an Event + +Now, lets post an event with a reference ID that we’ll use for a few other examples. + +First, navigate to [Event > POST /api/v{version}/events](https://api.exceptionless.io/docs/index.html#!/Event/Event_PostAsync) + +![Exceptionless API Post Event](/assets/img/news/05post-event1-300x204.png) + +You’ll see a few basic examples of events and some explanation of the resource in this panel. Make sure to give it a read. For this example, we’ll use a simple log event, with a brief message, and add a reference ID to it. _Note that you must also enter the current API version in the "version" field._ + +When we click "Try it out!" and get a 202 response code, we know we’ve created an event. + +![Exceptionless API Created Event](/assets/img/news/05post-event2-e1430946143322-300x92.png) + +### Get Event by Reference ID + +If we want to get the event we just created by it’s reference_id, we can navigate to [Event > GET /api/v2/events/by-ref/{referenceId}](https://api.exceptionless.io/docs/index.html#!/Event/Event_GetByReferenceId), enter that reference ID, and get back the details of the event. + +![Get Exceptionless Event by ReferenceID](/assets/img/news/06-get-by-reference-ID2-300x271.png) + +### Getting the Event via a Search Filter + +Another example of getting an event may include using the reference ID or another search filter we just created and getting all by a reference filter. You can use any [search filter](/docs/filtering-and-searching) in the filter parameter. + +To do so, navigate to [Event > GET /api/v2/events](https://api.exceptionless.io/docs/index.html#!/Event/Event_Get) and use the reference term to filter events by the reference ID. + +[![Exceptionless API Get All Filter Search](/assets/img/news/07-get-all-filter-reference-300x168.png)](/assets/img/news/07-get-all-filter-reference.png) + +Results + +![Exceptionless API Get Al Filter Search Results](/assets/img/news/07-get-all-filter-reference2-300x183.png) + +### Get Organizations and Projects + +Naturally, we can get all the organizations or projects associated with the current authorized token, as well. + +#### Organizations + +Navigate to [Organization > GET /api/v2/organizations](https://api.exceptionless.io/docs/index.html#!/Organization/Organization_Get) and click "Try it out!" + +![Exceptionless API Get Organization Results](/assets/img/news/08get-organizations2-300x202.png) + + +#### Projects + + +Navigate to [Project > GET /api/v2/projects](https://api.exceptionless.io/docs/index.html#!/Project/Project_Get) and click "Try it out!" + +![Exceptionless API Get Projects Results](/assets/img/news/09get-projects2-300x204.png) + + +## How to Authenticate to the API + + +### 1. Bearer Authentication + +The api documentation uses bearer authentication to authenticate to the API. You can do this in your apps too by specifying a bearer authorization header with your token as shown below. + +![Exceptionless Bearer Authentication](/assets/img/news/10-bearer-auth-key-300x164.png) + +### 2. Authenticate via the Query String + +Everything we’ve shown you today can be easily and cleanly accessed via a URL query string and your access token. + +For example, if we want to view our organizations, we simply navigate to https://api.exceptionless.io/api/v2/organizations, add the query string "?access_token={token}" and press enter to get the data. + +![Exceptionless Query String API Authentication](/assets/img/news/11-url-query-string-version-300x145.png) + +## Let Us Know What You Think! + +We've tried to make the API as easy and intuitive to use as possible, but we're always open to feedback and comments, so please let us know what could be better, easier, faster, etc. + +And, of course, if you have any questions about the API, please leave a comment here, send us an in-app support message, or simply submit the website [contact form](/contact/ "Contact Exceptionless"). diff --git a/docs/news/2015/2015-05-07-exceptionless-v2-0-1-shipped.md b/docs/news/2015/2015-05-07-exceptionless-v2-0-1-shipped.md new file mode 100644 index 0000000000..2169f1442f --- /dev/null +++ b/docs/news/2015/2015-05-07-exceptionless-v2-0-1-shipped.md @@ -0,0 +1,29 @@ +--- +title: "Exceptionless V2.0.1 Shipped!" +--- + +# Exceptionless V2.0.1 Shipped! + +This release focused on bug fixes since the 2.0 release and include the below notable changes. + +## Exceptionless Server + +* API Status page now also checks the status of Storage, Queues and Message Bus. +* **Added** the ability to requeue events (E.X., archived or events that failed to process). +* **Added** the ability to send out system and release notifications. +* Made the event posting and processing async. This has huge performance gains under load. +* The GeoIP Database is now stored in the storage folder. This made it easier to update it via a job as well as removed some extra configuration settings. +* Made some minor changes that make it a bit easier to self host (more to come 2.1). + +Please take a look at the Exceptionless [changelog](https://github.com/exceptionless/Exceptionless/compare/v2.0.0...v2.0.1) for a full list of the changes. + +## Exceptionless.UI + +* **Added** a busy indicators to some buttons allowing you to see the state of an action (E.G., Marking a stack as fixed). +* **Added** the ability to refresh the app if there is a critical website bug. +* **Fixed** a bug where some stack traces couldn't be displayed. +* Made some minor changes that make it a bit easier to self host (more to come 2.1). + +Please take a look at the Exceptionless.UI [changelog](https://github.com/exceptionless/Exceptionless.UI/compare/v2.0.0...v2.0.1) for a full list of the changes. + +## Let us know if you have any questions! diff --git a/docs/news/2015/2015-05-13-javascript-client-available-for-preview-testing.md b/docs/news/2015/2015-05-13-javascript-client-available-for-preview-testing.md new file mode 100644 index 0000000000..21c9c69fbf --- /dev/null +++ b/docs/news/2015/2015-05-13-javascript-client-available-for-preview-testing.md @@ -0,0 +1,29 @@ +--- +title: "JavaScript Client Available for Preview & Testing!" +--- + +# JavaScript Client Available for Preview & Testing! + +![Exceptionless JavaScript Client](/assets/img/news/javascript-client-header.jpg) + +That's right ladies and gentlemen, we've been working on a [JavaScript client](https://github.com/exceptionless/Exceptionless.JavaScript), and it's ready to peak it's head out into the wild. + +We're talking beta status here, but version 1.0 is on its way and we wanted to let you guys play with it as soon as possible to [provide feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues) and help us work out the bugs, etc, quicker. + +It's tough to contain our excitement about getting this out there, and we hope you'll check it out! + + + + [Check it Out!](https://github.com/exceptionless/Exceptionless.JavaScript) + + + +## Exceptionless JavaScript Client Overview + +The client supports Node.js and JavaScript, and you can find up-to-date installation, configuration, and usage documentation over on the [GitHub repo](https://github.com/exceptionless/Exceptionless.JavaScript). + +Just like the non-JavaScript client, unhandled exceptions will be automatically sent upon configuration, and you can send log messages, feature usage events, etc. All the normal Exceptionless functionality is available. + +## Wanted! + +Testers, developers, contributors, and feedback wanted! We want to make the Exceptionless JavaScript client **awesome**, but we need your help. Give us any feedback you might have via [GitHub](https://github.com/exceptionless/Exceptionless.JavaScript/issues) an in-app message, [contact form](/contact/ "Contact Exceptionless") submission, or comment right here on this blog post. We're more than happy to answer any and all questions, or help you get up and running. diff --git a/docs/news/2015/2015-05-20-exceptionless-node-js-javascript-client-demo.md b/docs/news/2015/2015-05-20-exceptionless-node-js-javascript-client-demo.md new file mode 100644 index 0000000000..fd97810805 --- /dev/null +++ b/docs/news/2015/2015-05-20-exceptionless-node-js-javascript-client-demo.md @@ -0,0 +1,159 @@ +--- +title: "Exceptionless Node.js JavaScript Client Demo" +--- + +# Exceptionless Node.js JavaScript Client Demo + +![Exceptionless Node.js JavaScript Client](/assets/img/news/node-js-header.jpg) + +Last week we announced our full featured [JavaScript client](/news/2015/2015-05-13-javascript-client-available-for-preview-testing), and we're super excited about releasing a version 1.0 soon. + +This week we'd like to put more details out there on the Node.js version of the JavaScript client, including installation, configuration, and usage. We've also set up an [Express.js sample app](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example/express/app.js) that you can spin up locally to play with things. + +Let's take a look. + +## How the JavaScript Client was Built + +Our javascript client is built in [typescript 1.5](https://github.com/Microsoft/TypeScript) and is transpiled to es5. We have a single client that works with both Node.js and JavaScript due to dependency injection and a [Universal Module Definition (UMD)](https://github.com/umdjs/umd). For capturing Node stack traces, we use [Felixge's Node Stack Trace](https://github.com/felixge/node-stack-trace) library. + +## Installing Exceptionless for Node.js + + 1. Install the package by running `npm install exceptionless --save-dev` + 2. Add the Exceptionless client to your app: + +```js +var client = require('exceptionless.node').ExceptionlessClient.default; +``` + +## Configuring the Client + +You can configure the Exceptionless client a few different ways for Node.js. The below is the most common way, but for more configuration options and documentation, visit the [Exceptionless.JavaScript GitHub repo](https://github.com/exceptionless/Exceptionless.JavaScript). _NOTE: The only required setting you need to configure is the client's apiKey._ + +Set the `apiKey` on the default ExceptionlessClient instance. + +```js +var client = require('exceptionless.node').ExceptionlessClient.default; +client.config.apiKey = 'API_KEY_HERE'; +``` + +## Sending Events + +Once configured, the Exceptionless Node.js JavaScript client will automatically send your dashboard any unhandled exceptions that happen in your application. If you would like to send additional event types, such as log messages, feature usages, etc, take a look at the below examples. + +Make sure to check out the [Exceptionless.JavaScript GitHub Repo](https://github.com/exceptionless/Exceptionless.JavaScript) for the latest examples and documentation. + +### Sending Log Messages, Feature Usages, etc + +```js +var client = require('exceptionless.node').ExceptionlessClient.default; + +client.submitLog('Logging made easy'); + +// You can also specify the log source and log level. +// We recommend specifying one of the following log levels: Trace, Debug, Info, Warn, Error +client.submitLog('app.logger', 'This is so easy', 'Info'); +client.createLog('app.logger', 'This is so easy', 'Info').addTags('Exceptionless').submit(); + +// Submit feature usages +client.submitFeatureUsage('MyFeature'); +client.createFeatureUsage('MyFeature').addTags('Exceptionless').submit(); + +// Submit a 404 +client.submitNotFound('/somepage'); +client.createNotFound('/somepage').addTags('Exceptionless').submit(); + +// Submit a custom event type +client.submitEvent({ message = 'Low Fuel', type = 'racecar', source = 'Fuel System' }); +``` + +### Manually Sending Errors + +In addition to automatically sending all unhandled exceptions, you can also manually send events to Exceptionless using our fluent [event builder API](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.6.4/src/EventBuilder.ts). + +The below example demonstrates sending a new error, "test," and setting the ReferenceID, Order and Quote properties, Tags, Geo, UserIdentity, and marking it as Critical. + +```js +var client = require('exceptionless.node').ExceptionlessClient.default; + +try { + throw new Error('test'); +} catch (error) { + client.createException(error) + // Set the reference id of the event so we can search for it later (reference:id). + // This will automatically be populated if you call client.config.useReferenceIds(); + .setReferenceId('random guid') + // Add the order object (the ability to exclude specific fields will be coming in a future version). + .setProperty("Order", order) + // Set the quote number. + .setProperty("Quote", 123) + // Add an order tag. + .addTags("Order") + // Mark critical. + .markAsCritical() + // Set the coordinates of the end user. + .setGeo(43.595089, -88.444602) + // Set the user id that is in our system and provide a friendly name. + .setUserIdentity(user.Id, user.FullName) + // Submit the event. + .submit(); +} +``` + +## Express.js Support + +If you are using [Express.js](http://expressjs.com/) to develop a web application, you can add Exceptionless and start collecting unhandled errors and 404s very quickly. To start, just add the following middleware to the bottom of your middleware definitions. + +```js +// This middleware processes any unhandled errors that may occur in your middleware. +app.use(function(err, req, res, next) { + client.createUnhandledException(err, 'express').addRequestInfo(req).submit(); + res.status(500).send('Something broke!'); +}); + +// This middleware processes 404’s. +app.use(function(req, res, next) { + client.createNotFound(req.originalUrl).addRequestInfo(req).submit(); + res.status(404).send('Sorry cant find that!'); +}); +``` + +## What Data is Collected? + +The JavaScript/Node.js client is full featured, will collect all the information our other clients collect, and has a fluent API as shown above. + +By default, we wire up to the processes' [uncaught exception handler](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.6.4/src/exceptionless.node.ts#L29-L31) to automatically send any unhandled exceptions to your Exceptionless dashboard. We also submit a log message if your app doesn't shut down properly via inspecting the [exit code](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.6.4/src/exceptionless.node.ts#L33-L81), which is very useful and lets you know what your app is doing. Additionally, any queued up events are processed and sent before your app closes. + +Each event contains environment and request information, as well, rounding out the complete list of Exceptionless features that we have made available via the JavaScript client, making it a great error and event reporting/logging solution for all your Node.js projects. + + +![Exceptionless Node.js Event Environment Details](/assets/img/news/node-js-event-environment-details-150x150.png) +_Environment Details_ + + + + +## Sample Express.js App + + +We have built a quick[Express.js sample app](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example/express/app.js) that you can play around with to get an idea of how the Node.js JavaScript client works with Exceptionless. + +**Run the sample app by following the steps below:** + + 1. Install [Node.js](https://nodejs.org/) + 2. [Clone or download our repository from GitHub](https://github.com/exceptionless/Exceptionless.JavaScript). + 3. Navigate to the example\express folder via the command line (e.g., cd example\express) + 4. Run npm install + 5. Open app.js in your favorite text editor and set the [apiKey](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example/express/app.js#L5-L6).. + 6. Run node app.js. + 7. Navigate to in your browser to view the express app. + 8. To create an error, navigate to + +## Troubleshooting + +We recommend enabling debug logging by calling `client.config.useDebugLogger();`. This will output messages to the console regarding what the client is doing. Please [contact us by creating an issue on GitHub](https://github.com/exceptionless/Exceptionless.JavaScript/issues) if you need assistance or have any feedback for the project. + +## Feedback + +As we move forward towards version 1.0 of our JavaScript client, we are looking for any and all feedback, so please don't hesitate to [let us know what you think, report a bug, etc](https://github.com/exceptionless/Exceptionless.JavaScript/issues). + +Thanks! diff --git a/docs/news/2015/2015-05-27-javascript-client-demo-exceptionless.md b/docs/news/2015/2015-05-27-javascript-client-demo-exceptionless.md new file mode 100644 index 0000000000..e29ad4df4e --- /dev/null +++ b/docs/news/2015/2015-05-27-javascript-client-demo-exceptionless.md @@ -0,0 +1,165 @@ +--- +title: "JavaScript Client Demo - Exceptionless" +--- + +# JavaScript Client Demo - Exceptionless + +![Exceptionless JavaScript Client](/assets/img/news/blog-header-javascript.jpg) + +We're getting closer and closer to version 1.0 of our [JavaScript client](/javascript-client-available-for-preview-testing/), and we wanted to give everyone a demo of installation, configuration, and usage. + +If you're using Node.js, make sure to check out last week's blog post for [Node specific examples](/news/2015/2015-05-20-exceptionless-node-js-javascript-client-demo). Otherwise, continue reading for JavaScript examples. + +As you read and begin playing with the Exceptionless JavaScript client, please make note of any feedback, bugs, etc, and [submit a GitHub issue](https://github.com/exceptionless/Exceptionless.JavaScript/issues) so we can fast track version 1.0 - we surely appreciate it! + + + +## How the JavaScript Client was Built + +We built our JavaScript client in [typescript 1.5](https://github.com/Microsoft/TypeScript) transpiled it to es5. Our single client works with both [Node.js](/news/2015/2015-05-20-exceptionless-node-js-javascript-client-demo) and JavaScript due to dependency injection and a [Universal Module Definition (UMD)](https://github.com/umdjs/umd). + +## Installing the Exceptionless JavaScript Client + +### Via Bower + + 1. Install the package by running `bower install exceptionless` + 2. Add the Exceptionless script to your HTML page. We recommend placing the script at the top of the document to ensure Exceptionless picks up and reports the absolute most potential exceptions and events. + +```html +```` +``` + +## Configuring the Client + +Configuration of the Exceptionless JavaScript client can be accomplished a variety of ways. We list the common ways below, but make sure to check the [Exceptionless.JavaScript GitHub repo](https://github.com/exceptionless/Exceptionless.JavaScript) for the most up to date documentation if you run into any problems using this example code. +_NOTE: The only required setting you need to configure is the client's apiKey._ + +### Configuration Options + +**1.** Configure the `apiKey` as part of the script tag. This method will be applied to all new instances of the ExceptionlessClient + +```html +```` +``` + +**2.** Set the `apiKey` on the default ExceptionlessClient instance. + +```js +var client = exceptionless.ExceptionlessClient.default; +client.config.apiKey = 'API_KEY_HERE'; +``` + +**3.** Create a new instance of the ExceptionlessClient and specify the `apiKey` or [configuration object](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.6.4/src/configuration/IConfigurationSettings.ts). _Note that the configuration object is optional._ + +```js +var client = new exceptionless.ExceptionlessClient('API_KEY_HERE'); // Required + +// or with a configuration object +//var client = new exceptionless.ExceptionlessClient({ + //apiKey: 'API_KEY_HERE', + //submissionBatchSize: 100 +//}); +``` + +## Sending Events + +Unhandled exceptions will automatically be sent to your Exceptionless dashboard once the JavaScript client is configured properly. In order to send additional events, including log messages, feature usages, and more, you can use the code samples below and check the [Exceptionless.JavaScript GitHub Repo](https://github.com/exceptionless/Exceptionless.JavaScript) for the latest examples and documentation. + +### Sending Log Messages, Feature Usages, etc + +```js +var client = exceptionless.ExceptionlessClient.default; + +client.submitLog('Logging made easy'); + +// You can also specify the log source and log level. +// We recommend specifying one of the following log levels: Trace, Debug, Info, Warn, Error +client.submitLog('app.logger', 'This is so easy', 'Info'); +client.createLog('app.logger', 'This is so easy', 'Info').addTags('Exceptionless').submit(); + +// Submit feature usages +client.submitFeatureUsage('MyFeature'); +client.createFeatureUsage('MyFeature').addTags('Exceptionless').submit(); + +// Submit a 404 +client.submitNotFound('/somepage'); +client.createNotFound('/somepage').addTags('Exceptionless').submit(); + +// Submit a custom event type +client.submitEvent({ message = 'Low Fuel', type = 'racecar', source = 'Fuel System' }); +``` + +### Manually Sending Errors + +To manually send events other than the automatically reported unhandled exceptions, you can use our fluent [event builder API](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.6.4/src/EventBuilder.ts). + +The below example demonstrates sending a new error, "test," and setting the ReferenceID, Order and Quote properties, Tags, Geo, UserIdentity, and marking it as Critical. + +```js +var client = exceptionless.ExceptionlessClient.default; + +try { + throw new Error('test'); +} catch (error) { + client.createException(error) + // Set the reference id of the event so we can search for it later (reference:id). + // This will automatically be populated if you call client.config.useReferenceIds(); + .setReferenceId('random guid') + // Add the order object (the ability to exclude specific fields will be coming in a future version). + .setProperty("Order", order) + // Set the quote number. + .setProperty("Quote", 123) + // Add an order tag. + .addTags("Order") + // Mark critical. + .markAsCritical() + // Set the coordinates of the end user. + .setGeo(43.595089, -88.444602) + // Set the user id that is in our system and provide a friendly name. + .setUserIdentity(user.Id, user.FullName) + // Submit the event. + .submit(); +} +``` + +## What Data is Collected? + +We built the JavaScript client to be full featured and allow you to report and log all the data our other clients do. It has a fluent API, as mentioned above, and is ready to rock and roll. + +We wire up to the window.onerror handler by default, in order to send unhandled exceptions to your Exceptionless dashboard automatically. + +Finishing off the Exceptionless JavaScript client features, every event also includes request information. + +A few screenshots of an individual event can be found below. + + +![Exceptionless JavaScript Event Request Details](/assets/img/news/javascript-client-event-request-info-150x150.png) +_Request Details_ + + + + +## Sample + + +We have put together an [example](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example) that you can use to get an idea of how everything works. It is available on the [GitHub Repo](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example). + +### To Get the Example Running... + + 1. Clone or download the [GitHub Repo](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example) + 2. Edit the HTML file in the root example folder and replace the [existing API Key](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example/index.html#L8) with yours. Also, comment out the [serverUrl](https://github.com/exceptionless/Exceptionless.JavaScript/blob/master/example/index.html#L16). + 3. Open the HTML file in your browser + 4. Open the console so that you can see the debug messages that the example generates + 5. Click the buttons on the page to submit an event + + +## Troubleshooting + + +Calling `client.config.useDebugLogger();` to enable debug logging is recommend and will output messages to the console regarding what the client is doing. Please [contact us by creating an issue on GitHub](https://github.com/exceptionless/Exceptionless.JavaScript/issues) if you need help or have any feedback regarding the JavaScript client. + +## Feedback + +As we move forward towards version 1.0 of our JavaScript client, we are looking for any and all feedback, so please don't hesitate to [let us know what you think, report a bug, etc](https://github.com/exceptionless/Exceptionless.JavaScript/issues). + +Happy coding! diff --git a/docs/news/2015/2015-06-04-javascript-node-js-client-version-1-release-candidate.md b/docs/news/2015/2015-06-04-javascript-node-js-client-version-1-release-candidate.md new file mode 100644 index 0000000000..11fb298eba --- /dev/null +++ b/docs/news/2015/2015-06-04-javascript-node-js-client-version-1-release-candidate.md @@ -0,0 +1,54 @@ +--- +title: "JavaScript & Node.js Client Version 1 Release Candidate" +date: 2015-06-04 +--- + +# JavaScript & Node.js Client Version 1 Release Candidate + +![Exceptionless JavaScript Client](/assets/img/news/javascript-release-candidate.jpg) + +If you've been following along the last few weeks, you know we've been working hard to get the new [JavaScript Client](/javascript-client-available-for-preview-testing/) up to speed and ready for a version 1 release. + +**We think we're there!** + +Whether you're a [JavaScript](/javascript-client-demo-exceptionless/) or [Node.js](/exceptionless-node-js-javascript-client-demo/) user, you'll be able to enjoy the same full featured exception and event reporting platform that our primary .NET client offers, with fewer platform specific boundaries. + +## Sure It's Ready? + +We have been doing extensive testing over the course of the last month, which has allowed us to identify issues and inefficiencies throughout. Each of those has been addressed with several improvements and fixes, leaving us with a much faster, more stable client. + +Many of the tweaks we made were related to IE9 and Node. Those issues have been resolved and things are working well now. In addition, we further increased performance by shrinking the library size fairly drastically. + +Moving forward, we will just be working on bug fixes related to user-reported issues as usage picks up. + +### Recent Bug Fixes, Issue Resolutions, & Improvements + +* Ensured compatibility with module formats like [es6](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts) ([SystemJS](https://github.com/systemjs/systemjs)/[jspm](http://jspm.io/)) and [RequireJS](http://requirejs.org/) +* Various IE9 and Node compatibility issues fixed +* Decreased library size to improve performance and efficiency +* Various other performance improvements +* Fixed Angular integration failures with Angular Router +* Fixed - Unable to integrate with Aurelia due to node being improperly detected +* Changed the implementation of the InMemoryStorage to do a get instead of a get and delete +* Unable to post events with the NodeSubmissionClient over http fixed +* Fixed - Unit tests are failing due to transpilation + +## Start Using It! + +We've already released a few blog posts (linked below) that detail how to get up and running, but please visit the [Exceptionless.JavaScript GitHub Repo](https://github.com/exceptionless/Exceptionless.JavaScript) for the most up-to-date documentation. + +**[JavaScript Users](/javascript-client-demo-exceptionless/)** can find installation, configuration, usage details and examples [here](/javascript-client-demo-exceptionless/). + +If you're a **[Node.js](/exceptionless-node-js-javascript-client-demo/) user**, follow [this article](/exceptionless-node-js-javascript-client-demo/) to get set up and running. + +We've also got [**examples/samples on GitHub**](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example) for JavaScript, Express, TypeScript, SystemJS, and RequireJS. + + + + [Try It Today!](https://github.com/exceptionless/Exceptionless.JavaScript) + + + +## Let Us Know What You Think + +We're suckers for feedback, so let us have it whether good, bad, or indifferent. Bugs, etc should be reported on the [GitHub Issues](https://github.com/exceptionless/Exceptionless.JavaScript/issues) page, but feel free to shoot us an in-app message, email, etc and let us know what you think and if you had any issues getting everything working. diff --git a/docs/news/2015/2015-06-09-javascript-node-js-client-v1-release-notes.md b/docs/news/2015/2015-06-09-javascript-node-js-client-v1-release-notes.md new file mode 100644 index 0000000000..dd4fd1002d --- /dev/null +++ b/docs/news/2015/2015-06-09-javascript-node-js-client-v1-release-notes.md @@ -0,0 +1,33 @@ +--- +title: "JavaScript / Node.js Client V1 Release Notes" +date: 2015-06-09 +--- + +# JavaScript / Node.js Client V1 Release Notes + +![Exceptionless Logo](/assets/img/news/exceptionless-logoBLK-300x75.png)Last week we announced the [V1 release candidate](/javascript-node-js-client-version-1-release-candidate/) for the Exceptionless JavaScript/Node.js Client. This week we've got official release notes for you! Have a look. + +## Release Notes + +* Client supports **JavaScript and Node** (Works everywhere) +* Send your errors, logs or feature usages to your [Exceptionless dashboard](https://be.exceptionless.io/) +* **Supports various module formats** such as [es6](http://www.ecma-international.org/ecma-262/6.0/) ([SystemJS](https://github.com/systemjs/systemjs)/[jspm](http://jspm.io/)), [UMD](https://github.com/umdjs/umd), [RequireJS](http://requirejs.org/), [CommonJS](http://www.commonjs.org/), or global +* We built the Exceptionless JavaScript/Nodes.js Client with the past and future browsers in mind. Everything is testable via components injected on startup (via dependency injection), which means you can **replace any component of the system to fit your specific needs**. +* Client is a **full feature parity of our .NET clients**, including: + * Support for custom objects + * Mark events as critical + * Server side settings + * Data exclusions + * Plugins + * and more... +* Includes first class integration for third party libraries like [AngularJS](https://angularjs.org/) and [Express](http://expressjs.com/) + + + + [Start Using it Today](https://github.com/exceptionless/Exceptionless.JavaScript) + + + +## Usage, Examples, and more... + +Everything you need to get up and running (including contributing/developing) can be found on the [Exceptionless.JavaScript GitHub repo](https://github.com/exceptionless/Exceptionless.JavaScript). JavaScript, Express, TypeScript, SystemJS, and RequireJS examples [can be found in the example folder](https://github.com/exceptionless/Exceptionless.JavaScript/tree/master/example). As always, you can contact us via an in-app message for help, or [submit an issue on GitHub](https://github.com/exceptionless/Exceptionless.JavaScript/issues) with bugs, feedback, etc. We're here to make sure you get things working properly so you can take full advantage of Exceptionless! diff --git a/docs/news/2015/2015-06-17-the-power-of-real-time-project-settings.md b/docs/news/2015/2015-06-17-the-power-of-real-time-project-settings.md new file mode 100644 index 0000000000..8a55859b68 --- /dev/null +++ b/docs/news/2015/2015-06-17-the-power-of-real-time-project-settings.md @@ -0,0 +1,124 @@ +--- +title: "The Power of Real-time Project Settings" +date: 2015-06-17 +--- + +# The Power of Real-time Project Settings + +Did you know there are customizable server/client configuration values within your Exceptionless Project's settings? Well **now you do** - and knowing is half the battle! + +These project level settings are a dictionary of key value pairs (string key, string value). They are defined server-side and automatically pushed to the client when they are updated. Using this feature allows you to control what you send without redeploying your app, which we think is pretty cool! + +**You can use these client configuration settings for a variety of applications, including:** + +* Controlling [data exclusions](/docs/security) for protecting sensitive information +* Enabling / Disabling user signups +* Turning logging on or off +* Enabling analytics +* Controlling information collection +* And many more! You can send any key value pair to control whatever you like within your app. + +Let's take a look at a JavaScript and .NET client usage example to get your rolling with this feature. + +## Adding a New Client Configuration Value + +![Exceptionless Client Configuration Settings](/assets/img/news/project-settings-page-300x209.png) + +Before we get started with more of an explanation and an example, we need to add a new key and value. To do so, we go to `Admin > Projects` in our Exceptionless Dashboard, select the project we are working on, then go to the "Settings" tab. + +This is where we can add a "New Client Configuration," which simply consists of the key and value. For the example below, we'll add the (fictional) `enableLogSubmission` key and set it to `true`. + +## How it Works + +When your application first starts up, your project's client configuration settings are read (from storage) and applied. + +If a setting value doesn’t exist in storage, it will be retrieved from the server after the next event submission occurs. We do this by inspecting the response headers and comparing a response header that contains the setting version. If the version doesn’t match the saved setting value then we make a request to get the setting and apply it. + +_It’s worth noting that we allow you to define your own default settings and overwrite them with server side settings, which we'll include in our example._ + +### How do I use the client configuration settings? + +In the example below, we will dynamically turn on or off the log event submissions at runtime without restarting the app or logging into the server to change configuration settings. + +**Why, you ask?** Maybe we don't care about log submission until there is a really tough issue to solve. With Client Configuration Values, we can simply turn it on only when needed. + +We’ll assume for this example that we are using the `enableLogSubmission` key we created above to control this. This setting is made up and doesn’t have to exist server side since we will be providing a default value client side. This allows us to define it via the project settings page at anytime and change our applications behavior. + +To control this we will be registering a new [client side plugin](/how-to-add-a-plugin-to-affect-events-in-exceptionless/) that runs every time an event is created. If our key (`enableLogSubmission`) is set to false and the event type is set to log, we will discard the event. + +### .NET Example + +```cs +ExceptionlessClient.Default.Configuration.AddPlugin("Conditionally cancel log submission", 100, context => { + var enableLogSubmission = context.Client.Configuration.Settings.GetBoolean("enableLogSubmission", true); + + // only cancel event submission if it’s a log event and enableLogSubmission is false + if (context.Event.Type == Event.KnownTypes.Log && !enableLogSubmission) { + context.Cancel = true; + } +}); +``` + +You might notice that we are calling the `GetBoolean` method to check the `enableLogSubmission` key. This is a helper method that makes it easy to consume saved client configuration values. The first parameter defines the settings key (name). The second parameter is optional and **allows you to set a default value** if the key doesn’t exist in the settings or was unable to be converted to the proper type (e.g., a boolean). + +#### .NET Helpers + +Above, we used the `GetBoolean` helper method. In the .NET client, we have a few helpers to convert string configuration values to different system types. These methods also contain overloads that allow you to specify default values. + +**Helper List** + +* `GetString` +* `GetBoolean` +* `GetInt32` +* `GetInt64` +* `GetDouble` +* `GetDateTime` +* `GetDateTimeOffset` +* `GetGuid` +* `GetStringCollection` (breaks a comma delimited list into an IEnumerable of strings) + +### JavaScript Example + +The same functionality above can also be achieved using our new [JavaScript Client](/news/2015/2015-06-09-javascript-node-js-client-v1-release-notes). + +```js +exceptionless.ExceptionlessClient.default.config.addPlugin('Conditionally cancel log submission', 100, function (context, next) { + var enableLogSubmission = context.client.config.settings['enableLogSubmission']; + + // only cancel event submission if it’s a log event and + // enableLogSubmission is set to a value and the value is not true. + if (context.event.type === 'log' && (!!enableLogSubmission && enableLogSubmission !== 'true')) { + context.cancelled = true; + } + + next(); +}); +``` + +## Subscribing to Setting Changes + +If you would like to be notified when client configuration settings are changed, you can subscribe to them using something like the below code. This is useful when you want to update your application in real time when settings change server side. + +### .NET + +```cs +ExceptionlessClient.Default.Configuration.Settings.Changed += SettingsOnChanged; + +private void SettingsOnChanged(object sender, ChangedEventArgs> args) { + Console.WriteLine("The key {0} was {1}", args.Item.Key, args.Action); +} +``` + +### JavaScript + +```js +exceptionless.SettingsManager.onChanged(function(configuration) { + // configuration.settings contains the new settings +}); +``` + +## Any Questions? + +These Client Configuration Values are somewhat of a hidden Exceptionless gem, but we think they are power and that many of our users can find real value in using them to control the flow of information, specifically sensitive data. + +If you have any questions or comments, please let us know. As usual, we're all ears! diff --git a/docs/news/2015/2015-06-22-exclude-and-protect-sensitive-data-within-exceptionless.md b/docs/news/2015/2015-06-22-exclude-and-protect-sensitive-data-within-exceptionless.md new file mode 100644 index 0000000000..0a6e929402 --- /dev/null +++ b/docs/news/2015/2015-06-22-exclude-and-protect-sensitive-data-within-exceptionless.md @@ -0,0 +1,51 @@ +--- +title: "Exclude and Protect Sensitive Data within Exceptionless" +--- + +# Exclude and Protect Sensitive Data within Exceptionless + +![Exceptionless Data Exclusions for Security](/assets/img/news/data-exclusions.png)We realize you may have sensitive data that could potentially be transmitted within an Exceptionless error, event, log message, etc. + +In order to help make sure that information is not compromised, we have included a [simple comma delimited field for data exclusions](/docs/security) on the Exceptionless Project Settings page where you can add field names that you would like to be excluded from any error or event that is reported. + +Once set, the excluded field data is discarded at the client level and never hits our servers. + +## Types of Data You Can Exclude + +You can exclude data from any of the following: + +* Extended Data Properties +* Form Fields +* Cookies +* Query Parameters + +## Data Exclusion Wildcards + +To be extra careful with your data, using * allows you to specify wildcards that can be used to dictate "starts with," "ends with," or "contains." + +* `string*` + Following the string with a wildcard removes any field that starts with the string from the event report. +* `*string` + If you prefix the field name with a wildcard, it will remove any field that ends with the string. +* `*string*` + Using a wildcard before and after the string means that the system will remove any field that contains the string. + +### Example + +![Exceptionless Security](/assets/img/news/data-exclusion-examples.png) + +One potential example is, let’s say, user addresses. Perhaps you have multiple user addresses that may get transmitted, and you want to exclude some or all of them. Maybe you have "HomeAddress" and "WorkAddress". + +To exclude only "HomeAddress" data, you would just add `HomeAddress` as an exclusion. The same goes for "WorkAddress." + +To exclude both, you could either add `HomeAddress` and `WorkAddress`, separated by a comma, or you could use `*Address` if those were the only two fields that ended with "Address." If those were the only fields that contained "Address" at all, you could use `*Address*`. + +It's easy stuff, but powerful enough to be aware of and use where possible to ensure security. + +## What Do You Exclude? + +We are sure you can come up with some creative exclusions for various types of sensitive data. At Exceptionless, we exclude any and all relatively sensitive data to protect our users as much as possible. + +Obviously, things like passwords, credit card info, etc are encrypted, but other fields such as addresses, etc, are also relatively sensitive information that typically doesn’t need to be displayed. + +What do you exclude? Do you have any feedback about this Exceptionless feature? Let us know! diff --git a/docs/news/2015/2015-06-29-exceptionless-case-study-scientific-lab-equipment.md b/docs/news/2015/2015-06-29-exceptionless-case-study-scientific-lab-equipment.md new file mode 100644 index 0000000000..ba62e08e78 --- /dev/null +++ b/docs/news/2015/2015-06-29-exceptionless-case-study-scientific-lab-equipment.md @@ -0,0 +1,44 @@ +--- +title: "Exceptionless Case Study - Scientific Lab Equipment" +date: 2015-06-29 +--- + +# Exceptionless Case Study - Scientific Lab Equipment + +![blog-header-image-small-case-study](/assets/img/news/blog-header-image-small-case-study.png)It's always great to hear back from our users, whether it's a simple "atta boy" or a full page's worth of feedback. + +Today we thought it would be nice to share a recent case study from one of our users that lives in the scientific laboratory and processing equipment space. Their company is a leading provider of stirring, mixing, and kneading machines, among other things, that are used by the pharmaceutical, chemical, food, paint, cosmetic, and plastics industries around the world. Neat! + +> "It helps me zero in on what could be the issue, AND have a documented track of what all errors I’ve seen." + + + +## The Questions + +When a user hits a certain number of sessions with Exceptionless, we shoot them a quick survey email asking them a few things that might help us improve our product and get a better feel for how our users are utilizing it's features. + +**In a nutshell, we ask the following:** + + 1. What's the number one customer-facing bug Exceptionless helped you squash? + 2. Were you surprised at the initial results of using Exceptionless for the first time? How many errors were you seeing? + 3. What is the number one internal bug you were able to track down with Exceptionless? + 4. If you had one feature you'd like us to add to Exceptionless, what would it be? + 5. What other examples or feedback do you have? + +## Answer Time! + +> "I’d say that Exceptionless helps me find all the bugs which I’d have to spend more time on zeroing in on, faster." + +The user was gracious enough to provide us with the following answers to the above general questions. + + 1. "Well, since our application is not yet released to the customer, I’m using Exceptionless to report bugs/crashes which I encounter routinely while testing the UI. It helps me zero in on what could be the issue, AND have a documented track of what all errors I’ve seen." + 2. "Since Exceptionless is being used by me DURING development, it’s not surprising at all! 🙂 Maybe 4-5 bugs per day in sporadic bouts of crashes. Sometimes no bugs for a long time!" + 3. "**More than ONE major bug**, I’d say that Exceptionless helps me find all the bugs which I’d have to spend more time on zeroing in on, faster." + 4. "Support for snapshots (user reviewed), memory dump files is my number ONE feature request." + 5. "Will update you on this once I release to customers. But it’s nice having the **confidence** that Exceptionless will help me squash bugs AS they get reported, instead of having to wait for that brave customer who girdles up his loins and takes up the onerous task of finding out how to report bugs and whom to report them to! Most customers would have just cursed me and gone ahead with workarounds! :)" + +## How About You? Got Any Feedback? + +**Consider this for a second:** If every user provided 10 minutes of feedback on the products they use and love, the owners of those products/programs/tools/experiences would be able to improve them much faster and with drastically more focus and drive. + +With that said... give us 5, 10, or maybe 15 minutes and answer the above questions for us in the comments below. We're no Microsoft - your voice **will be heard**, and any suggestions will be strongly considered/debated. Who knows - maybe we work on your feature request next! diff --git a/docs/news/2015/2015-07-09-exceptionless-documentation-has-moved-grown.md b/docs/news/2015/2015-07-09-exceptionless-documentation-has-moved-grown.md new file mode 100644 index 0000000000..aa8e33ad8f --- /dev/null +++ b/docs/news/2015/2015-07-09-exceptionless-documentation-has-moved-grown.md @@ -0,0 +1,50 @@ +--- +title: "Exceptionless Documentation has Moved & Grown" +date: 2015-07-09 +--- + +# Exceptionless Documentation has Moved & Grown + +![Exceptionless-documentation-github](/assets/img/news/Exceptionless-documentation-github.png)The [Exceptionless documentation has moved to GitHub](/docs/)! + +Over the past few weeks, we have taken all the existing documentation on the docs subdomain and migrated it over to the respective GitHub repo. + +We also pulled out worthy examples, demos, and tutorials from past blog posts and created pages for those, so information is in a more centralized area that is hopefully easier for our users to locate and utilize. + +As new features, demos, examples, and clients come online, expect to see them added to the new documentation system and updated regularly. + +## Exceptionless Documentation Tour + +### Primary Documentation (hub) + +![github-primary-docs](/assets/img/news/github-primary-docs-150x150.png) + +This documentation contains all the documentation and details/usage for the platform's features and dashboard/ui. That includes information on project settings, security, API usage, filtering & searching, email notifications, bulk actions, frequently asked questions, how to contribute to the project, and the basic requirements to run the platform. + +And, of course, you can get to the documentation for the individual clients (below) from this primary site as well. + +Basically, you can always start here and branch out to whatever client or feature you're looking for documentation for. + +[Check it out!](/docs/) + +### .NET Client Documentation + +![github-dotnet](/assets/img/news/github-dotnet-150x150.png) + +As you may have guessed, this documentation site resides within the Exceptionless.NET repo and contains .NET-specific info, examples, demos, and tutorials for different features. If you're a .NET user, this should be where you look for examples if you're just getting started or solutions to troubleshooting problems if you've run into a snag. + +[View the .NET Docs](/docs/clients/dotnet/) + +### JavaScript / Node.js Client Documentation + +![github-javascript](/assets/img/news/github-javascript-150x150.png) + +The newest addition to Exceptionless, our JavaScript / Node.js client, needs a place for documentation too! Naturally, that place is within the Exceptionless.JavaScript repo! Here you'll find JavaScript-specific details, examples, and tutorials for things like configuring the client, sending events, self hosting, RequireJS, SystemJS, TypeScript, Express, and client configuration values. + +We really hope this helps users familiarize themselves with the JavaScript client and get the most benefit out of it. We know its flexibility will help a ton of developers get their apps in order. + +[View the JavaScript Docs](/docs/clients/javascript/) + +## You Can Contribute, Too! + +Do you know something that could use a better example, description, or tutorial? Have you put together something that would add value for other Exceptionless users if added to the documentation? Shoot any thoughts, examples, feedback, or requests our way and we'll make sure it gets handled properly. diff --git a/docs/news/2015/2015-07-14-foundatio-pluggable-blocks-building-distributed-apps.md b/docs/news/2015/2015-07-14-foundatio-pluggable-blocks-building-distributed-apps.md new file mode 100644 index 0000000000..70c6646789 --- /dev/null +++ b/docs/news/2015/2015-07-14-foundatio-pluggable-blocks-building-distributed-apps.md @@ -0,0 +1,183 @@ +--- +title: "Introducing Foundatio - Pluggable Foundation Blocks for Building Distributed Apps" +date: 2015-07-14 +--- + +# Introducing Foundatio - Pluggable Foundation Blocks for Building Distributed Apps + +![Exceptionless Foundatio App Building Blocks](/assets/img/news/foundatio-article-featured-image.png)In the process of developing Exceptionless, we realized there was a lack of good, simple, open source solutions for caching, queues, locks, messaging, jobs, file storage, and metrics when building scaleable applications. + +We tried an open source Redis cache client for caching, but it went commercial (expensive) and there wasn't any in-memory implementations. For the message bus, we looked at [NServiceBus](http://particular.net/nservicebus) (good product, high cost, not open source friendly) and [MassTransit](http://masstransit-project.com/) (local setup a pain, Azure support lacking), but were left disappointed. For storage, we simply could not find a solution that was decoupled and supported in memory, file storage, or Azure Blog Storage. + +So, naturally, we built our own! + +Meet [Foundatio](https://github.com/FoundatioFx/Foundatio) - your key to painless, scalable development and testing for your app! Let's take a look at some examples, below. + + + + [Try Foundatio Today](https://github.com/FoundatioFx/Foundatio) + + + + + +## Using Foundatio + +To start using Foundatio for your project, simply [get the appropriate package from NuGet](https://www.nuget.org/packages?q=Foundatio). + +Below are small examples of what is possible with Foundatio caching, queues, locks, messaging, jobs, file storage, and metrics. We hope you find these explanations and samples useful, but please let us know if you have any questions or comments. + +### Caching + +Foundatio provides four cache implementations, all derived from the [`ICacheClient` interface](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Caching/ICacheClient.cs), that save you expensive operations when creating or getting data by allowing you to store and access the data super fast. + +These implementations include [InMemoryCacheClient](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Caching/InMemoryCacheClient.cs), [HybridCacheClient](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Caching/HybridCacheClient.cs), [RedisCacheClient](https://github.com/FoundatioFx/Foundatio.Redis/blob/master/src/Foundatio.Redis/Cache/RedisCacheClient.cs), and [RedisHybridCacheClient](https://github.com/FoundatioFx/Foundatio.Redis/blob/master/src/Foundatio.Redis/Cache/RedisHybridCacheClient.cs). Learn more about each in the [Foundatio Readme Caching section](https://github.com/FoundatioFx/Foundatio#caching). + +For Exceptionless, we use RedisHybridCacheClient to cache users, organizations, and projects, which has a huge performance boost since we don't have to serialize the item if it's in local memory cache. + +#### Foundatio Caching Sample + +```cs +using Foundatio.Caching; + +ICacheClient cache = new InMemoryCacheClient(); +cache.Set("test", 1); +var value = cache.Get("test"); +``` + +### Queues + +Foundatio includes three queue implementations, each derived from the [`IQueue` interface](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Queues/IQueue.cs), for First In, First Out (FIFO) message delivery. These include [InMemoryQueue](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Queues/InMemoryQueue.cs), [RedisQueue](https://github.com/FoundatioFx/Foundatio.Redis/blob/master/src/Foundatio.Redis/Queues/RedisQueue.cs), and [ServiceBusQueue](https://github.com/FoundatioFx/Foundatio.AzureServiceBus/blob/master/src/Foundatio.AzureServiceBus/Queues/AzureServiceBusQueue.cs). Read more in the [queues section of the readme](https://github.com/FoundatioFx/Foundatio#queues). + +[We use queues](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Web/Controllers/EventController.cs#L1142-L1151), along with Foundatio Storage (below) to queue events for Exceptionless. Using both allows us to keep payloads small and limit system load. + +#### Foundatio Queue Example + +```cs +using Foundatio.Queues; + +IQueue queue = new InMemoryQueue(); + +queue.Enqueue(new SimpleWorkItem { +Data = "Hello" +}); + +var workItem = queue.Dequeue(TimeSpan.Zero); +``` + +### Locks + +To ensure any resource is only accessed by one consumer at any one time, use one of the two Foundatio Locks implementations, each derived from the [`ILockProvider` interface](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Lock/ILockProvider.cs). These implementations include [CacheLockProvider](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Lock/CacheLockProvider.cs) and [ThrottlingLockProvider](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Lock/ThrottlingLockProvider.cs). These providers take an `ICacheClient`, ensuring code locks across machines. [Read more on the repo](https://github.com/FoundatioFx/Foundatio#locks). + +We use locks to only run single instances of jobs (below), and more. + +#### Foundatio Locks Sample + +```cs +using Foundatio.Lock; + +ILockProvider locker = new CacheLockProvider(new InMemoryCacheClient()); + +using (locker) { + locker.ReleaseLock("test"); + + using (locker.AcquireLock("test", acquireTimeout: TimeSpan.FromSeconds(1))) { + // ... + } +} +``` + +### Messaging + +Derived from the [`IMessageBus` interface](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Messaging/IMessageBus.cs), our three message bus implementations let you publish and subscribe to messages within your application. Use the [InMemoryMessageBus](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Messaging/InMemoryMessageBus.cs), [RedisMessageBus](https://github.com/FoundatioFx/Foundatio.Redis/blob/master/src/Foundatio.Redis/Messaging/RedisMessageBus.cs),or [ServiceBusMessageBus](https://github.com/FoundatioFx/Foundatio.AzureServiceBus/blob/master/src/Foundatio.AzureServiceBus/Messaging/AzureServiceBusMessageBus.cs) implementations based on your needs. [Read more about each implementation on GitHub](https://github.com/FoundatioFx/Foundatio#messaging). + +[Exceptionless utilizes the message bus](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Web/Hubs/MessageBusBroker.cs) extensively to pass messages such as events being created, stacks being changed, etc, throughout the system. + +#### Foundatio Messaging Example + +```cs +using Foundatio.Messaging; + +IMessageBus messageBus = new InMemoryMessageBus(); + +using (messageBus) { + messageBus.Subscribe(msg => { + // Got message + }); + + messageBus.Publish(new SimpleMessageA { + Data = "Hello" + }); +} +``` + +### Jobs + +Run jobs by calling `Run()` or passing it to the [`JobRunner` class](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Jobs/JobRunner.cs), which allows you to easily run jobs as Azure Web Jobs. All jobs are required to derive from the [`JobBase` class](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Jobs/JobBase.cs). + +Around here, [we use the jobs feature](https://github.com/exceptionless/Exceptionless/tree/master/src/Exceptionless.Core/Jobs) for processing events, sending mail messages, and more. Some jobs, such as our [DailySummaryJob](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Jobs/DailySummaryJob.cs#L51-L53), which we only want to run once, also use locks (above) to only run one instance. + +#### Foundatio Jobs Sample + +```cs +using Foundatio.Jobs; + +public class HelloWorldJob : JobBase { + public int RunCount { get; set; } + + protected override Task RunInternalAsync(CancellationToken token) { + RunCount++; + + return Task.FromResult(JobResult.Success); + } +} + +var job = new HelloWorldJob(); +job.Run(); // job.RunCount = 1; +job.RunContinuous(iterationLimit: 2); // job.RunCount = 3; +job.RunContinuous(token: new CancellationTokenSource(TimeSpan.FromMilliseconds(10)).Token); // job.RunCount > 10; +``` + +`Job.exe -t "MyLib.HelloWorldJob,MyLib"` + +### File Storage + +Derived from the [`IFileStorage` interface](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Storage/IFileStorage.cs), we offer three file storage implementations, including [InMemoryFileStorage](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Storage/InMemoryFileStorage.cs), [FolderFileStorage](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Storage/FolderFileStorage.cs), and [AzureFileStorage](https://github.com/FoundatioFx/Foundatio.AzureStorage/blob/master/src/Foundatio.AzureStorage/Storage/AzureFileStorage.cs). Read more on each in the [ReadMe](https://github.com/FoundatioFx/Foundatio#file-storage). _Using all `IFileStorage` implementations as singletons is recommended._ + +File storage is used by Exceptionless in conjunction with queues (above), among other things. + +#### Foundatio File Storage Example + +```cs +using Foundatio.Storage; + +IFileStorage storage = new InMemoryFileStorage(); +storage.SaveFile("test.txt", "test"); +string content = storage.GetFileContents("test.txt") +``` + +### Metrics + +Our three metric implementations derive from the [`IMetricsClient` interface](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Metrics/IMetricsClient.cs) and include [InMemoryMetricsClient](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Metrics/InMemoryMetricsClient.cs), [StatsDMetricsClient](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio/Metrics/StatsDMetricsClient.cs), and [MetricsNETClient](https://github.com/FoundatioFx/Foundatio/blob/master/src/Foundatio.MetricsNET/MetricsNETClient.cs). [Get the details on the repo](https://github.com/FoundatioFx/Foundatio#metrics). _Note that these implementations should be used as singletons._ + +Metrics are used throughout the Exceptionless system to provide insight into how the system is working and get external alerts if events are not processing or report how much load is on the current system. + +#### Foundatio Metrics Sample + +```cs +metrics.Counter("c1"); +metrics.Gauge("g1", 2.534); +metrics.Timer("t1", 50788); +``` + +## Development + +If you would like to contribute to Foundatio, clone the repo and open the Foundatio.slnx Visual Studio solution file to get started. Let us know if you have any questions or need any assistance. + +## The Future of Foundatio + +As with any development project, Foundatio is a work in progress and we will continue developing it, however it is extremely stable and used in production by various companies, including Exceptionless (obviously). The next major steps are **full Async support** (some implementations already have it), and **vnext support**. + +Naturally, we want to know what you think and what we should work on next, so [please let us know](https://github.com/FoundatioFx/Foundatio/issues)! + + diff --git a/docs/news/2015/2015-07-23-exceptionless-3-0-changes-to-build-process-dependencies-self-hosting.md b/docs/news/2015/2015-07-23-exceptionless-3-0-changes-to-build-process-dependencies-self-hosting.md new file mode 100644 index 0000000000..0f0084d76f --- /dev/null +++ b/docs/news/2015/2015-07-23-exceptionless-3-0-changes-to-build-process-dependencies-self-hosting.md @@ -0,0 +1,49 @@ +--- +title: "Exceptionless V3.0 - Changes to the Build Process, Dependencies, and Self Hosting" +--- + +# Exceptionless V3.0 - Changes to the Build Process, Dependencies, and Self Hosting + +![version-3-featured](/assets/img/news/version-3-featured.png)Version 2.0 was a pretty big rewrite for us, and we're happy with how everything played out, but that doesn't mean we're done! + +We've been working on 3.0, and it's ready. + +What was the focus, you ask? To make life **easier** for **you**! We've simplified the build process, removed dependencies, and drastically improved the ease of self hosting. + +Check out the details, below, and upgrade today! + +## Removed Dependencies + +Previously, MongoDB was a major dependency that increase the complexity of the overall project. All the data previously hosted in MongoDB is now hosted in ElasticSearch, making it **super easy** for users to self host or develop Exceptionless since you only need to set up ElasticSearch (which you had to do anyway). + +With this, Redis is no longer configured by default, but you can set it up easily by setting the connection string. We definitely recommend using it. + +Removal of the MongoDB dependency brings us one step closer to running Exceptionless on vNext, on any operating system. We hope to achieve this soon, but do not have a timeline. + +## Easier Self Hosting + +The goal is to make self hosting **as easy as possible** so anyone can set it up and try Exceptionless out. + +With Exceptionless 3.0, we now have a single build artifact that contains bo the SPA app and the API end server, with default configuration. The ZIP file contains a batch file you can run to download and start ElasticSearch, launch IIS Express with a temp website, and load your browser automatically with the Exceptionless test instance. This lets you load up everything and play around with Exceptionless **in a single click!** + +Another change to the configuration is that you now have the ability to set every Exceptionless API Setting via Environmental Variables. + +Check out the documentation for [detailed Self Hosting Configuration docs](/docs/self-hosting/). + +## Simplified Build Process + +In order to make it easier and faster to deploy, we removed the [OctopusDeploy](http://octopusdeploy.com) build dependency and are now using [Azure Git deploy](https://azure.microsoft.com/en-us/documentation/articles/web-sites-publish-source-control/), which pulls directly from a GitHub repository that contains the build artifacts. + +With this move, our mindset changed regarding the master branch. For us it means production, but for you it means that whatever is in our master branch is stable and currently deployed to live. We **no longer have to wait** for a build to complete, create a production release in OctopusDeploy, then manually deploy it, we just commit to git and the rest is history! + +Expect more on this topic from us soon. In the mean time, enjoy the simplified build process. + +## Upgrading to 3.0 + +The only users that need to worry about upgrading anything for this new release are self hosters. If you are self hosting Exceptionless, please review the [Self Hosting Documentation](/docs/self-hosting/), which contains information about upgrading your existing install. + +## So What? + +Well, what all this means for you is that we will be able to update things much quicker, and that life just got way easier for all you self hosters out there! + +Let us know what else we can do to make life easier for you. diff --git a/docs/news/2015/2015-07-29-self-hosting-exceptionless-free-and-fast.md b/docs/news/2015/2015-07-29-self-hosting-exceptionless-free-and-fast.md new file mode 100644 index 0000000000..c120e09319 --- /dev/null +++ b/docs/news/2015/2015-07-29-self-hosting-exceptionless-free-and-fast.md @@ -0,0 +1,43 @@ +--- +title: "Self Hosting Exceptionless - Free and Fast!" +--- + +# Self Hosting Exceptionless - Free and Fast! + +![Self Hosting Exceptionless](/assets/img/news/blog-header-image-self-hosting.jpg) + +**Self hosting allows you to run your own instance of [Exceptionless](/), our real-time error, feature, and log reporting tool, on your own systems - FOR FREE!** + +## Not Just Free, but Fast! + +When developing [Exceptionless 3.0](/exceptionless-3-0-changes-to-build-process-dependencies-self-hosting/), we put extensive focus on making self hosting much easier, and therefore more viable, for our users. + +It is now possible to get a test environment up and running on your local machine in **only a few minutes**, and production environments can be set up very quickly as well. + + + + [Self Host Today!](/docs/self-hosting/) + + + + + + Or continue reading for more information and a demonstration. + + + + + +## How Easy? Super Easy! + +### Demo Time! + +Getting your self hosted instance of Exceptionless up and running is super easy. In the video below, Blake does the entire install on his local machine and is sending events to Exceptionless in **less than 2 minutes!** + +Please note that you should review the requirements on the [Self Hosting Documentation](/docs/self-hosting/) page before installing your own instance. + +https://youtu.be/P01v289dR10 + +## We're Always Improving + +Exceptionless has come a long way, and it's only going to get easier, faster, and more robust moving forward. Our users are a huge part of that, so please [submit an issue on GitHub](https://github.com/exceptionless/Exceptionless/issues) or send us an in-app message if you have any feedbacks, bugs, installation questions, etc. Thanks! diff --git a/docs/news/2015/2015-08-17-user-spotlight-fun-stats-thanks-users.md b/docs/news/2015/2015-08-17-user-spotlight-fun-stats-thanks-users.md new file mode 100644 index 0000000000..7e6927502a --- /dev/null +++ b/docs/news/2015/2015-08-17-user-spotlight-fun-stats-thanks-users.md @@ -0,0 +1,84 @@ +--- +title: "User Spotlight, Plus Fun Stats - Thank You to All of Our Awesome Users!" +--- + +# User Spotlight, Plus Fun Stats - Thank You to All of Our Awesome Users! + +![Exceptionless Growth Statistics](/assets/img/news/blog-header-image-small-growth.png)This month (Aug, '15) we will surpass **5 MILLION EVENTS PER MONTH!** + +That's pretty huge, so we thought we would celebrate by **highlighting a few of the awesome companies** that use Exceptionless and throw out a some pretty cool statistics we dug up from the database. + +If your company isn't on this list, don't worry - it's not because we don't love you! If you would like your company highlighted on the website, simply send us an in-app message explaining how Exceptionless has helped you squash bugs and improve your development. + +## Fun Stats + +* Nearly **2000 ACTIVE projects** +* More than **1350 ACTIVE organizations** +* Right at **100 new organizations** and **140 new users** per month! +* **800,000 new events each month**, month over month - **4,600,000** total in July! + +## A Few of Our Awesome Users/Companies + +### User Report + +[![userreport_logo_cmyk](/assets/img/news/userreport_logo_cmyk.png)](http://www.userreport.com/)User Report is an online survey and feedback tool used to collect information about and from website visitors. The data User Report's tools identifies is useful in usability studies, helps websites better identify their demographics, gives users an easy way to provide feedback, and more. The company's solutions are used by ebay, Toyota, National Geographic, and other large national and international brands. + +Visit the [User Report website](http://www.userreport.com/) to learn more. + +### eMarketer + +[![eMarketerLogo-black](/assets/img/news/eMarketerLogo-black-300x93.png)](http://www.emarketer.com/)Used by Facebook, MasterCard, and other large worldwide brands, [eMarketer](http://www.emarketer.com/) provides insights into the digital marketing world by providing customers with the information they need to run their business effectively and efficiently online. This information includes industry-specific research, insights, and benchmarks. + +> "Exceptionless allows us to prioritize fixes smarter by showing frequently occurring errors. In real time!" - Ryan Hoffman, eMarketer + +### Actipro Software + +[![PageHeaderCompanyLogo](/assets/img/news/PageHeaderCompanyLogo.png)](http://www.actiprosoftware.com/)Actipro Software provides industry-leading .NET user interface controls for a variety of frameworks, including WPF, WinRT, Silverlight, and WinForms. They are known for their syntax-highlighting code editor control, SyntaxEditor, among other things. + +.NET developers should definitely check out [Actipro Software](http://www.actiprosoftware.com/). + +### Beth Israel Deaconess Medical Center - Harvard Medical School Teaching Hospital + +[BIDMC](http://www.bidmc.org/)is one of the nation's preeminent academic medical centers focusing on excellence in clinical care, research, and education. + +[![header_logo](/assets/img/news/header_logo.png)](http://www.bidmc.org/) + +> "The primary reasons that we switched to Exceptionless from our own code is that Exceptionless captures additional detail (including code line numbers), Exceptionless has a better interface and design for reviewing and managing errors and bugs (including summary views that we didn’t previously have), and we no longer need to maintain our own error-logging code." - Philip Dickerson, BIDMC + +### LegalDesk + +[![legaldesk.logo](/assets/img/news/legaldesk.logo_-150x150.png)](https://legaldesk.it/)LegalDesk is software designed for managing law firms or independent legal practices and includes everything from document organization and sharing to timesheets and finances/billing. + +Check out [LegalDesk's Website](https://legaldesk.it/) (Italian) + +### CodeSmith Tools + +[![codesmith-tools-large](/assets/img/news/codesmith-tools-large-300x51.png)](http://www.codesmithtools.com/)CodeSmith Tools is a Dallas-based software development company focused on creating software tools that increase developer productivity. Their flagship product, CodeSmith Generator, has seen huge success over the years as a template driven source code generator that automates common application source code creation for text-based languages. They also provide a variety of frameworks for generating proven architectures. + +Learn more about [CodeSmith Generator](http://www.codesmithtools.com/product/generator) or CodeSmith's other [Frameworks](http://www.codesmithtools.com/product/frameworks). + +### IKA + +[![imagesX](/assets/img/news/imagesX-e1439833186121.png)](http://ika.in/)IKA is a laboratory equipment maker in the research and development field that builds innovative magnetic stirrers, mixers, overhead stirrers, shakers, homogenizers, mills, rotary evaporators, calorimeters, laboratory reactors and the specially developed software for analysis applications. + +> "I’m using Exceptionless to report bugs /crashes which I encounter routinely while testing the UI. It helps me zero in on what could be the issue, AND have a documented track of what all errors I’ve seen... I’d say that Exceptionless helps me find all the bugs which I’d have to spend more time on zeroing in on, faster." - Bharat Mallapur, IKA + +Want to learn more, visit [IKA.in](http://ika.in/). + +### Teamaton + +[![logo-tagline-teamaton](/assets/img/news/logo-tagline-teamaton-300x78.png)](http://www.teamaton.com/)Teamaton is a small software development company focused on creating user-friendly and profitable web applications for its clients using .NET technologies. + +Right now, Teamaton is working on an intuitive time tracking tool where they have implemented Exceptionless to monitor errors during development. + +Learn more at [Teamaton.com](http://www.teamaton.com/). + +### The Agileist + +[![the-agileist](/assets/img/news/the-agileist-300x124.png)](http://theagileist.com/)The Agileist is a development company based in Kansas City that specializes in Azure web development, systems development, and systems integration in an agile environment. + +[TheAgileist.com](http://theagileist.com/) + +## Thanks Again! + +Once again, we'd like to extend our thanks to all the awesome users we have that make Exceptionless such a great project to work on and use. Everyone has provided excellent feedback, allowing us to continue pushing towards a faster, more efficient, more effective solution for all your error and event reporting needs. diff --git a/docs/news/2015/2015-08-27-squash-bugs-faster-speed-up-development-with-exceptionless.md b/docs/news/2015/2015-08-27-squash-bugs-faster-speed-up-development-with-exceptionless.md new file mode 100644 index 0000000000..7da806e0b3 --- /dev/null +++ b/docs/news/2015/2015-08-27-squash-bugs-faster-speed-up-development-with-exceptionless.md @@ -0,0 +1,65 @@ +--- +title: "Squash Bugs Faster & Speed Up Development with Exceptionless" +--- + +# Squash Bugs Faster & Speed Up Development with Exceptionless + +![Developer Bug Tracking](/assets/img/news/blog-header-image-js-demo.jpg) + + +## Calling All Developers! + + + +### **Stop** beating your head against the keyboard tracking down those hard-to-find bugs and cut down your development time in general by using Exceptionless to **report and log errors, feature usages, and any other event** within your project. + + + + + We're not just for [.NET developers](https://github.com/exceptionless/Exceptionless.Net) anymore. Our [JavaScript client](https://github.com/exceptionless/Exceptionless.JavaScript) allows you to use Exceptionless in almost **any development environment**, and you can get it up and running in minutes! + + + + + + Learn more below, including how to get started in **just about a minute and a half**! + + + + + + +Now Serving... + + +**5,000,000+ Events Per Month + 2000+ Active Projects** + + + + +> "Exceptionless is **awesome**. I've **STOPPED** worrying about whether I'm losing customers to bugs I don't know about." - Eric B. + +![](/assets/img/news/codesmith-client-logo-bar-left-short.png) + +## Up & Running In Minutes + +This 1:37 video demonstrates how quick and easy it is to get the Exceptionless JavaScript client up and running. Take a few minutes to integrate it with your project and **gain visibility you've never had before** on bugs, feature usages, and more! + +https://youtu.be/fNiJ0YolRPY + +![](/assets/img/news/codesmith-client-logo-bar-right-short.png) + +## **IT'S. THAT. EASY.** + +> "Exceptionless allows us to prioritize fixes smarter by showing frequently occurring errors. In real time!" - Ryan H. + +The only thing you need to get started is a [**free** Exceptionless account](https://be.exceptionless.io/signup), or you can even [host it yourself](/self-hosting-exceptionless-free-and-fast/)! Once you have that, you can user the [JavaScript](https://github.com/exceptionless/Exceptionless.JavaScript)or .[NET](https://github.com/exceptionless/Exceptionless.Net) client to get started pushing events to your new dashboard. + +Then you'll be on your way to becoming... **Exceptionless**. + + + + [Sign Up Today - FREE](https://be.exceptionless.io/signup) + + diff --git a/docs/news/2015/2015-09-02-find-software-bugs-exceptionless-javascript-client.md b/docs/news/2015/2015-09-02-find-software-bugs-exceptionless-javascript-client.md new file mode 100644 index 0000000000..047eddafe2 --- /dev/null +++ b/docs/news/2015/2015-09-02-find-software-bugs-exceptionless-javascript-client.md @@ -0,0 +1,48 @@ +--- +title: "Find Software Bugs with the Exceptionless JavaScript Client in Minutes" +date: 2015-09-02 +--- + +# Find Software Bugs with the Exceptionless JavaScript Client in Minutes + +![Exceptionless JavaScript Client](/assets/img/news/blog-header-image-post2b.png) +If you missed our [JavaScript Client announcement](/news/2015/2015-06-04-javascript-node-js-client-version-1-release-candidate), this is a great chance to see just how **quick and easy** the client is to install and use! You can be finding those hard to track down bugs, errors, and exceptions, as well as tracking other events and log messages, in literally minutes. + +We've made it super easy to get up and running, as you'll see below. Take a look and let us know what you think! + +### Report & Log Errors & Events in 1:37 + + + +https://youtu.be/fNiJ0YolRPY + + + + [Try It Today](https://github.com/exceptionless/Exceptionless.JavaScript) + + + +### The Text Version + +A simple **step-by-step guide** to getting the Exceptionless JavaScript Client demo up and running on your local machine. + +The only **pre-requisite** is an [Exceptionless account](https://be.exceptionless.io/signup), or you can [host the entire platform yourself](/self-hosting-exceptionless-free-and-fast/). **Open source**, baby! + + 1. Download and extract the [Exceptionless JavaScript Client](https://github.com/exceptionless/Exceptionless.JavaScript) from GitHub + 2. Log in to your [Exceptionless Dashboard](https://be.exceptionless.io/) and get your project's API key (Admin > Projects > _Select Project_ > API Keys) + * If you don't have a project, you'll need to create one by going to Admin > Projects > Add New Project + 3. Open the extracted folder on your local machine and go to the "example" folder, then edit index.html. + 4. Replace the API key in the exceptionless.js script tag with your own, and comment out the line with serverURL in it (not needed for demo). + 5. Open index.html in your browser and open your browser's developer tools console so we can see the events fire. + * We've added quick-fire buttons to this page that automatically generate events for you to play around with for the purpose of this demo. + 6. Click on one, generate 100 random events for instance, and you'll see the events queue up in the console. After a few seconds, you should see a queue processing notification telling you it's done processing. + 7. Go back to your Exceptionless project dashboard, and you will see the events hit the system in real time. + * Make sure you are viewing the appropriate project and time period in your dashboard, otherwise you might not see the new events come in. + +#### It's That Easy! + +As you can see, the JavaScript client is super easy, super fast, and super flexible, for use in almost any project you might have. + +We hope you'll give it a shot, and we also hope you'll let us know what you think by contacting us via an in-app message, [submitting an issue on GitHub](https://github.com/exceptionless/Exceptionless.JavaScript/issues), or [through the website](/contact/). + +_Here's to becoming Exceptionless!_ diff --git a/docs/news/2015/2015-10-22-introducing-foundatio-3-0-async-efficiency.md b/docs/news/2015/2015-10-22-introducing-foundatio-3-0-async-efficiency.md new file mode 100644 index 0000000000..0f33d6d51a --- /dev/null +++ b/docs/news/2015/2015-10-22-introducing-foundatio-3-0-async-efficiency.md @@ -0,0 +1,43 @@ +--- +title: "Introducing Foundatio 3.0! Now with Async & Increased Efficiency" +--- + +# Introducing Foundatio 3.0! Now with Async & Increased Efficiency + +![Foundatio 3.0](/assets/img/news/foundatio-blog-header-image-small.png)Foundatio is a pluggable, scalable, painless, open source solution for caching, queues, locks, messaging, jobs, file storage, and metrics in your app. + +In Version 3.0, we've made several improvements, including, as promised in our [initial Foundatio blog post](/news/2015/2015-07-14-foundatio-pluggable-blocks-building-distributed-apps), going full async. + +Take a closer look at the new enhancements, below, and [head over to the GitHub repo](https://github.com/FoundatioFx/Foundatio) to try Foundatio today. We think you'll find it very handy. + +For all our current users, you'll need to upgrade your [Foundatio NuGet package](https://www.nuget.org/packages?q=Foundatio) and existing Foundatio code to use the async implementations/conventions. The update should be fairly straightforward - we haven't had or heard of any issues so far, including when upgrading Exceptionless. + +## What's New in Foundatio 3.0 + +### API Changes + +We've gone **100% async**, which means no more blocking synchronous code, allowing your apps to be even more responsive. For more on async and its benefits, [take a look at this Microsoft article](https://msdn.microsoft.com/en-us/library/vstudio/hh191443(v=vs.140).aspx). + +Along with going completely async, we've **removed non async methods** from the API and **simplified the API overall**. We wanted to make it easy for developers to roll out new implementations and use the existing API. + +#### New methods + +We also **added new, useful methods** across all the APIs to make it easier to perform common tasks. One example includes adding CalculateProgress() to WorkItemHandlerJobs. We hope these helpers allow you to be more productive. + +### Efficiency Improvements + +Because we always want more speed out of our apps (and we know you do, too), we used Red Gate's [ANTS Performance Profiler](http://www.red-gate.com/products/dotnet-development/ants-performance-profiler/) to profile various apps, such as Exceptionless, and track down "hot" sections of code. By hot, we mean those pieces of code devoured more resources and took longer to run than all other application code. By doing so, we were able to pinpoint core pieces of Foundatio that were performing poorly compared to what they could be doing. **Then we fixed them.** + +#### A few optimization examples + +* **Maintenance code** in various locations like queues, caches, etc, could and would run in a tight loop, sometimes pegging the CPU to 100% depending on the configuration. By running through and removing that maintenance code, or changing the way it was implemented to be triggered only when needed, rather than running in a constant worker loop, we drastically reduced CPU load and increased efficiency. +* We also made **massive improvements to queues and locks**, on top of the maintenance code changes. Our Dequeue and AcquireLock methods would constantly pull for new items in a loop with a small timeout, which is obviously inefficient. Now we are using [async monitors](https://github.com/StephenCleary/AsyncEx/wiki/AsyncMonitor) and pulse when a message is received over the message bus. This allows for **huge improvements** as the code will wait/sleep for a single monitor (of multiple monitors that could be waiting) to get triggered. This means your app isn’t wasting CPU cycles waiting, or external network calls looking for locks or new queue items. Instead, it’s running your app code and getting immediately notified when the lock is available or a new queue item is enqueued. Pretty slick! +* **Caching** got a huge performance boost, too. For InMemoryCache clients, we moved from reflection-based object copying to using [Expression Trees](https://msdn.microsoft.com/en-us/library/bb397951.aspx). This reduced the time required to get items from cache by a large percentage. Read more about implementing Expression Trees and see the difference it makes [here](http://blog.nuclex-games.com/mono-dotnet/fast-deep-cloning/). + +## Check It Out - Feedback Appreciated! + +We made many other improvements to ensure your apps run fast when using Foundatio, too many to be listed here. If you're already using it, just update your NuGet package to the latest version to take advantage of these improvements. If you're not using it yet, [try it out](https://github.com/FoundatioFx/Foundatio). It's worth a shot, we promise! + +Once you've given it a go, please let us know what you like, or what you hate, by posting a [issue on Foundatio's GitHub Repo](https://github.com/FoundatioFx/Foundatio/issues). + +Until next time, happy coding! diff --git a/docs/news/2015/2015-10-26-javascript-client-v1-1-0-release.md b/docs/news/2015/2015-10-26-javascript-client-v1-1-0-release.md new file mode 100644 index 0000000000..16758972a2 --- /dev/null +++ b/docs/news/2015/2015-10-26-javascript-client-v1-1-0-release.md @@ -0,0 +1,23 @@ +--- +title: "Exceptionless JavaScript Client V1.1.0 Release" +--- + +# Exceptionless JavaScript Client V1.1.0 Release + +![Exceptionless JavaScript Client](/assets/img/news/blog-header-image-post2b-300x106.png)We've been hard at work on several things here at Exceptionless, including a minor version release of our [JavaScript Client](https://github.com/exceptionless/Exceptionless.JavaScript)! + +Please see the details of this release below. + +Also, we would like to give a shout out to [@frankerbersoll](https://github.com/frankebersoll), [@srijken](https://github.com/srijken) and the entire community for help squashing bugs, reporting issues, and providing general feedback. You guys rock. + +## Exceptionless JavaScript Client V1.1.0 Release Notes + +* Improved readme and docs. [[issue thread](https://github.com/exceptionless/Exceptionless.JavaScript/pull/31)] // _Credit: [@frankebersoll](https://github.com/frankebersoll)_ +* Bug Fix - Unhandled exceptions in Node.js were not being capture. [[issue thread](https://github.com/exceptionless/Exceptionless.JavaScript/pull/30)] // _Credit: [@frankebersoll](https://github.com/frankebersoll)_ +* Bug Fix - Data exclusions were not always working. [[issue thread](https://github.com/exceptionless/Exceptionless.JavaScript/pull/28)] // _Credit: [@srijken](https://github.com/srijken)_ +* Bug Fix - Cancelled state wasn't properly passed through the SubmitEvent callback. +* Temporarily disabled capturing of ajax errors [[issue thread](https://github.com/exceptionless/Exceptionless.JavaScript/issues/26)] + +You can [view the full change log](https://github.com/exceptionless/Exceptionless.JavaScript/compare/v1.0.1...v1.1.0) for a list of all changes in this release. + +You can also [Download Exceptionless JavaScript Client V1.1.0](https://github.com/exceptionless/Exceptionless.JavaScript/releases/tag/v1.1.0) on the official release page. diff --git a/docs/news/2015/2015-10-28-exceptionless-3-1-released-if-you-thought-it-was-fast-before.md b/docs/news/2015/2015-10-28-exceptionless-3-1-released-if-you-thought-it-was-fast-before.md new file mode 100644 index 0000000000..644ad6a779 --- /dev/null +++ b/docs/news/2015/2015-10-28-exceptionless-3-1-released-if-you-thought-it-was-fast-before.md @@ -0,0 +1,60 @@ +--- +title: "Exceptionless 3.1 Released! If You Thought It was Fast Before..." +date: 2015-10-28 +--- + +# Exceptionless 3.1 Released! If You Thought It was Fast Before... + +![exceptionles-3-1-header](/assets/img/news/exceptionles-3-1-header.png)If you thought Exceptionless was fast before, **prepare to have your mind blown** by what we've been able to do in version 3.1, which released today. + +In short, we've reduced cpu and memory usage, increase caching efficiency, and sped up searching, all quite significantly as you'll see below. + +Along with these speed boosts, we've also made Job improvements (look for a blog post on this soon) and upgraded to .NET 4.6 (**self-hosters**, please install .NET 4.6 on your servers before upgrading). + +Details on the release changes can be found below. + +## It's All About Speed! + +### CPU & Memory + +We reduced the CPU and Memory load **across the entire app**. This allows the application to use fewer resources, meaning it has more time to process additional events, making everything faster. Between making Exceptionless and [Foundatio](https://github.com/FoundatioFx/Foundatio) 100% Async and these improvements, we've drastically increased the efficiency of the entire platform. + +**Below**, we see the increase in performance from two examples. On the left, we see a reduction in CPU and Memory usage for a deployed web app instance. On the right is a visible reduction in CPU usage for an Elasticsearch node. + +![cpu-memory-percentage-improvements](/assets/img/news/cpu-memory-percentage-improvements-e1446046152986-1024x343.png) + +### Elasticsearch Queries + +By profiling the Elasticsearch queries for efficiency and usage, we've been able to reduce the overall number we were running and improve the efficiency on the ones that still are. + +![search-request-rate-improvements](/assets/img/news/search-request-rate-improvements-e1446046076483.png) + +### Caching + +Caching efficiency has been improved by removing redundant components that were utilizing valuable resources. For example, we removed the SignalR Redis Backplane, which drastically decreased the number of calls to Redis. Overall, we've made the app smarter throughout regarding how we cache and retrieve data. + +![cache-improvements-2](/assets/img/news/cache-improvements-2-e1446046201498-1024x346.png) + +![Caching-improvements](/assets/img/news/Caching-improvements-e1446046263253-300x224.png) + +### Long-running API Tasks + +We've offloaded long-running API tasks to background jobs, freeing up a lot of resources in the app and allowing us to scale work items independently. For example, marking a stack as fixed or removing a project may take a few moments to be updated now, but the trade-off is worth it. We're working on updating the UI experience to prompt users that the task is running in the background. + +## Other Improvements + +### Jobs + +We've made each Job a console app, so it's much easier to debug and deploy. Look for a full blog post on Job improvements soon. + +### .NET 4.6 + +Exceptionless is now running on .NET 4.6, which has improved startup time due to various improvements with the new version. **Self-hosting users** should be sure to upgrade to .NET 4.6 on their servers before updating Exceptionless. + +## Upgrading + +For full release notes and to download the latest version, please visit the [GitHub Release Page](https://github.com/exceptionless/Exceptionless/releases). + +## Always Improving + +**We're always striving to improve** the efficiency of Exceptionless and all of our projects. If you see any room for improvement or have any comments when using anything from us, please send us an in-app message, submit a GitHub issue or [contact us](/contact/) on the website. diff --git a/docs/news/2015/2015-12-02-exceptionless-net-3-2-release-notes.md b/docs/news/2015/2015-12-02-exceptionless-net-3-2-release-notes.md new file mode 100644 index 0000000000..c79573b1c4 --- /dev/null +++ b/docs/news/2015/2015-12-02-exceptionless-net-3-2-release-notes.md @@ -0,0 +1,75 @@ +--- +title: "Exceptionless.NET 3.2 Release Notes" +--- + +# Exceptionless.NET 3.2 Release Notes + +![Exceptionless Logo](/assets/img/news/exceptionless-logoBLK.png)The .NET Exceptionless client has received **several improvements** and **some bug fixes** in version 3.2. Details below! + +A special shout-out to @airwareic, [@srijken](https://github.com/srijken), [@xbelt](https://github.com/xbelt), and [@mgnslndh](https://github.com/mgnslndh) for contributing and helping make this release happen. **You guys rock!** + +**Please download and update to the latest** [source here](https://github.com/exceptionless/Exceptionless.Net/releases/tag/v3.2.0), and you can view the full [change log here](/why). + +## .NET Exceptionless Client v3.2.0 Release Details + +### Additions & Improvements + +**Read Configuration** +We added support for reading configuration from environmental variables and app settings + +**Closing Applications +** Closing applications after submission is now easier due to the new `SubmittedEvent` event handler. + +**Custom Persistence Settings +** The new `QueueMaxAttempts` and `QueueMaxAge` configuration settings allow custom persistence settings and are intended to improve offline support. Thanks @airwareic! + +**Data Exclusions Improvements** +We've made huge improvements to Data Exclusions, which now check default data and extra exception properties. + +**New Overloads +** Thanks @xbelt for creating overloads for `CreateLog` and `SubmitLog` to accept the `LogLevel` enum! + +**Custom Themes** +@mgnslndh updated the styling of the `CrashReportDialog` to play nice with custom themes. Thanks! + +**Dependencies +** All dependencies (Nancy, NLog, etc) have been updated. + +**Deprecated! +** The `EnableSSL` property has been marked Obsolete because it is no longer used. `ServerURL` is now being looked at for this. + +### Fixes + +**Startup() +** `Startup()` was overriding configured dependencies - Fixed! + +**Empty Errors +** We fixed a bug where you could have empty errors submitted with no stack trace info. + +**API Keys** + +* Previously set valid API keys were being overwritten with default API keys, so we fixed it. +* We also fixed an issue where `ApiKey` couldn't be changed after the client was initialized. + +**Reference IDs** +An issue with submitting generated reference IDs was resolved, thanks to @srijken + +**Updating WebAPI Package +** @srijken also fixed another issue where updating the WebApi package would remove the Exceptionless Module. Thanks again! + +**NLog** +Nlog wasn't working with .NET 4.0. This has been resolved. + +**IsolatedStorage** +There was a problem that caused IsolatedStorage to not be able to be used. Fixed! + +**Min Log Level** +NLog and log4net have been updated to allow setting the min log level. + +## What Say You? + +As always, we're listening to your feedback, comments, suggestions, and rants! + +* [.NET Client Feedback](https://github.com/exceptionless/Exceptionless.Net/issues/new) +* [JavaScript Client Feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues/new) +* [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) diff --git a/docs/news/2015/2015-12-03-exceptionles-javascript-1-2-release-notes.md b/docs/news/2015/2015-12-03-exceptionles-javascript-1-2-release-notes.md new file mode 100644 index 0000000000..2308e1ee63 --- /dev/null +++ b/docs/news/2015/2015-12-03-exceptionles-javascript-1-2-release-notes.md @@ -0,0 +1,32 @@ +--- +title: "Exceptionless.JavaScript 1.2 Release Notes" +date: 2015-12-03 +--- + +# Exceptionless.JavaScript 1.2 Release Notes + +![Exceptionless JavaScript Client](/assets/img/news/blog-header-image-post2b-300x106.png)We've got a quick release for the Exceptionless JavaScript Client that includes a few new additions to what it supports and a quick bug fix or two. + +Shout out to [@frankebersoll](https://github.com/frankebersoll) for his help! + +**Please download and update to the** [source code here](https://github.com/exceptionless/Exceptionless.JavaScript/releases/tag/v1.2.0), and view the full [change log here](https://github.com/exceptionless/Exceptionless.JavaScript/compare/v1.1.1...v1.2.0). + +## JavaScript Client v1.2 Notes + +### Errors + +@frankebersoll added support for deduplicating JavaScript errors. Thanks! + +### Data Collection + +Frank's back at it, adding support for collecting extra exception data that was already in the .NET client like module info, custom exception properties, and everything else that was already displayed in the UI when using the .NET client. + +### Node Info + +Support for collecting Node module info has also been added (thanks again, @frankebersoll). + +### Bug Fix - Invalid States + +An issue where Data Exclusions could cause events to be submitted in an invalid state has been fixed. + +### As always, let us know if you have any questions or feedback! diff --git a/docs/news/2015/2015-12-08-better-approach-running-azure-webjobs.md b/docs/news/2015/2015-12-08-better-approach-running-azure-webjobs.md new file mode 100644 index 0000000000..615cb4e4ab --- /dev/null +++ b/docs/news/2015/2015-12-08-better-approach-running-azure-webjobs.md @@ -0,0 +1,99 @@ +--- +title: "A Better Approach to Running Azure WebJobs" +--- + +# A Better Approach to Running Azure WebJobs + +![Azure Webjobs](/assets/img/news/jobs-blog-header-image.jpg) + +Lets talk about jobs in the Exceptionless world for a minute and **how you can use our methods to improve your Azure WebJobs.** + +A job is a specific task/process that runs and does something like send a mail message, etc. + +## Out with the Old + +**Prior to version 3.1**, we used an early version of the Foundatio Jobs system to run our out-of-process jobs via Azure WebJobs. We found it to be quite a pain to figure out which jobs were running or eating up system resources because every job was titled Job.exe (just like figuring out the w3wp IIS process is running). Also, just to run an out-of-process job, one would have to compile the source, copy dependencies to a common bin folder, and then run an executable (Job.exe) with parameters that specify the job type. + +These tedious and error-prone tasks that had to be completed just to get a job to run are a thing of the past. + +## In with the New + + + +**In Exceptionless 3.1** we focused on refining and improving jobs. To do so, we created a [new console application for each job](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Jobs) and specified settings in the code versus [error prone command line options as shown here](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Jobs/EventPostsJob.cs#L16-L22). + +Now, with [Foundatio](/introducing-foundatio-3-0-async-efficiency/), our open source app building block solution used in Exceptionless, you just define a new [Job](https://github.com/FoundatioFx/Foundatio#jobs) that runs (via the run method) and you can use the [Foundatio Jobs API](https://github.com/FoundatioFx/Foundatio#jobs) to run the job in process, out of process, continuous, or one time without changing the implementation. + +This new approach also gave us a great deployment strategy, for free. Simply copy the job executable and bin folders and run it anywhere! + +### Jobs (processes) running in Azure as an Azure web job + +![Exceptionless Jobs and Processes](/assets/img/news/Jobs-1024x670.jpg) + +### How you can implement a better Azure WebJob + +[Foundatio Jobs](https://github.com/FoundatioFx/Foundatio#jobs) allows you to run a long running process (in process or out of process) with out worrying about it being terminated prematurely. By using Foundatio Jobs you gain all of the following features **without changing your job implementation**: + +* Run job in process +* Run job out of process +* Run job with a start up delay +* Run job in an continuous loop with an optional interval delay. + +In this sample we'll just define a new class called HelloWorldJob that will hold our job that increments a counter and derives from JobBase. Please note that there are a few different base classes you can derive from based on your use case. + +```cs +using Foundatio.Jobs; + +public class HelloWorldJob : JobBase { + public int RunCount { get; set; } + + protected override Task RunInternalAsync(JobRunContext context) { + RunCount++; + return Task.FromResult(JobResult.Success); + } +} +``` + +Now that we have our job defined we can run our job in process with a few different options: + +```cs +var job = new HelloWorldJob(); +await job.RunAsync(); // job.RunCount = 1; +await job.RunContinuousAsync(iterationLimit: 2); // job.RunCount = 3; +await job.RunContinuousAsync(cancellationToken: new CancellationTokenSource(TimeSpan.FromMilliseconds(10)).Token); // job.RunCount > 10; +``` + +But our goal is to run this out of process in an Azure WebJob (this also works if you want to run this as a service or from the desktop). + +The first step is to create a new console application and reference the [Foundatio NuGet Package](https://www.nuget.org/packages/Foundatio/) and the project that contains our HelloWorldJob. We are going to call our console application HelloWorldJob. Inside of the Program class, we'll update the main method to run our job. + +```cs +using System; +using System.IO; +using JobSample; +using Foundatio.Jobs; +using Foundatio.ServiceProviders; + +namespace HelloWorldJob { + public class Program { + public static int Main(string[] args) { + // NOTE: This should be the path to your App_Data folder of your website. + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\..\Api\App_Data"); + if (Directory.Exists(path)) + AppDomain.CurrentDomain.SetData("DataDirectory", path); + + // Get a service provider so we can create an instance of our job. + var serviceProvider = ServiceProvider.GetServiceProvider("JobSample.JobBootstrappedServiceProvider,JobSample"); + + var job = serviceProvider.GetService(); + return new JobRunner(job, initialDelay: TimeSpan.FromSeconds(2), interval: TimeSpan.Zero).RunInConsole(); + } + } +} +``` + +The last steps are to simply compile the project and deploy it to your Azure website! + +### Questions? + +If you have any questions please feel free to contact us via our contact page, in app message, [GitHub issues](https://github.com/FoundatioFx/Foundatio/issues) or [Discord](https://discord.gg/6HxgFCx). diff --git a/docs/news/2015/2015-12-17-using-reference-ids-for-better-customer-service.md b/docs/news/2015/2015-12-17-using-reference-ids-for-better-customer-service.md new file mode 100644 index 0000000000..d7825c9225 --- /dev/null +++ b/docs/news/2015/2015-12-17-using-reference-ids-for-better-customer-service.md @@ -0,0 +1,127 @@ +--- +title: "Using Reference Ids for Better Customer Service" +--- + +# Using Reference Ids for Better Customer Service + +![Exceptionless Reference IDs](/assets/img/news/reference-ids-blog-header-image.png) + +This week we want to talk about **reference Ids** and how we use them to **improve customer service** for Exceptionless. And how we think you can do the same for your users. + +## What's a Reference Id? + +A reference id is a unique identifier, generated by the user, that allows you to look up a submitted event at a later time. This is important because _event Ids are not created until after the event is processed_, so there is no other way to look up an event. We also use Reference Ids to help deduplicate events server side, which is another reason why it’s important that they are unique. + +## Using Reference Ids for the Greater Good + + + +One of the ways we use Reference Ids is to **support end users**, something that is very important to us. There is nothing more frustrating than being unable to help a user that is experiencing a problem because you don’t know what they are seeing (when there could be thousands of errors in your app). + +To combat this issue, we always try to include a reference Id with every error message shown to the user. This allows end users to contact us with a Reference Id and receive help **immediately** for the error they are seeing because we can **easily track down and view it**. + +## Reference Id Example + +The Exceptionless clients have built in support to generate and track unique Reference Ids for every error event. Behind the scenes, we register a default Reference Id plugin that sets a Reference Id on submitted error events and stores the Reference Id in an implementation of ILastReferenceIdManager. The Reference Id manager’s goal is just to persist and retrieve the last used Reference Id. + +Since this is a default plugin, we can enable this behavior by calling the `UseReferenceIds()` method on the configuration object to register the default Reference Id on every error event. + +### C# Example + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.UseReferenceIds(); +``` + +### JavaScript Example + +```js +exceptionless.ExceptionlessClient.default.config.useReferenceIds(); +``` + +Please note that you can **create your own plugin** to create your very own Reference Id(s). + +To **get the the last used Reference Id**, you can call the `GetLastReferenceId()` helper method on the the `ExceptionlessClient` instance. + +#### C# + +```cs +using Exceptionless; +// Get the last created Reference Id +ExceptionlessClient.Default.GetLastReferenceId(); +``` + +#### JavaScript + +```js +// Get the last created Reference Id +exceptionless.ExceptionlessClient.default.getLastReferenceId(); +``` + +You might have noticed how easy it is to get or add Reference Id’s to your events automatically. This makes it a breeze to let your developers track down user-facing issues by displaying the Reference Id to your end users. + +We **display Reference Ids** to all of our end users anytime an error occurs in our ASP.NET WebAPI application. We accomplish this by adding a custom `[IExceptionHandler](http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling)` and return a new error response to include the Reference Id as shown below: + +```cs +public class ExceptionlessReferenceIdExceptionHandler : IExceptionHandler { + public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken) { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + var exceptionContext = context.ExceptionContext; + var request = exceptionContext.Request; + if (request == null) + throw new ArgumentException($"{typeof(ExceptionContext).Name}.{"Request"} must not be null", nameof(context)); + + context.Result = new ResponseMessageResult(CreateErrorResponse(request, exceptionContext.Exception, HttpStatusCode.InternalServerError)); + return TaskHelper.Completed(); + } + + private HttpResponseMessage CreateErrorResponse(HttpRequestMessage request, Exception ex, HttpStatusCode statusCode) { + HttpConfiguration configuration = request.GetConfiguration(); + HttpError error = new HttpError(ex, request.ShouldIncludeErrorDetail()); + + string lastId = ExceptionlessClient.Default.GetLastReferenceId(); + if (!String.IsNullOrEmpty(lastId)) + error.Add("Reference", lastId); + + // CreateErrorResponse should never fail, even if there is no configuration associated with the request + // In that case, use the default HttpConfiguration to con-neg the response media type + if (configuration == null) { + using (HttpConfiguration defaultConfig = new HttpConfiguration()) { + return request.CreateResponse(statusCode, error, defaultConfig); + } + } + + return request.CreateResponse(statusCode, error, configuration); + } +} +``` + +The next step is to replace the existing `IExceptionFilter` with the one above. + +```cs +Config.Services.Replace(typeof(IExceptionHandler), new ExceptionlessReferenceIdExceptionHandler()); +``` + +Finally, when an error occurs in your app, you’ll get a more user friendly error response that contains a Reference Id! + +```cs +{ + "message": "An error has occurred.", + "reference": "411085622e" +} +``` + +We’ve found that this allows consumers of our API to quickly contact us with a reference id and get up and running quickly! + +## Looking up Events by Reference Id + +You might be thinking: "Reference Ids are great, but what do I do with them now that I have one." Well, you can view the event that they reference on our site or via our API. This can be accomplished two different ways: + +* **Hotlinking**: You can link directly to a submitted event by outputting a link in your UI or logs (e.g. https://be.exceptionless.io/event/by-ref/YOUR\_REFERENCE\_ID) +* **Search**: You can search via our api/ui with `reference:YOUR_REFERENCE_ID` + +## Your Turn! + +We hope this article was helpful, and we'd love to know if you're using Reference Ids and how they've helped you help users, solve internal issues, etc. Post a comment below! diff --git a/docs/news/2015/2015-12-28-exceptionless-case-study-featured-on-elasticsearch.md b/docs/news/2015/2015-12-28-exceptionless-case-study-featured-on-elasticsearch.md new file mode 100644 index 0000000000..3904cb7674 --- /dev/null +++ b/docs/news/2015/2015-12-28-exceptionless-case-study-featured-on-elasticsearch.md @@ -0,0 +1,29 @@ +--- +title: "Elasticsearch Case Study - By Exceptionless" +date: 2015-12-28 +--- + +# Elasticsearch Case Study - By Exceptionless + +![Elasticsearch case study](/assets/img/news/elasticsearch-logo.png) + +We recently wrote a case study regarding how Elasticsearch has helped us improve speed and ease of scale as we've continued to improve Exceptionless. + +**Last week, Elasticsearch [published that case study on their blog](https://www.elastic.co/blog/being-exceptionless-with-elasticsearch)**, so we wanted to make sure our readers had a chance to check it out! + +We've written about our use of Elasticsearch in numerous articles before, including: + +* [Making the Move to Elasticsearch for Exceptionless 2.0](/news/2014/2014-09-03-making-move-elastic-search-exceptionless-2-0) +* [Filter Your Exceptions in Version 2.0 - Video Demo](/news/2014/2014-12-07-filter-your-exceptions-video-demo) +* [Exceptionless V3.0 - Changes to the Build Process, Dependencies, and Self Hosting](/news/2015/2015-07-23-exceptionless-3-0-changes-to-build-process-dependencies-self-hosting) +* [Exceptionless 3.1 Released! If You Thought It was Fast Before...](/news/2015/2015-10-28-exceptionless-3-1-released-if-you-thought-it-was-fast-before) + +**In the case study**, we discuss how Elasticsearch let us improve our real-time dashboard, work with time zones more easily, index data much faster, not have to worry so much about pre-aggregating data, maintain much less code, improve backup and restoration, shrink disk space usage, and, perhaps most importantly, drastically improve scalability. + +Basically, **we really like Elasticsearch** and you should check it out if you haven't already. + +## Do you use Elasticsearch? + +Let us know how it's helped you, or if you have any questions we might be able to answer, by commenting below! + + diff --git a/docs/news/2016/2016-01-27-new-releases-for-all-the-codes-exceptionless-3-2.md b/docs/news/2016/2016-01-27-new-releases-for-all-the-codes-exceptionless-3-2.md new file mode 100644 index 0000000000..38a521e102 --- /dev/null +++ b/docs/news/2016/2016-01-27-new-releases-for-all-the-codes-exceptionless-3-2.md @@ -0,0 +1,110 @@ +--- +title: "New Releases for ALL the Codes! Exceptionless 3.2" +--- + +# New Releases for ALL the Codes! Exceptionless 3.2 + +![Exceptionless 3.2 Highlights](/assets/img/news/exceptionless-3-2-release-notes.png)That's right folks - we've gone and released Exceptionless 3.2, which includes releases for Exceptionless.NET, Exceptionless.JavaScript, and Exceptionless.UI! Awe yeah. + +We're kind of excited, in case you couldn't tell. Big stuff in here, like **session tracking** (#BOOM), licensing changes (less confusion - it's a good thing), and **posting via HTTP GET** (such easy, much wow)! + +Lets get into some of the details... + +## Exceptionless 3.2.0 + +### + +### Sessions! + +**Track and automatically manage user sessions** for much more visibility into their user experience, how they interact with your app, and, of course, any errors or events that occur related to that user. This answers the age-old question, "What the hell was this guy doing when stuff blew up!?" + +[Check out the User Sessions post for more details and instructions!](/track-view-user-session-data-exceptionless/) + +![Exceptionless Event Sessions](/assets/img/news/sessions-2.png) + + + + + + +### HTTP GET! + +Now it's even easier to **integrate with Exceptionless from any environment**, because you can post event or meta data via HTTP GET! More info coming soon (blog post). + +### License Change + +The server and all Exceptionless projects are now using the [Apache License](https://github.com/exceptionless/Exceptionless/blob/master/LICENSE.txt), so there should be much less confusion on how things are licensed moving forward. Boring stuff, we know... but important. + +### User Location + +User locations are now resolved from geographic coordinates or the IP address. We look at the `geo` property for coordinates or an IP, then we inspect the IP. If no IP or geo coordinates present themsevles, we fall back to the client IP that the event was submitted from. + +### More Speed Improvements + +As always, we keep speed improvements in mind with each release. With 3.2, we've been able to make more **massive improvements in processing time for events** (over 250% per 1000 events!) and further reduce app startup times and elastic query execution times. #alwaysoptimizing! + +### Hourly Throttling + +The hourly event-throttling threshold has been **increased** from 5x to 10x the plan limit. The way we calculate it is by taking the plan limit and dividing it by the hours in the month, then multiplying it by 10. + +### Signup Experience + +The signup experience has been improved when inviting users, as well. Thanks [@mcquaiga](https://github.com/mcquaiga) and [@theit8514](https://github.com/theit8514) for your contribution! + +### Upgrading (Self Hosters) + +**Self hoster?** Need to upgrade? [The latest code can be downloaded from the release page.](https://github.com/exceptionless/Exceptionless/releases/tag/v3.2.0) All other users: No action required. + +* * * + +## Exceptionless.UI 2.3.0 + +User experience was the primary focus of this UI release, along with the new sessions feature. More details below, including other improvements and a few bug fix details. + +### Adding a New Project + +When adding a new project, users will now have a much better experience, and we added a JavaScript configuration section for JS projects. Check it out! + +### Reference id Lookup + +Support for looking up reference ids was added, so you can now navigate to `/event/by-ref/YOUR_REFERENCE_ID` to look up an event. + +### Other Improvements + +* Better messages and a loading mask has been added to data grids to improve user experience when filtering and loading data. +* Escaping of strack traces containing HTML or CSS has also been improved. +* You can now sort extended data items alphabetically. +* The request and environment info tabs for events now show additional extended data. + +### Bug Fixes + +* You can now create an organization or project that ends with a period or whitespace. +* Sometimes an incorrect time range would be set when users used the history chart/graph to select a period of time to drill down to. + +Check out the [Exceptionless.UI Changelog](https://github.com/exceptionless/Exceptionless.UI/compare/v2.2.0...v2.3.0) for all the code changes (87 files / 75 commits). + +* * * + +## Exceptionless.NET 3.3.2 + +Users on desktop applications can now opt-in to sessions by setting a default user and calling the below: + +```cs +ExceptionlessClient.Default.Configuration.UseSessions(); +``` + +Also, module info was not being included in some error reports, which was incorrect. That has now been fixed. + +The [full change log](https://github.com/exceptionless/Exceptionless.Net/compare/v3.3.1...v3.3.2) can be viewed on GitHub. + +* * * + +## Exceptionless.JavaScript 1.3.1 + +Besides integrating with the above, the only major change in the JavaScript client, like the .NET client, was that users can now op-in to sessions. To do so, set a default user and call the below: + +```cs +exceptionless.ExceptionlessClient.default.config.useSessions(); +``` + +Check out the [full change log](https://github.com/exceptionless/Exceptionless.JavaScript/compare/v1.3.0...v1.3.1) for all the dirty details. diff --git a/docs/news/2016/2016-02-01-track-view-user-session-data-exceptionless.md b/docs/news/2016/2016-02-01-track-view-user-session-data-exceptionless.md new file mode 100644 index 0000000000..2940312cd3 --- /dev/null +++ b/docs/news/2016/2016-02-01-track-view-user-session-data-exceptionless.md @@ -0,0 +1,134 @@ +--- +title: "Track and View User Session Data - New Exceptionless Feature!" +--- + +# Track and View User Session Data - New Exceptionless Feature! + +![app user session logging](/assets/img/news/sessions-dashboard-header2-1024x411.png) + +To many, this feature may be the missing piece... that connection you've always wanted to make between users, bugs, exceptions, app events, etc. I'm talking about, of course, **user session tracking!** + +That's right, you can now use Exceptionless to track users as they use your app, which of course will come in super handy when you want to know exactly what they did to stumble upon or cause an error or trigger an event. + +Continue reading to learn more about sessions and how you can enable them for your apps. + + + +## Session Overview + +First, you must have a paid (premium) Exceptionless plan to report on sessions if you are hosting with us. This is mainly because of the added resource requirements the feature puts on our infrastructure. We think it's definitely worth it, though! + +Sessions can be searched/filtered like all other events - they are just an event type like exceptions or logs. + +## What's in a User Session Event? + +Each user session records how long they were active and what they did. For instance, the average user session on be.exceptionless.io the first week we monitored it using the feature was two hours. + +With that, each user session event has a "Session Events" tab that displays all the relevant events that occurred during that session and allows you to see exactly what that user did. This is especially helpful, of course, if that session lead to an exception or noteworthy event in your app. + + + + [![App User Session Reporting](/assets/img/news/sessions-event-tab-user-footsteps-300x142.jpg)](/assets/img/news/sessions-event-tab-user-footsteps.jpg) + + + + + + All unique data that remains constant throughout the user session is also stored in the event, such as browser and environment information. + + + + + + [![app user session unique data](/assets/img/news/sessions-unique-user-data-300x155.jpg)](/assets/img/news/sessions-unique-user-data.jpg) + + + + +## Sounds Good. How do I Set it Up? + + +![sessions-dashboard-nav](/assets/img/news/sessions-dashboard-nav.jpg) First, you'll need to update to the latest client versions to enable sessions, then you'll have to follow the below steps to begin tracking them. Once you've got that set up, visit the new Sessions section under the Reports option on your main dashboard, or navigate directly to https://be.exceptionless.io/session/dashboard. If you are **self hosting**, make sure you [update to Exceptionless 3.2](/new-releases-for-all-the-codes-exceptionless-3-2/) first. + +### Turning On Session Tracking + +For Exceptionless to track a user for your app, you need to send a user identity with each event. To do so, you need to set the default user identity via the following client methods: + +#### C# + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.SetUserIdentity("UNIQUE_ID_OR_EMAIL_ADDRESS", "Display Name"); +``` + +#### JavaScript + +```js +exceptionless.ExceptionlessClient.default.config.setUserIdentity('UNIQUE_ID_OR_EMAIL_ADDRESS', 'Display Name'); +``` + +Once the user is set on the config object, it will be applied to all future events. + +**Please Note:** In WinForms and WPF applications, a plugin will automatically set the default user to the `**Environment.UserName**` if the default user hasn't been already set. Likewise, if you are in a web environment, we will set the default user to the request principal's identity if the default user hasn't already been set. + +If you are using WinForms, WPF, or a Browser App, you can enable sessions by calling the `EnableSessions` extension method. + +#### C# + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.UseSessions(); +``` + +#### JavaScript + +```js +exceptionless.ExceptionlessClient.default.config.useSessions(); +``` + +## How do Sessions get Created? + +Sessions are created in two different ways. Either the client can send a session start event, or we can create it automatically on the server side when an event is processed. + +We have a server-side plugin that runs as part of our pipeline process for every event - its sole purpose is to manage sessions by using a hash on the user's identity as a lookup for the session id. + +If the session doesnt' exist or the current event is a session event type, a new session id will be created. If we receive a `sessionend` event, we close that session and update the end time on the `sessionstart` event. + +We also have a `CloseInactiveSessionsJob` event that runs every few minutes to close sessions that haven't been updated in a set period of time. This allows you to efficiently show who is online and offline during a time window. + +## How do I Enable Near Real-Time Online/Offline Then? + +We do this by default in our JavaScript, WinForms, and WPF clients when you call the `UseSessions()` method. + +In the background, we send a `heartbeat` event every 30 seconds if no other events have been sent in the last 30 seconds. + +You can **disable this heartbeat** from being sent by passing `false` as an argument to the `UseSessions()` method. + +The WinForms and WPF clients will also send a `SessionEnd` event when the process exits. + +## Can I Manually Send SessionStart, SessionEnd, and heartbeat Events? + +Sure! You can send these events manually via our client API to start, update, or end a session. Please remember, though, that a user identity must be set. + +### C# + +```cs +using Exceptionless; +ExceptionlessClient.Default.SubmitSessionStart(); +await ExceptionlessClient.Default.SubmitSessionHeartbeatAsync(); +await ExceptionlessClient.Default.SubmitSessionEndAsync(); +``` + +### JavaScript + +```javascript +exceptionless.ExceptionlessClient.default.submitSessionStart(); +exceptionless.ExceptionlessClient.default.submitSessionHeartbeat(); +exceptionless.ExceptionlessClient.default.submitSessionEnd(); +``` + +[Source](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.6.4/src/ExceptionlessClient.ts#L112-L128) + +## Tell Us What You Think + +As always, please send us your feedback. You can post it here in the comments or [submit a GitHub Issue](https://github.com/exceptionless) and we will get back to you as soon as possible! We're always looking for contributors, as well, so don't be afraid to jump in and be the hero the code needs. Contributors get Exceptionless perks! diff --git a/docs/news/2016/2016-02-04-replacing-diy-exception-logging-with-exceptionless-case-study.md b/docs/news/2016/2016-02-04-replacing-diy-exception-logging-with-exceptionless-case-study.md new file mode 100644 index 0000000000..ff51f49d04 --- /dev/null +++ b/docs/news/2016/2016-02-04-replacing-diy-exception-logging-with-exceptionless-case-study.md @@ -0,0 +1,68 @@ +--- +title: "Replacing DIY Exception Logging with Exceptionless - Case Study" +--- + +# Replacing DIY Exception Logging with Exceptionless - Case Study + +[![referral-rock-logo](/assets/img/news/referral-rock-logo.png)](https://referralrock.com)Today we bring you a case study from the founder of [Referral Rock](https://referralrock.com) and serial entrepreneur, **Joshua Ho**. + +Referral Rock is a referral platform for small businesses that Josh created after he "... **realized small businesses lacked the tools to [make a customer referral program work](https://referralrock.com/blog/referral-programs-101-everything-you-need-to-build-a-referral-marketing-program/).**" The app allows businesses to easily and effectively create, implement, and administer a rock-solid referral program to help grow their business. + +Exceptionless recently became a part of Referral Rock's exception reporting and logging toolkit, replacing Joshua's home-grown exception logging solutions, and here are his thoughts! + + + + + + +" + + + + + +--- + +I've always done my own exception logging. Very basic stuff, where I would just log exceptions to my local drive. This gave me a nice place to just look at errors in my ASP.NET code. As with most code, it ended up in production deployments. At one point, I even built some web pages to view the logs remotely. Those little exception logging code snippets also made it into about 3-5 other projects as the years went by. I knew there was software out there that could do this, but I more or less had it solved for myself. +**But that changed recently.** + + +> "One **huge benefit** Exceptionless adds to my business is giving me the ability to provide better customer support." + +## Enter Exceptionless + +As I've been growing my own SaaS business for referral software, called [Referral Rock](https://referralrock.com/), I realized there were times my old solution wasn't effectively capturing all the exceptions and I would have to venture into the Event Log to find out what happened. Also, I liked being able to view the production server remotely, but my little web pages got lost somewhere and I wasn't excited about coding them again. Who likes to code the same thing more than once? Not I. + +> "I could see details on the requests, browser cookies, user identity... all much more than I could see using my old solution." + +So that led me to look for other solutions to view my exceptions remotely, which is when I found Exceptionless. With the help of support, I got it up and running fairly quickly. The guys at Exceptionless were very responsive and helpful in getting me setup. + +### Usage & Evaluation + +Being a startup, I was initially using the free version for about 2 weeks and was **blown away**. The UI was great and I love the AngularJS based responsiveness. Soon I had a great pulse on my production server. I could see details on the requests, browser cookies, user identity... all much more than I could see using my old solution. Once I had it set up, I started to see the benefits using other types of events in Exceptionless, such as logging. I started adding some logs when I was debugging an issue with a customer, and it worked great. + +> "With the help of support, I got it up and running fairly quickly. The guys at Exceptionless were very responsive and helpful in getting me setup." + +One **huge benefit** Exceptionless adds to my business is giving me the ability to provide better customer support. Not only do I know when errors are happening, but also who is seeing them. This allows me to have an opportunity to reach out to that specific customer, once the issue is fixed, and say something like "I saw you had and error when you did XYZ, I wanted to let you know it is fixed now so you can try it again". Taking opportunities to provide that level of service has helped my business. + +We are now running a paid version of Exceptionless with multiple projects and I look forward to adding more logs and playing with other features to give me even greater visibility into my web app. Thanks guys! + + +- Joshua Ho // Founder, [Referral Rock](https://referralrock.com) + + + +--- + + + + + +” + + + + +## No - Thank You, Josh! + +We love to see people enjoying Exceptionless - it's our baby, and we've put a lot of blood, sweat, and tears (I blame Blake) into it. Keep rocking it with Referral Rock! diff --git a/docs/news/2016/2016-02-10-add-reverse-geocoding-to-your-app.md b/docs/news/2016/2016-02-10-add-reverse-geocoding-to-your-app.md new file mode 100644 index 0000000000..deeedb8642 --- /dev/null +++ b/docs/news/2016/2016-02-10-add-reverse-geocoding-to-your-app.md @@ -0,0 +1,166 @@ +--- +title: "Add Reverse Geocoding to Your App" +--- + +# Add Reverse Geocoding to Your App + +![Reverse Geocoding](/assets/img/news/reverse-geocoding-header.jpg) + +We recently introduced reverse geocoding into Exceptionless and are now adding features to make full use of it. + +What we'd like to do in this blog article is **walk any interested developers through the process of adding it to their own app.** + +We'll talk about the resources and services we're using to pull it off, why we chose them, and give you code snippets for implementation. It's all open source, so we've also included links to all the relevant code in hopes it will make your life easier! + +Lets check it out. + +## What is Reverse Geocoding? + + + +It’s the process of taking geo coordinates or an IP Address and resolving it to a physical address (E.G., city, county, state/province, country). + +### Why You Need It + +![Reverse Geocoding - User Location](/assets/img/news/user-event-geo-location.jpg) + +Wouldn’t it be nice if you could **provide location services to your users automatically**? Maybe help them fill in a shipping form from a zip code or there current location? + +With the launch of Exceptionless 2.0 we added a geo property to all events. This allows us to translate valid latitude and longitude coordinates into a physical location. Our goal was to begin capturing the data then and enable different scenarios and uses later. This also allowed us to **show end users where their customers events are being submitted from.** + +### What does it cost? + +One of our primary goals with Exceptionless is to be **completely open source and easy to use** (both in setting up self hosting and using the product). We had to take this into account when picking any library or service, because we want a painless setup and no additional costs for self hosters, all while adding additional value! + +**Please note** that if you love the services we use, you should look into using one of their paid plans or at least promoting them with a positive review, shout out, etc (everyone needs to eat at the end of the day, right?). + +After researching many different services, we ended up goin + +g with [GeoLite2's free, offline, downloadable databases](http://dev.maxmind.com/geoip/geoip2/geolite2/). These databases are **free and updated once a month**, but if you require a more accurate and up-to-date database they offer a paid subscription. We also use their [open source library](https://github.com/maxmind/GeoIP2-dotnet) for interacting with the database in memory. + +## Automating the GeoIP Database Download + +We use our very own [Foundatio Jobs](https://github.com/FoundatioFx/Foundatio#jobs) to download the most up-to-date database. Foundatio Jobs allows us to run the job in process or out of process on a schedule in Azure. + +Alternatively, you could use the [PowerShell script](https://github.com/exceptionless/Exceptionless/blob/v3.5.1/Libraries/DownloadGeoIPDatabase.ps1) we created for downloading the database.  `[DownloadGeoIPDatabaseJob](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Jobs/DownloadGeoIPDatabaseJob.cs)` downloads the database over http and extracts the file contents to disk using [Foundatio Storage](https://github.com/FoundatioFx/Foundatio#file-storage). + +Please feel free to **take a look out our job** for a complete sample including logging and error handling: + +```cs +var client = new HttpClient(); +var file = await client.GetAsync("http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz", context.CancellationToken); +if (!file.IsSuccessStatusCode) + throw new Exception("Unable to download GeoIP database."); + +using (GZipStream decompressionStream = new GZipStream(await file.Content.ReadAsStreamAsync(), CompressionMode.Decompress)) + await _storage.SaveFileAsync("GeoLite2-City.mmdb", decompressionStream, context.CancellationToken); +``` + +## Looking up a Physical Address from an IP Address + +#### Resolving the geo coordinates into a location + +After we automate the database download, the next step involves loading the database in memory using the [open source library](https://github.com/maxmind/GeoIP2-dotnet) provided by MaxMind and querying by the IP address. The code below will do very basic IP validation and lookup the records using the API. + +```cs +private DatabaseReader _database; +public async Task ResolveIpAsync(string ip, CancellationToken cancellationToken = new CancellationToken()) { + if (String.IsNullOrWhiteSpace(ip) || (!ip.Contains(".") && !ip.Contains(":"))) + return null; + + var database = await GetDatabaseAsync(cancellationToken); + if (database == null) + return null; + + try { + var city = database.City(ip); + if (city?.Location != null) { + return new GeoResult { + Latitude = city.Location.Latitude, + Longitude = city.Location.Longitude, + Country = city.Country.IsoCode, + Level1 = city.MostSpecificSubdivision.IsoCode, + Locality = city.City.Name + }; + } + } catch (Exception) { + // The result was not found in the database + } + + return null; +} + +private async Task GetDatabaseAsync(CancellationToken cancellationToken) { + if (_database != null) + return _database; + + if (!await _storage.ExistsAsync("GeoLite2-City.mmdb")) { + Logger.Warn().Message("No GeoIP database was found.").Write(); + return null; + } + + try { + using (var stream = await _storage.GetFileStreamAsync("GeoLite2-City.mmdb", cancellationToken)) + _database = new DatabaseReader(stream); + } catch (Exception) { + // Unable to open GeoIP database. + } + + return _database; +} +``` + +Then, just call the `ResolveIPAsync` method with an IP address to look up the location details. + +```cs +var location = await ResolveIPAsync("YOUR_IP_ADDRESS_HERE"); +``` + +Feel free to take a look at `[MaxMindGeoIPService](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Insulation/Geo/MaxMindGeoIpService.cs)` for a complete sample that includes logging, error handling, caching of the results, and IP validation for higher lookup throughput. We’ve spent the time writing tests and optimizing it to ensure **its rock solid and works great**. So feel free to grab our IGeoIPService interfaces and models and use them in your app. + +**It’s worth noting** that in our app, we use the IP address provided in the event. This could come from a server request or the actual machine's IP address. We also fall back to the API consumer's client IP address. + +### Looking up a Physical Address from Geo Coordinates + +As stated previously, every event submitted to Exceptionless has a geo property that can be set. If it’s set, we will attempt to look up your location by the geo coordinates using a third party service. We used the open source [Geocoding.net library](https://github.com/chadly/Geocoding.net), which abstracts the major different third party reverse geocode services into an easy to use API (options are always good!). + +After we decided on the library, we evaluated a few API/lookup services based on cost and accuracy. We ended up going with the [Google Maps GeoCoding API](https://developers.google.com/maps/documentation/geocoding/usage-limits). They offer 2500 free requests per day and are one of the most used location services in the world. + +Next, let’s write the code that will look up our location from a latitude and longitude. You can find our complete example here. + +Remember to get your free api key from Google before running the code below. + +```cs +public async Task ReverseGeocodeAsync(double latitude, double longitude, CancellationToken cancellationToken = new CancellationToken()) { + var geocoder = new GoogleGeocoder("YOUR_API_KEY"); + var addresses = await geocoder.ReverseGeocodeAsync(latitude, longitude, cancellationToken); + var address = addresses.FirstOrDefault(); + if (address == null) + return null; + + return new GeoResult { + Country = address[GoogleAddressType.Country]?.ShortName, + Level1 = address[GoogleAddressType.AdministrativeAreaLevel1]?.ShortName, + Level2 = address[GoogleAddressType.AdministrativeAreaLevel2]?.ShortName, + Locality = address[GoogleAddressType.Locality]?.ShortName, + Latitude = latitude, + Longitude = longitude + }; +} +``` + +Finally, just call the `ReverseGeocodeAsync` method with a latitude and longitude to look up the location details. + +```cs +var location = await ResolveGeocodeAsync(44.5241, -87.9056); +``` + +## Final Thoughts on Reverse Geocoding + +It took us a bit of work and research initially to get everything working flawlessly for location services. We hope you grab our code off of GitHub to **save yourself all that work**. Also, it’s worth noting that we use [Foundatio Caching](https://github.com/FoundatioFx/Foundatio#caching) to cache the results of location lookups. It drastically increased the performance and cut down on our limited number of requests to rate-limited third party services! + +We also queue work items to look up the geo location since that can be an expensive operation. So, please take this into consideration anytime you are interacting with a third party service. + +## Feedback? Questions? + +Get in touch on [GitHub](https://github.com/exceptionless) or leave a comment below to let us know your thoughts or questions. We're always open to suggestions and will do what we can to help you out if you're having issues with implementation! diff --git a/docs/news/2016/2016-02-26-new-releases-exceptionless-3-2-1-net-client-3-3-5-and-ui-2-3-1.md b/docs/news/2016/2016-02-26-new-releases-exceptionless-3-2-1-net-client-3-3-5-and-ui-2-3-1.md new file mode 100644 index 0000000000..486a4439ae --- /dev/null +++ b/docs/news/2016/2016-02-26-new-releases-exceptionless-3-2-1-net-client-3-3-5-and-ui-2-3-1.md @@ -0,0 +1,85 @@ +--- +title: "New Releases: Exceptionless 3.2.1, .NET Client 3.3.6, JavaScript Client 1.3.2, UI 2.3.1" +--- + +# New Releases: Exceptionless 3.2.1, .NET Client 3.3.6, JavaScript Client 1.3.2, UI 2.3.1 + + + + ![Exceptionless error logging](/assets/img/news/blog-header-image-3.2.1.jpg) + + + +Since the [last major release](/new-releases-for-all-the-codes-exceptionless-3-2/) cycle, we've made several minor releases, including Exceptionless 3.2.1, Exceptionless.NET 3.3.5, and Exceptionless.UI 2.3.1. + +Lets take a look at some of the highlights, and you can check out the full release notes on each at the provided links, below. + +## Exceptionless 3.2.1 + +We fixed a few minor bugs made a few improvements to the main platform. Check them out! + +* Free accounts can now look up events by reference ID (bug). +* Improvements to posting events via GET. +* Items can now be added and removed from project data (bug). +* Users can log directly in to an existing account if they attempt to sign up with the same credentials now, rather than getting an error. +* [@VikzSharma](https://github.com/VikzSharma) fixed the "too many bad attempts" lockout feature. Thanks! +* There is also a once-an-hour limit on user signups and email address changes thanks to @VikzSharma. + +**Upgrading:** Only self-hosters need to worry about upgrading - see details on the [full release notes.](https://github.com/exceptionless/Exceptionless/releases/tag/v3.2.1) + +## Exceptionless.NET 3.3.3 - 3.3.6 + +We've pushed out several minor releases of the .NET client in the last few weeks. I'll cover the major stuff here, but you can view the [full release notes and get the latest source on GitHub](https://github.com/exceptionless/Exceptionless.Net/releases). + +### 3.3.6 + +* An issue causing query string params and cookies to be renamed when dictionary key names were being changed has been fixed. +* `client.Register()` now respects your session setting. +* Manual stacking now uses a model instead of a string, which lets us send a stack title and key value pairs telling the event how to be stacked. More info on the release page. + +**If you are using manual stacking**, this is a required update. [See the release page for the latest source.](https://github.com/exceptionless/Exceptionless.Net/releases/tag/v3.3.6) + +### 3.3.5 + +* New extension methods have been added for events, making it easier to set valid geo coordinates, tags, and more. +* A few new variables and parameters have been added for session heartbeats and id setting. See release notes for details. +* [@InlineASM](https://github.com/InlineAsm) fixed an issue for geolocations that have different separators - thanks! + +### 3.3.4 + +* [@ahmettaha](https://github.com/ahmettaha) added SubmitLog and CreateLog overloads without source parameters. Thanks! +* `ExceptionlessClient.Default.Configuration.UseDebugLogger()` only worked in debug mode with client source, so we replaced it with `ExceptionlessClient.Default.Configuration.UseInMemoryLogger()` +* The serializer wasn't always being passed through so it could get known event data helper methods, which was causing some silent failures - this has been fixed. + +### 3.3.3 + +* [@adamzolotarev](https://github.com/adamzolotarev) added the ability to take complete control over how an event is stacked (be careful) by adding the ability to do manual stacking by calling `EventBuilder.SetManualStackingKey("MyStackingKey")` +* You can now ignore events by user agent bot filter when you call `(ExceptionlessClient.Default.Configuration.AddUserAgentBotPatterns("*bot*"))` on the client side or edit project settings server side. +* The default max size limit of `RequestInfo` has been increased. +* Extra nesting has been reduced by merging `exception.Data` properties into the `Error.Data` dictionary. +* Bug Fix: `AggregatedExceptiones` that contain more than one inner exception are no longer discarded. +* Bug Fix: Machines with a Non-English locale will not process events when `SetGeo` is used. +* Bug Fix: `ArgumentNullException` will no longer be thrown if post data or cookies contain a null key. + +## Exceptionless.JavaScript 1.3.2 + +* [@frankebersoll](https://github.com/frankebersoll) contributed by adding support for offline storage, which can be enabled by calling `client.config.useLocalStorage()`. Thanks! +* User agent bots can be ignored via a filter now with ``(`client.config.addUserAgentBotPatterns("bot"))`` on the client side or via project settings on the server side. +* [@frankebersoll](https://github.com/frankebersoll) also added support for manual stacking (be careful! grants complete control). See release notes for instructions. +* The implementation of the angular `$stateChangeError` has also been improved. + +[Full release notes](https://github.com/exceptionless/Exceptionless.JavaScript/releases/tag/v1.3.2) + +## Exceptionless.UI 2.3.1 + +There's nothing major to report with the UI, just a few tweaks. + +* The project settings pages has been reworked by adding the ability to specify user namespaces, and user agents that the clients will ignore. @VikzSharma also fixed an issue where the single page app could be clickjacked - thanks again! + +[Full release notes and latest release download.](https://github.com/exceptionless/Exceptionless.UI/releases/tag/v2.3.1) + +## Questions? Let Us Know! + +If you've got any questions about any of the release notes above, please don't hesitate to let us know by commenting below or submitting an issue to the respective GitHub repo, above. + +Thanks for checking out our release notes. diff --git a/docs/news/2016/2016-03-08-custom-event-stacking-in-exceptionless.md b/docs/news/2016/2016-03-08-custom-event-stacking-in-exceptionless.md new file mode 100644 index 0000000000..ba5aa093c9 --- /dev/null +++ b/docs/news/2016/2016-03-08-custom-event-stacking-in-exceptionless.md @@ -0,0 +1,61 @@ +--- +title: "Custom Event Stacking in Exceptionless" +--- + +# Custom Event Stacking in Exceptionless + +![custom event stacking with exceptionless](/assets/img/news/custom-event-stacking-graphicl.png)Sometimes you just need things to be your way. + +We get it... your morning coffee, folded towels, and how events stack (group) in your event reporting application should be controllable and customizable. + +Well, thanks to a great suggestion by [@adamzolotarev](https://github.com/adamzolotarev), now they are! Well, the events, at least. + +## Why Custom Event Stacking? + +We do our best to group your events into relevant and smartly-named stacks, but there are cases where you may want to specifically name a stack and attribute certain events to it for organization, reporting, troubleshooting, or other reasons. + +To facilitate this need, we created `SetManualStackingKey`, which both .NET and JavaScript client users can set. + +## How Do I Create Custom Event Stacks? + +Adding your own custom stacking to events in Exceptionless is super easy. Below are examples for both .NET and JavaScript. + +In these examples, we are using `setManualStackingKey` and naming the custom stack "MyCustomStackingKey". + +So, any events you use the below for will be a part of the custom stack, and all other events, exceptiones, logs, feature usages, etc will still be stacked automatically, like normal, by the app. + +### .NET Custom Event Stack Example + +```cs +try { + throw new ApplicationException("Unable to create order from quote."); +} catch (Exception ex) { + ex.ToExceptionless().SetManualStackingKey("MyCustomStackingKey").Submit(); +} +``` + +Alternatively, you can set the stacking directly on an event (e.g., inside a plugin). + +```cs +event.SetManualStackingKey("MyCustomStackingKey"); +``` + +### JavaScript Custom Event Stack Example + +```js +var client = exceptionless.ExceptionlessClient.default; +// Node.Js +// var client = require('exceptionless').ExceptionlessClient.default; + +try { + throw new Error('Unable to create order from quote.'); +} catch (error) { + client.createException(error).setManualStackingKey('MyCustomStackingKey').submit(); +} +``` + +## How Do We Stack Up? + +We're always interested in what you think of Exceptionless' features and functionality, so let us know if you find custom stacking useful, need help implementing it, or just want to chat over on [GitHub](https://github.com/exceptionless). + +Thanks for reading! diff --git a/docs/news/2016/2016-03-16-simple-app-deployment-azure-continuous-deployment-github.md b/docs/news/2016/2016-03-16-simple-app-deployment-azure-continuous-deployment-github.md new file mode 100644 index 0000000000..546cd633c6 --- /dev/null +++ b/docs/news/2016/2016-03-16-simple-app-deployment-azure-continuous-deployment-github.md @@ -0,0 +1,119 @@ +--- +title: "Simple App Deployment with Azure Continuous Deployment and GitHub" +--- + +# Simple App Deployment with Azure Continuous Deployment and GitHub + +![simple app deployment](/assets/img/news/cloud-icon.png)We’ve learned a lot about simple app deployment since we first started Exceptionless. We initially went with what everyone else was doing (Octopus Deploy), but over time we thought we could greatly simplify and automate it, letting us focus on what matters, improving the product! + +Through a lot of testing and iterations of our deployment process, we think we finally nailed it. + +As such, we’d like to share with the community how we use Microsoft Azure Continuous Deployment and GitHub for **awesomely simple deployments. **And, how you can too. See the details of implementing this deploy workflow later in the article, below. + +## Exceptionless Deployment History + +### In the Beginning + +When we first started Exceptionless, we deployed it as a monolithic application, meaning the server and UI were one piece, or app. We used Octopus Deploy to deploy to a single IIS machine, which involved setting up a website and server for the Octopus Deploy service and configuring build agents, on each server we deployed to, that could deploy build artifacts. + +### The Move to Azure + +After a year or so of managing Exceptionless on colocation boxes in a Dallas data center, we realized that **we didn’t want to manage hardware anymore** and we could scale easier on a managed service like Azure. So, we moved to Azure, where we had to set up a VM just to manage deployments with Octopus Deploy. There were also issues that we ran into with deploying to Azure WebSitThis was annoying, since every time we wanted to do a release we had to log in and tell the system to deploy to production. + +We knew there had to be a better way. + +### Two Steps Forward... + +Soon, we decided to split the UI and Server apps so we could deploy and work on them independently. This also meant they could scale independently and one change to either wouldn’t cause the whole site to go down when deploying. Splitting the two helped a lot, but it **added more work** as we now had to manage two Octopus Deploy projects. So, we started looking at the [Continuous Deployment in Azure](https://azure.microsoft.com/en-us/documentation/articles/web-sites-publish-source-control/). + +### Aha! Eureka! Solution Time! + +We researched further and found out that if we used [Git Flow](https://github.com/nvie/gitflow) as a development workflow, we could ditch Octopus Deploy completely, remove that dependency, and just use Git push to manage our deployments. + +With Git Flow, you do all your work in feature branches and the **master branch is always stable**. This allows us to set up GitHub deployment on the master and deploy to Azure automatically, with no work required! So anytime we push to the GitHub master branch, it automatically deploys to production on Azure. That simple! + +#### Here is the BASIC workflow: + + 1. We create a new feature branch, then work on that branch until it is completed and tested. Testing is done on the website that is currently pointed to the feature branch, which is separate from production. + 2. When we commit to any branch, our continuous integration (CI) server picks up the changes via a GitHub webhook, pulls them down, then builds the project. + 3. We then take all of the build artifacts and push them to a second GitHub repository using the same branch that the code was pushed to (for example, the master branch). This allows you to see exactly what artifacts change between releases (stateless too) and different branches. + 4. Those changes are then automatically pushed via Azure Git Deploy. + 5. Profit! + +**This is very slick!** Since we push artifacts to the same branch they were built onto a build repository. We can then set up different environments that get auto deployed when we push to that branch. For example: When we are working on a feature, we commit to our branch. We can then set up a new website in Azure that pulls from the build server’s Git artifacts branch for that feature. This allows us to test and automate environments! + +## Detailed Continuous Deployment Setup + +Here are the details on our solution for simple app deployment using GitHub and Azure. + +### 1. Use AppVeyor to build the app. + +### 2. Store build artifacts in a separate GitHub artifacts repository. + +This works really well because you can see the entire history of your build artifacts and browse their contents. Plus, GitHub hosts it for free! + +We found that we could that GitHub could understand and parse into different links. We can click on the "Commit:" part of the message to link to the actual commit that is building to see exactly has changed. + +![github build history artifacts](/assets/img/news/github-build-history-artifacts-1024x380.jpg) + +We can then click on the build to see what artifacts changed. + +![gitHub build history details](/assets/img/news/gitHube-build-history-details-1024x193.jpg) + +Another great thing about using Git to store your artifacts is that you can easily clone the artifacts to your local machine to see the exact files that are being used in a specific environment. + +The artifacts repository has branches to match the branches of our code repo so we have separate build artifacts for each branch. This also means that we can just merge the feature into master when we are done and that will cause the production website that is pointed to our master repository to automatically get updated. So, it’s as simple as merge your branch to master to promote a build to production. + +![merge-branch-master promote build production](/assets/img/news/merge-branch-master-promote-build-production.jpg) + +**One issue** with this approach is that the repo can get large because we are storing binary files that change on every build. We are looking into using [Git Large File Support](https://git-lfs.github.com/) to fix this issue. + +### 3. Automate pushing of artifacts to a secondary GitHub repository. + +For our .NET application, [Exceptionless](https://github.com/exceptionless/Exceptionless), we invoke a PowerShell script on post build to clone and commit the changes to the [Git artifacts repository](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1). + + 1. Our first step is to [clone the existing build artifacts repo to an artifacts directory](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1#L10-L11). + 2. Next, we [change to the same branch that we are currently building, if it doesn’t exist we create it](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1#L20-L28). + 3. Then, we [remove all existing files in the artifacts folder](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1#L35-L36). This ensures we don’t have any conflicts and we can see exactly what was added or removed. + 4. Next, we [copy our build artifacts into the artifacts folder](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1#L38-L60). This allows us fine grained control over our artifacts. + 5. Next, we [try to commit all artifacts to the artifacts repository](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1#L62-L67). If there were no changes between the last build, then we exit. + 6. Next, we [push the artifacts to our GitHub artifacts repository](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1#L69-L78), which will then trigger Azure Continuous Deployment to pick up the changes. + 7. Finally, we [create tag the artifacts repository](https://github.com/exceptionless/Exceptionless/blob/master/Libraries/Push-Artifacts.ps1#L80-L87) which points to the specific GitHub commit we are building in our main repository. + +**For our static [Angular JavaScript app (UI)](https://github.com/exceptionless/Exceptionless.UI),** we invoke a [Grunt publish task](https://github.com/exceptionless/Exceptionless.UI/blob/master/src/Gruntfile.js#L51) from our post build event. The publish task called into a [gh-pages](https://github.com/tschaub/grunt-gh-pages) [task](https://github.com/exceptionless/Exceptionless.UI/blob/master/src/grunt/task-configs/gh-pages.js) that publishes our built dist folder to the GitHub artifacts repository automatically. + +### 4. Point Azure Continuous Deployment to the Artifacts Repository + +It will see when new artifact commits happen and automatically deploy the changes. + +![azure sees new artifact commit and deploys](/assets/img/news/azure-sees-new-artifact-commit-and-deploys-1024x846.jpg) + +Azure Continuous Deployment is another Git repository that we can easily view to see the history of deployments to each of our sites. It also allows us to easily roll back to previous versions. + +### 5. Use Environment Variables to Override Config Settings Per Environment + +Azure Websites makes this very easy. + +![azure override config settings environment variables](/assets/img/news/override-config-settings-environment-variables-1024x497.jpg) + +No production settings are stored in source control or artifacts repository. + +For our ASP.NET application, our settings class will look up named settings in the following order: + + 1. environment variables + 2. local config.json file + 3. app settings + +It will then fall back to a default value if no explicit settings are found. + +**Configuring our static Angular JavaScript app** is a bit more work since it can't look these settings up dynamically at runtime. So instead we add some code to our deployment process. + +* Azure automatically runs a [deploy.sh](https://github.com/exceptionless/Exceptionless.UI/blob/master/deploy.sh) file after getting the artifacts via git deploy. It’s sole job is to run a node script that rewrites our [app.config.js](https://github.com/exceptionless/Exceptionless.UI/blob/master/src/app.config.js) settings with settings defined in environment variables. + +## Conclusion + +You can create multiple Azure websites (think environments) that use Continuous Deployment and point them to multiple artifact branches to support different environments! + +**Pro Tip:** We created a website for our spa website that’s pre-built and points to your localhost Exceptionless server. This allows us to do work on the server part without setting up or configuring a local instance of our spa app. Development made simple! + +We won't lie, it took some work to get here, but **the good news is you can do this really easily too**. Please feel free to steal our deployment scripts and modify them for your projects. And let us know if you have questions along the way! diff --git a/docs/news/2016/2016-03-24-filter-improvements-exceptionless-single-page-app.md b/docs/news/2016/2016-03-24-filter-improvements-exceptionless-single-page-app.md new file mode 100644 index 0000000000..77f68ab76d --- /dev/null +++ b/docs/news/2016/2016-03-24-filter-improvements-exceptionless-single-page-app.md @@ -0,0 +1,55 @@ +--- +title: "Filter Improvements to the Exceptionless Single Page App" +--- + +# Filter Improvements to the Exceptionless Single Page App + +![SPA filter search solutions](/assets/img/news/user-experience-search-filter-changes.png)It's been a while since we introduced filtering and searching when we launched Exceptionless V2.0, so we decided recently that we wanted to take the feedback we've received and do a round of improvements to it. + +You may have already noticed the changes, but if not then the next time you log in you will see that the top bar has changed, giving you much quicker access to filtering and more upfront information. + +## Filter Changes to the Desktop View + +For the primary desktop view, we removed the magnifying glass icon in the top bar and simply filled the rest the bar with the filter (search) input box. This eliminates a click to get to the filtering system, and keeps it front and center at all times. + +One **important note** here is that if you want to show events that have been marked as fixed or hidden, you have to explicitly specify those filters, whereas previously those options were check boxes. So, you can use `hidden:false` or `hidden:true`, and `fixed:true` or `fixed:false` to view those events. Naturally, the default is false for both, showing events that have not been hidden or fixed. This means that in order to see both hidden and un-hidden events, you would need to use `hidden:false OR hidden:true`. Likewise, for fixed, you would need to use `fixed:true OR fixed:false`. + +You'll notice that the date/time filter has changed as well. Instead of an icon, we now display the current time frame being viewed, once again saving you a click and keeping things in front of you. + +As always, the filter still applies to the chosen time frame only. + +### Before + +![old1](/assets/img/news/old1.png) + +![old2](/assets/img/news/old2.png) + +### After + +![new7](/assets/img/news/new7.png) + +![old3](/assets/img/news/old3.png) + +## Mobile Changes & Functionality + +We also changed the user interface for smaller screens. + +Instead of the icons at the top of the screen, the time frame selector is now a major menu item in the mobile menu and displays the current selection with the filter/search field directly below it. + +This setup should allow users to filter and find the events they seek much quicker on mobile. + +### Before + +![new2](/assets/img/news/new2.png) + + + +### After + +![new3](/assets/img/news/new3.png) + +## Pretty Cool, Yeah? + +We think it's a pretty nice improvement. We got feedback from several users and think making everything visible at the top level of the user interface is an important change that saves time and keeps you informed. + +If you've got any additional feedback, please don't hesitate to let us know. We are always looking for ways to improve, and we use Exceptionless every day too, so we are always interested in saving ourselves time and making things easier on our end! diff --git a/docs/news/2016/2016-04-04-exceptionless-v3-3-0-now-with-even-more-awesome.md b/docs/news/2016/2016-04-04-exceptionless-v3-3-0-now-with-even-more-awesome.md new file mode 100644 index 0000000000..938e24f6ee --- /dev/null +++ b/docs/news/2016/2016-04-04-exceptionless-v3-3-0-now-with-even-more-awesome.md @@ -0,0 +1,50 @@ +--- +title: "Exceptionless V3.3.0 Release - Now with Even More Awesome" +--- + +# Exceptionless V3.3.0 Release - Now with Even More Awesome + +![Exceptionless 3.3.0 Release Notes](/assets/img/news/Exceptionless3-3-0-release-notes.jpg) + +We always work hard to keep improving Exceptionless, and this release is no different! + +Since the last release, we've put a lot of time into [making the filtering and searching more user friendly](/news/2016/2016-03-24-filter-improvements-exceptionless-single-page-app) and intuitive, improving the reliability of jobs, and of course fixing any bugs that you guys (or Exceptionless) have been able to find. + +Let's see what we've got going on, shall we? + +## What's Goin On? + +### Filter / Search + +For starters, as mentioned above, we relocated the search bar to exist on the top level of the UI, and the date picker filter now shows the current choice on the top level. Both icons were replaced, and we really think it's much more intuitive and efficient. You can read more and see examples over on the [dedicated blog post](/news/2016/2016-03-24-filter-improvements-exceptionless-single-page-app) we did last week. + +### New Stats API + +You can now get a timeline or numbers for a comma delimited list of fields using the new stats API, which is pretty cool. + +### Session Management + +Session management has been drastically improved by doing a few different things. For instance, inactive sessions are now closed faster, but they can be opened again if need be. We hid heartbeat events by default, too, and you can now specify manual sessions for desktop-based apps. + +### Manual Stacking + +We introduced [custom event stacking](/docs/manual-stacking) a few weeks ago, and [@adamzolotarev](https://github.com/adamzolotarev) has added the ability to specify a manual stacking key on the client side with this release. Thanks Adam! + +### Discard events created from bots + +A default list of bot wild card exclusions is now automatically set on new projects, so if you're upgrading, you now have the ability to run a maintenance job via the admin controller to set a default bot list. All events with user agents matching these wild cards will then be discarded on the client side. + +### Bugfixes! + +* Marking stacks as fixed or hidden was causing some significant slow down and sometimes wouldn't work at all. This has been remedied! +* Redis connection failures and lock timeouts were sometimes causing jobs to stop working or fail. We dug through and found what was causing that and fixed it as well. +* When the geo field contained a localized number, sometimes events were not being processed. This [localization](/news/2016/2016-02-10-add-reverse-geocoding-to-your-app) issue has been solved. +* And last but not least (well, maybe least), a seralization bug has been fixed that would cause query strings, cookies, and other extended data items to be transformed to lowercase and underscored. + +### Time to Upgrade + +Well, only if you're a self hoster. Everyone else will experience all of these awesome improvements and bug fixes the next time they log in. If you are a self hoster, please review the [Self Hosting Docs](/docs/self-hosting/) for info regarding upgrading your current Exceptionless install. Naturally, if you have any questions please let us know and we will get you taken care of. + +## In Conclusion + +You can find a complete comparison changelog over on [GitHub](https://github.com/exceptionless/Exceptionless/compare/v3.2.1...v3.3.0), where you can also submit any issues, etc if you run across anything. Please also let us know what you think of the changes by commenting below, pinging us on social media, or simply sending Blake a [glitter bomb](http://www.ruindays.com/products/spring-loaded-glitter-bomb) _(site/link not endorsed in any way, lol - first one I found!)_. diff --git a/docs/news/2016/2016-04-07-foundatio-featured-net-blog-version-4-0-release.md b/docs/news/2016/2016-04-07-foundatio-featured-net-blog-version-4-0-release.md new file mode 100644 index 0000000000..3b66f23359 --- /dev/null +++ b/docs/news/2016/2016-04-07-foundatio-featured-net-blog-version-4-0-release.md @@ -0,0 +1,41 @@ +--- +title: "Foundatio Featured on .NET Blog + Version 4.0 Release!" +--- + +# Foundatio Featured on .NET Blog + Version 4.0 Release! + +![Foundatio 4.0 release](/assets/img/news/foundatio-4.0.png)We've continued to focus some of our attention on our pluggable app foundation block solution, Foundatio, and last week it got some attention from the Microsoft .NET Blog as well! + +[Foundatio featured as Project of the Week on .NET Blog](https://blogs.msdn.microsoft.com/dotnet/2016/03/29/the-week-in-net-3292016/) + +We've also released V4.0, which has some new implementations, API changes, and, of course, bug fixes. + +Check out the details, below. + +## Foundatio 4.0 Release Notes + +### Implementations + +We've got a few new implementations with this release, including Amazon S3 storage, Azure Service Bus queue (thanks [@jamie94bc!](https://github.com/jamie94bc)), and Redis metrics client. Users should find those helpful. + +### API + +The APIs have been drastically simplified for ease of use and straightforwardness, which should allow for easier creation of new implementations and consumption of existing ones. + +Once example of this simplification is that we've paired down jobs to having only one lock, instead of four. + +Logging has also seen huge improvements to make sure we are aligned with future API implementations, etc. + +### Bugs + +More tests have been added since the previous release, and we've fixed a few major bugs as well. + +* Deadlocks were occurring in a few areas, which is now remedied. +* Dropped connections are now automatically healed, while previously we were seeing some issues. +* Cached reference types can no longer be updated. + +## Upgrading to Foundatio 4.0 + +If you're already using Foundatio, simply updated your NuGet package. If you're new and want to check it out, snag [Foundatio over on GitHub](https://github.com/FoundatioFx/Foundatio). + +And, as always, we're here to answer any questions or take any feedback you might have to offer! diff --git a/docs/news/2016/2016-04-18-how-many-users-affected-bugs-events.md b/docs/news/2016/2016-04-18-how-many-users-affected-bugs-events.md new file mode 100644 index 0000000000..c01446a728 --- /dev/null +++ b/docs/news/2016/2016-04-18-how-many-users-affected-bugs-events.md @@ -0,0 +1,94 @@ +--- +title: "Know How Many Users are Affected by Bugs and Events" +--- + +# Know How Many Users are Affected by Bugs and Events + +**![exceptionless user tracking](/assets/img/news/users-featured-image.png)Prioritizing your bug fixes and development time** in general can be a daunting task. + +Sometimes, as developers, **we want to work on this shiny widget** or this annoying bug, and we don't really have anything in our face telling us to **quit focusing on our dreams** and work on what matters to the bottom line. + +I can hear you over there: **"But, my dreams are important!"** Well, yes, but you don't get to have fun working on those until you've made your **users** happy by fixing the bugs that are affecting the majority of them or expanding on that feature that they are all using every single time they use your app. + +We've got something that will let you get those pesky tasks off your plate though, so you can move on to the fun stuff! + + + +## Who and How Bad Is It? + +Our new "users" column and "Most Users" dashboard lets you **know exactly what percentage of your users are being affected by events or using features**. This allows you to prioritize the most important bugs or features to work on right away and potentially backlog things that only a few users are having issues with or using. + +Of course, you'll need to be sending at least a user id (and preferably a display name) for each user. We'll cover how to do that later in the article. + +### Percentage of Users Column + +The new Users column on your Exceptionless dashboard displays a percentage value for each event stack that represents the number of users that have been affected by the event or, if it is a feature, that have used the feature. + +If you mouse over the percentage, you can see the number of users the percentage represents out of the total. + +These numbers are dynamically calculated for your selected timeframe that you are currently viewing. + +![users affected by bug](/assets/img/news/dashboardv2-edited-1024x662.png) + +### Most Users Dashboard + +Because the main dashboard shows you the most frequent events, not necessarily with the highest usage, **we thought it would be helpful to have a new dashboard that automatically sorts event stacks by the percentage of users affected,** letting you start at the top of an exception list, for example, and work your way down knowing you're always working on a bug, etc, that is affecting the highest percentage of users. + +![user event dashboard](/assets/img/news/dashboard-most-usersv2-edited-1024x644.png) + +## Setting User Identity + +In order to assure you are getting value out of the user feature, you want to make sure you are setting the user. For Exceptionless to track a user for your app, you need to send a user identity with each event. To do so, you need to set the default user identity via the following client methods: + +#### C# + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.SetUserIdentity("UNIQUE_ID_OR_EMAIL_ADDRESS", "Display Name"); +``` + +#### JavaScript + +```js +exceptionless.ExceptionlessClient.default.config.setUserIdentity('UNIQUE_ID_OR_EMAIL_ADDRESS', 'Display Name'); +``` + +Once the user is set on the config object, it will be applied to all future events. + +**Please Note:** In WinForms and WPF applications, a plugin will automatically set the default user to the `**Environment.UserName**` if the default user hasn't been already set. Likewise, if you are in a web environment, we will set the default user to the request principal's identity if the default user hasn't already been set. + +### ASP.NET Example + +You can also manually set the user info on the event directly. This is intended for **multi-user processes (web applications)[.](http://www.businessinsider.com/slack-free-unlimited-plan-has-limits-2015-6) **For most MVC and WebAPI packages, the user will be set automatically based on the logged in principal, so you don't have to do anything. + +```cs +// Import the exceptionless namespace. +using Exceptionless; +ExceptionlessClient.Default.CreateFeatureUsage("MyFeature").SetUserIdentity("123456789", "Blake Niemyjski").Submit(); +``` + +### JavaScript Example + +If you're using the JavaScript client, the entire session of the client will typically be for a single user, so you should be able to set it one time when they log in to your app. + +```js +exceptionless.ExceptionlessClient.default.setUserIdentity("id", "friendly name")` +``` + +Like with .NET, if you are running a multi-user process (Node.js), you'll need to set the user at the event level. + +```js +// javascript +var client = exceptionless.ExceptionlessClient.default; + +// Node.Js +// var client = require('exceptionless').ExceptionlessClient.default; + +client.createFeatureUsage('MyFeature’).setUserIdentity('123456789', 'Blake Niemyjski').submit(); +``` + +## How Will You Use this Data + +We are always interested in how our users use our features, and if our users feature helps our users help their users, well, that's a win win for our users and their users. Go users! + +Don't forget to stop by and let us know if you love or hate it, and of course let us know if you think we can improve on anything within Exceptionless. diff --git a/docs/news/2016/2016-04-27-exceptionless-keyboard-shortcuts.md b/docs/news/2016/2016-04-27-exceptionless-keyboard-shortcuts.md new file mode 100644 index 0000000000..6e93eb2f09 --- /dev/null +++ b/docs/news/2016/2016-04-27-exceptionless-keyboard-shortcuts.md @@ -0,0 +1,47 @@ +--- +title: "Exceptionless Keyboard Shortcuts" +--- + +# Exceptionless Keyboard Shortcuts + +![keyboard-shortcuts](/assets/img/news/keyboard-shortcuts.png)Today we've got a quick article on one of the little known features of Exceptionless: keyboard shortcuts. + +In an effort to help you navigate Exceptionless event stacks better and troubleshoot faster, we've added keyboard shortcuts that lets you do things like go to the stack from an individual event occurrence, copy the event JSON, navigate to the previous event occurrence, etc. + +Let's take a look at all the quick shortcuts you can use to make your Exceptionless usage more efficient. + +## Bringing Up the Shortcut List + +To bring up the keyboard shortcuts available to each page, simply hold the shift key and hit the forward slash key (SHIFT + /, think ?). This will bring up an overlay showing you which shortcuts are available on that specific page. + +Don't see shortcuts available on a page? Don't freak out, there may just not be any. Feel free to suggest something that you think would save yourself and others time, though! + +## What Shortcuts Exist? + +### Event Occurrences + +If you hit SHIFT + / (?) on an event occurrence, you will see three or four new options, depending on whether you are on the first occurrence in the stack or not. + +* **Go to Stack +** On any event occurrence, you can hit CTRL + UP to go to that event's stack quicker than finding the "Go To Stack" button and clicking. + +* **Copy Event JSON to Clipboard +** Hit CTRL + SHIFT + C to copy that event's JSON data to your clipboard. + +* **Previous Occurrence +** CTRL + BACK (LEFT) will take you to the previous event occurrence. + +* **Next Occurrence +** And CTRL + FORWARD (RIGHT) will take you to the next occurrence of that event. + +### Dashboards & Stacks + +On any dashboard or stack, SHIFT + / (?) brings up a simple overlay letting you know that ? will close the overlay and F1 will take you to the Exceptionless documentation on GitHub. + +We're open to suggestions for other dashboard or stack shortcuts, just let us know in the comments! + +## What Shortcuts Would You Use? + +We'd love to get some community input here. What shortcuts do you think would be useful on which Exceptionless pages? Do you have something you do repeatedly on a dashboard or stack page that you think a keyboard shortcut might speed up or make more efficient? Let us know in the comments and we'll do our best to implement your ideas! + +Happy coding. diff --git a/docs/news/2016/2016-05-19-new-client-releases-focus-on-sessions-real-time-configuration-and-logging.md b/docs/news/2016/2016-05-19-new-client-releases-focus-on-sessions-real-time-configuration-and-logging.md new file mode 100644 index 0000000000..175481b026 --- /dev/null +++ b/docs/news/2016/2016-05-19-new-client-releases-focus-on-sessions-real-time-configuration-and-logging.md @@ -0,0 +1,114 @@ +--- +title: "New Client Releases Focus on Sessions, Real Time Configuration, and Logging" +date: 2016-05-19 +--- + +# New Client Releases Focus on Sessions, Real Time Configuration, and Logging + +![net-3.5.0-js-1.4.0](/assets/img/news/net-3.5.0-js-1.4.0.png)Exceptionless.NET v3.5.0 and Exceptionless.JavaScript v1.4.0 have been released and they are chock full of **new features and feature improvements!** + +There weren't a whole lot of bug fixes with these releases. Could it be that Exceptionless is working and we've squelched most of the bugs? We think so! + +Notably, we focused on sessions, real time configuration, and logging, all of which we think you'll find super helpful. + +Read on for details. + +## Exceptionless .NET Client V3.5.0 and JavaScript Client V1.4.0 Release Notes + +### Session Heartbeats No Longer Count Towards Plan Limits! + +We've updated Session Heartbeats and Session End events to be sent through an optimized API end point, and they will no longer count towards your plane's event limits. + +### Real Time Project Configuration Improvements + +You can now exclude events by type and source, along with setting minimum log levels, **in real time**. So, for example, if you accidentally disable logging completely, you can **simply update your settings** and the updates will go into affect, restoring functionality! + +UI support will be expanded moving forward, but for the time being here is an example project configuration. + +#### Source + +**Key:** `@@EVENT_TYPE:SOURCE + +` + +**Value:** `false` + +Any event type or source can be used, and wildcards `*` are supported, so you can ignore whole event types and set the source to `*`. + +#### Disable Submissions of Events with Type Name + +**Key:** `@@error:*MyCustomException` + +**Value: **`false` + +This configuration will disable submission of any error event with a stack trace containing an exception with a type name that ends with `MyCustomException`. You could also remove the wildcard and specify the full type name with the namespace. + +#### Log Message Settings + +**Key:** `@@log:*` + +**Value:** `off` + +Even though log types are special cased, they still accept rue or false values, so this example completely turns off log messages. + +Other known values are `Trace`, `Debug`, `Info`, `Warn`, `Error`, `Fatal`, and `Off`. + +#### Minimum Log Level + +**Key: **`@@log:MyNamespace.EventPostsJob` + +**Value: **`Info` + +This example is setting the minimum log level for `EventPostsJob` to `Info`. + +### Automatically Check for Updated Configuration Settings on Client Idle + +We've implemented an a**utomatic recurring check for updated configuration settings** that occurs **two minutes** after the last event submission. + +A few notes: + +* Each configuration check **does not** count towards your account's plan limits. +* No user information will be sent - only the current configuration version. +* Nothing will be retrieved if no settings have been changed. + +The automatic recurring configuration settings check **can be disable** by calling: + +#### .NET + +```csharp +client.Configuration.UpdateSettingsWhenIdleInterval = TimeSpan.Zero; +``` + +#### JavaScript + +```javascript +client.config.updateSettingsWhenIdleInterval = -1;` +``` + +### New Easy Way to Exclude Events from Being Submitted in .NET + +You can now define a simple `Func<Event,bool>` callback to stop events from being submitted in the .NET client. + +For example, if I wanted to ignore any event with a `value` property of `2` I could use `client.Configuration.AddEventExclusion(e => e.Value.GetValueOrDefault() == 2);` + +### Bug Fix for SettingsCollection Boolean Values Support in .NET Client + +`SettingsCollection.GetBoolean(name)` was not supporting `` or `1` as boolean values, but now it does. We are also now supporting `yes` and `no` as valid values. + +### JavaScript Client Passing Settings Bug + +[@csantero](https://github.com/csantero) fixed an issue with passing settings to a new isntance of ExceptionlessClient - thanks! + +### Improved Stacking of Angular Response Errors in JavaScript Client + +^^^ Nothing much to say here - the header says it all! + +## Feedback + +We hope these new features and feature improvements help your Exceptionless experience, and we plan to continue to listen to user feedback and improve the system where improvements need to be made. To do that, though, we need to hear what you want out of the app. If you have a favorite feature request, or something that just bothers you, please let us know by dropping us a line on GitHub Issues under the appropriate repository, listed below, or just comment here and we'll figure it out! + +* [.NET Client Feedback](https://github.com/exceptionless/Exceptionless.Net/issues/new) +* [JavaScript Client Feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues/new) +* [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) + +Thanks for reading and have an awesome day! diff --git a/docs/news/2016/2016-05-26-session-heartbeats-no-longer-count-towards-plan-limits.md b/docs/news/2016/2016-05-26-session-heartbeats-no-longer-count-towards-plan-limits.md new file mode 100644 index 0000000000..7d171fc50f --- /dev/null +++ b/docs/news/2016/2016-05-26-session-heartbeats-no-longer-count-towards-plan-limits.md @@ -0,0 +1,49 @@ +--- +title: "Session Heartbeats No Longer Count Towards Plan Limits" +--- + +# Session Heartbeats No Longer Count Towards Plan Limits + +![session-tracking-revised](/assets/img/news/session-tracking-revised.png)That's right! We've re-imagined how session heartbeats and session end events should work on the back end and were able to make them much more efficient, allowing us to stop counting them toward user plan limits! + +This blog post explains our original goals and implementation of these session events, and how we were able to retain the same functionality of the feature while limiting resource usage. + +Our hope is that this will obviously make our users happy, but also that all the developers out there can benefit from our process and solution. + +## Genesis: Exceptionless Session Tracking + +In the beginning, we set out to create a sessions feature that allowed our users to submit a session start event and the session would be automatically updated by sending a session heartbeat event, as well as a session end event, respectively. + +These session heartbeats and session end events were meant to be session markers to show that a user was active or a session had ended. + +We wanted to **leverage our existing infrastructure,** and the easiest way to do so was to introduce new event types that we recognized. This meant that these events went through the client side plugins (extra work) and server side processing. As such, there was **no way to tell these events apart from any other event**. + +And because of that, they counted against user plan limits. + +## Noise + +After releasing the sessions feature, **it didn't take us long to notice that the heartbeats were noise**. However, we knew that users wanted to see what their customers or users were doing while being active throughout the session, so we didn't remove them. + +We knew they were counting towards plan limits, causing some users to reach theirs quickly, and we knew they were adding noise, thus limiting the feature's value, but we also wanted to keep the feature alive because of the _potential_ value offered. So, we had to react and make the entire feature more feasible, streamlined, and cheap. + +## Back to the Drawing Board + +We did some thinking (and coding), trying to determine the best way we could **provide end users with a great session tracking feature without over-taxing our system** in the process, and we were able to come up with a solution! + +So, we created a new GET API endpoint `/api/v2/events/session/heartbeat` ([api source](https://api.exceptionless.io/docs/index.html#!/Event/Event_RecordHeartbeatAsync)) that takes a session id or user id and a flag if the session is closed. This API endpoint then sets a unique session cache key with the current time. + +Our existing `CloseInactiveSessionsJob.cs` was already periodically polling for open sessions to check for inactive sessions so it could automatically close them after a period of time if no session end event was sent, so we just updated this job to check for the unique session cache keys ([source](hhttps://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Jobs/CloseInactiveSessionsJob.cs#L52)) and get the last time a heartbeat was sent in or see if it was closed. It then takes the appropriate action and updates the session event. + +Then we just updated the clients to call this new API endpoint when `await client.SubmitSessionHeartbeatAsync("id")` or `await client.SubmitSessionEndAsync("id")` is called. + +## Efficiency Achieved! + +Our new solution gives us the ability to have clients send us session heartbeat and session end information very efficiently, which lets us provide a great session tracking feature **without adding any additional cost** to our plans! + +That's how we like to roll, and we hope you find value from the feature and our run down of the process we went through to get it to our users. + +### Don't Forget to Update Your Client + +If you haven't already updated your client, please do so to start taking advantage of the free session events. + +And, as always, please let us know if you've got any feedback or questions. We'd love to hear from you! diff --git a/docs/news/2016/2016-06-28-exceptionless-4-0-net-core-asp-net-core-support.md b/docs/news/2016/2016-06-28-exceptionless-4-0-net-core-asp-net-core-support.md new file mode 100644 index 0000000000..56f65a4e21 --- /dev/null +++ b/docs/news/2016/2016-06-28-exceptionless-4-0-net-core-asp-net-core-support.md @@ -0,0 +1,25 @@ +--- +title: "Exceptionless.NET 4.0 - .NET Core and ASP.NET Core Support!" +--- + +# Exceptionless.NET 4.0 - .NET Core and ASP.NET Core Support! + +That's right folks, with the release of Exceptionless.NET 4.0 you can now build .NET applications with Exceptionless on Linux, MacOS, and Windows! + +We've added .NET Core, ASP.NET Core, and .NET Standard 1.2+ support. + +We know many of you have been waiting for this, and it's been a long time coming, but we sat down, put in the hours, and made it happen for you guys! + +![Exceptionless on Mac OSX](/assets/img/news/Screen-Shot-2016-06-28-at-3.08.17-PM.png)(/assets/img/news/Screen-Shot-2016-06-28-at-3.08.17-PM.png) + +The NuGet package now supports .NET Standard 1.2+, PCL Profile 151, and .NET 4.5. + +**To make upgrading easy**, the `Exceptionless.Portable` NuGet package still exists and is dependent on the `Exceptionless` Package. + +If .NET 4.0 is a requirement for your projects, you will need to continue using the Exceptionless.NET v3.5 NuGet Packages, which are not being deprecated. + +As a matter of housekeeping, we removed the `ExceptionlessClient.Current` property, which was replaced with `ExceptionlessClient.Default` in v2.0.0, and the configuration `EnableSSL` properties (also deprecated in v2). + +## Upgrading + +Updating the NuGet packages should be all you need to do if you are upgrading from Exceptionless.NET v2 or v3. Take a look at the [upgrade guide](/docs/clients/dotnet/upgrading) if you have any questions. diff --git a/docs/news/2016/2016-07-13-exceptionless-3-4-new-user-dashboards-job-reliability-bug-fixes.md b/docs/news/2016/2016-07-13-exceptionless-3-4-new-user-dashboards-job-reliability-bug-fixes.md new file mode 100644 index 0000000000..1847e9d0be --- /dev/null +++ b/docs/news/2016/2016-07-13-exceptionless-3-4-new-user-dashboards-job-reliability-bug-fixes.md @@ -0,0 +1,61 @@ +--- +title: "Exceptionless 3.4 - New User Dashboards, Job Reliability, and Bug Fixes" +--- + +# Exceptionless 3.4 - New User Dashboards, Job Reliability, and Bug Fixes + +![Exceptionless 3.4](/assets/img/news/exceptionless-3-4-header.png)(/assets/img/news/exceptionless-3-4-header.png) + +The latest Exceptionless release has several additions we think most of our users will find helpful. We sat down and worked on the UI, fixed some bugs, and spend a considerable amount of time improving reliability and efficiency of some of the primary pieces of the app. + +If you're a self hoster, you'll need to [upgrade your existing install](/docs/self-hosting/upgrading-self-hosted-instance), but if you're hosting with us there is no action required on your part to experiences the Exceptionless 3.4. + +For more information about this release, take a look below and/or review the [full release notes over on GitHub](https://github.com/exceptionless/Exceptionless/releases/tag/v3.4.0). + +## UI Updates + +These updates were all pushed with [Exceptionless.UI 2.5](https://github.com/exceptionless/Exceptionless.UI/releases/tag/v2.5.0) a few days prior to this release of the main app. Enjoy! + +### Search Wildcard + +You can now use `*` to show **all** events in the search box. Woohoo! + +### Most Users Dashboard + +The new most users dashboard allows you a quick view of events sorted by the highest number of affected users. This is great for helping prioritize your work pipeline. + +Also, as an aside, we've added the users affected column to the dashboard. We know some of you guys will find that helpful. + +### New Keyboard Shortcuts + +MacOS & Linux keyboard shortcut support has been added, as well as additional shortcuts such as `C` to chat with support, `S` to focus the search bar, and `g` `a` to go to your account. Hit `SHIFT` + `/` (also known as `?` ) to access the keyboard shortcut list on any screen. + +As an aside here, there is also now a `` button near the top of the event occurrence that lets you quickly copy the JSON to your clipboard with a click. + +## Other Updates + +This is just a quick list of everything else we tweaked, updated, added, or fixed with the v2.4 release. + +### Performance & Reliability + +We made several reliability and performance enhancements to queue and job processing. A few specific examples include fixing auto-abandoned jobs and instances where batch events weren't being requeued. + +### Heartbeat API Endpoints + +Previously we had [worked on making heartbeat events efficient](/news/2016/2016-05-26-session-heartbeats-no-longer-count-towards-plan-limits) so we didn't have to count them toward event quotas, and with this release we've added new API Endpoints that allow clients to submit those heartbeats cheaply. + +### Active Directory Authentication + +Support has been added for Active Directory Authentication. Thanks [@laughinggoose](https://github.com/laughinggoose)! To enable this feature, head over to the [Active Directory Authentication](/docs/self-hosting/kubernetes#active-directory-authentication) documentation page on GitHub. + +### Count + +This `Count` property was added to the event model that tracks deduplicated events and allows for some pretty cool metrics from here on out while avoiding the full cost of storing every event. + +### MaximumRetentionDays + +`MaximumRetentionDays` is pretty self explanatory. It controls the max retention perdiod for events, which allows the retention job and plans to be smarter about cleaning up old data. + +### Bugs + +SignalR (web sockets) support wasn't always working in some hosting environments such as AWS, so we fixed a few bugs related to that. diff --git a/docs/news/2016/2016-08-01-real-time-app-configuration-event-settings.md b/docs/news/2016/2016-08-01-real-time-app-configuration-event-settings.md new file mode 100644 index 0000000000..41f863b8c4 --- /dev/null +++ b/docs/news/2016/2016-08-01-real-time-app-configuration-event-settings.md @@ -0,0 +1,158 @@ +--- +title: "Real Time App Configuration and Event Settings with Exceptionless" +--- + +# Real Time App Configuration and Event Settings with Exceptionless + +![exceptionless-project-settings-header](/assets/img/news/exceptionless-project-settings-header.png) + +## Bet You Didn't Know Exceptionless Could Do This... + +Have you ever needed to **cut through the noise and just focus on one type of event** _(in real time)_, such as only error logs, to track down a bug? + +Do you want to **limit certain types of event reporting** _(in real time)_ to save your event quota and limit clutter? + +What about **controlling your application's settings or features** _**in real time**_ via Exceptionless, without having to update your files and deploy your app!? + +Well, with our client configuration settings, **you can do all that, and more**, in **real time**, on a per-project basis via your Exceptionless dashboard! + +## How Could This Help Me? + +We'll talk details, below, but first lets look at a few scenarios where the above could be useful. + +### Scenario 1 - Way too many events! + +Let's say you're on the small plan, and you've got a bunch of warning log events clogging your system that you know about and are working on, but they are pushing you over your plan limits. + +#BOOM - set a minimum log level of error, and Exceptionless won't report those warnings anymore and they won't count against your plan limits! This is a great way to get the most out of your Exceptionless plan. + +### Scenario 2 - This Authentication Issue is KILLING Me! + +Maybe you're having major issues with an authentication bug, but you've already set minimum log levels to only include errors. Well, now you also want to see the trace values for those events without opening the flood gates for every event by removing your minimum log level. + +#NOPROBLEM - Just add a key for authentication that just lets trace events through! + +### Scenario 3 - You Said Something About Controlling My App's Features In Real Time? + +Yup! Our client configurations are basically just a key value pair dictionary, but what makes them powerful and helps them control **your** application's features is that they get updated in nearly real-time, meaning you can build settings, features, etc into your app that react to value changes, and if you change that configuration setting in Exceptionless, your app will react almost instantly! + +This can be super useful, especially if changing your app's settings would normally require you to deploy to production. No need - just use Exceptionless! + +## Primer: How Project Settings Work + +First, settings updates **do not count towards plan limits**. We say that because each time an event is submitted, we send a response header with the current configuration version to the client, and if a newer version is available, it is retrieved and the latest configuration is applied. That means that config changes are nearly **real time.** + +When the client is idle, we also check for config changes, including five seconds after client startup if no events are submitted at startup, and every two minutes after the last event submission. + +If the version hasn't changed, nothing is retrieved, **limiting data transfer,** and no user information is ever sent when checking. + +### Turning Off Automatic Updating + +If you do not want the configuration settings to update when idle, you can turn off automatic updates. To do so, please follow the respective [.NET](/docs/clients/dotnet/client-configuration-values#updating-client-configuration-settings) or [JavaScript/Node.js](/docs/clients/javascript/client-configuration-values#updating-client-configuration-settings) documentation. + +## The Main Event: Client Configuration + +![client-configuration](/assets/img/news/client-configuration-300x143.png) + +Exceptionless client configurations are a dictionary of key value pairs that can be used to control the behavior of your app in real time by doing things like controlling data exclusions, protecting sensitive data, enabling and disable features, or disabling certain types of events (`error`, `usage`, `log`, `404`, or `session`). + +We also have some built in configuration key naming conventions (`@@EVENT_TYPE:SOURCE`) that the clients recognize for ignoring events based on event type and event source. Just replace `EVENT_TYPE` part with the event type (E.G., `error`, `log`...) and the `SOURCE` (E.G., exception type or log source) you'd like the setting to apply to. Next, specify key value of `false` to discard matching events client side. It's worth noting that  `log` event types can also accept a log level value (E.G., `Trace`, `Debug`, `Info`, `Warn`, `Error`, or `Fatal`). + +For example, we can use it to turn off all error events of type, lets say, `System.ArgumentNullException`, by using the key `@@error:System.ArgumentNullException` and the value `false`. + +Or, we could turn off all error events entirely by using the `*` wildcard. So, the key would be `@@error:*` and the value would be `false` again. + +### Examples for the Above Scenarios + +#### Scenario 1 + +In scenario 1, above, we were trying to save our plan limits by limiting log events to only errors. So our Client Configuration key would simply be `@@log:*` with value `Error`. + +#### Scenario 2 + +Here we already limited our log events to errors, but now we're troubleshooting a specific issue with authentication (let's say we're using the AuthController API), so we want to look at the trace messages coming through. We can override any general minimum log levels that we've defined by setting a level for a specific log source. So, all we would do is add the `@@log:*AuthController` key with value `Trace`! Then, when the bug's fixed, turn it off as needed. + +#### Scenario 3 + +This is the cool one. Here you are wanting to, let's say, pass a value for a setting in your app that turns something on or off without having to re-deploy everything. This is super easy to accomplish all we need to do is create a setting which will control our feature! Let's assume we have have a feature flag to show a welcome screen. We will name this feature flag `enableWelcomeScreen` and create a new configuration setting respectively with a value of `true` (_You can change this value at any time_). These changes will be pushed based on the above "How Project Settings Work" section automatically, all we have to do is check the setting as shown below. + +#### C# + +```cs +using Exceptionless; +// Check the configuration settings for our enableWelcomeScreen feature flag with a default value of false. +if (ExceptionlessClient.Default.Configuration.Settings.GetBoolean("enableWelcomeScreen", false)) { + // Show the welcome screen! +} +``` + +#### JavaScript + +```js +// Check the configuration settings for our enableWelcomeScreen feature flag +if (exceptionless.ExceptionlessClient.default.config.settings['enableWelcomeScreen'] === true) { + // Show the welcome screen! +} +``` + +Pretty cool, right! + +For more details on client configuration, check out the [Client Configuration Project Settings documentation](/docs/project-settings#client-configuration). Specific usage examples can be found on the [.NET](/docs/clients/dotnet/client-configuration-values) and [JavaScript/Node.js](/docs/clients/javascript/client-configuration-values) documentation pages respectively. + +## Other Project Settings You Might Find Useful + +### General + +![general](/assets/img/news/general-300x132.png) + +If you go to Admin > Projects in Exceptionless, you can choose the project you would like to edit the settings for. Each project can have unique settings. + +The default tab is "General," which simply houses the project name and attached organization. Nothing fancy here - pretty self explanatory. + +### API Keys + +![exceptionless api keys](/assets/img/news/api-keys-300x127.png) + +This tab is where you can generate an API key for your project. Again, pretty self explanatory. Hit "New API Key" and one gets generated. For more details on API usage, check out the [API Usage documentation](/docs/api/) on GitHub. + +### Settings + +![exceptionless project settings](/assets/img/news/settings-300x281.png) + +This is where you can set data exclusions, customize error stacking, and build in some spam detection to your project. + +#### Data Exclusions + +There are several use cases where you might not want to send some data to your Exceptionless project. This field allows you to enter a comma delimited list of field names that will be removed and not transferred to Exceptionless. The perfect example here is a password field, or other personal and sensitive data. + +The `*` wildcard is supported in this field and can be used at the end (`password*`), beginning(`*password`), or on both sides (`*password*`) of the field name to further customize your data exclusion. + +#### Error Stacking + +Control over error stacking is another level of customization project settings allows. You can specify user namespaces or common methods to ignore. More details below. + +**User Namespaces** + +Here you can enter a comma delimited list of namespace names that own your application. With those in place, the only methods that will be considered stacking targets are ones inside those namespaces. + +**Common Methods** + +If your code has shared utility methods that may generate a bunch of errors, this could be useful. Enter a comma delimited list of common method names that shouldn't be used as stacking targets, and they will be ignored. + +#### Spam Detection + +Spam is the worst. So, we added a "Spam Detection" list of common user agents that should be ignored, which you can add to as you see fit. This eliminates a lot of noise, and can be customized to help trim even more depending on your application. + +Along with the comma delimited list of user agents to ignore, you can also tick the box that says "Reduce noise by automatically hiding high volumes of events coming from a single client IP address." This can ward off large numbers of events being submitted by a spammer or attack on your app. + +#### Integrations + +![exceptionless integrations](/assets/img/news/integrations-300x143.png) + +Integrations with tools like Slack, HipChat, JIRA, Basecamp, and others are very popular and can add a level of automated notifications, etc, to your workflow. So, on the integrations tab of your project's configuration you can create web hooks to integrate with your service or others as mentioned. Each web hook has a URL that it can call, and options for when it should be called. When a selected event occurs, a POST request is submitted with either event or stack data in JSON format. For more details and sample data, visit the [Exceptionless integrations documentation](/docs/integrations). + +## That About Covers It! + +We hope this will help you make the most out of your Exceptionless projects, allowing you to save some event submissions, get that customization you were looking for, etc. + +Please let us know if you have any questions, comments, concerns, bugs, or anything else we can help with! diff --git a/docs/news/2016/2016-08-08-set-application-version-for-improved-regression-notifications-and-stacking.md b/docs/news/2016/2016-08-08-set-application-version-for-improved-regression-notifications-and-stacking.md new file mode 100644 index 0000000000..fd8dc0c314 --- /dev/null +++ b/docs/news/2016/2016-08-08-set-application-version-for-improved-regression-notifications-and-stacking.md @@ -0,0 +1,46 @@ +--- +title: "Set Application Version for Improved Regression Notifications and Stacking" +--- + +# Set Application Version for Improved Regression Notifications and Stacking + +![versioning](/assets/img/news/versioning-300x163.png)(/assets/img/news/versioning.png)Do you get annoyed and overwhelmed by event and error notifications? + +You probably have more than one version of your application running, and often **older versions of your app may still be triggering events** that have been fixed in newer versions. + +**Those events and notifications aren't very ****helpful**, so we implemented a versioning system that allows you to set an application version on all events! + +After setting an application version, **when you mark an event fixed and give it a version number, it will only regress if it occurs again in a newer version of your app.** + +That means there is **less noise for you to wade through, and you can focus on new issues** in your application without seeing old or non-relevant events constantly. + +## How to Set an Application Version + +Setting an application version in Exceptionless is easy. By default, we attempt to resolve one automatically based on assembly attributes, but we recommend specifying one yourself for improved reliability and accuracy using the following examples. + +### .NET Version Specification Example + +```cs +using Exceptionless; +ExceptionlessClient.Default.Configuration.SetVersion("1.2.3"); +``` + +### JavaScript/Node.JS Version Specification Example + +```js +exceptionless.ExceptionlessClient.default.config.setVersion("1.2.3"); +``` + +## Fixed! + +Great! Now, when you mark an error stack as fixed and enter the version that you fixed it in, that event stack will have a `Fixed In [Version]` tag and will only regress if it occurs again in a later version of your app. If it does regress, the stack then gets the `REGRESSED` tag. + + +![Regressed](/assets/img/news/regressed-300x91.jpg)(/assets/img/news/regressed.jpg) +_Regressed_ + + + +If you would like to view fixed events, you can always use the `*` wildcard or `fixed:true` in search. + +**We hope you find this feature useful**, and as always don't hesitate to leave us feedback over on [GitHub](https://github.com/exceptionless/Exceptionless/issues) or by commenting below. diff --git a/docs/news/2016/2016-08-29-exceptionless-helps-identify-issue-affecting-25000-users-case-study.md b/docs/news/2016/2016-08-29-exceptionless-helps-identify-issue-affecting-25000-users-case-study.md new file mode 100644 index 0000000000..394dc7b298 --- /dev/null +++ b/docs/news/2016/2016-08-29-exceptionless-helps-identify-issue-affecting-25000-users-case-study.md @@ -0,0 +1,51 @@ +--- +title: "Exceptionless Helps Identify Issue Affecting 25,000 Users - Case Study" +--- + +# Exceptionless Helps Identify Issue Affecting 25,000 Users - Case Study + +![CEVO, Inc. Logo](/assets/img/news/cevo-logo-300x60.png)Case study time! + +Today we've got a great example of Exceptionless helping software developers identify major issues in their web applications affecting thousands of users. + +In this case, the problem was major enough that the development team stopped using WPF and rewrote their entire UI layer! + +Here's what Will Graham, [CEVO, Inc.](http://cevo.com/) developer, had to say when we asked him a few Exceptionless case study questions. + +## Exceptionless Case Study - CEVO, Inc. + +### What’s the number one customer-facing bug Exceptionless helped you squash? + +> "The issue was so prevalent we completely ditched WPF and rewrote our UI layer in GDI+/WinForms" - Will Graham, CEVO, Inc + +**Will:** + +Definitely crashes related to .NET Framework installation corruptions on end-user machines. While Exceptionless didn't (and can't) immediately point and say, "here's how to fix it", it did shine light on an issue that was affecting approximately 5% of our 500,000 installed base. The issue was so prevalent we completely ditched WPF and rewrote our UI layer in GDI+/WinForms, but **Exceptionless gave us insight to see the problem and how many users were being affected**. + +### Were you surprised at the initial results of using Exceptionless for the first time? How many errors were you seeing? + +> "Exceptionless has changed our internal development process and how we approach code. Proper error handling and visibility is now a first-class priority for us and Exceptionless makes it super easy." - Will Graham, CEVO, Inc + +**Will:** + +Yes and no. **Error handling and tracking had always been more of an afterthought** - like, something is wrong, we need to look into it now. **We weren't aware of issues until after our users reported it** and filtering out the noise to find the signal of real issues was a time consuming process. Running on the Azure stack, we were **frustrated with the information provided** in the default diagnostics logging. + +**When we added Exceptionless, we knew we had problems** with our system, we just didn't know where and to what extent. To be honest, **Exceptionless has changed our internal development process** and how we approach code. Proper error handling and visibility is now a first-class priority for us and Exceptionless makes it super easy. + +### What is the number one internal bug you were able to track down with Exceptionless? + +**Will:** + +The biggest bug would have to be intermittent failures on our Service Bus instance. Using the metrics provided by Exceptionless, we were able to spend time implementing fault tolerance in very focused areas of the code based on incidence rate and end-user impact. + +### If you had one feature you’d like us to add to Exceptionless, what would it be? + +**Will:** + +I'm not a huge fan of the current dashboard. It's effective, but with the amount of data Exceptionless has at it's disposal, I feel there's more interesting (and actionable) information that can be shown. + +## We Love It! + +Thanks for your time, Will! We love to hear from our users, and we'll definitely take that dashboard feedback and see what we can do there to make it more useful. + +Do you have feedback on Exceptionless? Has it helped you find bugs and beat them into submission? Join us in the [Exceptionless Discord](https://discord.gg/6HxgFCx) and let us know! diff --git a/docs/news/2017/2017-01-11-2016-recap-let-there-be-stats.md b/docs/news/2017/2017-01-11-2016-recap-let-there-be-stats.md new file mode 100644 index 0000000000..60d74b9941 --- /dev/null +++ b/docs/news/2017/2017-01-11-2016-recap-let-there-be-stats.md @@ -0,0 +1,108 @@ +--- +title: "2016 Recap - Let there be STATS!" +--- + +# 2016 Recap - Let there be STATS! + +[![Exceptionless 2016 in review](/assets/img/news/2016-in-review-1024x538.jpg)](/2016-recap-let-stats/) + +We were curious, so we thought we would put together some stats for 2016, along with and a recap of some of the notable changes and progression. Enjoy! + +## General Exceptionless Stats + +* **Over 120,000,000** events processed +* 4716 users +* 3614 projects +* 2809 organizations + + + +## Release Stats + +### Exceptionless Server: + +* 7 releases +* 88 watching +* 774 stars +* 236 forks + +### Exceptionless UI: + +* 6 releases +* 9 watching +* 38 stars +* 34 forks + +### Foundatio: + +* 4 releases +* 65 watching +* 472 stars +* 97 forks + +## Popular Blog Posts / Updates + +Judging by the traffic to these posts and updates, they're all worth a read. Check them out! + +* [Sending Log Messages to Exceptionless](/news/2015/2015-03-31-sending-log-messages-to-exceptionless) +* [A Better Approach to Running Azure WebJobs](/news/2015/2015-12-08-better-approach-running-azure-webjobs) +* [Simple App Deployment with Azure Continuous Deployment and GitHub](/news/2016/2016-03-16-simple-app-deployment-azure-continuous-deployment-github) +* [Exceptionless.NET 4.0 - .NET Core and ASP.NET Core Support!](/news/2016/2016-06-28-exceptionless-4-0-net-core-asp-net-core-support) +* [Exceptionless API Usage and Overview](/news/2015/2015-05-06-exceptionless-api-usage-and-overview) + +## Notable Changes / Milestones + +### Server License Changes + +We changed the server licensing to use the Apache license. Now, every Exceptionless project is under the Apache license and there should be no more confusion on how it's licensed. [Read more here.](/news/2016/2016-01-27-new-releases-for-all-the-codes-exceptionless-3-2) + + +### Session Tracking & Management + +The ability to track and automatically manage a users session was added, giving you visibility into how long and what a user did while they were using your product. This also answers the question, "what did my users do leading up to this exception?" [Read more here.](/news/2016/2016-02-01-track-view-user-session-data-exceptionless) + +### Fixed by Version + +In 2016, we also added the ability to mark an event as fixed in a specific version of your app. [Read more here.](/news/2016/2016-08-08-set-application-version-for-improved-regression-notifications-and-stacking) + +### Performance & Reliability + +We spent a lot of time this past year making massive performance and reliability improvements across the board. Tons of bugs got fixed along the way, and additions like bulk updates and deletes, along with optimized query generation got squeezed in there, too! One big factor here is that it has allowed us to move to Elasticsearch 5 _much_ quicker because all of these improvements allowed us to do things more generically throughout. Much less code to update/change! + +#### Elasticsearch 5 + +Like we mentioned above, we've done a ton of work to ensure we can move to Elasticsearch 5: + +* Insanely fast document indexing and searching +* Dynamic aggregations (allowing us to do completely customize stats on any data) +* Reindexing support +* Daily indexes +* Making it easier to self host +* Getting one step closer to server being able to run cross-platform + +We have been doing QA on the Elasticsearch 5 migration since the end of the year and it is currently still in progress - coming soon! + +### Open Source ALL the Things + +We open sourced two major new libraries this year: + +* [Foundatio.Repositories](https://github.com/FoundatioFx/Foundatio.Repositories) + Foundatio.Repositories are generic repositories with an implementation for Elasticsearch +* [Foundatio.Parsers](https://github.com/FoundatioFx/Foundatio.Parsers) + Foundatio.Parsers are Lucene query parsers that allow you to validate or modify Lucene queries with ease! + +### Other Noteworthy Enhancements + +* Added [Geo location features](/news/2016/2016-02-10-add-reverse-geocoding-to-your-app) + +* Added [Keyboard shortcuts](/exceptionless-keyboard-shortcuts/) +* The [API is now 100% Async](/news/2015/2015-10-22-introducing-foundatio-3-0-async-efficiency) +* Had third-party security review conducted +* Made it even easier to self host. +* Massive [improvements to Foundatio](/news/2016/2016-04-07-foundatio-featured-net-blog-version-4-0-release) (100% Async, new implementations) + +## Onward to 2017 - Stay Tuned for a Roadmap! + +We've got big things coming up, like Exceptionless 5.0 with Elasticsearch 5, which should boost performance gains like 80% faster indexing, lower memory usage, and native reindexing support! No slowing down over here, so stay tuned and enjoy the ride. + +And, as always, if you have anything you'd like to see in upcoming Exceptionless releases, please let us know! diff --git a/docs/news/2017/2017-01-18-upgrading-elasticsearch-1-x-5-x-live-coding-session.md b/docs/news/2017/2017-01-18-upgrading-elasticsearch-1-x-5-x-live-coding-session.md new file mode 100644 index 0000000000..f2e855e404 --- /dev/null +++ b/docs/news/2017/2017-01-18-upgrading-elasticsearch-1-x-5-x-live-coding-session.md @@ -0,0 +1,29 @@ +--- +title: "Upgrading from Elasticsearch 1.x to 5.x - Live Coding Session" +--- + +# Upgrading from Elasticsearch 1.x to 5.x - Live Coding Session + +[![elasticsearch 1.x to 1.5 upgrade](/assets/img/news/live-stream-1-elasticsearch-header-1024x538.jpg)](https://www.liveedu.tv/niemyjski/videos/xAYyE-exceptionless-weekly-demo-1-9-17) + +## New Weekly Coding Live Stream + +In the first episode our **all new** [weekly live streaming demo session](https://www.liveedu.tv/niemyjski/videos/xAYyE-exceptionless-weekly-demo-1-9-17), Blake talks about the recent push to migrate Exceptionless from Elasticsearch 1.x to Elasticsearch 5.x. + +One major part of this project has been updating [Foundatio.Repositories](https://github.com/FoundatioFx/Foundatio.Repositories) and [Foundatio.parsers](https://github.com/FoundatioFx/Foundatio.Parsers), both of which are parts of our [pluggable foundation block project for building distributed apps](https://github.com/FoundatioFx/Foundatio), to support Elasticsearch 5.x. + +Once that was complete, we then worked on reindex scripts for migrating data from Elasticsearch 1.x to 5.x using [Elasticsearch's external reindex](https://www.elastic.co/guide/en/elasticsearch/reference/5.1/docs-reindex.html). + +Check out the live stream, and tune in weekly for the next episode. + +Want Blake to demo something specific? Just leave a comment here and we'll make sure he gets it done! + + +### [WATCH NOW](https://www.liveedu.tv/niemyjski/videos/xAYyE-exceptionless-weekly-demo-1-9-17) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-01-24-2017-exceptionless-feature-functionality-and-enhancement-roadmap.md b/docs/news/2017/2017-01-24-2017-exceptionless-feature-functionality-and-enhancement-roadmap.md new file mode 100644 index 0000000000..8c874558fb --- /dev/null +++ b/docs/news/2017/2017-01-24-2017-exceptionless-feature-functionality-and-enhancement-roadmap.md @@ -0,0 +1,62 @@ +--- +title: "2017 Exceptionless Feature, Functionality, and Enhancement Roadmap" +date: 2017-01-24 +--- + +# 2017 Exceptionless Feature, Functionality, and Enhancement Roadmap + +![exceptionless feature roadmap for 2017](/assets/img/news/elasticsearch-2017-roadmap-header-1024x538.jpg) + +Can you believe it's almost February already! Us either. No rest for the whicked, though, as we sit down to get cranking on our list of Exceptionless changes for 2017. + +We have a a great list of features, functionality changes, and enhancements planned, and no doubt we'll work in a few other popular feature requests and, naturally, bug fixes along the way. + +Let's take a look at the primary roadmap, shall we? + +## Upgrading to Elasticsearch 5 + +Upgrading to Elasticsearch 5 has been in the works for some time now, with early testing starting in late 2016. As of January 23rd, we have [officially pushed the upgrade to production](https://github.com/exceptionless/Exceptionless/issues/145) and are looking for feedback, missed bugs, and performance improvement reports from anyone using it! + +### Primary Elasticsearch 5 Benefits + +* Elasticsearch 5 is the latest version of [ElasticSearch](https://www.elastic.co/products) and brings in massive improvements to event indexing speed, reduced memory sizes, and much more. +* The Elasticsearch libraries support .NET Core, bringing us one step closer to fulfilling a vision that includes cross-platform support. +* Our new implementation is built on a new, faster Microsoft Azure and SSD storage infrastructure. This will greatly increase the indexing and searching performance,  reducing dashboard latencies, among other things. +* With the power of [Foundatio.Parsers](https://github.com/FoundatioFx/Foundatio.Parsers) project, we have gained the ability to consume generic aggregations and pivot/report on data any way our users like it. +* This upgrade also makes it easier to self host through the use of containers. Our goal is to move the entire app to use containers, which will allow you to self host in seconds! +* We will now be doing daily indexes for more performance, fine grained backups, and the ability to more quickly change our indexes. + +## Future Exceptionless Notification Changes + +We're always working on notifications, we've got [several distinct changes we want to work on in 2017](https://github.com/exceptionless/Exceptionless/issues/177). Here are a few of the important ones: + +* We will continue working on rich, rule based notifications for email, services like Slack and HipChat, and more. +* Pausing notifications will soon be a thing! +* You'll also be able to set up notifications based on the rate of events, so you can know when issues are ramping up or getting out of hand. +* Lastly, you will be able to receive a periodic digest email based on activity. + +## Porting to .NET Core and Containers + +* We want to port the Exceptionless app to [.NET Core](https://www.microsoft.com/net/core) so we can run it anywhere (macOS, Linux or Windows). +* Running on .NET Core also brings massive performance improvements and lower overhead, which will have positive trickle down affects throughout the app. +* Once we support .NET Core, we can containerize the entire app, allowing us to scale more easily. +* These changes will make self hosting super simple. You'll basically be able to run "docker run -d exceptionless\`" and be done! + +## Custom Exceptionless Dashboards + +We know the dashboard is crucial for many things, and we want to make them more customizable to fit each user's individual cases. At the same time, we want to make sure we maximize business value. So, we plan on working on several [features and functional aspects of dashboards](https://github.com/exceptionless/Exceptionless/issues/229), namely: + +* Creating pre-define dashboards that are more granular, such as device usage, breakdown by exception type, etc. +* Allow users to create their own custom dashboards. + +## New Exceptionless Clients + +We really want to add new native clients to Exceptionless, and are including that as a major goal for 2017. Everything we are working on is moving in that direction, one way or the other, and we hope to make further announcements in this department soon! + +We are, of course, always accepting pull requests as well! + +## What Are We Missing? + +What have we forgotten? We know everything isn't included on this list, but if we have missed something big that you can't live without, please let us know! + +Otherwise, look for a new version announcement **very soon**, and get ready to upgrade and take advantage of several of these new upcoming changes. diff --git a/docs/news/2017/2017-02-01-setting-new-elasticsearch-cluster-reindexing-mappings-live-code-demo.md b/docs/news/2017/2017-02-01-setting-new-elasticsearch-cluster-reindexing-mappings-live-code-demo.md new file mode 100644 index 0000000000..e7c57bbe68 --- /dev/null +++ b/docs/news/2017/2017-02-01-setting-new-elasticsearch-cluster-reindexing-mappings-live-code-demo.md @@ -0,0 +1,27 @@ +--- +title: "Setting Up New Elasticsearch Cluster, Reindexing & Mappings - Live Code Demo" +--- + +# Setting Up New Elasticsearch Cluster, Reindexing & Mappings - Live Code Demo + +[![](/assets/img/news/170116-live-code-demo-1024x538.jpg)](https://www.liveedu.tv/niemyjski/videos/k4JO7-exceptionless-weekly-demo-1-16-17) + +## Getting Ready for Exceptionless 4.0! + + + +In this live code review, we go over some of the recent changes and processes to get ready for Exceptionless 4.0, which include implementing a new Elasticsearch cluster, reindexing into it using the Elastic Arm templates, and updating existing events mapping. + +The [Elastic Arm templates](https://github.com/elastic/azure-marketplace) automate the setup of an Elasticsearch with a few clicks, which is awesome. + +Then, we had to [update our existing events mapping](https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-put-mapping.html) to have a last updated field and is deleted flag so we can do [incremental reindex passes](https://www.elastic.co/guide/en/elasticsearch/reference/5.1/docs-reindex.html). + + +## [WATCH NOW](https://www.liveedu.tv/niemyjski/videos/k4JO7-exceptionless-weekly-demo-1-16-17) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-02-07-exceptionless-4-0.md b/docs/news/2017/2017-02-07-exceptionless-4-0.md new file mode 100644 index 0000000000..f9269b9627 --- /dev/null +++ b/docs/news/2017/2017-02-07-exceptionless-4-0.md @@ -0,0 +1,59 @@ +--- +title: "Exceptionless 4.0 is Here!" +--- + +# Exceptionless 4.0 is Here! + +![Exceptionless 4.0 Announcement](/assets/img/news/exceptionless-4.png)That's right folks, Exceptionless 4.0 is here and we've got the full low-down on all the improvements, upgrades, and enhancements in this week's blog article, along with how to upgrade instructions for self hosters. + +The primary focus of version 4.0 was to add support for Elasticsearch 5. By migrating from Elasticsearch 1.7 to 5, we removed growing technical debt and benefited greatly in the process. Here is an overview of the benefits gained by migrating to Elasticsearch 5 in 4.0.0. + +## Performance + +Since we first migrated to Elasticsearch 1.x from MongoDB, we've learned a lot of hard lessons. With 4.0 and the upgrade to Elasticsearch 5, we took all those lessons and applied them to the new release and infrastructure setup. Here are some performance improvements and notes that came out of those implementations. + +* We've moved from monthly indexes to daily indexes. This change means that when you are filtering by the last 24 hours or last week, you are greatly reducing the amount of work Elasticsearch has to do to return the requested data. + +* Because of this, the average use case will see between **25% and 80% improvement to indexing** throughput. This means that, with the same hardware, we can index the same documents much faster! + +* We moved from Groovy scripts to Painless scripts, which are **four times faster**. By moving to Painless scripts, we also greatly simplified the burden of having to modify configuration files to enable scripting! + +* Elasticsearch has added a lot of new data types since 1.7, and we are now taking advantage of them to **reduce memory, storage and query costs.** This means we can query the same data faster, using less memory doing it. We've also set up more sensible defaults to ensure we don't index very long strings. + +* We've also made several performance and reliability improvements to snapshots (backups). + +## Self Hosting improvements + +Our goal is to have everyone be able to setup and use Exceptionless in a matter of minutes. One of the areas that had hendered a lot of self hosters in the past was forgetting to update the elasticsearch.yml file, which is no longer an issue with the migration to Painless scripts. If you're a self hoster, check out the + +* The move to using Painless scripts as part of bulk updates and ingest pipelines reduced the burden of having to modify configuration files to enable scripting! Long gone are the times where you would have to reset your setup because you missed a configuration step. + +* We've also added various maintenance jobs that handle backups and restores automatically, so you don't have to worry about losing your data! + +* **Future upgrades should be seamless** as Elasticsearch now handles reindexing out of the box! Once you have migrated your data to Elasticsearch 5, we think future major upgrades will just be handled by the Exceptionless app itself! + +* You can now also use [Docker](https://hub.docker.com/_/elasticsearch) or [Azure arm templates](https://github.com/elastic/azure-marketplace) to quickly set up a cluster. We really like this direction and will continue moving down this path, hopefully getting to the point where you can click a single button and have an Exceptionless production instance running locally! + +## Dashboards + +With Exceptionless 4.0.0, we continued to focus on finishing up backend improvements to both our [repositories](https://github.com/FoundatioFx/Foundatio.Repositories) and [parsers](https://github.com/FoundatioFx/Foundatio.Parsers) that we made in the 3.5 releases. We feel that **all the pieces are finally in place to allow us to do custom dashboards in the near future**, something we talk about in our [2017 Roadmap blog post](/2017-exceptionless-feature-functionality-and-enhancement-roadmap/). + +[Foundatio.Parsers](https://github.com/FoundatioFx/Foundatio.Parsers) now gives us the ability to define and validate custom aggregations using Lucene-style syntax. For example, lets say I want a date histogram that shows the min, max and average event value. I'd just need to pass `date:(date min:value max:value avg:value)` to the following endpoint: [`/api/v2/events/count?aggregations=date:(date min:value max:value avg:value)`](https://api.exceptionless.io/docs/index.html#!/Event/Event_GetCountAsync) to return aggregations across a time series! + +## Upgrading to 4.0.0 + +The only users that need to worry about upgrading anything for this new release are self hosters. If you are self hosting Exceptionless, please review the [Self Hosting Documentation](/docs/self-hosting/), which contains information about upgrading your existing install. + +Also, please take a look at the [change log](https://github.com/exceptionless/Exceptionless/compare/v3.5.1...v4.0.0) for a full list of the changes. + +## Always Improving + +We’re always striving to improve the efficiency of Exceptionless and all of our projects. If you see any room for improvement or have any comments when using anything from us, please send us an in-app message, [submit a GitHub issue](https://github.com/exceptionless/Exceptionless/issues) or [contact us](/) on the website. + +## And Lastly, Thanks! + +We'd like to say thank you to the community, project sponsors, and the Elasticsearch team for helping us ship 4.0.0. You guys rock! + +### Want to know what's coming next? + +[Check out the 2017 Roadmap](/2017-exceptionless-feature-functionality-and-enhancement-roadmap/) and let us know your thoughts on our planned development. diff --git a/docs/news/2017/2017-02-15-exceptionless-4-0-enhancement-overview-live-code-demo.md b/docs/news/2017/2017-02-15-exceptionless-4-0-enhancement-overview-live-code-demo.md new file mode 100644 index 0000000000..1e5914da13 --- /dev/null +++ b/docs/news/2017/2017-02-15-exceptionless-4-0-enhancement-overview-live-code-demo.md @@ -0,0 +1,37 @@ +--- +title: "Exceptionless 4.0 Enhancement Overview - Live Code Demo" +--- + +# Exceptionless 4.0 Enhancement Overview - Live Code Demo + +[![Exceptionless 4 Enhancement Overview](/assets/img/news/exceptionless-4-enhancement-live-demo-1024x538.jpg)](https://www.liveedu.tv/niemyjski/videos/9WmaQ-exceptionless-weekly-demo-1-23-17) + +We recently [announced Exceptionless 4.0](/exceptionless-4-0/), but we also recorded a [short demo of some of the enhancements](https://www.liveedu.tv/niemyjski/videos/9WmaQ-exceptionless-weekly-demo-1-23-17) and talked through them. + +**In this live code/feature/functionality review video, Blake talks about:** + +* Deploying Elasticsearch 5.x to production with completely new Azure resources. + +* Fixing bugs and doing extensive testing on the new Elasticsearch 5 and Azure implementation. + +* Massive performance boosts due to daily indexes, SSD-backed storage, and bug fixes. These boosts should result in near0instant page loads and huge improvements to session dashboards. + +* Automating cluster setup using Azure CLI and Elasticsearch ARM Templates. + +* A new custom SSH script that allows us to quickly and securely connect to machines, as well as forward ports for things like Kibana. + +* New Azure resources and dashboards. + +* Setting up WebJobs to run as cron jobs. + +* We also found [PM2](http://pm2.keymetrics.io/), a new way to manage Node.js services for our [StatsD](https://github.com/etsy/statsd) service. + + +## [WATCH VIDEO](https://www.liveedu.tv/niemyjski/videos/9WmaQ-exceptionless-weekly-demo-1-23-17) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-02-17-live-code-demo-new-query-validation-di-issues-error-handling.md b/docs/news/2017/2017-02-17-live-code-demo-new-query-validation-di-issues-error-handling.md new file mode 100644 index 0000000000..4a0460b03d --- /dev/null +++ b/docs/news/2017/2017-02-17-live-code-demo-new-query-validation-di-issues-error-handling.md @@ -0,0 +1,29 @@ +--- +title: "Live Code Demo - New Query Validation, DI Issues, and Error Handling" +--- + +# Live Code Demo - New Query Validation, DI Issues, and Error Handling + +[![](/assets/img/news/query-validation-di-issues-error-handling-1024x538.jpg)](https://www.liveedu.tv/niemyjski/videos/4DDYJ-exceptionless-weekly-demo-2-1-17) + +This week's live code demo comes to you during a week of final testing and tweaks prior to our [launch of Exceptionless 4.0](/exceptionless-4-0/). + +Blake dives into and shows you the code for several important improvements and fixes, which we've listed below. + +* We've added a much improved Query Validator to the repositories and Exceptionless. + +* Some DI issues with running jobs under the debugger have also been fixed. + +* Then, we added error handling around heartbeat submission end points. + +* And finally, an issue where the app would blow up when trying to save invalid reference ids has been fixed. + + +## [Watch Video](https://www.liveedu.tv/niemyjski/videos/4DDYJ-exceptionless-weekly-demo-2-1-17) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-02-22-live-code-demo-review-of-exceptionless-4-0-launch.md b/docs/news/2017/2017-02-22-live-code-demo-review-of-exceptionless-4-0-launch.md new file mode 100644 index 0000000000..100d0c265c --- /dev/null +++ b/docs/news/2017/2017-02-22-live-code-demo-review-of-exceptionless-4-0-launch.md @@ -0,0 +1,28 @@ +--- +title: "Live Code Demo & Review of Exceptionless 4.0 Launch" +date: 2017-02-22 +--- + +# Live Code Demo & Review of Exceptionless 4.0 Launch + +[![](/assets/img/news/170221-live-code-review-header-1024x538.jpg)](https://www.liveedu.tv/niemyjski/videos/bG9BO-exceptionless-weekly-demo-2-6-17-3) + +During the [Exceptionless 4.0 Release](https://github.com/exceptionless/Exceptionless/releases/tag/v4.0.0), we covered a lot of enhancements and changes. In this week's Live Code Demo, Blake reviews the 4.0 release notes and talks through other tweaks and post-launch cleanup. + +## In this Live Code Demo Episode... + +* Exceptionless 4.0 has been released for a few weeks now, with ElasticSearch 5 running in production for even longer. Let's take another look at the release notes and talk through some notable topics. +* We look at the self hosting & upgrading documentation, which has been updated for Exceptionless 4.0. +* In the process of the latest release, we upgraded Foundatio to new csproject format, logging many bugs on the .NET CLI along the way. Blake reviews this in the above video as well. +* In the end, we obviously had to merge in pull requests and clean up issues, which he also reviews. +* Lastly, we cleaned up the new Azure infrastructure! + + +## [WATCH NOW](https://www.liveedu.tv/niemyjski/videos/bG9BO-exceptionless-weekly-demo-2-6-17-3) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-02-28-duplicate-event-total-fix-setting-min-log-levels-foundatio-updates-live-code-demo.md b/docs/news/2017/2017-02-28-duplicate-event-total-fix-setting-min-log-levels-foundatio-updates-live-code-demo.md new file mode 100644 index 0000000000..1c465a8c83 --- /dev/null +++ b/docs/news/2017/2017-02-28-duplicate-event-total-fix-setting-min-log-levels-foundatio-updates-live-code-demo.md @@ -0,0 +1,30 @@ +--- +title: "Duplicate Event Total Fix, Setting Min Log Levels, Foundatio Updates, and more - Live Code Demo" +--- + +# Duplicate Event Total Fix, Setting Min Log Levels, Foundatio Updates, and more - Live Code Demo + +[![exceptionless duplicate event totals, min log levels, foundatio](/assets/img/news/170228-header-1024x538.jpg)](https://www.liveedu.tv/niemyjski/2qyKy-exceptionless-weekly-demo-2-20-17/bGgd4-exceptionless-weekly-demo-2-13-17/) + +Blake's back at it this week, onward to something new after the Exceptionless 4.0 launch. Today we talk deduplicate event totals, setting minimum log levels, updates to Foundatio, and tracking down an event processor job issue! + +* We had previously reverted to earlier commits that showed the deduplicated event total separately from the event total, but since we are running on new indexes now, we are able to reliably **include the deduplicated total as the total number of events**. [_GitHub Issue #270_](https://github.com/exceptionless/Exceptionless/issues/270) +* You can now set the min log level in configuration using: + + ```cs + ExceptionlessClient.Default.SetDefaultMinLogLevel(LogLevel.Warn); + ``` + + _[Learn more](https://github.com/exceptionless/Exceptionless.Net/commit/bc29626a8c70fb23cb22983f8e55818b8f889cb2)_ +* The [Foundatio](https://github.com/FoundatioFx/Foundatio) updates we made include performance and handling improvements to the message bus. [Learn more about these improvements on GitHub](https://github.com/FoundatioFx/Foundatio/commit/c66ce6691614fca4ef423a34505a51ea0f2f354f). We also added IHybridCacheClient interface marker, giving you granular control over dependency injection. Now, you can inject either a cache client or a hybrid cache client much easier. _[Learn more.](https://github.com/FoundatioFx/Foundatio/commit/c0e30a08a80c4a29a47c83d8dda32316e4a9ed04)_ +* Lastly for this week, we are working on tracking down the root cause of an issue with the event processor job that is causing it to stop processing events. More on that soon! + + +## [WATCH NOW](https://www.liveedu.tv/niemyjski/2qyKy-exceptionless-weekly-demo-2-20-17/bGgd4-exceptionless-weekly-demo-2-13-17/) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-03-08-email-logging-ui-improvements-foundatio-updates-live-code-demo.md b/docs/news/2017/2017-03-08-email-logging-ui-improvements-foundatio-updates-live-code-demo.md new file mode 100644 index 0000000000..dba94e784c --- /dev/null +++ b/docs/news/2017/2017-03-08-email-logging-ui-improvements-foundatio-updates-live-code-demo.md @@ -0,0 +1,53 @@ +--- +title: "Email Logging, UI Improvements, Foundatio Updates, and more - Live Code Demo" +date: 2017-03-08 +--- + +# Email Logging, UI Improvements, Foundatio Updates, and more - Live Code Demo + +[![Exceptionless live code demo 2/20/17](/assets/img/news/live-code-demo-170308-1024x538.jpg)](https://www.liveedu.tv/niemyjski/2qyKy-exceptionless-weekly-demo-2-20-17/xAq0E-exceptionless-weekly-demo-2-20-17/) + +Watch out this week, Blake's on fire! We're talking email loggings, UI tweaks, Exceptionless.NET updates and fixes, Foundatio updates, and Foundatio.Repositories updates. Lot's going on, let's check it out in [this week's Live Code Demo](https://www.liveedu.tv/niemyjski/2qyKy-exceptionless-weekly-demo-2-20-17/xAq0E-exceptionless-weekly-demo-2-20-17/). + +## Exceptionless Updates + +This week, we made improvements to email logging and documentation when running in dev mode. Find out more by watching the live coding video or visiting the [Exceptionless repo on GitHub](https://github.com/exceptionless/Exceptionless). + +## Exceptionless + +We were only showing the exception tab if there was an event type of error, previously, but now we are always showing the exception tab if an exception is part of an event. + +[View Repo](https://github.com/exceptionless/Exceptionless) + +## Exceptionless.NET + +* We added SetException EventBuilder overload so you can submit any event type with an exception object. +* Then, we fixed an issue where the client could blow up on startup while trying to wire up to trace listeners. +* Finally, we also fixed an issue where signed web packages http handlers weren't being registered with the right namespace. + +[View Repo](https://github.com/exceptionless/Exceptionless.Net) + +## Foundatio + +* Attempted to track down issues where the redis queues would stop processing. +* Worked with Microsoft to get our unit tests discoverable on the new csproject format. +* Added new [Foundatio.Jobs commands package](https://github.com/FoundatioFx/Foundatio/commit/50dddaa52d3cc929a62d42b40f8d767e4f916545) that allows you to quickly discover and get command line help on your jobs. + +[View Repo](https://github.com/FoundatioFx/Foundatio) + +## Foundatio.Repositories + +* Fixed various issues with running data migration scripts for the first time. +* Fixed an issues with GetByIds where falling back to search wouldn't take into account multiple pages of results. + +[View Repo](https://github.com/FoundatioFx/Foundatio.Repositories) + + +## [WATCH NOW](https://www.liveedu.tv/niemyjski/2qyKy-exceptionless-weekly-demo-2-20-17/xAq0E-exceptionless-weekly-demo-2-20-17/) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-04-04-bug-fixes-archival-format-foundatio-updates.md b/docs/news/2017/2017-04-04-bug-fixes-archival-format-foundatio-updates.md new file mode 100644 index 0000000000..99036d5885 --- /dev/null +++ b/docs/news/2017/2017-04-04-bug-fixes-archival-format-foundatio-updates.md @@ -0,0 +1,33 @@ +--- +title: "Weekly Update - Bug Fixes, Archival Format Changes, and Foundatio Updates" +--- + +# Weekly Update - Bug Fixes, Archival Format Changes, and Foundatio Updates + +This week we've got some cool stuff in our weekly update! Along with the below, you can now follow along over on the new [YouTube Exceptionless Weekly Updates playlist](https://www.youtube.com/playlist?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V), so make sure to check it out and [subscribe](https://www.youtube.com/user/exceptionless?sub_confirmation=1)! + +### Let's Get Down To Business + +#### Updates to Exceptionless + +* We fixed an issue where you couldn't run Exceptionless on AWS because you couldn't install plugins on their ElasticSearch service. _[#280](https://github.com/exceptionless/Exceptionless/issues/280)_ + +* The archival format has also been change from `projected\year\month\day` to `year\month\day\hour\projectid`. This allows you to quickly restore or download all events in a time period without enumerating all backed up projects. + +#### Foundatio Updates + +* In Foundatio, we fixed an issue where Redis Queues could deadlock, causing them to stop processing. This was being caused from topic messages locking the calling thread. + +#### Updates to Foundatio Repositories + +* GetById and GetByIds now take an Id Type which allows us to specify routing information and much more. We have an implicit conversion that handles existing signatures. + + +## [WATCH NOW](https://youtu.be/osuMyj6eW98?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + + + + + [Watch more Live Code Demos](/category/live-coding/) + + diff --git a/docs/news/2017/2017-04-04-march-update-rollup-new-releases-updates-bug-fixes.md b/docs/news/2017/2017-04-04-march-update-rollup-new-releases-updates-bug-fixes.md new file mode 100644 index 0000000000..ebee0843c0 --- /dev/null +++ b/docs/news/2017/2017-04-04-march-update-rollup-new-releases-updates-bug-fixes.md @@ -0,0 +1,73 @@ +--- +title: "March Update Rollup - New Releases, Updates, Bug fixes, and more!" +--- + +# March Update Rollup - New Releases, Updates, Bug fixes, and more! + +March was a productive month! We got tons done, and we're here to share everything with you so you're up to date and can hold us accountable if you notice any bugs in the changes. + +Let's get to it! + +## Week of 3/6/2017 + +### Search query fix, Implemented AsyncAutoResetEvent in Foundatio, Upgraded project format + +* Fixed an issue in Exceptionless where any search query starting with data. was being modified. +* In Foundatio, the main repository that will contain the default deployment and EditorConfig settings for all of our projects, an effort was made to use less locking in queues and the CacheLockProvider by using AsyncAutoResetEvent, a lighter weight async primitive. +* We also upgraded to the new VS2017 project format in our Foundatio repositories. + +## Week of 3/13/2017 + +### Attended Elastic{ON} 17, Released Foundatio 5.0, PowerShell script update, RabbitMQ update, IMessageBus breakage, Marker interface addition + +* Blake attended [Elastic{ON}](https://www.elastic.co/elasticon/conf/2017/sf) and talked to product teams about issues we've been running into, as well as the future of Elasticsearch. +* **Foundatio** + * [Released Version 5.0 of Foundatio](https://github.com/FoundatioFx/Foundatio/releases/tag/v5.0.0) + * We also modified an existing PowerShell script that updates existing projects to the VS2017 project format. + * And, of course, we added some more documentation! +* **Foundatio Repositories** + * Updated the RabbitMQ queues to use the delayed message exchange + * Broke the IMessageBus.Subscribe API surface by changing the signature to SubscribeAsync + * Added a marker interface when patching documents + +[Watch the 3/13/2017 update video](https://youtu.be/G-faYRV7-qI?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + +## Week of 3/20/2017 + +### Released Exceptionless 4.0.1, Performance improvements, Bug fixes, Exceptionless.NET udpates, Foundatio Amazon SQS queues and CloudWatch metrics pull requests, Foundatio reindexing improvements + +* **Exceptionless** + * [Released Exceptionless version 4.0.1](https://github.com/exceptionless/Exceptionless/releases/tag/v4.0.1) + * We upgraded to the latest Foundatio and Repositories builds, which brings in some performance improvements and bug fixes. + * Visual Studio 2017 is now a requirement to debug any Exceptionless project. + * Various bug fixes +* **Exceptionless.Net** + * Upgraded to VS2017 project format and fixed an asp.net core bug. + * All nightly builds for all of our NuGet packages can now be found on [myget](https://www.myget.org/gallery/exceptionless). +* **Foundatio** + * New pull request for Amazon SQS queues and CloudWatch metrics + * We also had some more documentation contributions! +* **Foundatio Repositories** + * We made some improvements around reindexing. + * Then we also fixed a few various bugs + +[Watch the 3/20/2017 update video](https://youtu.be/B9gVzFmBzyY?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + +## Week of 3/27/2017 + +### Event metadata archiving, Amazon SQS queus and CloudWatch metrics pull requests, Blake speaks at code camp + +* This week we added a setting in Exceptionless for [disabling the archiving of event metadata](https://github.com/exceptionless/Exceptionless/pull/287) +* For Foundatio, a new pull request was made for Amazon SQS queues and CloudWatch metrics. We've done a lot of work to queues and the message buses to make the constructors have options classes that get passed in. We've also done a lot of work to the Azure implementations to try and optimize them and fix bugs. +* Lastly, Blake spoke at [Northeast Wisconsin Code Camp](http://newcodecamp.com/) over the weekend on exception driven development. [The slides can be found here.](https://github.com/exceptionless/MediaKit/tree/master/presentations/exceptionless) + +[Watch the 3/27/2017 update video](https://youtu.be/x9JB3BgYELQ?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + + +## [WATCH NOW](https://youtu.be/njr7ang0BQg?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + + + + + [Watch more Live Code Demos](/category/live-coding/) + diff --git a/docs/news/2017/2017-04-10-azure-functions-email-client-foundatio-4317-weekly-update.md b/docs/news/2017/2017-04-10-azure-functions-email-client-foundatio-4317-weekly-update.md new file mode 100644 index 0000000000..f498329cac --- /dev/null +++ b/docs/news/2017/2017-04-10-azure-functions-email-client-foundatio-4317-weekly-update.md @@ -0,0 +1,20 @@ +--- +title: "Azure Functions, Email Client, Foundatio - 4/3/17 Weekly Update" +--- + +# Azure Functions, Email Client, Foundatio - 4/3/17 Weekly Update + +Q2 2017 is here already, whether we are ready for it or not! [In March, we released several new updates to Exceptionless and Foundatio](/news/2017/2017-04-04-march-update-rollup-new-releases-updates-bug-fixes), so our first update in April isn't crazy, but here we go! + +## Exceptionless Updates + +* We took some time to look into supporting Azure Functions. [learn more](https://github.com/exceptionless/Exceptionless/pull/293) +* And we received a few pull requests, one of which was for [updating our email client to support different protocols](https://github.com/exceptionless/Exceptionless/pull/291). + +## Foundatio Updates + +* This past week, we worked on some bug fixes related to queue processing in Foundatio. + + +## [WATCH NOW](https://youtu.be/ShnXh4Mgx4U?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + diff --git a/docs/news/2017/2017-04-21-exceptionless-net-client-and-core-releases-bugs-usability-performance-self-hosting.md b/docs/news/2017/2017-04-21-exceptionless-net-client-and-core-releases-bugs-usability-performance-self-hosting.md new file mode 100644 index 0000000000..126fd39850 --- /dev/null +++ b/docs/news/2017/2017-04-21-exceptionless-net-client-and-core-releases-bugs-usability-performance-self-hosting.md @@ -0,0 +1,70 @@ +--- +title: "Exceptionless.NET client, core, UI, releases - Bugs, Usability, Performance, Self Hosting" +date: 2017-04-21 +--- + +# Exceptionless.NET client, core, UI, releases - Bugs, Usability, Performance, Self Hosting + +![](/assets/img/news/new-releases-header3-1024x538.jpg) + +This past week we released Exceptionless 4.0.2 and Exceptionless.NET 4.0.3, consisting of maintenance updates that fixed several usability issues for self hosters, various performance, issues, bug fixes, and some general improvements. + +Below is a highlight of the release notes, and don't forget to let us know how we're doing or what can improve by following the relevant links to GitHub and posting an "issue." + +Lastly, thanks to all of our contributors for helping us solve problems, add functionality, and improve Exceptionless! + +## Exceptionless 4.0.2 Release Notes + +* Both [@caesay](https://github.com/caesay) and [@edwardmeng](https://github.com/edwardmeng) submitted pull requests and helped us solve an issue with sending emails (issue [#290](https://github.com/exceptionless/Exceptionless/issues/290)). [MailKit](https://github.com/jstedfast/MailKit), a "cross-platform mail client library," has now been integrated, adding "fully featured and RFC-compliant SMTP, POP3, and IMAP client implementations" into Exceptionless. + * There were also a few issues with email when hosting in different environments, such as Azure Functions. In this case, all email settings must be stored in settings and not web.config. So, we moved the MailKit implementation to the insulation project and cleaned up the main mailer class, among a few other tweaks, to further improve email sending in the app. Thanks again caesay and edwardmeng! + * **If you are self hosting**, please update the email settings in `appSettings` +* Support for Azure Storage Queues has been added to the app. +* A bug that could cause an exception and make the stack work queue be abandoned when a stack of events was deleted has been fixed. +* The GeoIP database was being downloaded each time the app was restarted. That has also been fixed. +* Incorrect emails were being generated in some self hosted and dev environments because the BASE_URL didn't contain the proper hashbang (#!). Fixed that issue in this release, as well. +* [View the full changelog.](https://github.com/exceptionless/Exceptionless/compare/v4.0.1...v4.0.2) + +### Upgrading to Exceptionless 4.0.2 + +You should only worry about upgrading if you are a self-hoster. If this is the case, please see the [Exceptionless self hosting documentation](/docs/self-hosting/). **Note that changes to the Elasticsearch configuration were made in this release**, so make sure to review the documentation for more information. + +## Exceptionless.NET 4.0.3 Release Notes + +### New Features + +* log4net .NET Core support has been added. +* 404 reporting support in ASP.NET Core has been added. +* You can now set the min log level in configuration by calling `SetDefaultMinLogLevel`, allowing you to set a temporary min log level that is used until the server settings are retrieved. +* Client IP support for X-Forwarded-For has been added (thanks [@barankaynak](https://github.com/barankaynak)!), which enables us to properly identify individual users and also helps when using proxy servers. +* You can now more easily capture the HttpActionContext by adding `SetHttpActionContext` extension methods to web clients, allowing request and user info to be captured by default when manually submitting events. +* We added SetException overload so you can now submit any event type with an exception object. So, for instance, you can now submit a log message through with an exception object and the exception tab will show. + +### Bug Fixes + +* Fixed an issue where the ASP.NET Core 1.1 runtime was sometimes preventing clients from reporting any data. +* Fixed an issue where exceptions that converted to 404's were not running the event exclusion logic. +* Fixed an issue where the duplicate checker plugin could DOS itself if you had client logging enabled (disabled by default - only meant for diagnostic logging). +* Fixed an issue where the NLog logger wasn't setting event type. +* Fixed an issue with package configuration of signed web packages. +* Fixed an issue where adding our trace listener could blow up due to other invalid configured trace listeners. +* Upgraded to the latest version of BenchMarkDotNet and ensure benchmarks run (Contrib [@adamsitnik](https://github.com/adamsitnik)) + +### Upgrading + +Just update your NuGet packages. For more info, check out the [upgrade guide](/docs/clients/dotnet/upgrading). + +[View the full changelog.](https://github.com/exceptionless/Exceptionless.Net/compare/v4.0.2...v4.0.3) + +## Exceptionless.UI 2.6.2 Release Notes + +* Previously, long, single-line content could cause the user interface to go crazy while updating event lists. This has been fixed (thanks @caesay!). +* Also, tags now wrap to the next line, instead of overflowing the content area. @caesay strikes again! +* [View the full changelog.](https://github.com/exceptionless/Exceptionless.UI/compare/v2.6.1...v2.6.2) + +## Feedback Requested + +We **want** to know what you think about Exceptionless - what you think we should add, fix, streamline, improve, etc. Please let us know! + +* [.NET Client Feedback](https://github.com/exceptionless/Exceptionless.Net/issues/new) +* [JavaScript Client Feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues/new) +* [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) diff --git a/docs/news/2017/2017-04-25-weekly-update-review-new-releases.md b/docs/news/2017/2017-04-25-weekly-update-review-new-releases.md new file mode 100644 index 0000000000..84e29e6a16 --- /dev/null +++ b/docs/news/2017/2017-04-25-weekly-update-review-new-releases.md @@ -0,0 +1,44 @@ +--- +title: "Weekly Update - Review of New Releases and More" +date: 2017-04-25 +--- + +# Weekly Update - Review of New Releases and More + +Last week we [announced release notes](/news/2017/2017-04-21-exceptionless-net-client-and-core-releases-bugs-usability-performance-self-hosting) for Exceptionless 4.0.2, Exceptionless.NET 4.0.3, and Exceptionless.UI 2.6.2. In our weekly update this week, we review some of those changes/updates, Foundatio changes, and more. Check it out! + +## Exceptionless Live Stream Update 4/13/17 + +### Exceptionless Core Updates + +In Exceptionless Core, we added support for [MailKit](https://github.com/jstedfast/MailKit), pipeline action and plugin level metrics, and the ability to dynamically shut down functionality via the configuration. We also made pipeline performance improvements. There are more performance improvements to make, + +### Foundatio Updates + +For [Foundatio](https://github.com/FoundatioFx/Foundatio), we updated the Azure storage copy implementation to copy server side, fixed an issue where FolderFileStorage wasn't behaving properly when renaming files that exist, and fixed a Redis cache client issue where deleting cache items by wild card was erroring out if there were no matching keys. +- Updated the azure storage copy implementation to copy server side. + +### Changes to Exceptionless.NET + +For the .NET client, we merged in changes to csproj and released version 4.0.3. Make sure to [check out the release notes](/news/2017/2017-04-21-exceptionless-net-client-and-core-releases-bugs-usability-performance-self-hosting) and upgrade! + +### Updates to Exceptionless.UI + +In Exceptionless.UI, lists of tags now wrap to the next line, and we fixed an issue where long user names would cause the UI to go crazy. + +### Updates to Foundatio.Repositories + +Here, we fixed a caching issue where you couldn't set the key without enabling cache, and we simplified index creation and stopped using a lock. + + +## [WATCH NOW](https://youtu.be/rwl4FfyNCtc?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + + + + diff --git a/docs/news/2017/2017-05-02-exceptionless-weekly-update-4172017.md b/docs/news/2017/2017-05-02-exceptionless-weekly-update-4172017.md new file mode 100644 index 0000000000..dbc4ac9186 --- /dev/null +++ b/docs/news/2017/2017-05-02-exceptionless-weekly-update-4172017.md @@ -0,0 +1,36 @@ +--- +title: "Exceptionless Weekly Update 4/17/2017" +date: 2017-05-02 +--- + +# Exceptionless Weekly Update 4/17/2017 + +Nothing too crazy going on in this week's update. A few tweaks to Exceptionless, Exceptionless.NET, and Exceptionless.JavaScript. Check out the details below, and don't forget to let us know how we're doing! + +## Weekly Code & Development Update - 4/17/2017 + +### Exceptionless Core Updates + +This week we released the Exceptionless 4.0.2 minor release with a few fixes and tweaks. Check out the [Exceptionless 4.0.2 release details](https://github.com/exceptionless/Exceptionless/releases/tag/v4.0.2) over on GitHub. Self hosters are the only ones that will need to worry about upgrading. + +We also made some good strides in reducing the amount of IO work the event post queues have to do. Woohoo! + +Lastly, for Exceptionless core, we merged in MailKit and continued improving email notifications. + +## Exceptionless.NET Client Update + +The only really notable thing we did for the .NET client is fix the ProcessQueue method, making sure it blocks until the queue has been processed. + +## Exceptionless.JavaScript Client Update + +For our JavaScript client, we want to work on supporting universal apps, but first we have to upgrade to the latest version of TypeScript, so we did some work this week toward that. + + +## [WATCH NOW](https://youtu.be/NH1sDXUnsBI?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + diff --git a/docs/news/2017/2017-05-10-weekly-update-42417-blake-speaking-north-dallas-net.md b/docs/news/2017/2017-05-10-weekly-update-42417-blake-speaking-north-dallas-net.md new file mode 100644 index 0000000000..7f5813762c --- /dev/null +++ b/docs/news/2017/2017-05-10-weekly-update-42417-blake-speaking-north-dallas-net.md @@ -0,0 +1,28 @@ +--- +title: "Weekly Update for 4/24/17 - Blake Speaking @ North Dallas .NET and more!" +date: 2017-05-10 +--- + +# Weekly Update for 4/24/17 - Blake Speaking @ North Dallas .NET and more! + +In this week'd update, Blake does a little traveling and speaking, and both Exceptionless and Foundatio.Repositories get an update! + +## Blake Speaks @ North Dallas .NET + +On May 3, Blake spoke at the [North Dallas .NET User Group](http://northdallas.net/) meetup in Plano. The topic was Exception Driven Development, and of course he killed it! Naturally, the Exceptionless love was shared to all. + +## Exceptionless & Foundatio.Repositories Updates + +For Exceptionless, we worked on upgrading the email templates to use Zurb for emails and handlebars. We also fixed an issue where you could only log in 15 times in a 15 minute time period. + +For Foundatio.Repositories, [query if (FieldEqualsIf) support](https://github.com/FoundatioFx/Foundatio.Repositories/commit/86c1539a9fdb12880db9a4fba1dccdc27055ccea) has been added. + + +## [WATCH NOW](https://youtu.be/NnSylKATHo4) + + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + diff --git a/docs/news/2017/2017-05-16-email-improvements-foundatio-updates-512017.md b/docs/news/2017/2017-05-16-email-improvements-foundatio-updates-512017.md new file mode 100644 index 0000000000..6e4b1aad52 --- /dev/null +++ b/docs/news/2017/2017-05-16-email-improvements-foundatio-updates-512017.md @@ -0,0 +1,30 @@ +--- +title: "Daily Summary Email Improvements, Foundatio Updates, and more - Weekly Update 5/1/2017" +date: 2017-05-16 +--- + +# Daily Summary Email Improvements, Foundatio Updates, and more - Weekly Update 5/1/2017 + +In the 5/1/17 weekly update, Blake talks email notification improvements, bug fixes, and Foundatio.Repositories and Foundatio.Parsers updates. Check out the video above or read the details below. + +## Updates to Exceptionless + +In the past few weeks, we have made massive improvements to the daily summary emails, and added support for json-ld. You can keep up with continued email improvements over on [issue 177 on GitHub](https://github.com/exceptionless/Exceptionless/issues/177). Let us know what you think there! + +We also fixed a bug with the Redis cache client improperly setting batch cached keys. + +## Foundatio.Repositories & Foundatio.Parsers Updates + +We updated Foundatio.Repositories so that it no longer ignores the version property. + +For Foundatio.Parsers, we merged code and server mapping properties. + + +## [WATCH NOW](https://youtu.be/-Uyf2a9oiGw?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + diff --git a/docs/news/2017/2017-05-16-project-level-usage-ui-foundatio.md b/docs/news/2017/2017-05-16-project-level-usage-ui-foundatio.md new file mode 100644 index 0000000000..196c522cb7 --- /dev/null +++ b/docs/news/2017/2017-05-16-project-level-usage-ui-foundatio.md @@ -0,0 +1,37 @@ +--- +title: "Collect Project Level Usage Stats, UI Updates, Foundatio Updates - Weekly Video 5/8/2017" +date: 2017-05-16 +--- + +# Collect Project Level Usage Stats, UI Updates, Foundatio Updates - Weekly Video 5/8/2017 + +We've snuck in lots of updates for this past week! New features have been added, such as collecting project-level usage statistics, the ability to add notes to API keys, and much more. Oh, and we're no longer throttling free plans! That's for Exceptionless core, but we've also made updates  to the Exceptionless UI and Foundatio core, Foundatio.Repositories, and Foundatio.Parsers. Check everything out, below. + +## Exceptionless Changes + +* We added the ability to collect project-level usage statistics. This allows us to view usage, show total blocked in emails, and more. It would also allow us to tweak rate limiting on a per-project basis. +* You can now add notes to API keys in the app. +* We also stopped throttling free plans. +* And, finally, we introduced variou mail templates into the mix. + +## Exceptionless.UI Updates + +* On the manage project page, we are now showing project usage statistics. +* On the sessions dashboard, we have added the ability to see active users. +* On the stack and session dashboards, we are now always showing hidden or fixed events. +* When you select a usage time range, you will be redirect to the organization or project dashboard. + +## Updates to Foundatio, Foundatio.Repositories, and Foundatio.Parsers + +* In Foundatio core, we merged in the CloudWatch Metric clients and SQS changes. We also moved each client into its own repo. +* For Foundatio.Repositories and Foundatio.Parsers, we created the final 1.x release and merged in the Elasticsearch 5 branches. + + +## [WATCH NOW](https://youtu.be/Ca4EOBO1EGI?list=PLGHP7IVwFs_81fZTMgF7Dm5e0Ax4YvW_V) + + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + diff --git a/docs/news/2017/2017-05-30-email-notification-improvements-walkthrough-and-details.md b/docs/news/2017/2017-05-30-email-notification-improvements-walkthrough-and-details.md new file mode 100644 index 0000000000..002ba992fe --- /dev/null +++ b/docs/news/2017/2017-05-30-email-notification-improvements-walkthrough-and-details.md @@ -0,0 +1,34 @@ +--- +title: "Email Notification Improvements - Walkthrough and Details" +date: 2017-05-30 +--- + +# Email Notification Improvements - Walkthrough and Details + +![exceptionless email notifications](/assets/img/news/email-improvements-header-1024x538.jpg) + +Recently, we made several improvements to our email notifications, adding additional details, improving rendering, and more. Blake has mentioned it in a few of his [weekly update videos](/category/weekly-updates/), but today we wanted to walk you through it and add a few more details, with examples. Check it out! + +## Exceptionless Email Notification Implementation + +We decided to use [Zurb's Foundation for Emails](https://github.com/zurb/foundation-emails) to help us create emails that look great on all email clients. The reason we went with Zurb is because it has clean markup that translates to good old (ugly) HTML that just works. It also works great with [Handlebars.Net](https://github.com/rexm/Handlebars.Net) which we use to render the email content. + +An example of one of our event notification emails can be found [here](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.EmailTemplates/src/pages/event-notice.html). + +Then, we run a [Node.js build task](https://github.com/exceptionless/Exceptionless/tree/master/src/Exceptionless.EmailTemplates#build-commands) to transform the templates into some pretty [crazy html markup](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Mail/Templates/event-notice.html) that works everywhere. The markup at that link contains the Handlebars.Net syntax. + +These templates are stored as embedded resources so we can use them from any environment and render them out with ease! Here is a [code example](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.Core/Mail/Mailer.cs#L260-L277) of how we perform that task. + +We added [JSON-LD](https://json-ld.org/) support, to the emails to give us rich contextual actions, by starting with this [Google Developer tutorial](https://developers.google.com/gmail/markup/getting-started) and ended up with [the below implementation](https://github.com/exceptionless/Exceptionless/blob/master/src/Exceptionless.EmailTemplates/src/pages/event-notice.html#L75-L94). _It's worth noting that we had to go through their verification process for the actions to be enabled._ + +```html + +``` + +We tested the emails in Outlook for Windows and Mac, Paper Cut, Gmail on Safari, and Apple Mail. Then, we used [Litmus](https://litmus.com) to test a wide range of clients before publishing and pushing everything live. + +## Questions? Comments? + +We hope our build out here can help other developers, and we would love to hear your feedback, questions, or comments either here on the blog or over on [GitHub](https://github.com/exceptionless/Exceptionless/issues)! + +Code on. \ No newline at end of file diff --git a/docs/news/2017/2017-06-05-exceptionless-slack-integration.md b/docs/news/2017/2017-06-05-exceptionless-slack-integration.md new file mode 100644 index 0000000000..46c5378bbe --- /dev/null +++ b/docs/news/2017/2017-06-05-exceptionless-slack-integration.md @@ -0,0 +1,44 @@ +--- +title: "Exceptionless Slack Integration, Further Improved Notifications" +date: 2017-06-05 +--- + +# Exceptionless Slack Integration, Further Improved Notifications + +As you guys know, we've been working on [notification improvements](/email-notification-improvements-walkthrough-and-details/) lately. This latest video update by Blake is no different and involves [Slack](https://slack.com/) integration! + +If you're not familiar with Slack, definitely check it out. It's a great app for communicating with your team, and much more. For Exceptionless, it's been something we've wanted to integrate closely with for a while now, because email can be very tedious and overwhelming. With Slack integration, you can set up a specific channel for your Exceptionless notifications to go to, and have an organized eye on your events. + +Watch the video above for an explanation of the integration, and see below on how to set it up for yourself. + +## Set up Slack Notifications for Exceptionless + +First, go into your project's settings in the Exceptionless app and click on the Integrations tab. + +![](/assets/img/news/exceptionless-slack-setup.png)(/assets/img/news/exceptionless-slack-setup.png) + +Then, click on "Add Slack Notifications" and log in to your slack team. + +Once logged in, you will need to select the channel you want Exceptionless Notifications to post to and click Authorize. + +Once authorized, you can then configure the different notification settings by going back to the Exceptionless app and into the project's integrations tab again. + +![](/assets/img/news/exceptionless-slack-settings.png)(/assets/img/news/exceptionless-slack-settings.png) + +Once integrated and configured, notifications will look something like the below screenshot, with the message, type of event, stack trace, links to actions, etc. + +![Exceptionless Slack notification](/assets/img/news/exceptionless-slack-example.jpg)(/assets/img/news/exceptionless-slack-example.jpg) + +We're excited to keep improving notifications, and would love for you guys to test this out for us. + +Integrations with other chat & productivity tools like HipChat and Microsoft Teams are on our list, as well, so if you use these please ping us and let us know so we can gauge interest! + + +## [WATCH NOW](https://youtu.be/U9GbYqWK1ik) + + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + diff --git a/docs/news/2017/2017-06-20-slack-integration-updates-bug-fixes-weekly-update-5222017.md b/docs/news/2017/2017-06-20-slack-integration-updates-bug-fixes-weekly-update-5222017.md new file mode 100644 index 0000000000..fd45e73baa --- /dev/null +++ b/docs/news/2017/2017-06-20-slack-integration-updates-bug-fixes-weekly-update-5222017.md @@ -0,0 +1,18 @@ +--- +title: "Slack Integration Updates and Bug Fixes - Weekly Update 5/22/2017" +date: 2017-06-20 +--- + +# Slack Integration Updates and Bug Fixes - Weekly Update 5/22/2017 + +https://youtu.be/WtHj9e4M9zU + +This week we have a quick update, where we focus on bug fixes and improvements to our [recent Slack Integration](/exceptionless-slack-integration/). + +Check out the video, above, and please let us know if you have any questions, comments, or concerns! + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + diff --git a/docs/news/2017/2017-06-26-improvements-exceptionless-slack-integration.md b/docs/news/2017/2017-06-26-improvements-exceptionless-slack-integration.md new file mode 100644 index 0000000000..7bb6bac13a --- /dev/null +++ b/docs/news/2017/2017-06-26-improvements-exceptionless-slack-integration.md @@ -0,0 +1,28 @@ +--- +title: "More Improvements to Exceptionless Slack Integration" +date: 2017-06-26 +--- + +# More Improvements to Exceptionless Slack Integration + +In this week's video, Blake covers a quick update on the Exceptionless Slack integration, along with a minor update to Foundatio. + +Take a look! + +## Slack Integration Update + +We have been tweaking the recent Slack integration over the past month or so, and this week we noticed that action URLs being created incorrectly and failures weren't being handle correctly with rate limiting. So, those two issues have been tweaked and should be working much better now. + +### In Foundatio News + +A big shout out to [@pwelter34](https://github.com/pwelter34) for submitting a pull request that added support for [Serilog](https://serilog.net/) to [Foundatio](https://github.com/FoundatioFx) - Paul! + + +## [WATCH NOW](https://youtu.be/k4CMOk5lpVw) + + + + + [Watch more Live Code Demos](/category/weekly-updates/) + + diff --git a/docs/news/2017/2017-06-28-weekly-update-codesmith-generator-serilog-sink-foundatio-redis-updates.md b/docs/news/2017/2017-06-28-weekly-update-codesmith-generator-serilog-sink-foundatio-redis-updates.md new file mode 100644 index 0000000000..935de53e19 --- /dev/null +++ b/docs/news/2017/2017-06-28-weekly-update-codesmith-generator-serilog-sink-foundatio-redis-updates.md @@ -0,0 +1,26 @@ +--- +title: "Weekly Update: CodeSmith Generator, Serilog Sink, and Foundatio.Redis Updates" +date: 2017-06-28 +--- + +# Weekly Update: CodeSmith Generator, Serilog Sink, and Foundatio.Redis Updates + +Blake's been busy lately, including some work on one of our other projects, [CodeSmith Generator](http://www.codesmithtools.com/product/generator), to update Exceptionless to the latest version. Naturally, this got him thinking about other potential improvements while we were doing work on Serilog Sink for Exceptionless and Foundatio.Redis, as well. + +Watch the video to hear the full story! + +## CodeSmith Generator Gets Latest Exceptionless Update + +While updating our WPF application, [CodeSmith Generator](http://www.codesmithtools.com/product/generator), to the latest version of Exceptionless, Blake brainstorms several improvements that could be made to help take advantage of plugins, isolate Exceptionless from other plugins, etc. + +## Serilog Sink + +There was an issue that was breaking the ability to update to the latest version of Exceptionless. This has now been fixed. + +## Foundatio.Redis Update + +Deserialization wasn't working properly with binary serializers, but the issue has been resolved. + + +## [WATCH NOW](https://youtu.be/bqhdaFdgr4M) + diff --git a/docs/news/2017/2017-08-15-javascript-client-v1-5-release-details-notes.md b/docs/news/2017/2017-08-15-javascript-client-v1-5-release-details-notes.md new file mode 100644 index 0000000000..f89bc3668d --- /dev/null +++ b/docs/news/2017/2017-08-15-javascript-client-v1-5-release-details-notes.md @@ -0,0 +1,33 @@ +--- +title: "JavaScript Client V1.5 Release Details & Notes" +date: 2017-08-15 +--- + +# JavaScript Client V1.5 Release Details & Notes + +![exceptionless.javascript 1.5](/assets/img/news/js-client-1.5-release-1024x538.jpg) +Exceptionless.JavaScript v1.5 Release Notes + +### Unversal App Support + +The major update for 1.5 is that we have added support for universal apps (React Universal). + +To view the exact changes required to get everything working and set up, [click here](https://github.com/niemyjski/react-redux-universal-hot-example/commit/7f7c01ca1b328f3389c3919a53376bccbbfe1f08). + +### Other 1.5 Updates + + + +* Added support for exceptions that are passed in and are just strings. +* Updated TraceKit to the latest version, which adds support for parsing PhantomJS errors and greatly improves native stack traces. +* Thanks [@caesay](https://github.com/caesay) for updating TypeScript to the latest version, as well! + +### Bug Fixes + +* Fixed a bug where exceptionless would fail to load when used with webpack. +* Fixed a bug where browser module info was not being populated. +* Fixed a bug where ILog.trace was piped to the wrong console function which would error under IE (thanks [@srijken](https://github.com/srijken){.user-mention}!) +* Fixed a few bugs with angular integration +* Fixed a bug with submitLog not respecting log message and log level + +For a full change log, select an applicable release on the [Exceptionless.JavaScript GitHub Release page](https://github.com/exceptionless/Exceptionless.JavaScript/releases). diff --git a/docs/news/2017/2017-08-30-universal-javascript-support-added-exceptionless-javascript.md b/docs/news/2017/2017-08-30-universal-javascript-support-added-exceptionless-javascript.md new file mode 100644 index 0000000000..85ad1f29c4 --- /dev/null +++ b/docs/news/2017/2017-08-30-universal-javascript-support-added-exceptionless-javascript.md @@ -0,0 +1,26 @@ +--- +title: "Universal JavaScript Support Added to Exceptionless.JavaScript" +date: 2017-08-30 +--- + +# Universal JavaScript Support Added to Exceptionless.JavaScript + +![Exceptionless Universal JavaScript](/assets/img/news/universal-javascript-1024x538.jpg) + +Recently, we released [Exceptionless.JavaScript 1.5](/news/2017/2017-08-15-javascript-client-v1-5-release-details-notes). The major update for the release was the addition of universal JavaScript (React Universal) support! More details below. The key is that we can now run in server side node apps, or in the browser, with a single script and do the right thing! + +> TL;DR: Isomorphism is the functional aspect of seamlessly switching between client- and server-side rendering without losing state. Universal is a term used to emphasize the fact that a particular piece of JavaScript code is able to run in multiple environments. - [Gert Hengeveld, Isomorphism vs Universal JavaScript](https://medium.com/@ghengeveld/isomorphism-vs-universal-javascript-4b47fb481beb) + + + +We have gotten lots of requests for Universal JavaScript support. What this means is that you can use a library in the browser or server without any changes from the end user. This is great because you can just consume the library and just know it will work using the same API service no matter where you want to use it. The main con of using a universal client is the increased payload size as you know have to send node support to the browser as well. + +We implemented universal JavaScript support by bundling both the browser and node scripts together. But it wasn't as easy as concatenating the files together. We had to refactor the node and browser entry points so that they would automatically run, while ensuring that the initialization of environment specific code (storage, network, etc.) only ran when specific environment conditions were met. This is pretty easy to do with an [IIFE function](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression) and a quick if check as shown [here](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.5.4/src/exceptionless.ts#L14-L38). Next, we needed to provide a [new entry point that imported both of the entry points](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v1.5.4/src/exceptionless.universal.ts) which ensures that browser and node entry points run. + +This update adds support for universal apps, and a React Universal sample that shows the exact changes that were required to get everything working and setup can be found [here](https://github.com/niemyjski/react-redux-universal-hot-example/commit/7f7c01ca1b328f3389c3919a53376bccbbfe1f08). The pull request for universal support can be found [here](https://github.com/exceptionless/Exceptionless.JavaScript/pull/75). + +**To target it**, you just need to reference the universal script (exceptionless.universal.js), this will happen automatically if you install via browserfiy or webpack. + +## Questions? Feedback? + +Let us know what you think about the new Universal JavaScript support over on [GitHub](https://github.com/exceptionless/Exceptionless.JavaScript/issues)! diff --git a/docs/news/2017/2017-10-06-slack-integration-update-recap.md b/docs/news/2017/2017-10-06-slack-integration-update-recap.md new file mode 100644 index 0000000000..52fa1da8fc --- /dev/null +++ b/docs/news/2017/2017-10-06-slack-integration-update-recap.md @@ -0,0 +1,35 @@ +--- +title: "Slack Integration Update & Recap" +--- + +# Slack Integration Update & Recap + +![Exceptionless Slack Integration](/assets/img/news/slack-integration-ft-img-1024x538.jpg) + +Since we first introduced Slack integration with the goal of further improving notifications in Exceptionless, we've come back around with updates, a few bug fixes, and wanted to give everyone a quick all-in-one overview of the feature! + +Thanks to everyone that has provided feedback, bug reports, and suggestions. If _you_ have any, don't hesitate to [submit an issue over on GitHub](https://github.com/exceptionless/Exceptionless/issues). We're always looking to improve and would love your input! + +Along the way, we have run into **incoming webhook issues**, some **usability/setup workflow updates** that needed to be made to make the process more usable, and, among other things, **incorrectly created action URLs** that weren't being handled correctly with rate limiting. + +We'll cover **setting up Slack integration with Exceptionless** below, but you can also review the [original post](/news/2017/2017-06-05-exceptionless-slack-integration) and [weekly update video](https://youtu.be/U9GbYqWK1ik), the [first bug fix update](/news/2017/2017-06-20-slack-integration-updates-bug-fixes-weekly-update-5222017) and [video](https://youtu.be/WtHj9e4M9zU), and the most recent [Slack integration improvement update](/news/2017/2017-06-26-improvements-exceptionless-slack-integration) and [video](https://youtu.be/k4CMOk5lpVw). + +## Setting up Slack Notifications for Exceptionless + +First, go into your project's settings in the Exceptionless app and click on the Integrations tab. + +![Exceptionless Slack setup](/assets/img/news/exceptionless-slack-setup.png) + +Then, click on "Add Slack Notifications" and log in to your slack team. + +Once logged in, you will need to select the channel you want Exceptionless Notifications to post to and click Authorize. + +Once authorized, you can then configure the different notification settings by going back to the Exceptionless app and into the project's integrations tab again. + +Once integrated and configured, notifications will look something like the below screenshot, with the message, type of event, stack trace, links to actions, etc. + +We're excited to keep improving notifications, and would love for you guys to continue testing and providing feedback! What else would you like to see happening with notifications? What are we doing right, and wrong? + +Integrations with other chat & productivity tools like HipChat and Microsoft Teams are on our list, as well, so if you use these please ping us and let us know so we can gauge interest! + +Until next time, code on my friends. diff --git a/docs/news/2017/2017-11-07-exceptionless-net-4-1-release-net-standard-2-0-microsoft-extensions-logging-support-and-more.md b/docs/news/2017/2017-11-07-exceptionless-net-4-1-release-net-standard-2-0-microsoft-extensions-logging-support-and-more.md new file mode 100644 index 0000000000..f4494c5d95 --- /dev/null +++ b/docs/news/2017/2017-11-07-exceptionless-net-4-1-release-net-standard-2-0-microsoft-extensions-logging-support-and-more.md @@ -0,0 +1,35 @@ +--- +title: "Exceptionless.NET 4.1 Release - .NET Standard 2.0 & Microsoft.Extensions.Logging Support, and more!" +--- + +# Exceptionless.NET 4.1 Release - .NET Standard 2.0 & Microsoft.Extensions.Logging Support, and more! + +![Exceptionless.NET 4.1 Release](/assets/img/news/exceptionless-net-4-1-release-1024x538.jpg) + +[Exceptionless.NET](https://github.com/exceptionless/Exceptionless.Net) 4.1 is here and we wanted to make a quick blog post highlighting the new features, bug fixes, and of course upgrading. + +In this release, we focused primarily on adding .NET Standard 2.0 support, along with ongoing performance enhancements and bug fixes. + +More details, below: + +## Exceptionless.NET 4.1 New Features + + 1. We've added .NET Standard 2.0 support, which allows you to easily integrate with UWP applications now. + 2. Microsoft.Extensions.Logging support has also been added via the Exceptionless.Extensions.Logging client. Thank you [@moogle001](https://github.com/moogle001) for contributing to this feature! + 3. Thanks to [@jamierushton](https://github.com/jamierushton), we now allow `null` and `default` values to be serialized, which translates to greater insight into contextual data. + 4. We're now using [GitLink](https://github.com/GitTools/GitLink) to debug packages more easily. + +## Version 4.1 Bug Fixes + +* GetFiles has been replaced with the EnumerateFiles method to improve performance in FolderObjectStorage. Thanks [@edwardmeng](https://github.com/edwardmeng) for that contribution! +* @edwardmeng also helped us improve diagnostic logging by including timestamps and log level. Thanks again! + +## Upgrading to Exceptionless.NET 4.1 + +If you are using our hosted service, you do not need to upgrade anything on your end. If you are self hosting Exceptionless and upgrading from version 2 or 3, you should just have to update your NuGet packages. See our [upgrade guide](/docs/clients/dotnet/upgrading) for more information. + +Check out the [official release notes](https://github.com/exceptionless/Exceptionless.Net/releases/tag/v4.1.0) here, or view the [full changelog](https://github.com/exceptionless/Exceptionless.Net/compare/v4.0.4...v4.1.0) if you are interested in a complete list of changes. + +## How are we doing? + +As always, we want to know what you think! If you have questions, concerns, or any feedback, please [submit an issue over on the GitHub repo](https://github.com/exceptionless/Exceptionless.Net/issues/new). diff --git a/docs/news/2018/2018-01-31-asp-net-bug-tracking-software.md b/docs/news/2018/2018-01-31-asp-net-bug-tracking-software.md new file mode 100644 index 0000000000..0ba75cf1c9 --- /dev/null +++ b/docs/news/2018/2018-01-31-asp-net-bug-tracking-software.md @@ -0,0 +1,55 @@ +--- +title: "ASP.NET Bug Tracking Software" +--- + +# ASP.NET Bug Tracking Software + +![asp.net bug tracking software platform](/assets/img/news/asp-net-bug-tracking-software-platform-1024x538.jpg) + +Bug tracking. Two words that you’ll never be able to escape as a developer. Our goal as developers is to always create a high quality product with pristine code, but let’s face it, nobody’s perfect and accidents happen. Bugs are going to pop up no matter how hard we work or how much we plan ahead. They’re an inevitable part of the job and the more complex your project becomes, the more likely unexpected bugs are to start popping up. + +You can try and track these little annoyances manually, like some kind of an animal, or use a bug tracking software to significantly speed up the process and provide a log of what happened and where to prevent future iterations of the same issue. + +## WHAT IS BUG TRACKING? + +At its core, bug tracking is when a developer tracks, logs, and resolves a bug or issue that caused their software to not perform as intended. This could be as simple as a missing semicolon or trailing slash or as complicated as a vulnerability in your back end. + +In the old days of yesteryear, there weren’t any (good) bug tracking software platforms so developer had to exhaustively QA test their code before publishing and even then, they couldn’t catch everything. Bugs sometimes went to production undetected and they relied on users to report issues so they could investigate them manually later. As you can imagine, this was an incredibly time consuming and tedious process that ate up far too much time and resources that could have been spent developing the next great feature to propel sales. + +### IMPORTANCE OF BUG TRACKING + +At the risk of sounding pretentious, Kurt Vonnegut said that "Everyone wants to build and nobody wants to do maintenance." Whether we like it or not, we can’t always build the next big feature or streamline the functionality of our platform. Sometimes we have to hunt down elusive bugs and do maintenance to keep our code clean and keep a solid foundation so we can keep building. + +Ignoring or intentionally leaving bugs to multiply in the code can damage your company’s reputation (and revenue) if one of these errors affects your customers’ ability to do their job or compromises their information. It will save everyone involved a ton of time, money, and headache if you simply implement a bug tracking software from the get go. Your code will stay clean and you’ll stop losing users, leads, and customers. It’s a win / win for everyone. + +## ASP.NET FRAMEWORK OVERVIEW + +ASP.NET is a coding model used to build enterprise class applications with minimal coding. This not only cuts down on the amount of man hours necessary to complete your project, but also simplifies running and maintaining said application due to its (relative) simplicity. If you’re new to the ASP.NET platform, do not be surprised if it’s not the easiest thing to pick up, but once you do, you’ll understand why it’s one of the most popular development platforms out there. (There are a ton of [tutorials](https://www.asp.net/learn) & [learning environments](https://www.microsoft.com/web/webmatrix/) if you’re looking to learn the platform.) + +## ASP.NET BUG TRACKING SOFTWARE PLATFORM + +Just because ASP.NET is a simplified coding platform doesn’t mean that you won’t have bugs. If anything, it can make them a bit tougher to find, but that’s where having an integrated bug tracking suite comes into play. + +Our bug tracking software suite helps development teams find, record, and categorize bugs and errors in real time for your ASP.NET websites, applications, and services. It organizes information in an intuitive and easy to digest dashboard to help your platform become exceptionless. + +### REAL TIME BUG DISCOVERY + +Bugs can happen anywhere at anytime and if you aren’t watching, they can go unnoticed for months, sometimes years. Our bug tracking software runs in the background of your ASP.net platform 24/7/365 so if something happens, we have a full report with the data you need to craft surgical solution with ease + +### DETAILED BUG REPORTS + +Once a bug has been discovered and tracked, there’s no need to attempt to replicate the issue. A detailed report is automatically created that intelligently organizes important information to help resolve the bug. + +Curious about what else is captured in our reports? Check out the full write up on our [detailed error reports](/whats-included-exceptionless-detailed-error-reports/). + +### INTUITIVE ERROR GROUPING + +For ease of browsing, our platforms groups errors together based on a variety of criteria, i.e. date, type, platform, browser, etc. to help you drill down and pinpoint the cause of bugs in your application. It also keeps a full history of the exception even after it’s been resolved in case it resurfaces in the future. + +### EMAIL NOTIFICATIONS + +You no longer have to worry about your customers letting you know about bugs or checking a dashboard every morning. Simply update your notification settings and get instant emails when an error happens, only when new errors happen, or not at all. You can even flag resolved errors to send emails in the event that regress to their previously broken state. + +## RECAP + +Bugs are an inescapable part of any ASP.NET application, but they don’t have to be an unmanageable nuisance. Implementing an error tracking solution will help you organize bugs as they occur while providing vital information that will help you pinpoint the cause and quickly resolve them. Keep your development teams updating your application with new features with an ASP.NET bug tracking software. diff --git a/docs/news/2018/2018-04-30-c-bug-tracking-software.md b/docs/news/2018/2018-04-30-c-bug-tracking-software.md new file mode 100644 index 0000000000..52ce40e16a --- /dev/null +++ b/docs/news/2018/2018-04-30-c-bug-tracking-software.md @@ -0,0 +1,52 @@ +--- +title: "C# Bug Tracking Software" +--- + +# C# Bug Tracking Software + +![](/assets/img/news/c-sharp-bug-tracking-software-1024x538.jpg) + +Bugs, exceptions, issues, faults, errors, incidents, whatever you want to call them, they’re unavoidable. No matter how elegantly you think you wrote your code, no matter how many user cases you think you’ve covered, your application is going to have bugs and part of our jobs is to find those bugs and fix them. You can track these bugs using an Excel or Google sheet (if you’re a glutton for punishment), but the best way is to use a bug tracking platform that tracks, records, reports, and manages these exceptions for you. + +## WHAT IS BUG TRACKING? + +In its simplest form, bug tracking is when a developer is alerted to an event when their code does not operate as intended. They catalog the issue, collect as much information as they can that led to said event, and attempt to recreate it so they can fix the problem. + +As you can imagine, doing all of this manually becomes quite unwieldy the larger an application gets. On top of that, with larger applications comes additional layers of complexity that a user simply can’t account for or give you the proper information to set you on the path for resolving their bug. This is why it’s so important to have an automated event tracker. + +### IMPORTANCE OF BUG TRACKING + +A bug tracking software of any kind is a must have for any sort of application at any stage of development, even months or years after it goes live. The larger your product, the more important it is to have some form of bug tracking implemented. (This is also a tell tale sign of whether or not a development team is worth their salt.) + +You can spend hours, days, weeks, and even months trying to track down a bug if you don’t have the right information. Having a software platform in place for tracking bugs helps your development team work smarter and faster when troubleshooting these issues. The software will record, document, and organize these bugs automatically with critical information about the user, event, and the application at the time it occurred. No more chasing down info. It’s already done for you! + +## C# FRAMEWORK OVERVIEW + +C# is one of, if not the most used programming language of the last 15 years. It’s an elegant object oriented language that allows developers to build .NET applications. While it can be daunting at first if you aren’t familiar with it, it’s actually quite simple to use and relatively easy to learn. However, the applications can get quite complicated because of its structure. A misplaced bracket, variable, or object can cause cascading issues that aren’t easy to detect or remedy. + +### C# BUG TRACKING SOFTWARE + +Due to the potentially complicated landscape that is a C# application, detecting, diagnosing, and fixing a bug can be a near-Herculean task, especially if you aren’t the developer that originally created said application. It may have been coded in a non-optimal way or due to time constraints, it had to be done in a hacky way that’s just waiting to implode. This is where a bug tracking solution for your C# application is an invaluable addition to your infrastructure. + +### REAL TIME BUG DISCOVERY + +You can’t be everywhere at once and see everything, especially in the larger C# applications. Having C# bug tracking software guarantees that you can be with it collecting data in the background. Regardless of when a bug occurs, our platform will have a full report with everything you need to set your development team in the right direction. + +### CUSTOM OBJECTS + +Exceptionless’ automated bug tracking already tracks an enormous amount of contextual information automatically, but you can track even more information by creating a custom object. If you want to grab info on what was in a customer’s before it threw a bug, custom object. Once created, you can set these objects as top level tabs to improve their visibility. + +### INTUITIVE ERROR GROUPING + +Every bug is intelligently tracked on our dashboard and consolidated into stacked groups based on where it occurred and the type of bug. Not only does this keep things nice and tidy, but it also lets you triage whether or not a bug needs to be fixed as soon as possible. These reports also persist after the bug has been fixed so you have historical data just in case the bug resurfaces later. + +### DETAILED BUG REPORTS + +Our bug reports extensively tracks a robust set of information to help you quickly track down and fix the error. The default information covers type of error, stack trace, date, request information, and environment information, but that can easily be expanded upon and tailored to your application with custom objects. + +### FLUENT API + +We have extensively documented our platform and API to make it easy and painless to use. You can use our fluent API to easily add custom objects, tags, and other information as well as marking certain errors as vitally important. + +RECAP +Troubleshooting and fixing bugs is part of our jobs as developers and, as the saying goes, we need to work smarter, not harder so we can spend more time creating new features to our applications rather than patching errors. Exceptionless’ C# bug tracking software will intuitively, and automatically, organize any bugs that do occur to help you pinpoint the cause so your application can get back on track. diff --git a/docs/news/2018/2018-06-02-event-tracking-and-logging-software.md b/docs/news/2018/2018-06-02-event-tracking-and-logging-software.md new file mode 100644 index 0000000000..91d5884fb9 --- /dev/null +++ b/docs/news/2018/2018-06-02-event-tracking-and-logging-software.md @@ -0,0 +1,40 @@ +--- +title: "Event Tracking and Logging Software" +--- + +# Event Tracking and Logging Software + +![](/assets/img/news/event-tracking-logging-software-1024x538.jpg) +Whether you’re developing a quick module, application, or full blown, go-to-market product, you’re going to need some form of event logging throughout the development process. It can be done without, but you’ll be making your job multiple magnitudes more difficult and losing valuable man hours that could be put towards making your product better instead of just not breaking. + +## WHAT IS EVENT LOGGING? + +Event logging provides a detailed record of events, bugs, and custom triggers that occur in your application, environment, or product. The information collected gives you a wealth of data to both forensically troubleshoot a bug after it’s occurred as well as proactively to prevent future errors. + +This now service is now an invaluable resource to increase your development team’s efficiency and productivity as well as increasing visibility of what goes on behind the scenes in your development environment. On top of that, it also helps maximize application uptime and operation by minimizing the long-term effects of bugs and unwanted events. + +### INTUITIVELY PARSE EVENT DATA + +Individual raw event logs are too dense and unwieldy to be reviewed. If you were to rely on the raw data, you’d need to specifically hire someone to dig through all that info to pass on the important info to your developers. Event tracking software will parse the data and catalog the important information in an intuitive manner to make everyone’s lives easier. In a nutshell, it will shine a light on the needle in your proverbial haystack. + +### FAST AND EASY REPORTING + +The great thing about event tracking is that it’s running around the clock. When you and your team aren’t in the office, it’s keeping a watchful eye on your project and collecting data 24/7. It collects data from all sources across your development environment and all of this data is funneled to your dashboard for real-time reporting and criteria based sorting. This allows you to both find the event you’re looking for and quickly dive into its potential causes. + +### INTELLIGENT EVENT GROUPING + +Exceptionless groups common events into stacks based on where the event occurred and the type of error. This cleans up and consolidates the data on your dashboard and in your reports to keep it from being cluttered as well as keeping that information in a single place for your analysis. Even though the event’s footprint is smaller, you’ll still be able to identify larger iterations of the same event to prioritize your work. + +### SAVE TIME ON MAINTENANCE + +It can be incredibly difficult to replicate an event that a user encountered. There’s a slew of information you need to accurately track the cause and the user simply may not, or cannot, provide it. You could spends hours or days just trying to isolate what triggered an event. Hours that could have been put towards building a new feature or getting your product to market. + +Event tracking software makes it so a bug that once took a week to find can be found, patched, and pushed live in a matter of minutes or hours instead of days or weeks. Spend less time on maintenance and more time innovating. + +### EVENT LOGGING SOFTWARE PAYS FOR ITSELF + +Your developers’ time is valuable, and expensive. Even though it’s important, having them blindly diving down rabbit holes to chase bugs and other events can be incredibly costly and not productive. Not every project has a big budget and you may have to work faster and more efficiently to wrap it up without going over budget. While an event logging software may sound like an additional expense, the amount of time you save troubleshooting and fixing bugs will easily cover the cost. And the great thing is, the more you use it, the more you save. + +### USER FRIENDLY DASHBOARD + +All the information in the world won’t help you if it’s impossible to dig through. We specifically built our dashboard to give a clear high level view of your application while still being clear the further you drill down into individual events and bugs. You can quickly view the health of your application, track data from actually users, and intelligently drill down into recent errors. It seamlessly unites metrics and productivity while you analyze and explore data to rapidly troubleshoot your application. diff --git a/docs/news/2019/2019-08-29-exceptionless-5-0-release-asp-net-core-localization-support-and-more.md b/docs/news/2019/2019-08-29-exceptionless-5-0-release-asp-net-core-localization-support-and-more.md new file mode 100644 index 0000000000..345dd88439 --- /dev/null +++ b/docs/news/2019/2019-08-29-exceptionless-5-0-release-asp-net-core-localization-support-and-more.md @@ -0,0 +1,39 @@ +--- +title: "Exceptionless 5.0 Release - ASP.NET Core & Localization Support, and more!" +--- + +# Exceptionless 5.0 Release - ASP.NET Core & Localization Support, and more! + +![Exceptionless 5.0 Localization](/assets/img/news/exceptionless-5.0-localization.png) + +[Exceptionless](https://github.com/exceptionless/Exceptionless) 5.0 is here and we wanted to make a quick blog post highlighting the new features, bug fixes, and of course upgrading. + +In this release, we focused primarily on migrating the application to ASP.NET Core, localization, along with ongoing performance enhancements and bug fixes. + +More details, below: + +## Exceptionless 5.0 New Features + + 1. Exceptionless now runs on ASP.NET Core! This brings in many performance advantages as well as cross platform support. + 2. Docker/Kubernetes based hosting is now the default hosting model. This will bring seamless and quick upgrades while reducing the amount of environmental related errors. + 3. Added Chinese localization support. Thanks [@Varorbc](https://github.com/Varorbc), [@edwardmeng](https://github.com/edwardmeng) for that contribution! + 4. Added support for using various different cloud hosted services (e.g., Aliyun, Minio, S3) and metric providers (e.g., InfluxDB). Thanks [@edwardmeng](https://github.com/edwardmeng) for that contribution! + 5. When viewing 404 event types, you will now see a grid column for IP addresses. This will allow you to quickly identify any bots or security scans that might be happening to your applications. + 6. In addition to client side plugins that will remove sensitive user data, we've added server side code as well to remove any missed sensitive user data. + 7. Added the ability to delete your account on the manage account page. + +## Version 5.0 Bug Fixes + +* Various user interface usability issues have been fixed in this release. Please view the UI release notes ([v2.8.0](https://github.com/exceptionless/Exceptionless.UI/releases/tag/v2.8.0) for more info). +* Fixed a bug where notifications and web hooks would be sent for fixed events. +* Updated [Foundatio](https://github.com/FoundatioFx/Foundatio) which uses a task queue to resolve dead locking and thread exhaustion. + +## Upgrading to Exceptionless 5.0 + +If you are using our hosted service, you do not need to upgrade anything on your end. If you are self hosting Exceptionless and upgrading from version 4 or 5, a little work is needed to get up and running using the new docker images and configuration. See our [upgrade guide](/docs/self-hosting/upgrading-self-hosted-instance) for more information. + +Check out the [official release notes](https://github.com/exceptionless/Exceptionless/releases/tag/v5.0.0) here, or view the [full changelog](https://github.com/exceptionless/Exceptionless/compare/v4.1.0...v5.0.0) if you are interested in a complete list of changes. + +## How are we doing? + +As always, we want to know what you think! If you have questions, concerns, or any feedback, please [submit an issue over on the GitHub repo](https://github.com/exceptionless/Exceptionless/issues/new). diff --git a/docs/news/2020/2020-09-23-using-an-error-monitoring-service-to-track-user-experience.md b/docs/news/2020/2020-09-23-using-an-error-monitoring-service-to-track-user-experience.md new file mode 100644 index 0000000000..1fc93f6887 --- /dev/null +++ b/docs/news/2020/2020-09-23-using-an-error-monitoring-service-to-track-user-experience.md @@ -0,0 +1,96 @@ +--- +title: "Using an Error Monitoring Service to Track User Experience" +date: 2020-09-23 +--- + +# Using an Error Monitoring Service to Track User Experience + +In development, we tend to think of errors as things that are thrown when our code does not execute properly. Errors can be caught and handled or they can be missed and result in uncaught exceptions. But how do we classify errors that are not directly caused by the code we write? How do we identify and address errors that are caused by the design decisions we made (or didn't make)? + +You may already be using an error monitoring service, and if you are, you could continue using that and reach for yet another tool to help you with your user experience woes. Or, rather than adding another product to your endless list of tools that keep your application running, you can use the error monitoring service to both monitor for traditional errors and user experience problems. + +Let's take a look at how we can do this. There are plenty of logging services out there, and most of them do the same thing. However, we're going to take a look at [Exceptionless](/). Exceptionless is an especially attractive choice for three reasons: + + 1. Fair pricing on their hosted version + 2. It's [open-source](https://github.com/exceptionless/Exceptionless) and can be totally self-hosted + 3. The API allows us to do exactly what I'm proposing in this article. + +While self-hosting may be an attractive option (and one that I will surely write about ina future post), we're going to sign up for a free account using Exceptionless's hosted platform. To do so, go to [https://exceptionless.com](/) and click the Sign Up button in the top-right: + + +![Exceptionless home page](/assets/img/news/exceptionless_site.jpeg) + + +Once you sign up, you'll be prompted to name your team and project. You'll also need to choose the language in which your project is written. I'm choosing NodeJS, but you can choose whatever language applies to you because I'll be referencing cURL commands to keep our solution as general-purpose and adaptable as possible. Once you've created a project, you will be provided an API Key. Hold on to that, we'll need to use it as a bearer token later. + +*Pro-tip: To convert a cURL command to the language of your choice, use [Postman](https://www.postman.com/) and import the raw command. You can then choose the code option and see how to run the API call in the language you prefer. + +You'll want to follow the documentation to set up your codebase to send errors appropriately to Exceptionless, but we will also need to think about how we are going to handle these UX errors. + +To do this, let's first think about some of the problems a user may face on a site and how we can handle them. A simple example that I can think of is what I'm going to call "Happy Path Slippage." We build applications with a happy path in mind. It's how we test, naturally. We have to force ourselves to test outside of the happy path, so it's also important to monitor how often our users deviate from the happy path. + +Let's say we have a simple e-commerce application. The happy path, in this case, would be: + + 1. User signs up + 2. User searches for a product + 3. User adds product to shopping cart + 4. User checks out + +That is the ideal flow, but we know users won't always follow that flow. However, what we don't know is how often users will deviate and if they do deviate. To track this with Exceptionless, we are going to use simple GET requests with a query parameter to build a funnel analysis. We will want to track product searches, shopping cart adds, and checkouts. + +Let's start with the setup for product searches. Remember, we're going to use a GET request. You can read more of the Exceptionless documentation [here](https://api.exceptionless.io/docs/index.html), but the request is pretty simple. We will want to pass in an indicator that the event is a `productSearch` and what the product is. We can do that like this: + +```bash +curl --location --request GET 'https://api.exceptionless.io/api/v2/events/submit/usage?source=productSearch&message=YOUR_PRODUCT' \ +--header 'Authorization: Bearer YOUR_API_KEY' +``` + +Feel free to add whatever product name you'd like in the query. Just replace `YOUR_PRODUCT` with the name of the product you'd like to track. You can run the cURL command from the command line or you can use it to build a real request you would use in your app. If we run that then take a look at our dashboard in Exceptionless, we can start to make use of the data. + +The Exceptionless dashboard takes you to a handy chart of most frequent exceptions/errors. However, we're tracking User Experience issues tied to features in our application, so those events won't appear on the Exceptions dashboard. Instead, if you click the Features Usage link on the left navigation, then click Events, you should see your new `productSearch` event. + + +![Features Usage Dashboard Example](/assets/img/news/dashboard_empty.png) + + +Pretty cool! This alone starts to become useful. We can cut out a separate analytics tracking tool by using our error monitoring service (Exceptionless in this case) to track events outside the normal error reporting. But we can take it a step further. + +Remember, we want to track the funnel from search to checkout. So, let's send through another event representing a `cartAdd` when a user adds a product to their shopping cart. Here we are adding an extra parameter to also track how many of the product is added to the cart. + +```bash +curl --location --request GET 'https://api.exceptionless.io/api/v2/events/submit/usage?source=cartAdd&value=QUANTITY_ADDED&message=YOUR_PRODUCT' \ +--header 'Authorization: Bearer YOUR_API_KEY' +``` + +Exceptionless has real-time monitoring, so if you flip back to your dashboard after running the above command, you should already see the event in the list: + + +![Cart Add Example](/assets/img/news/dashboard_evenets.png) + + +I think you're already seeing how easy this is, but let's round this out by adding a `checkout` event to track. + +```bash +curl --location --request GET 'https://api.exceptionless.io/api/v2/events/submit/usage?source=checkout&message=YOUR_PRODUCT' \ +--header 'Authorization: Bearer YOUR_API_KEY' +``` + +Again, your Exceptionless dashboard should update in real-time. This is starting to shape up! Now, let's dive into the events because right now we have the start of a nice funnel analysis, but we don't know yet what products were searched for, added to the cart, and checked out. The cool thing here is we can click into an event like `productSearch` for example and get detailed info. + +Go ahead and try it. Click on the event and you'll be taken to a dedicated Event Occurrence page. + + +![Event Occurrence Example](/assets/img/news/event_occurence.png) + + +This is useful information. Combined with our user experience funnel analysis, we can start to make product decisions. Just for fun, I want to show you what this could look like when leveraging the Most Frequent view. + +Again, we should click on the Features Usage link on the side navigation. This time, we'll choose the Most Frequent option. I've created a bunch of events so that we can see how useful the Most Frequent view can be. + + +![Funnel Example](/assets/img/news/funnel_example.png) + + +Now we have the makings of a useful way of tracking the user experience right from within our error reporting tool. The benefit here is that we can use a single tool to help us with monitoring, bugs, event tracking, and user experience. [Exceptionless](/) makes this incredibly easy, is self-hostable, is open source, and if you choose the hosted option is very affordable. + +Go forth and track errors AND user experience all in one place. diff --git a/docs/news/2020/2020-09-24-why-we-upgraded-our-production-application-to-net-5-0.md b/docs/news/2020/2020-09-24-why-we-upgraded-our-production-application-to-net-5-0.md new file mode 100644 index 0000000000..f433638e91 --- /dev/null +++ b/docs/news/2020/2020-09-24-why-we-upgraded-our-production-application-to-net-5-0.md @@ -0,0 +1,61 @@ +--- +title: "Why We Upgraded Our Production Application to .NET 5.0" +date: 2020-09-24 +--- + +# Why We Upgraded Our Production Application to .NET 5.0 + +--- + +> ## Update: Microsoft has [officially released .NET 5.0!](https://devblogs.microsoft.com/dotnet/announcing-net-5-0/) + +--- + +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 [Exceptionless](https://exceptionless.com/), 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. + +To give you a little background, .NET 5.0 was [introduced in May of 2019](https://devblogs.microsoft.com/dotnet/introducing-net-5/). 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 [announced September 13, 2020](https://devblogs.microsoft.com/dotnet/announcing-net-5-0-rc-1/). 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. + +All in, the upgrade took about one hour and was a very small commit. You can actually [see the commit here](https://github.com/exceptionless/Exceptionless/commit/874f08e70a3ded2762f8d34df0378de38d7a3193). 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. + +* 1.4 TB Elasticsearch Cluster +* 173M Elasticsearch Documents +* 384M Redis Operations/Day +* 122M HTTP Requests/Day +* 2,476 GitHub Stars +* 568 GitHub Forks + +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, and Docker improvements for our self-hosted solution. + +## Performance Improvements + +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. + +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 [focus Microsoft put on continuing to improve performance](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/#gc) in this area and felt the gains were enough to really tilt us towards our production release of Exceptionless using .NET 5.0. + +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 + + + +## New C# Features + +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! + +Pattern matching in C# 9 is a feature we are particularly excited about. If you're interested in a deep dive into the improvements here, [Anthony Giretti has a great post](https://anthonygiretti.com/2020/06/23/introducing-c-9-improved-pattern-matching/) 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. + +Records are an exciting new feature in C# 9 as well. Data immutability is important, once again, for—you guessed it—performance. The way [Dave Brock puts it](https://daveabrock.com/2020/07/06/c-sharp-9-deep-dive-records) on his blog is apt: + +> Immutable types reduce risk, are safer, and help to prevent a lot of nasty bugs that occur when you update your object. + +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. + +## Docker Improvements + +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. + +.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. + +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. + +## Conclusion + +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. diff --git a/docs/news/2020/2020-09-30-how-to-self-host-your-error-monitoring-service.md b/docs/news/2020/2020-09-30-how-to-self-host-your-error-monitoring-service.md new file mode 100644 index 0000000000..dfae9642aa --- /dev/null +++ b/docs/news/2020/2020-09-30-how-to-self-host-your-error-monitoring-service.md @@ -0,0 +1,67 @@ +--- +title: "How to Self-Host Your Error Monitoring Service" +date: 2020-09-30 +--- + +# How to Self-Host Your Error Monitoring Service + +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. [Ghost](https://ghost.org) is a popular example of this from the blogging world. Some analytics serves, including [Matomo](https://matomo.org/matomo-on-premise/), allow users to choose between a hosted and a self-hosted solution. In that same vein, [Exceptionless](https://exceptionless.com) provides a self-hosted option for those who would like to host their own error monitoring. + +Today, we're going to walk through setting up a self-hosted Exceptionless instance. Let's get started! + +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 [download Docker for desktop](https://www.docker.com/get-started) if you don't already have it. Once you're able to download that and start it, you should then be able to execute `docker` commands from the command line. Test it out by running `docker stats` in the command line. + +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. + +Let's make sure we can get Exceptionless running locally. Ready for how easy this is? Are you? + +Ok, start up Docker Desktop, then in your command line, run: + +`docker run --rm -it -p 5200:8080 exceptionless/exceptionless:latest` + +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. + +When the process in your command line finishes up, open your browser and navigate to `http://localhost:5200`. If all went well, you should see the Exceptionless login page. + +[![Exceptionless self-hosted login page](/assets/img/news/self-hosted-login.png)](/assets/img/news/self-hosted-login.png) + +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. + +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. + +```shell +curl --location --request POST 'http://localhost:5200/api/v2/auth/login' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "email": EMAIL_ADDRESS, + "password": PASSWORD + }' +``` + +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. [Here are the full API docs for Exceptionless](https://api.exceptionless.io/docs/index.html). + +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. + +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: + +```shell +docker run --rm -it -p 5200:8080 \ + -v $(pwd)/esdata:/usr/share/elasticsearch/data \ + exceptionless/exceptionless:latest +``` + +If you're using PowerShell, you'll instead want to run: + +```shell +docker run --rm -it -p 5200:8080 ` + -v ${PWD}/esdata:/usr/share/elasticsearch/data ` + exceptionless/exceptionless:latest +``` + +Now, when you sign up at `http://localhost:5200`, 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. + +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. [Check out the instructions here](/docs/self-hosting/docker#simple-setup-wssl-support-and-smtp). + +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, [that's covered too](https://exceptionless.com). + +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 😉) diff --git a/docs/news/2020/2020-10-23-introducing-exceptionless-7.md b/docs/news/2020/2020-10-23-introducing-exceptionless-7.md new file mode 100644 index 0000000000..5e99b81e08 --- /dev/null +++ b/docs/news/2020/2020-10-23-introducing-exceptionless-7.md @@ -0,0 +1,42 @@ +--- +title: "Introducing Exceptionless 7" +date: 2020-10-23 +--- + +# Introducing Exceptionless 7 + +Feedback and community support is the key to growing a successful open-source company, and you all have provided us some of the best feedback possible. With your feedback, we just released one of our biggest improvements yet. This release includes changes on both the application interface and the core functionality. We wanted to highlight some of the main improvements and why we did it. + +## New Statuses + +![new statuses](statuses.png) + +This improvement is more than just visual. We heard the feedback from you loud and clear. There are stacks you don't want to track, but filtering them out on your end is difficult. For that reason, we are introducing the "Discarded" status. If you mark a stack with this status, it will not be tracked in your dashboards and, more importantly, **it won't count against your plan limits** 🎉. + +![actions example](status.png) + +As part of this improvement, we also consolidated statuses. Operations that were duplicative or didn't make sense were removed or combined. + +Adding a status means your dashboards will be updated in real-time with these statuses as quick indicators to help you understand your stacks. You can [read more about this feature and the goals we had here](https://github.com/exceptionless/Exceptionless/releases/tag/v7.0.1). + +## Dashboards + +All dashboards now have a both high level stats and a timeline view by default. This gives you better information at a glance and allows you to go deeper with your stacks and events as needed. + +![example dashboard](dashboard_7_0.png) + +You'll also notice we've renamed some of our stats labels to make things a little more clear. + +## Navigation + +We've made some minor adjustments to navigation icons, spacing, and more to make the experience in Exceptionless better as you move throughout the application. + +![example navigation](navigation.png) + +## We want to hear from you + +We are constantly improving based on user feedback. If you'd like to reach out, please do so any time. You can also add your feedback at either of the two links below: + +* [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) + +Happy building! diff --git a/docs/news/2020/2020-10-26-set-default-log-levels.md b/docs/news/2020/2020-10-26-set-default-log-levels.md new file mode 100644 index 0000000000..434c2e7991 --- /dev/null +++ b/docs/news/2020/2020-10-26-set-default-log-levels.md @@ -0,0 +1,50 @@ +--- +title: "Set Default Log Levels" +date: 2020-10-26 +--- + +# Set Default Log Levels + +## Customize Your Log Levels on the Fly + +Imagine this scenario. You're debugging your application. You KNOW there is a problem, but your logs aren't showing you anything helpful. You've bounced your head off your desk at least 34 times. Then it hits you! + + +You've configured your error monitoring service to only capture FATAL errors, but this error is surely some other level. Your log level settings need to be updated. + + +The good news is you've figured out what the problem is (at least what the problem is that's keeping you from debugging the real problem). The bad news is you now have to update your applications code to ensure the right log levels are being passed through to your error monitoring service. You have to save your code, re-deploy, then start re-testing. + + +That's a pretty terrible experience, but fortunately, it's one that Exceptionless has solved for you. + + +You can customize the log levels Exceptionless will track for you. ON. THE. FLY. You don't have to touch your code. Instead, should you run into the problem above, you can change your default log level and it will be applied immediately. Any new events coming through that match the level you set will now be stacked up and tracked for you. + +We recognize that every application is different. Every developer is different. Being able to easily customize the data captured through Exceptionless is an important part of our mission. This is why in v7.0.5, we have updated the user interface to support default log level selections. + +![Log Level Settings](log_level.png) + +As you can see in the image above, the current example default is "Warn." You can override that default on the Stacks page any time you'd like. But if you want to customize that default log level from the start and have it apply across the board, you can do so on your settings page. + +![Set Default Log Level on the Settings Page](setting.png) + +## Why Do Log Levels Matter + +Logging is key to understanding problems in your application, but it can also act as a historical record useful for post-mortems and general analysis. However, not all logs are important or necessary. And even if they are, you may want to filter them out in certain scenarios. + +Enter log levels. + +Log levels control what types of messages are logged. The general definition of log levels, and what we use at Exceptionless is: + +TRACE +DEBUG +INFO +WARN +ERROR +FATAL +OFF + +By setting your log levels, you are essentially saying you'd like to see information grouped into the buckets defined by the log level. For example, if you'd only like to log the most severe issues, you might select a log level of FATAL. + +We want to help you with this flow by automatically accepting or ignoring errors and messages that don't match the log levels you've defined in Exceptionless. We think this will help you better manage your exceptions, reporting, and overall development flow. We can't wait to hear your feedback. If there's any questions, suggestions, or general feedback, we'd love to hear from you. You can reply here or open an issue on Github. diff --git a/docs/news/2020/2020-10-29-comparing-monitoring-services.md b/docs/news/2020/2020-10-29-comparing-monitoring-services.md new file mode 100644 index 0000000000..bf7b22c2ee --- /dev/null +++ b/docs/news/2020/2020-10-29-comparing-monitoring-services.md @@ -0,0 +1,61 @@ +--- +title: "Comparing Monitoring Services" +date: 2020-10-29 +--- + +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: + +* [Log Rocket](https://logrocket.com) +* [Sentry](https://sentry.io) +* [Exceptionless](https://exceptionless.com) + +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. + +# Log Rocket + +[Log Rocket](https://logrocket.com) 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. + +> 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. + +- [Matthew Arbesfeld, co-founder of Log Rocket](https://techcrunch.com/2019/03/21/logrocked-nabs-11m-series-a-to-fix-web-application-errors-faster/?guccounter=1&guce_referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8&guce_referrer_sig=AQAAAIPY3DnugxcKUD8lyUXLl-FXSS29_pkxK32gWJb_Kp0lGk2YWj19tXm2PCHIjj4kFV6DBtRurKKebhBH5czcymF2Ct0k_D1UFvoJtxkD-76DSFmTqD07uaoxVS69YzFZLa-QsEcsoiwVbHWBFkLyRywxOBu8baLFu34hztJrZSCa) + +![Log Rocket example](log_rocket.png) + +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. + +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. + +# Sentry + +[Sentry](https://sentry.io) 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. + +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. + +![Sentry Example](sentry.png) + +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. + +One big differentiator for Sentry is its focus on providing services for a wide array of platforms. + +> 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. +- [Techcrunch, 2019](https://techcrunch.com/2019/09/24/sentry-raises-40-million-series-c-led-by-accel-for-its-error-tracking-software/) + +# Exceptionless + +[Exceptionless](https://exceptionless.com) has been around the longest of the three services reviewed here. Created as a software offering from the parent company [CodeSmith Tools](https://www.codesmithtools.com/), 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. + +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. + +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. + +Digging into the product features, Exceptionless provides one of the cleanest views for understanding events and errors in your application. + +![Example error details](/assets/img/event-occurrence-1024x791.jpg) + +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. + +# So Which One is Right For You? + +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. + +In the end, the choice is yours. \ No newline at end of file diff --git a/docs/news/2020/2020-11-11-self-hosted-error-monitoring-on-azure.md b/docs/news/2020/2020-11-11-self-hosted-error-monitoring-on-azure.md new file mode 100644 index 0000000000..a0a485b07f --- /dev/null +++ b/docs/news/2020/2020-11-11-self-hosted-error-monitoring-on-azure.md @@ -0,0 +1,180 @@ +--- +title: "Self Hosted Error Monitoring on Azure" +date: 2020-11-11 +--- + +# Self Hosted Error Monitoring on Azure + +We [previously wrote about](https://exceptionless.com/news/2020/2020-09-30-how-to-self-host-your-error-monitoring-service/) how to run a self-hosted instance of Exceptionless locally. Today, we are going to explore how to deploy a self-hosted instance to Azure. First, let's remind you what Exceptionless is and how it's different from other error monitoring services. + +## What is Exceptionless + +Exceptionless is a cloud-based error monitoring service that focuses on real-time data injestion and configuration. Exceptionless sets itself apart from the competition through its real-time pipeline and how it combines events to make them actionable through a process called stacking. + +Unlike most error monitoring services, Exceptionless is dedicated to the open-source community and the entire code base is available on Github to inspect, contribute to, or fork. And, of course, Exceptionless can be self-hosted. + +That last bit is what we'll be focusing on today. + +## Getting Started + +To start, you'll need to sign up for a Microsoft Azure account if you don't have one already. Head on over to [Azure's Cloud Computing site](https://azure.microsoft.com/en-us/) and sign up for a free account. You'll be asked to enter your card information, but you won't be charged unless you upgrade beyond their free plan. Once you've signed up, you'll be able to go to your portal and start a project. + +![Azure Portal](quickstart.png) {.text-center} + +Click on the "Deploy virtual machine" option. You'll then have the option to create a Linux virtual machine or a Window virtual machine. We're going to be using Linux for the sake of this tutorial, so go ahead and select that option. Now, we can configure our virtual machine (VM). + +![Configuration for VM](configuration.png) {.text-center} + +You can leave your Subscription option as the default selection. You will need to create a resource group. Click the "Create new" button beneath the resource group section. You'll need to give this group a name. We'll call it "Exceptionless". Next, we need to give our VM a name. You can name it whatever you'd like, but I'm going to keep it simple: `exceptionless-vm`. + +Next, you can change your Region if you'd like. I'm going to leave it set to the default. I will also leave my Availability Options and Availability Zone as the default. Make sure the image you select is Ubuntu Server 18.04 LTS. The next part is important. It's likely that the recommended VM instance selection is way too expensive and will blow through your free plan on Azure. You may find that you need to bump things up in the future, but for now, it's ok to start with the *B1s*. This machine will give you: + +* 1GB RAM +* 4 GB Temp Storage +* 1 CPU + +We're not doing heavy computations with our machine, so this should be fine. + +Now, you'll need to decide how you authenticate into your VM. I highly recommend SSH but you are welcome to use username and password. If you choose the SSH route, Azure can generate the keypair for you. The final step on this page is to select your allowed inbound ports. We will change this later. For now, we're going to allow SSH, HTTP, and HTTPS while we're getting set up. + +![Allowed Ports](ports.png) {.text-center} + +You can look through the other tabs in your configuration settings, but I'm going to leave everything as default. So, now we can click "Review and Create." + +You'll be asked to confirm your settings. Once you do, if you chose to authenticate with an SSH key, you'll be prompted to download this keypair. Please do so and store it somewhere safe and somewhere you'll remember. Your VM should be creating now. In a few minutes, it will be accessible. + +## Accessing Your VM + +When you VM is done creating, you'll be able to click the Go To Resource button. Otherwise, when you log into your Azure account, it will be displayed as a Recent Resource: + +![Recent Resources on Azure](resources.png) {.text-center} + +Once you go to your VM resource, you'll see a Connect button at the top of the screen. Click that and you'll see instructions for connection. You'll follow the appropriate instructions for your chosen method of authentication. For me, I'll be following the SSH instructions and will document those here. + +Open the terminal client of your choice and enter the following: + +`chmod 400 PATH_TO_PEM_FILE` + +Now you can connect as a root user: + +`ssh -i azureuser@PUBLIC_IP` + +Your IP address will be listed on your Azure resource page. + +If all went well, you have now accessed your VM. However, we are accessing our machines as the root user. This isn't the best idea. So, we're going to create a new user and we will run all of our commands, installations, etc with this new user. + +`sudo adduser USERNAME` + +You'll be prompted to enter a password for this user and confirm that password. Go ahead and do that. When you're done, you'll be prompted to enter the user's information. You can just hit Enter to bypass selections here. + +Now, when you SSH into your VM, you can log in as the user you create like this: + +`sudo login` + +Now, let's give our new user admin privledges. + +`sudo usermod -aG sudo USERNAME` + +With all of this complete, we should be ready to install dependencies! + +## Installing Dependencies + +The first thing we need to do is update our Linux instance. To do that, simply run the following command: + +`sudo apt-get update` + +Next, we're going to install dependencies for Docker, which we will use to help us self-host Exceptionless. + +```bash +sudo apt-get install \ + apt-transport-https \ + ca-certificates \ + curl \ + gnupg-agent \ + software-properties-common +``` + +Now, we need to add Docker's official GPG key. [Per their docs](https://docs.docker.com/engine/install/ubuntu/), we should run: + +`curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -` + +We should verify the fingerprint for the GPG key by running the following: + +`sudo apt-key fingerprint 0EBFCD88` + +The next step requires us to know the architecture our VM is running on. You can confirm this by running the following command: + +`dpkg --print-architecture` + +You should be running on an amd64 machine. But just to be safe, we'll include the instructions for amd64, armhf, and arm64. + +**amd64** + +```bash +sudo add-apt-repository \ + "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) \ + stable" +``` + +**armhf** + +```bash +sudo add-apt-repository \ + "deb [arch=armhf] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) \ + stable" +``` + +**arm64** + +```bash +sudo add-apt-repository \ + "deb [arch=arm64] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) \ + stable" +``` + +Now, we'll need to run our update command again and then move on to installing the Docker engine. + +`sudo apt-get update` + +To install the engine, run: + +`sudo apt-get install docker-ce docker-ce-cli containerd.io` + +Let's make sure Docker was installed successfully. Run the following to test a Docker image: + +`sudo docker run hello-world` + +If you see the results "Hello from Docker!" you're good to go. + +## Running Exceptionless + +There are [three options for running a self-hosted Exceptionless instance](https://exceptionless.com/docs/self-hosting/). The first option is for testing only and will delete data between restarts. The second option retains data on disk between restarts. The third option retains data and enables email notifications. + +We're going to skip the first option and email alerts and setup is a bit more advanced than this tutorial cares to go. So, we will go with the second option. + +Per the Exceptionless documentation, this set up: + +> ...runs a simple version of Exceptionless with data persisted between runs in a sub-directory of the current directory called esdata. It uses an embedded single node Elasticsearch cluster and does not have backups. It is recommended that you create your own Elasticsearch cluster for production deployments of Exceptionless. + +While it may be recommended that we run our own Elasticsearch cluster, we're not going to do that in this tutorial. + +So, let's get it going! + +Run the following command: + +```bash +sudo docker run --rm -it -p 5200:8080 \ + -v $(pwd)/esdata:/usr/share/elasticsearch/data \ + exceptionless/exceptionless:latest +``` + +After some initial installation, you should see a constant log output indicating that Exceptionless is running. Congratulations, the first big hurdle has been overcome! + +Now, we need to figure out how to access our instance from the outside world. It's cool to see it running in our VM, but we don't want to SSH in when we want to send events, right? Let's take care of that now. + +## Opening Ports + +If you remember, we didn't really lock down our ports when setting up our VM. We're going to make sure we can access port 5200 and lock everything else down. In reality, you'll probably want to put this all behind Nginx and only allow access to the port from specific IP addresses, but that's beyond the scope of this tutorial. diff --git a/docs/news/2020/2020-12-7-why-you-should-be-practicing-exception-driven-development.md b/docs/news/2020/2020-12-7-why-you-should-be-practicing-exception-driven-development.md new file mode 100644 index 0000000000..5bc9d8c654 --- /dev/null +++ b/docs/news/2020/2020-12-7-why-you-should-be-practicing-exception-driven-development.md @@ -0,0 +1,63 @@ +--- +title: "Why You Should be Practicing Exception Driven Development" +date: 2020-12-07 +--- + +# Why You Should be Practicing Exception Driven Development + +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. + +## Exception Driven Development + +Jeff Atwood, of [Coding Horror](https://blog.codinghorror.com/), wrote a [blog post](https://blog.codinghorror.com/exception-driven-development/) 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. + +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. + +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. + +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. + +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? + +## Why Exception Driven Development + +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: + +> The question isn't how many bugs you will ship but how fast you can fix them. + +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. + +Wait, what? + +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. + +You don't want to turn into this guy, right? + +![Picture of an angry cat acting as tech support](tech_support.png) {.text-center} + +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. [That is possibly how many bugs](https://www.quora.com/What-is-the-average-ratio-of-bugs-to-a-line-of-code) you have in your software *right now*. Knowing this, don't you think it's important to try to find these bugs before your users have to tell you about them? + +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? + +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? + +## How to Practice Exception Driven Development + +If you remember, the first step of exception-driven development is to collect *contextual* 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: + +* What user had this problem? +* Where in the application did the problem occur? +* Has the problem occurred previously? +* What actions did the user take leading up to the issue? + +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 [Exceptionless](https://exceptionless.com) make this easy. + +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 [Exceptionless](https://exceptionless.com) is. + +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 **almost** distracted you. + +Once your code is shipped, if you are using [Exceptionless](https://exceptionless), 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. + +## Conclusion + +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. \ No newline at end of file diff --git a/docs/news/2020/dashboard_7_0.png b/docs/news/2020/dashboard_7_0.png new file mode 100644 index 0000000000..687a79678e Binary files /dev/null and b/docs/news/2020/dashboard_7_0.png differ diff --git a/docs/news/2020/log_level.png b/docs/news/2020/log_level.png new file mode 100644 index 0000000000..e51238689d Binary files /dev/null and b/docs/news/2020/log_level.png differ diff --git a/docs/news/2020/log_rocket.png b/docs/news/2020/log_rocket.png new file mode 100644 index 0000000000..2a39823ef3 Binary files /dev/null and b/docs/news/2020/log_rocket.png differ diff --git a/docs/news/2020/navigation.png b/docs/news/2020/navigation.png new file mode 100644 index 0000000000..5ce5f5abf9 Binary files /dev/null and b/docs/news/2020/navigation.png differ diff --git a/docs/news/2020/sentry.png b/docs/news/2020/sentry.png new file mode 100644 index 0000000000..49d83066f8 Binary files /dev/null and b/docs/news/2020/sentry.png differ diff --git a/docs/news/2020/setting.png b/docs/news/2020/setting.png new file mode 100644 index 0000000000..89ab5a187f Binary files /dev/null and b/docs/news/2020/setting.png differ diff --git a/docs/news/2020/status.png b/docs/news/2020/status.png new file mode 100644 index 0000000000..5bdc677651 Binary files /dev/null and b/docs/news/2020/status.png differ diff --git a/docs/news/2020/statuses.png b/docs/news/2020/statuses.png new file mode 100644 index 0000000000..5ed7a7f73f Binary files /dev/null and b/docs/news/2020/statuses.png differ diff --git a/docs/news/2020/tech_support.png b/docs/news/2020/tech_support.png new file mode 100644 index 0000000000..0675927e14 Binary files /dev/null and b/docs/news/2020/tech_support.png differ diff --git a/docs/news/2021/2021-01-12-debugging-a-.net-serverless-app.md b/docs/news/2021/2021-01-12-debugging-a-.net-serverless-app.md new file mode 100644 index 0000000000..52a86a8b11 --- /dev/null +++ b/docs/news/2021/2021-01-12-debugging-a-.net-serverless-app.md @@ -0,0 +1,187 @@ +--- +title: "Debugging a .NET Serverless App" +date: 2021-01-12 +--- + +# Debugging a .NET Serverless App + +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. + +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. + +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 `dotnet` cli to install a new Lambda template, but first we need to make sure we have the [Amazon Lambda Templates Package](https://www.nuget.org/packages/Amazon.Lambda.Templates). + +Once that's installed, create a new directory. I'm calling mine `MyFunction`, but you can call yours whatever you'd like. Change into that directory and run the following command: + +`dotnet new lambda.EmptyFunction --name MyFunction` + +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 `Function.cs`. You'll also have a *very* helpful README, and a json file with some default configuration. We're not going to be editing anything besides the `Function.cs` file, but it's good to know what's provided out of the box when generating a new lambda project. + +We now need to add [Exceptionless](https://exceptionless.com?utm_source=serverless-blog-post) 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: + +`dotnet add package Exceptionless` + +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. + +Open up the `Function.cs` file again and add the Exceptionless namespace like this: + +`using Exceptionless;` + +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. + +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: + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Exceptionless; + +using Amazon.Lambda.Core; + +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace MyFunction +{ + public class Function + { + public async Task FunctionHandler(string input, ILambdaContext context) + { + var client = new ExceptionlessClient(c => + { + c.ApiKey = "YOUR EXCEPTIONLESS API KEY"; + }); + + await using var _ = new ProcessQueueScope(client); + + try + { + if (input == null) + { + throw new Exception("input value is required"); + } + return "Hello, " + input + "!"; + } + catch (Exception ex) + { + client.SubmitException(ex); + return ex.Message; + } + } + } + + internal class ProcessQueueScope : IAsyncDisposable { + private readonly ExceptionlessClient _exceptionlessClient; + + public ProcessQueueScope(ExceptionlessClient exceptionlessClient) { + _exceptionlessClient = exceptionlessClient; + } + + public async ValueTask DisposeAsync() { + await _exceptionlessClient.ProcessQueueAsync(); + } + } +} +``` + +We've added the Exceptionless namespace, we've converted the function to take in a string and return a hello world string. + +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. + +Because we need to make sure events are sent to Exceptionless before the function ends, we are using the `ProcessQueueScope` instance. This helper class processes the internal queue when the `FunctionHandler` is disposed. + +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 `test` folder. Nested in that folder is a test file called `MyFunction.Test.cs`. We're going to edit this file a bit and run our tests from the command line. + +Update the file to look like this: + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Xunit; +using Amazon.Lambda.Core; +using Amazon.Lambda.TestUtilities; + +using MyFunction; + +namespace MyFunction.Tests +{ + public class FunctionTest + { + [Fact] + public async Task HelloWorldFunction() + { + var function = new Function(); + var context = new TestLambdaContext(); + var upperCase = await function.FunctionHandler("John", context); + + Assert.Equal("Hello, John!", upperCase); + } + } +} +``` + +This test should pass and we should not be sending anything to Exceptionless. To test it, switch into `MyFunction/test/MyFunction.Tests` and run `dotnet test`. + +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. + +Add the following to your test file: + +```csharp + public class ErrorTest +{ + [Fact] + public async Task ErrorFunctionTest() + { + var function = new Function(); + var context = new TestLambdaContext(); + var helloworld = await function.FunctionHandler(null, context); + + Assert.NotEqual("Hello, John!", helloworld); + } +} +``` + +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. + +Open up your Exceptionless dashboard and you should see something like `Exception in FunctionHandler input value is required`. If you click on it, you'll see more details like this: + +![Event Occurrence](exception.png) + +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. + +Cool, so we created an exception. What about something a little more complex? + +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: + +```csharp + try +{ + if (input == null) + { + throw new Exception("input value is required"); + } + client.SubmitFeatureUsage("Serverless Function"); + return "Hello, " + input + "!"; +} +catch (Exception ex) +{ + client.SubmitException(ex); + return ex.Message; +} +``` + +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. + +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. + +In our dashboard, if we look at all event, we will see our feature usage event logged. + +![Feature usage event example](featureUsage.png) + +## Conclusion + +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 [Exceptionless](https://exceptionless.com) 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 [here](https://github.com/exceptionless/Exceptionless.Net/tree/master/samples/Exceptionless.SampleLambda) and [here](https://github.com/exceptionless/Exceptionless.Net/tree/master/samples/Exceptionless.SampleLambdaAspNetCore). diff --git a/docs/news/2021/2021-01-19-how-to-use-react-hooks-to-monitor-events-in-your-app.md b/docs/news/2021/2021-01-19-how-to-use-react-hooks-to-monitor-events-in-your-app.md new file mode 100644 index 0000000000..8464d4bbdf --- /dev/null +++ b/docs/news/2021/2021-01-19-how-to-use-react-hooks-to-monitor-events-in-your-app.md @@ -0,0 +1,234 @@ +--- +title: "How to Use React Hooks to Monitor Events in Your App" +date: 2021-01-19 +--- + +# How to Use React Hooks to Monitor Events in Your App + +The [introduction of Hooks in React](https://reactjs.org/docs/hooks-intro.html) 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. + +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 [Exceptionless](https://exceptionless.com) for three reasons: + +1. Real-time updates +2. It's open-source +3. The Exceptionless JavaScript client gives us a singleton option (which makes for a good example in this post) + +Let's get started by starting a new React project. You'll need to have the following available on your machine: + +* Node >= 8.10 +* npm >= 5.6 +* Text editor + +Assuming you have that ready, open up a terminal. To create a new React project, simply run: + +`npx create-react-app Monitoring-App` + +Replace `Monitoring-App` with whatever you'd like to call your project. When everything is done, change into your new application's directory (`cd Monitoring-App`). Now, we need to install the Exceptionless JavaScript client. + +To do so, simple run: + +`npm install exceptionless` + +When that's done installing, start your app (`npm start`) and open your project directory in the text editor of your choice. + +### What are Hooks? + +React's docs have the simplest definition of Hooks and I think it's worth calling that out here: + +> Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. + +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 *anything*. 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. + +Hooks introduced a new way to handle lifecycle events in React as well. Gone are the `componentDidMount` and `componentDidUpdate` methods. In is the simple and elegant `useEffect` function. + +You can read a lot more about the logic behind React's introduction of hooks [here](https://reactjs.org/docs/hooks-intro.html), but for the sake of this tutorial, I think that's enough of an intro. + +## Creating our first Hook + +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 `hooks`. Let's do that. + +Create a folder within the `src` directory of your project called `hooks`. 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 `useFunctionPurpose` 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 `useNavigation`. For us, we're going to call our file `useMonitoring`. + +Create that file inside the `hooks` 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. + +`import { useState, useEffect } from 'react';` + +I briefly touched on `useEffect`. It can be thought of in the same context as `componentDidMount` or `componentDidUpdate`. We'll make use of this to handle some logic in the setup of our Exceptionless client. `useState` can be thought of like `this.state` and `this.setState` in React class components. + +Next, we'll get access to the Exceptionless JavaScript client like this: + +`import { ExceptionlessClient } from "exceptionless/dist/exceptionless";` + +Note: it's important to reference the `/dist/exceptionless` file because Exceptionless targets multiple environments and we want to make sure to import the right one. + +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 every time 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 `default` client from Exceptionless like this: + +`const defaultClient = ExceptionlessClient.default;` + +If you haven't done so, get yourself an API Key from Exceptionless. You can [sign up for a free account here](https://exceptionless.com). 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: + +`defaultClient.config.apiKey = process.env.REACT_APP_EXCEPTIONLESS_API_KEY;` + +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: + +```javascript +export const useMonitoring = ({ config, useDefault }) => { + // Code goes here +} +``` + +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: `config` and `useDefault`. If we are making use of the default singleton instance of the Exceptionless client, `useDefault` would be true and `config` would be null. However, if we are creating a custom instance of the Exceptionless client, `config` would be an object and `useDefault` would be either null or false. + +Let's handle that logic. At the top of your function add the following: + +`const [client, setClient] = useState(defaultClient);` + +We are making use of the built-in `useState` hook here. We are simply defining a `client` state variable, defining a function that will be used to update that variable (`setClient`), 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? + +Next, we're going to use the built-in `useEffect` hook to determine what client should be returned for use in the particular part of the app that requested it. + +```javascript +useEffect(() => { + if(useDefault) { + return client; + } else if(config) { + config.apiKey = process.env.REACT_APP_EXCEPTIONLESS_API_KEY; + setClient(new ExceptionlessClient(config)); + } else { + throw "Please pass useDefault as true or a config object in"; + } + }); +``` + +In this case, it's best to think of our `useEffect` function in the same way you think of `componentDidUpdate`. Any update to the component that called our `useMonitoring` Hook will trigger another event within our `useEffect` function. + +If you wanted this `useEffect` method to operate more like `componentDidMount`, you would structure it like this: + +```javascript +useEffect(() => { + +}, []) // <-- This array says only run this function once when the component mounts +``` + +The empty array in the above example can be filled with a list of dependencies. Say, for example, you want your `useEffect` method to run everytime some specific variable changes, you would just pass that variable name into the array. + +Ok back to our `useEffect` method. You can see we are checking the `useDefault` 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 `useDefault` 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. + +If no `config` object is provided, we throw an error. You could take this a step further and check if the `config` 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. + +The final thing you need to do in your `useMonitoring` function is return the client. Just as easy as it sounds: + +`return client;` + +Here's the whole, complete file: + +```javascript +import { useState, useEffect } from 'react'; +import { ExceptionlessClient } from "exceptionless/dist/exceptionless"; +const defaultClient = ExceptionlessClient.default; +defaultClient.config.apiKey = process.env.REACT_APP_EXCEPTIONLESS_API_KEY; + +export const useMonitoring = ({ config, useDefault }) => { + const [client, setClient] = useState(defaultClient); + useEffect(() => { + if(useDefault) { + return client; + } else if(config) { + config.apiKey = process.env.REACT_APP_EXCEPTIONLESS_API_KEY; + setClient(new ExceptionlessClient(config)); + } else { + throw "Please pass useDefault as true or a config object in"; + } + }); + return client; +} +``` + +Ready to use this bad boy? + +## Using your custom Hook + +We created a basic React app, so let's just make use of what comes out of the box. Open your `App.js` file, and import your new custom Hook. + +`import { useMonitoring } from "./hooks/useMonitoring";` + +You'll also need to import the built-in `useEffect` Hook from React: + +`import { useEffect } from 'react';` + +Now, withing the main `App` function, you can use your new custom Hook: + +`const exceptionlessClient = useMonitoring({ useDefault: true });` + +How can we test this now? Well, let's make use of the `useEffect` function to throw an error as soon as the component mounts. + +```javascript +useEffect(() => { + throwException(); +}, []); +``` + +As you remember, the empty array at the end of the function says this should only run once when the component mounts. + +Now, define the actual `throwException` function like this: + +```javascript +const throwException = () => { + try { + throw new Error("Whoops, it broke"); + } catch (error) { + exceptionlessClient.submitException(error); + } +} +``` + +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. + +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. + +![Example exception from React app](example_react_exception.png) + +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. + +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 `useMonitoring` hook. + +But Exceptionless is more than just errors. Let's build a quick, more practical example. + +## Usage Tracking + +In your `App.js` file, we're going to remove all the boilerplate and add some ugly buttons. No styling in this post. This is what your `App.js` file should look like now: + +```javascript +import { useMonitoring } from "./hooks/useMonitoring"; + +function App() { + const exceptionlessClient = useMonitoring({ useDefault: true }); + + const handleButtonClick = (planName) => { + exceptionlessClient.submitFeatureUsage(planName); + } + return ( + + + + + + + + ); +} + +export default App; +``` + +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. + +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. + +![Feature usage example](feature_usage_react.png) + +## Wrapping up + +There is a lot more you can do with Exceptionless. For example, you may have noticed, we have only passed in the `useDefault` prop to our custom Hook. You can completely customize your Exceptionless configuration and pass in a `config` prop instead. I would encourage you to [read up on the options here](https://exceptionless.com/docs/clients/javascript/client-configuration/). + +Exceptionless [provides a lot of methods](https://exceptionless.com/docs/clients/javascript/sending-events/) built into its JavaScript client that will make debugging, logging, and tracking easier. diff --git a/docs/news/2021/2021-01-26-saying-thanks-to-the-open-source-community-through-sponsorship.md b/docs/news/2021/2021-01-26-saying-thanks-to-the-open-source-community-through-sponsorship.md new file mode 100644 index 0000000000..be422d0815 --- /dev/null +++ b/docs/news/2021/2021-01-26-saying-thanks-to-the-open-source-community-through-sponsorship.md @@ -0,0 +1,62 @@ +--- +title: "Saying Thanks to the Open Source Community Through Sponsorship" +date: 2021-01-26 +--- + +# Saying Thanks to the Open Source Community Through Sponsorship + +Exceptionless has always been committed to the open-source software ecosystem. In fact, [Exceptionless is entirely open-source](https://github.com/Exceptionless), 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. + +## Thanking Open Source Contributions Through Sponsorship + +Today, we're excited to announce that [we have sponsored Ben Adams](https://github.com/sponsors/benaadams) 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. + +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. + +"Thanks" doesn't pay the bills. Exposure doesn't pay the bills. + +We don't want to see open-source developers shut down their projects. We want developers to have optionality. [A quote from Kitze](https://medium.com/@kitze/github-stars-wont-pay-your-rent-8b348e12baed), the founder of Sizzy and other products, really illustrates this sentiment well: + +> 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. + +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. + +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. + +## Ben Adams + +![Ben Admas Github Profile](./benadams.png) + +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: + +* His projects have 2,600 Github stars (which, again, don't pay the bills 😉) +* He has over 20,000 commits +* He has contributed to 25 different projects +* He's opened over 1,500 pull requests + +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. + +For the gamers and the game developers, Ben has you covered too. He is the CTO of Illyriad Games which makes [Age of Ascent](https://www.ageofascent.com/). 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 [makes heavy use of .NET](https://youtu.be/dqYlKkexth0) and other Microsoft-related services. + +Other people recognize Ben's contributions too: + +> Since the beginning of the .NET Core journey we’ve had some amazing contributors but I seriously enjoy working with +@ben_a_adams! +-[David Fowler](https://twitter.com/davidfowl/status/1353087429364879361) + +> There's smart, then there's crazy. Then there's Crazy Smart. That's Ben (and he's a lovely chap, too)! +-[Rich Turner](https://twitter.com/bitcrazed/status/1354144181837414400) + +> Junior .Net Developer +Senior .Net Developer +Ben Adams .Net Developer +😁 😁 😁 +-[Marco Rossignoli](https://twitter.com/MarcoRossignoli/status/1166733777206468608) + +## How Does Sponsorship Work? + +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. + +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. + +Thanks so much, Ben! We look forward to working with you and following your continued contributions across the open-source community. diff --git a/docs/news/2021/2021-02-22-how-to-debug-electron-apps.md b/docs/news/2021/2021-02-22-how-to-debug-electron-apps.md new file mode 100644 index 0000000000..8ef474a878 --- /dev/null +++ b/docs/news/2021/2021-02-22-how-to-debug-electron-apps.md @@ -0,0 +1,48 @@ +--- +title: "How to Debug Electron Apps" +date: 2021-02-22 +--- + +# How to Debug Electron Apps + +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. + +If you're not familiar with [Electron](https://www.electronjs.org/), 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. + +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. + +We're going to be making use of [Exceptionless](https://exceptionless.com) 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. + +From within your Electron app's project directory run `npm i exceptionless`. + +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 `main.js` file, add the following below your other import/require statements: + +``` +const { ExceptionlessClient } = require("exceptionless") +const client = ExceptionlessClient.default.config.apiKey = "YOUR API KEY" +``` + +You can get your project API key in the Exceptionless project settings page. + +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 `client.submitLog("Function called")` 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 `client.submitException(error)` with your error. + +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 `ipcMain` to listen for events from the frontend code. An example of this might look like: + +```javascript +ipcMain.on("Save File", async (event, message) => { + try { + await fs.writeFileSync("/path/to/where/you/want/to/store/the/file", message) + client.submitLog(`Wrote file successfully with the following content: ${message}`) + } catch(e) { + client.submitException(e) + } +}); +``` + +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. + +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 `writeFileSync` 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. + +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. + +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. \ No newline at end of file diff --git a/docs/news/2021/2021-03-24-how-to-build-a-custom-go-api-client.md b/docs/news/2021/2021-03-24-how-to-build-a-custom-go-api-client.md new file mode 100644 index 0000000000..a382ab41de --- /dev/null +++ b/docs/news/2021/2021-03-24-how-to-build-a-custom-go-api-client.md @@ -0,0 +1,212 @@ +--- +title: "How to Build a Custom Go Client For a REST API" +--- + +# How to Build a Custom Go Client For a REST API + +![Picture of gophers working](./go_gophers.jpg) + +[Exceptionless](https://exceptionless.com) 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. + +First, a little about Go. [Go](https://golang.org/) 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 [gRPC APIs](https://www.programmableweb.com/news/what-grpc-api-and-how-does-it-work/analysis/2020/10/08), but that does not prevent it from being used with REST APIs, as we'll see here today. + +### Getting Started + +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. + +[You can find those instructions here](https://golang.org/doc/install). + +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. + +### The Main File + +In Go, you will always have a `main.go` 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 `main.go` file. Inside that file, let's start by declaring our package and importing a module. Add the following: + +```go +package main + +import ( + "fmt" +) +``` + +Your file won't do anything yet, but we're laying the groundwork. We have declared our package as `main`, and we have imported the built-in `fmt` library from Go for formatting. + +Next, we need a `main` function, so let's create that. Add the following below your import statement: + +```go +func main() { + fmt.Println("Hello, world") +} +``` + +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: + +``` +go run . +``` + +You should see `Hello, world` printed in the command line terminal window. + +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 `main.go` 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. + +### Creating an API Helper + +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. + +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 `api.go`. + +Inside that file, make sure to reference the main package at the top like this: + +`pacakage main` + +We are also going to import a couple packages here as well, so your file should look like this: + +```go +package main + +import ( + "bytes" + "log" + "net/http" +) +``` + +These packages are all built into Go itself. You can install external packages as well, and we'll explore that soon. + +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: + +* GET +* POST +* PUT +* DELETE +* PATCH + +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. + +Let's start by building the POST method since its the backbone of our client. In your `api.go` file, below the import statement, add the following: + +```go +//Post posts to the Exceptionless Server +func Post(endpoint string, postBody string, authorization string) string { + baseURL := "YOUR API URL/" + url := baseURL + endpoint + var jsonStr = []byte(postBody) + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) + req.Header.Set("Authorization", "Bearer "+authorization) + req.Header.Set("Content-Type", "application/json") + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + return string(resp.Status) +} +``` + +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 `postBody` is of type `string`. If your API is expecting a different format, make sure you type your variable properly here. The other two arguments in our `Post` function are pretty self explanatory. The `endpoint` string is the endpoint on your API you want to call. The `authorization` 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. + +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 `bytes.NewBuffer(jsonStr)` call. + +Now, let's put together our `GET` function: + +```go +//GET makes api GET requests +func Get(endpoint string, authorization string) map[string]interface{} { + baseURL := "YOUR API URL/" + + url := baseURL + endpoint + + httpClient := &http.Client{} + req, err := http.NewRequest("GET", url, nil) + + if err != nil { + fmt.Println(err) + } + + req.Header.Add("accept", "application/json") + req.Header.Add("Authorization", "Bearer "+authorization) + + res, err := httpClient.Do(req) + if err != nil { + fmt.Println(err) + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + } + + var result map[string]interface{} + json.Unmarshal([]byte(body), &result) + return result +} +``` + +Much like out `POST` request, our `GET` request takes in arguments. We only need the `endpoint` and the `authorization` 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. + +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 `json.Unmarshal()` as shown above. + +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. + +## Convenience Functions + +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: + +```json +{ + "BookTitle": "The Great Gatsby", + "Author": "F. Scott Fitzgerald", + "Rating": 7 +} +``` + +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: + +```go +type BookRating struct { + BookTitle string + Author string + Rating uint +} +``` + +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. + +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 `POST` 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: + +```go +func RateBook(title string, author string, rating uint): bool { + newRating := BookRating{ + BookTitle: title, + Author: author, + Rating: rating + } + + json, err := json.Marshal(newRating) + if err != nil { + fmt.Println(err) + return false + } + + resp, err := Post("rateBook", string(json), "API KEY") + if err != nil { + fmt.Println(err) + return false + } + + return true +} +``` + +In the `RateBook` 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 `Post` function we created earlier. When we are building the JSON payload, we must use `json.Marshal` to convert our struct to a type that can be used with our REST API. + +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 `Configure` function with the developer's API Key and storing the key in memory. + +## Wrapping Up + +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, [give it a shot now](https://exceptionless.com). + + diff --git a/docs/news/2021/2021-04-02-how-to-monitor-events-in-swift.md b/docs/news/2021/2021-04-02-how-to-monitor-events-in-swift.md new file mode 100644 index 0000000000..2a45518911 --- /dev/null +++ b/docs/news/2021/2021-04-02-how-to-monitor-events-in-swift.md @@ -0,0 +1,323 @@ +--- +title: "How To Monitor Events in Swift" +date: 2021-04-02 +--- + +# How To Monitor Events in Swift + +Swift, best known as the programming language that enables iOS, iPadOS, and macOS developers to build apps, has been growing in popularity over the years. [As of February of 2020](https://www.zdnet.com/article/programming-language-popularity-apples-objective-c-tumbles-down-the-rankings/), it had leaped into the top-10 of most popular programming languages. While Swift can be used for more than just Apple platform products, we're going to keep things simple today and focus on how to set up event monitoring with Swift in an iOS app. + +For this tutorial, we're going to be using [Exceptionless to collect events, so you'll need to sign up for a free account here](https://exceptionless.com). You're also going to need the following: + +* Mac computer (sorry Windows and Linux folks) +* Xcode +* Xcode command line tools + +## Getting Set Up + +If you don't already have Xcode installed on your Mac, do so now. [You can grab an install here](https://developer.apple.com/xcode/). If you already have it installed, you will need to make sure you are upgraded to Xcode 12. To check your version, open Xcode and check to see that you have version 12 or above. It'll look like this: + +![Xcode version](./xcode_version.png) + +Once you're done installing it, you can check that everything was successful by either firing up Xcode or running the command I showed above. Now, we need to make sure you have the Xcode command line tools. These should be installed automatically when you install Xcode, but we want to be sure. To check if these were installed, run the following in Terminal: + +``` +xcode-select -p +``` + +If a path is printed out, you're all good. That's all you need. Open up Xcode, and we'll get started. + +## Creating a Project + +Once you've opened Xcode, you're going to create a new project. Choose iOS and choose App, then click Next. + +![iOS app creation in Xcode](./create_app.png) + +Next, you'll give the app a name in the Product Name section. I'll call mine Exceptionless Events. Make sure your interface is SwiftUI, your lifecycle is SwiftUI App, and your language is Swift. Then, click Next. + +You'll be asked where you want to store your code. Choose a folder that makes sense for you. When you've done that, your new project will load up. It should look like this: + +![Example iOS project](./example_project.png) + +We're not going to spend a lot of time building an actual iOS app here, but we'll add enough functionality to test errors and test logging events. To set ourselves up, we're going to create two buttons in the UI. So, inside your `ContentView.Swift` file, replace the `Text` element with this: + +```swift +VStack{ + Spacer() + Button(action: {}) { + Text("Log Message") + } + Spacer() + Button(action: {}) { + Text("Log Error") + } + Spacer() +} +``` + +Note: the `Spacer` items are just there to make the screen a little more manageable (not necessarily prettier). Each button has a label and each has an action. However, the actions don't do anything just yet. We'll get that taken care of next. + +Above your `body` declaration, add these two functions: + +```swift +private func submitEvent() { + print("event") +} +private func submitError() { + print("error") +} +``` + +Then, back inside your body, change each button's action to call the associated function like this: + +```swift +VStack{ + Spacer() + Button(action: submitEvent) { + Text("Log Message") + } + Spacer() + Button(action: submitError) { + Text("Log Error") + } + Spacer() +} +``` + +Just to test that everything is working, click the play button at the top of the Xcode window. This will build the app and launch a simulator. Click each button and make sure "event" and "error" print out in the console. Pro tip: the console may be shrunk down and hidden. At the bottom of your Xcode window, hover over the section that looks like this and drag to increase the window size so you can see the console. + +![console example](./console.png) + +Assuming all is working, we can move on to using Exceptionless! + +## Creating the Exceptionless Class + +We're going to handle all of the event processing and posting through a single class. You may want to refactor into multiple classes in a production project, but this will get the point across, I think. + +Let's create a new file. In the file menu bar, click File, New, File, and be sure to choose a Swift file and not SwiftUI. Let's name the new file `Exceptionless.swift`. + +Inside that file, we're going to create our `Exceptionless` class. Add the following so your file looks like this: + +```swift +import Foundation + +class Exceptionless { + var apiKey: String + init(apiKey: String) { + self.apiKey = apiKey + } + + func submit(type: String, event: String) { + switch type { + case "log": + print("log") + case "error": + print("error") + default: + print("log") + } + } + + private func logMessage(logMessage: String) { + + } + + private func logError(errorEvent: String) { + + } +} +``` + +This class doesn't do anything besides accept the Exceptionless API key, but you can see we're starting to frame out how to build our event monitoring system. To keep things simple, the `submit` function accepts a type of event (in string form) and it accepts the event string. The event string for the purposes of this example should be a simple log message or error message. + +Let's test what we have out so far. We want to connect our two buttons from earlier to the function, `submit`, that we created in the `Exceptionless` class. We should see the console print out "log" or "error" depending on what button we press. + +Back inside your `ContentView.swift` file, replace the actions for each button like this: + +```swift +var body: some View { + VStack{ + Spacer() + Button(action: {Exceptionless.init(apiKey: "YOUR API KEY").submit(type: "log", event: "Log Message")}) { + Text("Log Message") + } + Spacer() + Button(action:{Exceptionless.init(apiKey: "YOUR API KEY").submit(type: "error", event: "Log Error")}) { + Text("Log Error") + } + Spacer() + } +} +``` + +This is a very simplified example. In reality, your buttons would be calling some other action and you'd be catching errors or logging events dependent on what that action does. Let's test this out, though. We don't actually need an API Key yet, so leave the `apiKey` string as is. Run your project on a simulator and click each button. You should see "log" and "error" printed in the console. + +Congratulations! You just built a class within Swift that will act as the framework for submitting events. + +## Building Events + +We're going to keep things simple. [The Exceptionless API](https://api.exceptionless.io/docs/index.html) has some great documentation and some simple examples that we'll be making use of. Let's start by updating out switch statement to actually call the functions specific to events or errors: + +```swift +func submit(type: String, event: String) { + switch type { + case "log": + return logMessage(logMessage: event) + case "error": + return logError(errorEvent: event) + default: + print("log") + } +} +``` + +You can do whatever you'd like with your default case. I'm going to keep it as a print statement, though. What we've done is we've said if we call `submit` with a type of "log", we will call the `logMessage` function. If we call `submit` with a type of "error", we will call the `logError` function. + +Let's build out the `logMessage` function fist. Replace the existing empty function with this: + +```swift +private func logMessage(logMessage: String) { + let now = Date() + let formatter = ISO8601DateFormatter() + let datetime = formatter.string(from: now) + let eventDictionary : [String: Any] = [ "type": "log", "message":logMessage, "date": datetime ] + let jsonData = (try? JSONSerialization.data(withJSONObject: eventDictionary, options: []))! + let jsonString = String(data: jsonData, encoding: String.Encoding.ascii)! + print (jsonString) +} +``` + +Because the Exceptionless API takes JSON body payloads, we want to build our event into JSON. To do that, we first start with a dictionary. As you can see, we are creating an `eventDictionary` which is simply keyvalue pairs in string format. We add in the date in ISO format so we know when our events happen. The actual event message is what we passed in all the way back from when we clicked the button. + +We take that dictionary and convert it to JSON with Swift's built-in `JSONSerialization` function. Before posting to the API, let's take a look at the output in the console and make sure we're happy with it. + +Build and run the app, then click "Log Message". You should see the following printed in the console: + +``` +{"message":"Log Message","date":"2021-04-05T13:34:39Z","type":"log"} +``` + +Your date will, of course, be different. + +Ok, we've gotten this far. Let's build our error function. Don't worry, we'll come back and think about how we want to actually post these events to Exceptionless. + +Replace the empty `logError` function with this: + +```swift +private func logError(errorEvent: String) { + let now = Date() + let formatter = ISO8601DateFormatter() + let datetime = formatter.string(from: now) + + let errorDictionary : [String: Any] = ["message": errorEvent, "type": "System.Exception"] + + let errorJson = (try? JSONSerialization.data(withJSONObject:errorDictionary, options: []))! + let errorJsonString = String(data: errorJson, encoding: String.Encoding.ascii)! + let eventDictionary : [String: Any] = [ "type": "error", "@simple_error":errorJsonString, "date": datetime ] + let jsonData = (try? JSONSerialization.data(withJSONObject: eventDictionary, options: []))! + let jsonString = String(data: jsonData, encoding: String.Encoding.ascii)! + print (jsonString) +} +``` + +You'll see this function is very similar to the `logMessage` function. However, we are nesting data in our JSON, so we need two dictionaries. We use one dictionary to house the "@simple_error" and another to house the entire event. In other words, nest the JSON version of our `errorDictionary` inside the JSON version of our `eventDictionary`. + +Let's build and run the app and try both buttons. You should see the following printed out: + +``` +{"message":"Log Message","date":"2021-04-05T13:46:58Z","type":"log"} +{"type":"error","@simple_error":"{\"message\":\"Log Error\",\"type\":\"System.Exception\"}","date":"2021-04-05T13:46:59Z"} +``` + +Your dates will be different, but the rest should look about the same. We now have a Log Event AND an Error Event. I think we're ready to post to the Exceptionless API. + +Remember, if you haven't done so, you'll need to sign up for a [free Exceptionless account](https://exceptionless.com), create a project, and grab an API Key. + +## Posting To The API + +When we post to the Exceptionless API, we are posting JSON data. In the examples above, we are printing the JSON string version of what we will ultimately push to the API. Let's see how it will look when actually posting to the API. + +Within our Exceptionless class, let's create a new private function called `postToAPI`. + +```swift +private func postToApi(event: Data) { + let url = URL(string: "https://collector.exceptionless.com/api/v2/events")! + + var request = URLRequest(url: url) + request.httpMethod = "POST" + + // insert json data to the request + request.httpBody = event + request.setValue("application/json; charset=utf-8", + forHTTPHeaderField: "Content-Tye") + request.setValue("application/json; charset=utf-8", + forHTTPHeaderField: "Accept") + request.setValue("Bearer " + self.apiKey, + forHTTPHeaderField: "Authorization") + + let task = URLSession.shared.dataTask(with: request) { data, response, error in + guard let data = data, error == nil else { + print(error?.localizedDescription ?? "No data") + return + } + let responseJSON = try? JSONSerialization.jsonObject(with: data, options: []) + if let responseJSON = responseJSON as? [String: Any] { + print(responseJSON) + } + } + + task.resume() +} +``` + +Walking through this new function, let's take a look at what's going on. First, we are setting the URL for our API request. This is a hardcoded value and probably not something you'd want to do in a production application. + +Next, we are creating a new request and assigning values to the request. You'll note that our `postToAPI` function accepts a `Data` value argument called `event`. That is what we will be posting to the API and it represents the JSON version of the event we build when we click Log Message or Log Error. + +Then, we set header values for our request. Take note, that we are assigning the `Authorization` value by using our Exceptionless API key. We'll need to get that key from Exceptionless before actually sending events. \ + +Finally, we are posting the request using `URLSession`. + +To actually call this function, we need to make two minor changes. First, back in your `ContentView.swift` file, we need to add our Exceptionless API key in where we left placeholder text. Again, this is not how you'd assign the API Key in a production app, but it's a simple example to get you going. + +Now, back in the `Exceptionless.swift` file, let's update both the `logMessage` and `logError` functions. Instead of converting our event to a JSON string, we're going to leave it as JSON and pass it through to our `postToAPI` function like this: + +```swift +private func logMessage(logMessage: String) { + let now = Date() + let formatter = ISO8601DateFormatter() + let datetime = formatter.string(from: now) + let eventDictionary : [String: Any] = [ "type": "log", "message":logMessage, "date": datetime ] + let jsonData = (try? JSONSerialization.data(withJSONObject: eventDictionary, options: []))! + postToApi(event: jsonData) +} +``` + +And here's the `logError` function: + +```swift +private func logError(errorEvent: String) { + let now = Date() + let formatter = ISO8601DateFormatter() + let datetime = formatter.string(from: now) + + let errorDictionary : [String: Any] = ["message": errorEvent, "type": "System.Exception"] + + let errorJson = (try? JSONSerialization.data(withJSONObject:errorDictionary))! + let errorJsonString = String(data: errorJson, encoding: String.Encoding.ascii)! + let eventDictionary : [String: Any] = [ "type": "error", "@simple_error":errorJsonString, "date": datetime ] + let jsonData = (try? JSONSerialization.data(withJSONObject: eventDictionary))! + + postToApi(event: jsonData) +} +``` + +Go ahead and build and run your app. Click the Log Message button and then the Log Error button. You won't see anything printed in the console, but if you go into your Exceptionless dashboard, you should see a new log and a new exception. + +![Exceptionless dashboard](./example_swift_events.png) + +Congratulations! You just built a simple event monitoring service in native Swift code. You can extend this pretty easily thanks to the Exceptionless class and leverage it in a production application. + +Swift is a fun language, but when using it to build mobile applications, it can be difficult to debug and track events. Exceptionless can help, and hopefully this tutorial shows how to implement such event tracking in SwiftUI and Swift. + +If you'd like to see the sample Xcode project, [we have a repo for it here](https://github.com/exceptionless/Exceptionless-Swift-Example). \ No newline at end of file diff --git a/docs/news/2021/2021-04-19-navigating-the-exceptionless-world-of-go.md b/docs/news/2021/2021-04-19-navigating-the-exceptionless-world-of-go.md new file mode 100644 index 0000000000..dea1994080 --- /dev/null +++ b/docs/news/2021/2021-04-19-navigating-the-exceptionless-world-of-go.md @@ -0,0 +1,146 @@ +--- +title: "Navigating The Exceptionless World of Go" +date: 2021-04-19 +--- + +# Navigating The Exceptionless World of Go + +Go does not have the concept of exceptions. Welp, I guess [Exceptionless](https://exceptionless.com) doesn't apply. Let's pack it up and head home, everyone. + +Kidding, of course. While Go really doesn't have the concept of exceptions, errors still happen in Go codebases, and those errors need to be handled. Having recently built an Exceptionless client in Go, we had the opportunity to take a deep dive into the Go programming language, and we'd like to share some of what we discovered along the way. + +### No Scrubs, No Exceptions + +![Gif of No Scrubs music video](https://media.giphy.com/media/ty48ztZKklU6k/giphy.gif) + +Let's take a quick look at why the Go programming language doesn't have exceptions, and then we can dive into how we work around this. From the Go FAQ: + +> We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional. + +Essentially, Go doesn't want any scrubs (try/catch paradigm) hanging out the passenger side of their best friend's (that's you) ride trying to call things exceptions. Not everything is fatal. Not everything is an exception. Errors can happen without being so extraordinary to be considered an exception. As such, Go made the opinionated decision to simply not acknowledge exceptions as a construct. + +For those instances where an error is truly catastrophic, Go has some build in mechanism to handle and recover. Those are [documented here](https://blog.golang.org/defer-panic-and-recover). + +So with no exceptions, how should errors be handled when using Exceptionless? + +### No Exceptions != No Errors + +Just because there are no exceptions doesn't mean there are no errors. Fortunately, Go has a well-documented paradigm for handling errors without the need for something like an exception. + +Every function you write in Go can have multiple return values. So, a well-written function will return both an error and the actual function's response. Let's take a look at a very basic example of this. + +```go +package main + +import ( + "github.com/go-errors/errors" +) + +func CombineStrings(string1 string, string2 string) (string, error) { + var errToReturn error + + if string1 == "" || string2 == "" { + errToReturn = errors.New(fmt.Sprintf("Strings must have at least one character")) + } + + returnValue := string1 + string2 + return returnValue, errToReturn +} +``` + +In this example, we are using the `go-errors` module to build an error of the type `error`. We do a simple check to see if both of the string arguments to our function are not empty. If either is empty, we assign an error to the variable `errToReturn`. Then, in our return statement, we return both the expected return value of the function and the error. + +When calling this function, the developer needs to first check for an error before moving on. That might look like this: + +```go +combinedString, err := CombineString("hello, ", "world") + +if err != nil { + //Handle Error +} + +fmt.Print(combinedString) +``` + +If an error is so bad that your code cannot execute any further, you may want to call Go's built in handler, `panic`, like this: + +```go +if err != nil { + panic(err) +} +``` + +### Ok, So How Do We Use Exceptionless in an Exceptionless Environment? + +Exceptionless (that's us) is a way of thinking about your code. It does not actually rely on the concepts of exceptions. In fact, Exceptionless is so much more than error/exception handling. + +So, with that framing, it becomes a lot more clear that Exceptionless can very easily be used within Go code to handle errors. In fact, the structure for using Exceptionless in Go is not all that different from other programming languages. + +We have a (currently as of the writing of this post) beta version of a [Go Exceptionless client](https://github.com/exceptionless/Exceptionless.Go). You can find that here. I'll show you how to use the client, but do note that the client API could change until it's out of beta. The goal here is less about showing off the Go client and more about showing you how to handle errors with an event monitoring service within Go. + +The first thing you'll need to do is sign up for Exceptionless and get an API Key. [You can sign up here](https://exceptionless.com). Once you've done that, you'll need to install the Exceptionless Go client in your project. To do so, simply run the following: + +``` +go get https://github.com/exceptionless/Exceptionless.Go +``` + +Once that's installed, import it into your project like this: + +```go +import ( + "github.com/exceptionless/Exceptionless.Go" +) +``` + +Now, let's take a look at how we would use the client. On app startup (probably in your `main` function), you can initialize and configure the client like this: + +```go +func main() { + config := exceptionless.Exceptionless{ + ApiKey: "YOUR API KEY" + } + exceptionless.Configure(config) +} +``` + +With the Exceptionless client configured, you can now use it to handle all sorts of events in your app. We're going to focus in on exception—or, not exceptions as the case might be with go 😉. + +Let's use our example function from earlier as the example. + +```go +package main + +import ( + "github.com/go-errors/errors" + "github.com/exceptionless/Exceptionless.Go" +) + +func SomOtherFunction() { + combinedString, err := CombineString("", "world") + +if err != nil { + exceptionless.SubmitError(err) +} + +fmt.Print(combinedString) +} + +func CombineStrings(string1 string, string2 string) (string, error) { + var errToReturn error + + if string1 == "" || string2 == "" { + errToReturn = errors.New(fmt.Sprintf("Strings must have at least one character")) + } + + returnValue := string1 + string2 + return returnValue, errToReturn +} +``` + +If you remember the `CombineStrings` function will return an error if either string is empty. So in my mock function `SomeOtherFunction`, I am calling `CombineStrings` and passing in an empty string. When the error comes back, all we need to do is handle it with Exceptionless using `exceptionless.SubmitError()`. Simple as that. + +### Conclusion + +There is a lot more you could do. The Exceptionless Go client allows you to build custom events with more info. You could even bypass the client entirely and make an http request directly to the [Exceptionless API](https://api.exceptionless.com) in your error handler. + +But the point is, despite Go being an exceptionless programming environment, you can catch errors and report them. So that means Exceptionless is actually a match made in heaven for the *exceptionless* environment of Go. \ No newline at end of file diff --git a/docs/news/2021/2021-08-16-how-to-use-error-boundaries-in-react.md b/docs/news/2021/2021-08-16-how-to-use-error-boundaries-in-react.md new file mode 100644 index 0000000000..ffda47f3aa --- /dev/null +++ b/docs/news/2021/2021-08-16-how-to-use-error-boundaries-in-react.md @@ -0,0 +1,210 @@ +--- +title: "How To Use Error Boundaries in React" +date: 2021-08-16 +--- + +# How To Use Error Boundaries in React + +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. + +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. [Error Boundaries allow developers to catch and handle](https://reactjs.org/docs/error-boundaries.html) errors in the presentational layer of React applications. From the React team's announcement: + +> 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. + +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 [Exceptionless](https://exceptionless.com?utm_source=first_signup&utm_medium=blog&utm_campaign=error_boundary) (an open-source error handling and monitoring tool) and React work really well together. + +Let's run through a quick tutorial that creates a React app that does the following: + +* Creates an Error Boundary +* Forces an error in a function component +* Recovers from that error +* Reports it to our monitoring service (Exceptionless) + +## Getting Started + +For this tutorial, you will need to have the following installed: + +* Node.js v12 or greater +* NPM +* Text editor +* [Free account on Exceptionless](https://exceptionless.com?utm_source=second_signup&utm_medium=blog&utm_campaign=error_boundary) + +With those things in place, let's generate our React app. From the command line, run the following: + +`npx create-react-app error-boundary-example` + +When your app is created, change into the directory and install the Exceptionless React package: + +`cd error-boundary-example && npm i @exceptionless/react` + +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. + +## Creating an Error Boundary in React + +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. + +Inside your new file, add the following: + +```js +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 ( + + + +# Uh oh! + + + + This wasn't supposed to happen. If you continue to see this message, + please reach out to support. + + + + + ); + } + + return this.props.children; + } +} + +export default ErrorBoundary; +``` + +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. + +Now, we need to connect this to our application components. + +## Wrapping The App Component + +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: + +```js +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( + + + + + , + document.getElementById('root') +); + +reportWebVitals(); +``` + +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: + +```js +import logo from './logo.svg'; +import './App.css'; + +function App() { + return ( + + +
+ +{undefinedVariable} + + + + + Edit src/App.js and save to reload. + + + [Learn React](https://reactjs.org) +
+ + + ); +} + +export default App; +``` + +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... + +...an error message still. What gives? + +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. + +Pretty cool! + +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. + +## Capturing Errors + +Now that we can display a message, Let's work on capturing the error and sending it to our reporting system—Exceptionless. + +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 this guide to do so](/docs/api/api-getting-started). + +Let's take a look at what the code looks like. This is what you should update your `index.js` file to look like: + +```js +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 () => { + await Exceptionless.startup((c) => { + c.apiKey = "YOUR API KEY"; + c.useDebugLogger(); + + c.defaultTags.push("Example", "React"); + }); +}; + +startExceptionless(); + +ReactDOM.render( + + + + + + + , + document.getElementById('root') +); + +reportWebVitals(); +``` + +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: + +![exception events with error boundary example](./ErrorBoundaryException.png) + +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. + +## Wrapping Up + +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. + +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 [Exceptionless](https://exceptionless.com?utm_source=third_signup&utm_medium=blog&utm_campaign=error_boundary) today. diff --git a/docs/news/2021/2021-09-09-announcing-the-new-exceptionless-javascript-client.md b/docs/news/2021/2021-09-09-announcing-the-new-exceptionless-javascript-client.md new file mode 100644 index 0000000000..8ec3116d1e --- /dev/null +++ b/docs/news/2021/2021-09-09-announcing-the-new-exceptionless-javascript-client.md @@ -0,0 +1,53 @@ +--- +title: "Announcing The New Exceptionless JavaScript Client" +date: 2021-09-09 +--- + +# Announcing The New Exceptionless JavaScript Client + +![Exceptionless announcement](./js_client_2_0_announcement.png) + +We have had a JavaScript client for several years, but it was quickly becoming out of date. To help address the issues with a fast-moving JavaScript landscape and to extend our JavaScript support, we have recently released a completely rewritten client that supports multiple JavaScript frameworks. + +If you just want to dive into the documentation, [you can review that here](/docs/clients/javascript/). If you want the story behind the rewrite, let's talk about some of the challenges we wanted to solve. + +1. Support for additional frameworks +2. Bring the client up to modern JavaScript standards +3. Have a little more code separation +4. Provide a better developer experience + +We'll talk about each one of these points in a little more detail. But first, let's dive into the architecture a bit. + +![Exceptionless JS architecture diagram](./exceptionless.drawio.png) + +Everything starts with Exceptionless JS Core. From there, we extend into specific environment implementations. The Node.js environment has different requirements than tha browser environment. Framework-specific environments like React and Vue have different requirements than the browser environment. By starting with the Core JS implementation, we can extend in any direction to any framework. + +Speaking of frameworks... + +## Support for additional frameworks + +When Exceptionless launched, the JavaScript ecosystem was powered by Bower, front-end applications were built with jQuery, and supporting IE6 was a legitimate concern on the minds of many developers. Over time, the ecosystem grew. We got React, Vue, Express, Typescript support became popular, and React Native made it easy for web devs to jump into building mobile apps. + +While Exceptionless continued to work well for most use cases, it was clear we needed an updated client to support the exploding ecosystem. React Native was one of our specific targets because Exceptionless's JS client flat-out couldn't work in React Native. But while we were at it, we wanted to make Vue.js support easier, add some native React functionality, and more. What we arrived at is a more robust client with individual sub-clients for various frameworks. + +## Bring the client up to modern JavaScript standards + +ECMAScript has progressed a lot in the last ten years. It was clear that we would need to re-write our client to keep up. With our new implementation, it will be much easier to stay on top of new features and experimental features. + +The JavaScript client is a set of ESM modules built on modern JavaScript, so Exceptionless is set now and into the future. + +## Have a little more code separation + +This is not a question of monorepo or not. Instead, we recognized that we were trying to cover browser code and server code all in one package. This made things difficult, not to mention we didn't yet have support for specific frameworks (besides Angular 1.0). + +Since we knew we were going to extend our support, it made sense to rebuild the client in a way that allowed us to publish updates to specific sub-modules rather than to the entire core JavaScript client every time. + +## Provide a better developer experience + +Developers are at Exceptionless's core. We are developers. We are part of the open-source community. Everything we build should make life easier for developers. + +This new version of our JavaScript client makes things significantly easier. Developers can reach for a specific client module, like Vue.js for example, rather than trying to shoehorn in a vanilla JavaScript client. React developers now have Error Boundary support built into the Exceptionless client. React Native developers can now use the client instead of writing raw API requests on their own. + +--- + +It took months of work, but the new Exceptionless JavaScript client is a completely rebuilt, all-new solution to event monitoring in JS. Exceptionless is proud to support the vibrant JavaScript ecosystem, and we believe this release positions us to update and stay ahead (or as close to ahead as anyone can get) of new JavaScript standards and updates into the future. diff --git a/docs/news/2021/2021-09-20-associate-users-with-events-to-track-event-impact.md b/docs/news/2021/2021-09-20-associate-users-with-events-to-track-event-impact.md new file mode 100644 index 0000000000..b9b658bb2e --- /dev/null +++ b/docs/news/2021/2021-09-20-associate-users-with-events-to-track-event-impact.md @@ -0,0 +1,254 @@ +--- +title: "Associate Users With Events To Track Event Impact" +date: 2021-09-20 +--- + +# Associate Users With Events To Track Event Impact + +If you've ever used any error and event monitoring service, there has probably come a point where you are pulling out your hair trying to figure out if an issue is actually a major problem or if it's impacting just one user. [Exceptionless](https://exceptionless.com), an open-source event monitoring service, helps with this out of the box by making use of event stacks. But you can extend Exceptionless's functionality and automatically associate users with events. So, that one error that happens 15,000 times a day, maybe it's just a single user who wrote some bad code. + +Let's take a look at how we can associate user with events using the new [Exceptionless JavaScript client](/news/2021/2021-09-09-announcing-the-new-exceptionless-javascript-client). + +We're going to create a simple Node.js Express server, drop in Exceptionless, then track events with user details tied in. To get started, let's create a new Express project. Fire up your command line terminal and run this command: + +``` +npx express-generator --no-view exceptionless-users +``` + +When that's done, run: + +``` +cd exceptionless-users && npm install +``` + +If you're not familiar with Express servers, let's take a look at the project structure so understand what we'll be doing. In the project folder, there will be an entry file called `app.js`. This file tells the server what to do. The express-generator library takes care of setting this up, and it even sets up some example routes for us. You'll see a `routes` folder with an `index.js` and a `users.js` file. Each of those files contain endpoints we can make use of. + +In a real project, you'd customize this to your app's needs, but we're going to use what came out of the box with some small alterations. Before we make those alterations, let's install the Exceptionless Node.js client: + +``` +npm i @exceptionless/node +``` +Let's take a moment to update our new Express project to use [ESM](https://nodejs.org/api/esm.html). Start by opening the `package.json` file. We need to add a line in there that says `"type": "module",`. You can place this right above the `"script"` line. + +Then, open up your `app.js` file, and we need to convert our `require` statements to `import` statements. You'll also need to update the export at the bottom. Here's what the top of the file should look like: + +```js +import express from 'express'; +import cookieParser from 'cookie-parser'; +import logger from 'morgan'; + +import indexRouter from "./routes/index.js"; +import usersRouter from "./routes/users.js"; +``` + +The export at the bottom should be updated to look like this: + +```js +export default app; +``` + +Now, we need to make similar changes to our `routes` files. Open up `routes/index.js` and change the `require` statement to `import` statement like this: + +```js +import express from 'express'; +``` + +Then, change the export to look like this at the bottom: + +```js +export default router; +``` + +Do the same thing in `routes/users.js` and you'll be all set. + +Ok, now we can really dive in. In the `users.js` file, you can see it comes with a single GET route that will list all users. Let's set up a very simple user mapping in this file. Above the route, add the following: + +```js +const users = [ + { + key: "123", + user: { + name: "Justin Hunter", + email: "justin@email.com", + userId: "76a62f17-e177-4cc5-b2aa-49a4d59c99a5" + } + }, + { + key: "456", + user: { + name: "Sarah Sanders", + email: "sarah@email.com", + userId: "6840f55b-6694-49b9-b609-40fbcbf155fe" + } + } +] +``` + +In a real app, you'd be getting your users from a database, most likely. But we are just trying to highlight Exceptionless's event handling with user attributes, so we can hard-code things. + +Now, let's create a middleware function to check the API key on each request to our endpoints. You can add this below the `users` variable: + +```js +const authentication = (req, res, next) => { + const apiKey = req.headers['x-api-key']; + const keyFound = users.find(u => u.key === apiKey); + if(!keyFound) { + return res.status(401).send("Unauthorized"); + } + res.locals.user = keyFound.user; + next(); +} +``` + +This middleware just checks to see if the key provided is a valid API Key. We could log invalid requests here in Exceptionless, but I'd rather us focus on logging valid requests so we can capture the user info. + +To test things out so far, let's update the existing GET route to use our middleware and to return a list of users. Change that route code to look like this: + +```js +router.get('/', authentication, async function(req, res, next) { + const mappedUsers = users.map((u) => {return { + name: u.user.name, + email: u.user.email, + userId: u.user.userId + }}); + res.json(mappedUsers); +}); +``` + +The route now checks for a valid API key, the it returns an array of users with their API Keys removed (security first, kids!). We can try this by running our server and making a simply HTTP request. Open up the entry file, `app.js`, and add this before the export statement: + +```js +app.listen(4000, () => { + console.log("Server is listening on port 4000"); +}) +``` + +Then start the server: + +``` +npm run start +``` + +Then in another command line tab, run: + +``` +curl --location --request GET 'http://localhost:4000/users' +``` + +You should get an unauthorized response which means the middleware is doing its job. Let's add in an API Key: + +``` +curl --location --request GET 'http://localhost:4000/users' \ +--header 'x-api-key: 123' +``` + +Now, you should get back an array of two users with their API keys removed. Perfect! Now we can get started on what we came here to do—associate user data to events tracked in Exceptionless. + +Create a new endpoint in that same file that looks like this: + +```js +router.post('/', authentication, async function(req, res, next) { + try { + if(!validBody(req.body)) { + throw "No user object provided"; + } + users.push({ + apiKey: null, + user: req.body + }); + res.json(req.body); + } catch (error) { + res.status(400).send(error); + } +}) +``` + +we also need to create our `validBody` function. You can add this right below the `authentication` middleware function: + +```js +const validBody = (body) => { + if(!body.name || !body.email || !body.userId) { + return false; + } + + return true; +} +``` + +This endpoint allows anyone with a valid API key to add new users. New users should be added without an API. If the request body is empty, we will throw an error. Before wiring this up to Exceptionless, let's test this endpoint out. + +But wait, I don't want to have to keep restarting the server when we make changes. Let's make this easier. Kill your server, then run: + +``` +npm i nodemon +``` + +In your `pacakage.json` file, add a `dev` script like this: + +``` +"dev": "nodemon node ./bin/www" +``` + +Now, restart your server with `npm run dev`. After any changes to the code, the server will automatically restart. + +Ok, now let's test our endpoint without and with a body payload: + +``` +curl --location --request POST 'http://localhost:4000/users' \ +--header 'x-api-key: 123' +``` + +You should get an error back. Now, try with a valid body: + +``` +curl --location --request POST 'http://localhost:4000/users' \ +--header 'x-api-key: 123' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "name": "New Guy", + "email": "newguy@email.com", + "userId": "97f78146-3967-4a80-972c-2fcccad6f45f" +}' +``` + +Now, you should get a 200 response with the newly added resource. Ok, we have our endpoint working. Let's connect it to Exceptionless so that we can track events by user. + +At the top of your file, require in Exceptionless: + +```js +import { Exceptionless } from "@exceptionless/node"; +await Exceptionless.startup("YOUR API Key"); +``` + +You can get your API key by [following these instructions](/docs/api/api-getting-started). + +Now, back in your POST endpoint, let's add the following to the catch: + +```js +... +await Exceptionless.createException(error).setUserIdentity(res.locals.user).submit(); +res.status(400).send(error); +``` + +Whenever we have an error where the body payload is invalid, we will now find the user who is making the request based on their API key and assign that user to the event that is reported to Exceptionless. + +Let's fire off a bad event again. This time, if all goes well, the user and the event will be reported back to Exceptionless. Run: + +``` +curl --location --request POST 'http://localhost:4000/users' \ +--header 'x-api-key: 123' +``` + +You will get the same error back as earlier, but if you look at your Exceptionless dashboard, you'll see the event came through and is now associated to your user. + +![User association](./user_error.png) + +Why is this type of data important? Because you can now start to track both errors and events at the user level and make better decisions. Do you need to jump on the bug you just saw come through? Maybe, but first see how many users are impacted. Exceptionless can provide that information at a glance. Just click on the "Most Users" tab on the left. + +![Most users example](./most_users.png) + +These events, of course, do not have to be tied to errors. You can track the frequency users are clicking on certain buttons. You can track page views. You can track successful interactions. All of this is powerful information that can help you build a better product. + +The source code for this simple server example is [in this gist](https://gist.github.com/polluterofminds/d055afc6be61d077e2f0871491a7c9ce). + +If you're ready to jump in, install [Exceptionless](https://exceptionless.com) into your own app, and start monitoring events with user data attached! \ No newline at end of file diff --git a/docs/news/2021/2021-10-04-how-to-monitor-events-in-your-svelte-app.md b/docs/news/2021/2021-10-04-how-to-monitor-events-in-your-svelte-app.md new file mode 100644 index 0000000000..2d8d6858fe --- /dev/null +++ b/docs/news/2021/2021-10-04-how-to-monitor-events-in-your-svelte-app.md @@ -0,0 +1,170 @@ +--- +title: "How To Monitor Events in Your Svelte App" +date: 2021-10-07 +--- + +# How To Monitor Events in Your Svelte App + +It seems there is a new JavaScript framework launched everyday. And while that is largely true, some standout above the rest. When [Svelte](https://svelte.dev/) 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 [named the most-loved web framework](https://insights.stackoverflow.com/survey/2021#section-most-loved-dreaded-and-wanted-web-frameworks). + +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. + +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, [Exceptionless](https://exceptionless.com) alongside our Svelte app. + +What you'll need: + +* Node.js v12 or higher +* A free Exceptionless account +* Text editor + +## Getting Started + +We'll get started by signing up for Exceptionless. Note, you can also run this locally by grabbing the source code and [following the instructions here](https://github.com/exceptionless/Exceptionless). 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": + +![New project set up](./new_project.png) + +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. + +Now, we can generate our Svelte project. We'll use deget so that we can get a full project scaffolding set up easily. [Read more about that here](https://svelte.dev/blog/the-easiest-way-to-get-started). + +``` +npx degit sveltejs/template exceptionless-svelte +cd exceptionless-svelte + +npm install +``` + +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: + +``` +npm i @exceptionless/browser +``` + +Now, you can fire up the app by running: + +``` +npm run dev +``` + +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! + +## Handling Events With Exceptionless + +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 `App.svelte` file. So, let's start there. Open your `exceptionless-svelte` project in your favorite code editor, then find the `App.svelte` file. + +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. + +Let's import Exceptionless at the top of our script tag, and then let's start Exceptionless up. + +```js +import { Exceptionless } from "@exceptionless/browser" +Exceptionless.startup("YOUR API KEY"); +``` + +Notice that we had to wrap our startup call in a function. This is because [Svelte doesn't yet support to-level awaits](https://github.com/sveltejs/svelte/issues/5501). If it did, we would simply call `await Exceptionless.startup("YOUR API KEY")`. + +This `App.svelte` 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 `main.js` file, you'll see a prop variable called `name`. We also have that variable at the top of our `App.svelte` 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 [here](https://svelte.dev/tutorial/reactive-declarations). + +So, first, in the HTML, between your `main` tags, change things to look like this: + +```html +
+ +# Hello {name}! + + +Type a new name below to change the name variable. + + +
+``` + +Then in your `script` tag, add a `handleChange` function like this: + +```js +const handleChange = (e) => { + name = e.target.value; +} +``` + +Save your code, then visit localhost:5200. 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! + +Let's change our `handleChange` 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. + +Change the `handleChange` function to look like this: + +```js +const handleChange = async (e) => { + name = e.target.value; + await Exceptionless.submitFeatureUsage("Name Change"); +} +``` + +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. + +![Feature Usage](./feature_usage_dashboard.png) + +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. + +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. + +Under the input element in your `main` html tags, add this button: + +```html + + + + + +``` + +Then in your script tag, add the `unhandledError` function: + +```js +const unhandledError = async () => { + throw new Error("You shouldn't be clicking that!"); +} +``` + +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. + +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: + +![Exception](./svelte_error.png) + +The beauty of this is you can click all the way through that exception and see the details of the error: + +![error details](./stack%20trace.png) + +Now, what if you do want to handle errors and add in some additional context? Exceptionless has you covered. Create a new function called `handleError`: + +```js +const handleError = async () => { + try { + throw new Error("Handled error"); + } catch(error) { + await Exceptionless.createException(error).addTags("handled").setUserDescription("joe@email.com", "power user").submit(); + } +} +``` + +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. + +Let's create a button in the app and test this: + +```html + + + + + +``` + +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? + +## Wrapping Up + +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. + +But it doesn't stop there. You can track just about anything you can imagine with [Exceptionless](https://exceptionless.com). Svelte plus Exceptionless work...uhhh...**exceptionionally** well together. Give them both a try today! + diff --git a/docs/news/2021/ErrorBoundaryException.png b/docs/news/2021/ErrorBoundaryException.png new file mode 100644 index 0000000000..b8df42c315 Binary files /dev/null and b/docs/news/2021/ErrorBoundaryException.png differ diff --git a/docs/news/2021/benadams.png b/docs/news/2021/benadams.png new file mode 100644 index 0000000000..a5c4fdafea Binary files /dev/null and b/docs/news/2021/benadams.png differ diff --git a/docs/news/2021/console.png b/docs/news/2021/console.png new file mode 100644 index 0000000000..fc15bae1cc Binary files /dev/null and b/docs/news/2021/console.png differ diff --git a/docs/news/2021/create_app.png b/docs/news/2021/create_app.png new file mode 100644 index 0000000000..d9c66924c6 Binary files /dev/null and b/docs/news/2021/create_app.png differ diff --git a/docs/news/2021/example_project.png b/docs/news/2021/example_project.png new file mode 100644 index 0000000000..810d7b9425 Binary files /dev/null and b/docs/news/2021/example_project.png differ diff --git a/docs/news/2021/example_react_exception.png b/docs/news/2021/example_react_exception.png new file mode 100644 index 0000000000..d8e38ec75e Binary files /dev/null and b/docs/news/2021/example_react_exception.png differ diff --git a/docs/news/2021/example_swift_events.png b/docs/news/2021/example_swift_events.png new file mode 100644 index 0000000000..ac12e20a40 Binary files /dev/null and b/docs/news/2021/example_swift_events.png differ diff --git a/docs/news/2021/exception.png b/docs/news/2021/exception.png new file mode 100644 index 0000000000..0fc3d49cd9 Binary files /dev/null and b/docs/news/2021/exception.png differ diff --git a/docs/news/2021/exceptionless.drawio.png b/docs/news/2021/exceptionless.drawio.png new file mode 100644 index 0000000000..999685aeb2 Binary files /dev/null and b/docs/news/2021/exceptionless.drawio.png differ diff --git a/docs/news/2021/featureUsage.png b/docs/news/2021/featureUsage.png new file mode 100644 index 0000000000..9abac285b1 Binary files /dev/null and b/docs/news/2021/featureUsage.png differ diff --git a/docs/news/2021/feature_usage_dashboard.png b/docs/news/2021/feature_usage_dashboard.png new file mode 100644 index 0000000000..171deec5be Binary files /dev/null and b/docs/news/2021/feature_usage_dashboard.png differ diff --git a/docs/news/2021/feature_usage_react.png b/docs/news/2021/feature_usage_react.png new file mode 100644 index 0000000000..aa83a619bd Binary files /dev/null and b/docs/news/2021/feature_usage_react.png differ diff --git a/docs/news/2021/go_gophers.jpg b/docs/news/2021/go_gophers.jpg new file mode 100644 index 0000000000..df1064868e Binary files /dev/null and b/docs/news/2021/go_gophers.jpg differ diff --git a/docs/news/2021/js_client_2_0_announcement.png b/docs/news/2021/js_client_2_0_announcement.png new file mode 100644 index 0000000000..1c597a2c96 Binary files /dev/null and b/docs/news/2021/js_client_2_0_announcement.png differ diff --git a/docs/news/2021/most_users.png b/docs/news/2021/most_users.png new file mode 100644 index 0000000000..46a20e7d24 Binary files /dev/null and b/docs/news/2021/most_users.png differ diff --git a/docs/news/2021/new_project.png b/docs/news/2021/new_project.png new file mode 100644 index 0000000000..48d38e8fcc Binary files /dev/null and b/docs/news/2021/new_project.png differ diff --git a/docs/news/2021/stack trace.png b/docs/news/2021/stack trace.png new file mode 100644 index 0000000000..be78e0a503 Binary files /dev/null and b/docs/news/2021/stack trace.png differ diff --git a/docs/news/2021/svelte_error.png b/docs/news/2021/svelte_error.png new file mode 100644 index 0000000000..d40b0ad0e9 Binary files /dev/null and b/docs/news/2021/svelte_error.png differ diff --git a/docs/news/2021/user_error.png b/docs/news/2021/user_error.png new file mode 100644 index 0000000000..f56b9ea4ea Binary files /dev/null and b/docs/news/2021/user_error.png differ diff --git a/docs/news/2021/xcode_version.png b/docs/news/2021/xcode_version.png new file mode 100644 index 0000000000..1416f60da0 Binary files /dev/null and b/docs/news/2021/xcode_version.png differ diff --git a/docs/news/2023/2023-01-26-exceptionless.net-5.0.0-released.md b/docs/news/2023/2023-01-26-exceptionless.net-5.0.0-released.md new file mode 100644 index 0000000000..91f926f235 --- /dev/null +++ b/docs/news/2023/2023-01-26-exceptionless.net-5.0.0-released.md @@ -0,0 +1,26 @@ +--- +title: "Exceptionless.Net 5.0.0 Released" +date: 2023-01-26 +--- + +# Exceptionless.Net 5.0.0 Released + +We are thrilled to announce the release of our latest version of the [Exceptionless .NET client](https://github.com/exceptionless/Exceptionless.Net), version 5.0. This release includes a major new feature, support for Blazor. + +## Blazor Support + +Blazor is a framework for building web applications using C# and Razor, a markup syntax for HTML. It allows developers to build interactive, client-side web applications with .NET. This means that you can now use Exceptionless to track and report errors in your Blazor applications with the same ease and flexibility that you have come to expect from our .NET client. + +With this release, Exceptionless now supports both server-side and client-side Blazor. This means that you can track and report errors that occur on the server, as well as in the browser. This is particularly useful for debugging and troubleshooting issues that may only occur in certain browser environments. + +Upgrading to the latest version of the Exceptionless .NET client is simple. Just update your [NuGet package](https://www.nuget.org/packages/Exceptionless/), and you’re good to go. As always, our documentation is available to help you with the upgrade process, and our support team is always here to answer any questions you may have. + +## We want to hear from you + +We are constantly working to improve our .NET client and provide the best error tracking and reporting experience for .NET developers. With the addition of Blazor support, we believe that we have taken another step forward in achieving that goal. We can't wait to see what you build with it! + +* [.NET Client Feedback](https://github.com/exceptionless/Exceptionless.Net/issues/new) +* [JavaScript Client Feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues/new) +* [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) + +The team at Exceptionless diff --git a/docs/news/2023/2023-03-28-exceptionless.javascript-3.0.0-released.md b/docs/news/2023/2023-03-28-exceptionless.javascript-3.0.0-released.md new file mode 100644 index 0000000000..bbbf3462fc --- /dev/null +++ b/docs/news/2023/2023-03-28-exceptionless.javascript-3.0.0-released.md @@ -0,0 +1,58 @@ +--- +title: "Exceptionless.JavaScript 3.0.0 Released" +date: 2023-03-28 +--- + +# Exceptionless.JavaScript 3.0.0 Released + +We are excited to announce our [latest release](https://github.com/exceptionless/Exceptionless.JavaScript/releases/tag/v3.0.0), which not only clears the entire [JavaScript client](https://github.com/exceptionless/Exceptionless.JavaScript) GitHub backlog but also brings in a whole range of awesome new capabilities! + +Our team has been hard at work, and we believe this update will greatly improve the developer experience while addressing critical issues and enhancing the overall functionality of our offering. Below are some of the highlights of this release. + +## Graceful Termination + +The improved client behavior now ensures a graceful termination when the last app statement executes, resulting in a significantly better CLI/Lambda experience for developers. + +## New Features + +This release includes a plethora of new features and fixes, such as: + +- Support for serializing event data with a `maxDepth`. As part of this we did a lot of work to add a [prune implementation](https://github.com/exceptionless/Exceptionless.JavaScript/blob/v3.0.0/packages/core/src/Utils.ts#L193-L367) that handles all cases like circular references, Typed Arrays, Unsupported types (E.G., Buffers) and more +- Improved handling of different promise rejection error types +- Ignoring errors created by browser extensions +- Session management improvements + +## Developer Experience Boost + +We have now made it easier to access all transitive exports (from `@exceptionless/core`) in dependent packages. This resolves issues with browser bundles and `@exceptionless/core` imports, ultimately enhancing the developer experience. + +## Updated Readme for Node --enable-source-maps + +Our readme now includes updated information on Node `--enable-source-maps`, ensuring developers have the most up-to-date guidance for using this feature. + +## Bug Fixes + +We have addressed several bugs in this release, including: + +- Fixing configuration default data not having exclusions applied +- Preventing timers from firing when the API key isn't configured +- Preserving event type if the event has an error +- Catching and logging storage API call errors + +## Enhanced Error Handling + +We now use the toError function for jQuery and Angular errors, fixing issues where the client may have thrown an exception due to an invalid error type. Additionally, we have added examples for various error browser integrations (e.g., jQuery). + +## Breaking Changes + +Our new release targets ES2021 and ESM Node 18 (fetch built-in). This allows us to reduce the size of our bundles by removing polyfills. + +## We want to hear from you + +This release reflects our commitment to continuously improving our product and offering the best possible experience for our users. We encourage you to explore the new features and enhancements, and as always, we welcome your feedback and suggestions. + +- [.NET Client Feedback](https://github.com/exceptionless/Exceptionless.Net/issues/new) +- [JavaScript Client Feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues/new) +- [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) + +The team at Exceptionless diff --git a/docs/news/2023/2023-03-29-exceptionless-8.0.0-released.md b/docs/news/2023/2023-03-29-exceptionless-8.0.0-released.md new file mode 100644 index 0000000000..5b46ca6537 --- /dev/null +++ b/docs/news/2023/2023-03-29-exceptionless-8.0.0-released.md @@ -0,0 +1,60 @@ +--- +title: "Exceptionless 8.0.0 Released" +date: 2023-03-29 +--- + +# Exceptionless 8.0.0 Released + +We are thrilled to announce our [latest update](https://github.com/exceptionless/Exceptionless/releases/tag/v8.0.0), packed with new features, improvements, and bug fixes designed to elevate your experience with our platform. With support for Discord notifications, Elasticsearch 8, OpenTelemetry, .NET 7, and arm64, we're confident that this release will make a significant impact. Plus, we've merged our UI codebase into our main repo, streamlining self-hosting and development for our users. + +### Unified UI and Web Project + +We have merged the UI into the web project to streamline self-hosting and development, making it easier for users to manage and maintain their projects. This makes it much easier to deploy and get started with our project without having to clone multiple repositories or configure multiple docker images! + +## API Token Suspension: + +You now have the ability to suspend API tokens, giving you greater control over your account security. Just navigate over to your manage projects `API Keys` tab and click on the `Disable` button. + +![Project Settings Disable API Key](/assets/img/news/project-settings-api-keys-disable.png) + +This will bring up a modal to confirm you want to disable the API Key. + +![Project Settings Disable API Key Modal](/assets/img/news/project-settings-api-keys-disable-modal.png) + +You can always reenable the API Key later by clicking on the `Enable` button. + +### Expanded Notification Support + +We've added the ability to send Slack webhook messages if the URL ends with `/slack`. This feature allows you to [send notification messages](https://ptb.discord.com/developers/docs/resources/webhook#execute-slackcompatible-webhook) to Discord and other platforms, keeping you informed about your projects. + +### Elasticsearch 8 Support + +Our latest update includes support for Elasticsearch 8, ensuring that you can take advantage of the latest features and improvements offered by Elasticsearch. + +### OpenTelemetry Support + +We have added support for OpenTelemetry, enabling you to better monitor and trace exactly how the exceptionless application is operating + +### Arm64 Support + +Our platform now supports arm64 hosting, expanding compatibility and ensuring a seamless experience across various platforms. This not only increases performance but saves on self hosting costs. + +### Upgrade to .NET 7 + +We have upgraded to .NET 7, providing you with the latest features and performance enhancements from the .NET ecosystem. + +## Upgrading to 8.0 + +Self-hosters need to pay attention to the upgrade process for this release. If you are self-hosting Exceptionless, please review the [Self Hosting Documentation](https://exceptionless.com/docs/self-hosting/), which contains information about upgrading your existing installation. + +## We want to hear from you + +This release reflects our commitment to constantly enhancing our platform and offering the best possible experience for our users. For a complete list of changes, please review the [change log](https://github.com/exceptionless/Exceptionless/compare/v7.2.1...v8.0.0). + +We encourage you to explore the new features and enhancements, and as always, we welcome your feedback and suggestions. + +- [.NET Client Feedback](https://github.com/exceptionless/Exceptionless.Net/issues/new) +- [JavaScript Client Feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues/new) +- [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) + +The team at Exceptionless diff --git a/docs/news/2023/2023-05-04-exceptionless.net-6.0.0-released.md b/docs/news/2023/2023-05-04-exceptionless.net-6.0.0-released.md new file mode 100644 index 0000000000..f8fc43eecb --- /dev/null +++ b/docs/news/2023/2023-05-04-exceptionless.net-6.0.0-released.md @@ -0,0 +1,40 @@ +--- +title: "Exceptionless.Net 6.0.0 Released" +date: 2023-05-04 +--- + +# Exceptionless.Net 6.0.0 Released + +We are thrilled to announce the release of version 6 of the [Exceptionless .NET client](https://github.com/exceptionless/Exceptionless.Net). Our team has been working to enhance the client's out of the box functionality and clear out the entire backlog of feature requests and issues! + +## HTTP Header support + +We added the ability to automatically capture available HTTP Headers when gathering the Request Info! + +![Request Info Headers](/assets/img/news/request-info-headers.png) + +The headers will be displayed on the events `Request` tab. + +## Logging Improvements + +We've made changes to all our logging targets like (E.G., [NLog](https://www.nuget.org/packages/Exceptionless.NLog), [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Exceptionless.Extensions.Logging), [Serilog](https://www.nuget.org/packages/Serilog.Sinks.Exceptionless)) to automatically configure the default log level to Trace via the `ExceptionlessClient.Default.Configuration.SetDefaultMinLogLevel` method. This method controls how we process log levels until we have server side dynamic log levels! Now users will see logs immediately on app startup when a logging provider is configured. + +We've also updated NLog from version 4 to version 5! Bringing in many new enhancements to the logging provider through community contribution! + +## Breaking changes + +We had to introduce some necessary breaking changes around serialization. Rest assured, we've kept these breaking changes minimal and they should not effect anyone. For more information, please refer to the [upgrade guide](https://exceptionless.com/docs/clients/dotnet/upgrading/). + +## Upgrading + +Upgrading to the latest version of the Exceptionless .NET client is simple. Just update your [NuGet package](https://www.nuget.org/packages/Exceptionless/), and you're good to go. As always, our [documentation](https://exceptionless.com/docs/clients/dotnet/upgrading/) is available to help you with the upgrade process, and our support team is always here to answer any questions you may have. + +## We want to hear from you + +We are constantly working to improve our .NET client and provide the best error tracking and reporting experience for .NET developers. + +* [.NET Client Feedback](https://github.com/exceptionless/Exceptionless.Net/issues/new) +* [JavaScript Client Feedback](https://github.com/exceptionless/Exceptionless.JavaScript/issues/new) +* [Exceptionless Feedback](https://github.com/exceptionless/exceptionless/issues/new) + +The team at Exceptionless diff --git a/docs/news/_data.yml b/docs/news/_data.yml new file mode 100644 index 0000000000..1fa7740711 --- /dev/null +++ b/docs/news/_data.yml @@ -0,0 +1,2 @@ +layout: layouts/post.vto +author: Blake Niemyjski diff --git a/docs/news/index.md b/docs/news/index.md new file mode 100644 index 0000000000..cf6348438f --- /dev/null +++ b/docs/news/index.md @@ -0,0 +1,184 @@ +--- +title: "News" +description: "Exceptionless news, release notes, and engineering updates." +--- + +# News + + +## 2023 + +- 2023-05-04 - [Exceptionless.Net 6.0.0 Released](/news/2023/2023-05-04-exceptionless.net-6.0.0-released) +- 2023-03-29 - [Exceptionless 8.0.0 Released](/news/2023/2023-03-29-exceptionless-8.0.0-released) +- 2023-03-28 - [Exceptionless.JavaScript 3.0.0 Released](/news/2023/2023-03-28-exceptionless.javascript-3.0.0-released) +- 2023-01-26 - [Exceptionless.Net 5.0.0 Released](/news/2023/2023-01-26-exceptionless.net-5.0.0-released) + +## 2021 + +- 2021-10-07 - [How To Monitor Events in Your Svelte App](/news/2021/2021-10-04-how-to-monitor-events-in-your-svelte-app) +- 2021-09-20 - [Associate Users With Events To Track Event Impact](/news/2021/2021-09-20-associate-users-with-events-to-track-event-impact) +- 2021-09-09 - [Announcing The New Exceptionless JavaScript Client](/news/2021/2021-09-09-announcing-the-new-exceptionless-javascript-client) +- 2021-08-16 - [How To Use Error Boundaries in React](/news/2021/2021-08-16-how-to-use-error-boundaries-in-react) +- 2021-04-19 - [Navigating The Exceptionless World of Go](/news/2021/2021-04-19-navigating-the-exceptionless-world-of-go) +- 2021-04-02 - [How To Monitor Events in Swift](/news/2021/2021-04-02-how-to-monitor-events-in-swift) +- 2021-03-24 - [How to Build a Custom Go Client For a REST API](/news/2021/2021-03-24-how-to-build-a-custom-go-api-client) +- 2021-02-22 - [How to Debug Electron Apps](/news/2021/2021-02-22-how-to-debug-electron-apps) +- 2021-01-26 - [Saying Thanks to the Open Source Community Through Sponsorship](/news/2021/2021-01-26-saying-thanks-to-the-open-source-community-through-sponsorship) +- 2021-01-19 - [How to Use React Hooks to Monitor Events in Your App](/news/2021/2021-01-19-how-to-use-react-hooks-to-monitor-events-in-your-app) +- 2021-01-12 - [Debugging a .NET Serverless App](/news/2021/2021-01-12-debugging-a-.net-serverless-app) + +## 2020 + +- 2020-12-07 - [Why You Should be Practicing Exception Driven Development](/news/2020/2020-12-7-why-you-should-be-practicing-exception-driven-development) +- 2020-10-29 - [Comparing Monitoring Services](/news/2020/2020-10-29-comparing-monitoring-services) +- 2020-10-26 - [Set Default Log Levels](/news/2020/2020-10-26-set-default-log-levels) +- 2020-10-23 - [Introducing Exceptionless 7](/news/2020/2020-10-23-introducing-exceptionless-7) +- 2020-09-30 - [How to Self-Host Your Error Monitoring Service](/news/2020/2020-09-30-how-to-self-host-your-error-monitoring-service) +- 2020-09-24 - [Why We Upgraded Our Production Application to .NET 5.0](/news/2020/2020-09-24-why-we-upgraded-our-production-application-to-net-5-0) +- 2020-09-23 - [Using an Error Monitoring Service to Track User Experience](/news/2020/2020-09-23-using-an-error-monitoring-service-to-track-user-experience) + +## 2019 + +- 2019-08-29 - [Exceptionless 5.0 Release - ASP.NET Core & Localization Support, and more!](/news/2019/2019-08-29-exceptionless-5-0-release-asp-net-core-localization-support-and-more) + +## 2018 + +- 2018-06-02 - [Event Tracking and Logging Software](/news/2018/2018-06-02-event-tracking-and-logging-software) +- 2018-04-30 - [C# Bug Tracking Software](/news/2018/2018-04-30-c-bug-tracking-software) +- 2018-01-31 - [ASP.NET Bug Tracking Software](/news/2018/2018-01-31-asp-net-bug-tracking-software) + +## 2017 + +- 2017-11-07 - [Exceptionless.NET 4.1 Release - .NET Standard 2.0 & Microsoft.Extensions.Logging Support, and more!](/news/2017/2017-11-07-exceptionless-net-4-1-release-net-standard-2-0-microsoft-extensions-logging-support-and-more) +- 2017-10-06 - [Slack Integration Update & Recap](/news/2017/2017-10-06-slack-integration-update-recap) +- 2017-08-30 - [Universal JavaScript Support Added to Exceptionless.JavaScript](/news/2017/2017-08-30-universal-javascript-support-added-exceptionless-javascript) +- 2017-08-15 - [JavaScript Client V1.5 Release Details & Notes](/news/2017/2017-08-15-javascript-client-v1-5-release-details-notes) +- 2017-06-28 - [Weekly Update: CodeSmith Generator, Serilog Sink, and Foundatio.Redis Updates](/news/2017/2017-06-28-weekly-update-codesmith-generator-serilog-sink-foundatio-redis-updates) +- 2017-06-26 - [More Improvements to Exceptionless Slack Integration](/news/2017/2017-06-26-improvements-exceptionless-slack-integration) +- 2017-06-20 - [Slack Integration Updates and Bug Fixes - Weekly Update 5/22/2017](/news/2017/2017-06-20-slack-integration-updates-bug-fixes-weekly-update-5222017) +- 2017-06-05 - [Exceptionless Slack Integration, Further Improved Notifications](/news/2017/2017-06-05-exceptionless-slack-integration) +- 2017-05-30 - [Email Notification Improvements - Walkthrough and Details](/news/2017/2017-05-30-email-notification-improvements-walkthrough-and-details) +- 2017-05-16 - [Daily Summary Email Improvements, Foundatio Updates, and more - Weekly Update 5/1/2017](/news/2017/2017-05-16-email-improvements-foundatio-updates-512017) +- 2017-05-16 - [Collect Project Level Usage Stats, UI Updates, Foundatio Updates - Weekly Video 5/8/2017](/news/2017/2017-05-16-project-level-usage-ui-foundatio) +- 2017-05-10 - [Weekly Update for 4/24/17 - Blake Speaking @ North Dallas .NET and more!](/news/2017/2017-05-10-weekly-update-42417-blake-speaking-north-dallas-net) +- 2017-05-02 - [Exceptionless Weekly Update 4/17/2017](/news/2017/2017-05-02-exceptionless-weekly-update-4172017) +- 2017-04-25 - [Weekly Update - Review of New Releases and More](/news/2017/2017-04-25-weekly-update-review-new-releases) +- 2017-04-21 - [Exceptionless.NET client, core, UI, releases - Bugs, Usability, Performance, Self Hosting](/news/2017/2017-04-21-exceptionless-net-client-and-core-releases-bugs-usability-performance-self-hosting) +- 2017-04-10 - [Azure Functions, Email Client, Foundatio - 4/3/17 Weekly Update](/news/2017/2017-04-10-azure-functions-email-client-foundatio-4317-weekly-update) +- 2017-04-04 - [Weekly Update - Bug Fixes, Archival Format Changes, and Foundatio Updates](/news/2017/2017-04-04-bug-fixes-archival-format-foundatio-updates) +- 2017-04-04 - [March Update Rollup - New Releases, Updates, Bug fixes, and more!](/news/2017/2017-04-04-march-update-rollup-new-releases-updates-bug-fixes) +- 2017-03-08 - [Email Logging, UI Improvements, Foundatio Updates, and more - Live Code Demo](/news/2017/2017-03-08-email-logging-ui-improvements-foundatio-updates-live-code-demo) +- 2017-02-28 - [Duplicate Event Total Fix, Setting Min Log Levels, Foundatio Updates, and more - Live Code Demo](/news/2017/2017-02-28-duplicate-event-total-fix-setting-min-log-levels-foundatio-updates-live-code-demo) +- 2017-02-22 - [Live Code Demo & Review of Exceptionless 4.0 Launch](/news/2017/2017-02-22-live-code-demo-review-of-exceptionless-4-0-launch) +- 2017-02-17 - [Live Code Demo - New Query Validation, DI Issues, and Error Handling](/news/2017/2017-02-17-live-code-demo-new-query-validation-di-issues-error-handling) +- 2017-02-15 - [Exceptionless 4.0 Enhancement Overview - Live Code Demo](/news/2017/2017-02-15-exceptionless-4-0-enhancement-overview-live-code-demo) +- 2017-02-07 - [Exceptionless 4.0 is Here!](/news/2017/2017-02-07-exceptionless-4-0) +- 2017-02-01 - [Setting Up New Elasticsearch Cluster, Reindexing & Mappings - Live Code Demo](/news/2017/2017-02-01-setting-new-elasticsearch-cluster-reindexing-mappings-live-code-demo) +- 2017-01-24 - [2017 Exceptionless Feature, Functionality, and Enhancement Roadmap](/news/2017/2017-01-24-2017-exceptionless-feature-functionality-and-enhancement-roadmap) +- 2017-01-18 - [Upgrading from Elasticsearch 1.x to 5.x - Live Coding Session](/news/2017/2017-01-18-upgrading-elasticsearch-1-x-5-x-live-coding-session) +- 2017-01-11 - [2016 Recap - Let there be STATS!](/news/2017/2017-01-11-2016-recap-let-there-be-stats) + +## 2016 + +- 2016-08-29 - [Exceptionless Helps Identify Issue Affecting 25,000 Users - Case Study](/news/2016/2016-08-29-exceptionless-helps-identify-issue-affecting-25000-users-case-study) +- 2016-08-08 - [Set Application Version for Improved Regression Notifications and Stacking](/news/2016/2016-08-08-set-application-version-for-improved-regression-notifications-and-stacking) +- 2016-08-01 - [Real Time App Configuration and Event Settings with Exceptionless](/news/2016/2016-08-01-real-time-app-configuration-event-settings) +- 2016-07-13 - [Exceptionless 3.4 - New User Dashboards, Job Reliability, and Bug Fixes](/news/2016/2016-07-13-exceptionless-3-4-new-user-dashboards-job-reliability-bug-fixes) +- 2016-06-28 - [Exceptionless.NET 4.0 - .NET Core and ASP.NET Core Support!](/news/2016/2016-06-28-exceptionless-4-0-net-core-asp-net-core-support) +- 2016-05-26 - [Session Heartbeats No Longer Count Towards Plan Limits](/news/2016/2016-05-26-session-heartbeats-no-longer-count-towards-plan-limits) +- 2016-05-19 - [New Client Releases Focus on Sessions, Real Time Configuration, and Logging](/news/2016/2016-05-19-new-client-releases-focus-on-sessions-real-time-configuration-and-logging) +- 2016-04-27 - [Exceptionless Keyboard Shortcuts](/news/2016/2016-04-27-exceptionless-keyboard-shortcuts) +- 2016-04-18 - [Know How Many Users are Affected by Bugs and Events](/news/2016/2016-04-18-how-many-users-affected-bugs-events) +- 2016-04-07 - [Foundatio Featured on .NET Blog + Version 4.0 Release!](/news/2016/2016-04-07-foundatio-featured-net-blog-version-4-0-release) +- 2016-04-04 - [Exceptionless V3.3.0 Release - Now with Even More Awesome](/news/2016/2016-04-04-exceptionless-v3-3-0-now-with-even-more-awesome) +- 2016-03-24 - [Filter Improvements to the Exceptionless Single Page App](/news/2016/2016-03-24-filter-improvements-exceptionless-single-page-app) +- 2016-03-16 - [Simple App Deployment with Azure Continuous Deployment and GitHub](/news/2016/2016-03-16-simple-app-deployment-azure-continuous-deployment-github) +- 2016-03-08 - [Custom Event Stacking in Exceptionless](/news/2016/2016-03-08-custom-event-stacking-in-exceptionless) +- 2016-02-26 - [New Releases: Exceptionless 3.2.1, .NET Client 3.3.6, JavaScript Client 1.3.2, UI 2.3.1](/news/2016/2016-02-26-new-releases-exceptionless-3-2-1-net-client-3-3-5-and-ui-2-3-1) +- 2016-02-10 - [Add Reverse Geocoding to Your App](/news/2016/2016-02-10-add-reverse-geocoding-to-your-app) +- 2016-02-04 - [Replacing DIY Exception Logging with Exceptionless - Case Study](/news/2016/2016-02-04-replacing-diy-exception-logging-with-exceptionless-case-study) +- 2016-02-01 - [Track and View User Session Data - New Exceptionless Feature!](/news/2016/2016-02-01-track-view-user-session-data-exceptionless) +- 2016-01-27 - [New Releases for ALL the Codes! Exceptionless 3.2](/news/2016/2016-01-27-new-releases-for-all-the-codes-exceptionless-3-2) + +## 2015 + +- 2015-12-28 - [Elasticsearch Case Study - By Exceptionless](/news/2015/2015-12-28-exceptionless-case-study-featured-on-elasticsearch) +- 2015-12-17 - [Using Reference Ids for Better Customer Service](/news/2015/2015-12-17-using-reference-ids-for-better-customer-service) +- 2015-12-08 - [A Better Approach to Running Azure WebJobs](/news/2015/2015-12-08-better-approach-running-azure-webjobs) +- 2015-12-03 - [Exceptionless.JavaScript 1.2 Release Notes](/news/2015/2015-12-03-exceptionles-javascript-1-2-release-notes) +- 2015-12-02 - [Exceptionless.NET 3.2 Release Notes](/news/2015/2015-12-02-exceptionless-net-3-2-release-notes) +- 2015-10-28 - [Exceptionless 3.1 Released! If You Thought It was Fast Before...](/news/2015/2015-10-28-exceptionless-3-1-released-if-you-thought-it-was-fast-before) +- 2015-10-26 - [Exceptionless JavaScript Client V1.1.0 Release](/news/2015/2015-10-26-javascript-client-v1-1-0-release) +- 2015-10-22 - [Introducing Foundatio 3.0! Now with Async & Increased Efficiency](/news/2015/2015-10-22-introducing-foundatio-3-0-async-efficiency) +- 2015-09-02 - [Find Software Bugs with the Exceptionless JavaScript Client in Minutes](/news/2015/2015-09-02-find-software-bugs-exceptionless-javascript-client) +- 2015-08-27 - [Squash Bugs Faster & Speed Up Development with Exceptionless](/news/2015/2015-08-27-squash-bugs-faster-speed-up-development-with-exceptionless) +- 2015-08-17 - [User Spotlight, Plus Fun Stats - Thank You to All of Our Awesome Users!](/news/2015/2015-08-17-user-spotlight-fun-stats-thanks-users) +- 2015-07-29 - [Self Hosting Exceptionless - Free and Fast!](/news/2015/2015-07-29-self-hosting-exceptionless-free-and-fast) +- 2015-07-23 - [Exceptionless V3.0 - Changes to the Build Process, Dependencies, and Self Hosting](/news/2015/2015-07-23-exceptionless-3-0-changes-to-build-process-dependencies-self-hosting) +- 2015-07-14 - [Introducing Foundatio - Pluggable Foundation Blocks for Building Distributed Apps](/news/2015/2015-07-14-foundatio-pluggable-blocks-building-distributed-apps) +- 2015-07-09 - [Exceptionless Documentation has Moved & Grown](/news/2015/2015-07-09-exceptionless-documentation-has-moved-grown) +- 2015-06-29 - [Exceptionless Case Study - Scientific Lab Equipment](/news/2015/2015-06-29-exceptionless-case-study-scientific-lab-equipment) +- 2015-06-22 - [Exclude and Protect Sensitive Data within Exceptionless](/news/2015/2015-06-22-exclude-and-protect-sensitive-data-within-exceptionless) +- 2015-06-17 - [The Power of Real-time Project Settings](/news/2015/2015-06-17-the-power-of-real-time-project-settings) +- 2015-06-09 - [JavaScript / Node.js Client V1 Release Notes](/news/2015/2015-06-09-javascript-node-js-client-v1-release-notes) +- 2015-06-04 - [JavaScript & Node.js Client Version 1 Release Candidate](/news/2015/2015-06-04-javascript-node-js-client-version-1-release-candidate) +- 2015-05-27 - [JavaScript Client Demo - Exceptionless](/news/2015/2015-05-27-javascript-client-demo-exceptionless) +- 2015-05-20 - [Exceptionless Node.js JavaScript Client Demo](/news/2015/2015-05-20-exceptionless-node-js-javascript-client-demo) +- 2015-05-13 - [JavaScript Client Available for Preview & Testing!](/news/2015/2015-05-13-javascript-client-available-for-preview-testing) +- 2015-05-07 - [Exceptionless V2.0.1 Shipped!](/news/2015/2015-05-07-exceptionless-v2-0-1-shipped) +- 2015-05-06 - [Exceptionless API Usage and Overview](/news/2015/2015-05-06-exceptionless-api-usage-and-overview) +- 2015-04-30 - [Filter and Searching Tutorial Video - Exceptionless](/news/2015/2015-04-30-filter-and-searching-tutorial-video-exceptionless) +- 2015-04-16 - [An Exceptionless NuGet Package Tour](/news/2015/2015-04-16-an-exceptionless-nuget-package-tour) +- 2015-04-06 - [How to Add a Plugin to Affect Events in Exceptionless](/news/2015/2015-04-06-how-to-add-a-plugin-to-affect-events-in-exceptionless) +- 2015-03-31 - [Sending Log Messages to Exceptionless](/news/2015/2015-03-31-sending-log-messages-to-exceptionless) +- 2015-03-25 - [Logging Feature Usages with Exceptionless](/news/2015/2015-03-25-logging-feature-usages-with-exceptionless) +- 2015-03-12 - [IT'S GO TIME - Exceptionless 2.0 Launched!](/news/2015/2015-03-12-its-go-time-exceptionless-2-0-launched) +- 2015-02-11 - [Exceptionless 2.0 Live Preview! Do You Want to Build a Sandbox?](/news/2015/2015-02-11-exceptionless-2-0-live-preview-want-build-sandbox) +- 2015-01-12 - [Exceptionless 2.0 Update - SO CLOSE!](/news/2015/2015-01-12-exceptionless-2-0-update-close) + +## 2014 + +- 2014-12-12 - [Bulk Actions Sneak Peak in Exceptionless 2.0 - Video](/news/2014/2014-12-12-bulk-actions-sneak-peak-exceptionless-2-0-video) +- 2014-12-07 - [Filter Your Exceptions in Version 2.0 - Video Demo](/news/2014/2014-12-07-filter-your-exceptions-video-demo) +- 2014-11-26 - [Exceptionless 2.0 User Interface FIRST LOOK](/news/2014/2014-11-26-exceptionless-2-0-user-interface-first-look) +- 2014-10-23 - [AngularJS and Exceptionless 2.0](/news/2014/2014-10-23-angularjs-exceptionless-2-0) +- 2014-10-13 - [Services and Other Technologies the Exceptionless Team Uses](/news/2014/2014-10-13-services-technologies-exceptionless-team-uses) +- 2014-10-02 - [Client Side Technology the Exceptionless Team Uses](/news/2014/2014-10-02-client-side-technology-exceptionless-team-uses) +- 2014-09-26 - [Server Side Technology the Exceptionless Team Uses](/news/2014/2014-09-26-server-side-technology-exceptionless-team-uses) +- 2014-09-03 - [Making the Move to Elasticsearch for Exceptionless 2.0](/news/2014/2014-09-03-making-move-elastic-search-exceptionless-2-0) +- 2014-08-21 - [Case Study: Server Expiration Error for Pre-Alpha Game Release](/news/2014/2014-08-21-case-study-server-expiration-error-pre-alpha-game-release) +- 2014-08-13 - [Upcoming Exceptionless Version 2.0 Overview & Review](/news/2014/2014-08-13-upcoming-exceptionless-version-2-0-overview-review) +- 2014-08-07 - [New Price Plans for Medium to Large Teams/Projects](/news/2014/2014-08-07-new-price-plans-medium-large-teamsprojects) +- 2014-07-29 - [Job System Enhancements - Version 2's Got Em!](/news/2014/2014-07-29-job-system-enhancements-version-2s-got-em) +- 2014-07-17 - [Version 2.0's New Message Bus and Queueing Systems](/news/2014/2014-07-17-version-2-0s-new-message-bus-queueing-systems) +- 2014-07-03 - [Exceptionless 2.0 Client Rewrite Sneak Peek Usage Example](/news/2014/2014-07-03-exceptionless-2-0-client-rewrite-sneak-peek-usage-example) +- 2014-06-25 - [Coming in Exceptionless 2.0 - A Pluggable System](/news/2014/2014-06-25-coming-exceptionless-2-0-pluggable-system) +- 2014-06-12 - [More from the Upcoming Exceptionless 2.0: Simplified API](/news/2014/2014-06-12-upcoming-exceptionless-2-0-simplified-api) +- 2014-06-03 - [Exceptionless 1.5 Released!](/news/2014/2014-06-03-exceptionless-1-5-released) +- 2014-05-28 - [Event Based Reporting System Coming in Version 2.0](/news/2014/2014-05-28-event-based-reporting-system-coming-version-2-0) +- 2014-05-20 - [Exceptionless 2.0 - In the Making](/news/2014/2014-05-20-exceptionless-2-in-the-making) +- 2014-05-04 - [Web Application Errors and the 80-20 Rule](/news/2014/2014-05-04-web-application-errors-80-20-rule) +- 2014-04-29 - [A Few Recent Exceptionless Case Studies](/news/2014/2014-04-29-recent-exceptionless-case-studies) +- 2014-04-18 - [Exception Handling & Logging Tool for ASP.NET, Web API, WebForms, WPF, Console, MVC, and more](/news/2014/2014-04-18-net-error-exception-handling-wpf-mvc) +- 2014-04-11 - [Intelligent App Error Grouping Helps Organize Your Exceptions](/news/2014/2014-04-11-intelligent-app-error-grouping-helps-organize-exceptions) +- 2014-04-04 - [Exceptionless Now Hosted on Azure](/news/2014/2014-04-04-exceptionless-now-hosted-azure) +- 2014-03-26 - [Detailed Error Reports - What's Included?](/news/2014/2014-03-26-whats-included-exceptionless-detailed-error-reports) +- 2014-03-17 - [Exceptionless 1.4 Released](/news/2014/2014-03-17-exceptionless-1-4-released) +- 2014-03-10 - [Achievement Unlocked - 1000 Accounts and Over 8,000,000 Errors Reported!](/news/2014/2014-03-10-achievement-unlocked-1000-accounts-8-million-errors) +- 2014-03-05 - [New Support for NancyFX - Thanks Luisrudge!](/news/2014/2014-03-05-new-support-nancyfx-thanks-luisrudge) +- 2014-02-25 - [Installing Exceptionless from GitHub](/news/2014/2014-02-25-installing-excteptionless-github) +- 2014-02-18 - [Fork Us! Exceptionless Goes Open Source](/news/2014/2014-02-18-fork-us-exceptionless-goes-open-source) +- 2014-02-13 - [Exceptionless 1.3 Released](/news/2014/2014-02-13-exceptionless-1-3-released) +- 2014-02-07 - [XML Parsing Exception Caught and Fixed - Case Study](/news/2014/2014-02-07-xml-parsing-exception-caught-fixed-case-study) +- 2014-02-03 - [Receive Error Notifications from Your App via Email](/news/2014/2014-02-03-app-error-notifications) +- 2014-01-24 - [Catching a Server-Side Browser Cookie Support Error - Case Study](/news/2014/2014-01-24-server-browser-cookie-error) +- 2014-01-15 - [An In-Depth Look at the Exceptionless Project Portal](/news/2014/2014-01-15-project-portal-tour) +- 2014-01-04 - [Find Leaking Exceptions by Eliminating Empty Catch Blocks - Case Study](/news/2014/2014-01-04-find-leaking-exceptions-eliminate-empty-catch-block) + +## 2013 + +- 2013-12-24 - [.NET Exception Reporting and Why You Need It](/news/2013/2013-12-24-net-exception-reporting-why-you-need-it) +- 2013-12-19 - [Exceptionless 1.2.0 Released](/news/2013/2013-12-19-exceptionless-1-2-0-released) +- 2013-12-19 - [Find Customer Facing Bugs with Exceptionless - Case Study](/news/2013/2013-12-19-find-customer-facing-bugs-with-exceptionless-case-study) +- 2013-08-06 - [Exceptionless 1.1.0 Released](/news/2013/2013-08-06-exceptionless-1-1-0-released) +- 2013-08-06 - [Introducing Exceptionless](/news/2013/2013-08-06-introducing-exceptionless) diff --git a/docs/news/index.vto b/docs/news/index.vto new file mode 100644 index 0000000000..5ea80777c9 --- /dev/null +++ b/docs/news/index.vto @@ -0,0 +1,15 @@ +--- +title: News +layout: layouts/base.vto +description: Exceptionless news, release notes, and engineering updates. +tags: [] +--- + + +
+
+ +
+
diff --git a/docs/pricing.vto b/docs/pricing.vto new file mode 100644 index 0000000000..350b5ebe28 --- /dev/null +++ b/docs/pricing.vto @@ -0,0 +1,159 @@ +--- +title: Pricing +layout: layouts/base.vto +description: Exceptionless hosted and self-hosted pricing. +--- + + +
+
+
+
+
+
+
+
+
+
Free
+
$0Per Month
+
+
+
    +
  • 1 project / 1 user
  • +
  • 3 days event retention
  • +
  • 3,000 events per month
  • +
  • No premium features
  • +
+
+
+
+
+
+
+
Small
+
$15Per Month
+
+
+
    +
  • 5 projects / 10 users
  • +
  • 30 days event retention
  • +
  • 15,000 events per month
  • +
  • Premium features included
  • +
+
+
+
+
+
+
+
Medium
+
$49Per Month
+
+
+
    +
  • 15 projects / 25 users
  • +
  • 90 days event retention
  • +
  • 75,000 events per month
  • +
  • Premium features included
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
Large
+
$99Per Month
+
+
+
    +
  • Unlimited projects / users
  • +
  • 180 days event retention
  • +
  • 250,000 events per month
  • +
  • Premium features included
  • +
+
+
+
+
+
+
+
Extra Large
+
$199Per Month
+
+
+
    +
  • Unlimited projects / users
  • +
  • 180 days event retention
  • +
  • 1,000,000 events per month
  • +
  • Premium features included
  • +
+
+
+
+
+
+
+
Enterprise
+
$499Per Month
+
+
+
    +
  • Unlimited projects / users
  • +
  • 180 days event retention
  • +
  • 3,000,000 events per month
  • +
  • Premium features included
  • +
+
+
+
+
+
+
+ +
+
+

Frequently Asked Questions

+
+
Can I try before I buy?
+
Yes! Just use our free plan and start tracking exceptions, log messages or feature usages in minutes.
+
Can I change my plan at any time?
+
Yes. You can change your plan at any time.
+
Can I cancel my account at any time?
+
If you decide that you no longer want to use Exceptionless, simply cancel before your next billing period.
+
What happens if I go over my error limit?
+
We will simply send you a notification. If you continually exceed your limit, you will be asked to upgrade your plan or your account will be closed.
+
What are the premium features?
+
Premium features are only available in the paid plans. Here is a list of the premium features:
+
+
    +
  • Searching
  • +
  • Error occurrence notifications (only daily summaries are allowed in the free plan)
  • +
  • Web hooks, Slack integration, and Zapier integration
  • +
  • Additional premium features coming soon.
  • +
+
+
Can I host Exceptionless myself?
+
Sure! Feel free to visit Exceptionless on GitHub for hosting details if you have the resources to set it up.
+
+
+
+
+

Important Information

+
    +
  • No credit card required.
  • +
+
+
+
+
+
+
diff --git a/docs/privacy.md b/docs/privacy.md new file mode 100644 index 0000000000..fdd73cc09a --- /dev/null +++ b/docs/privacy.md @@ -0,0 +1,38 @@ +--- +title: "Privacy Policy" +layout: "layouts/page.vto" +--- + +We collect the e-mail addresses of those who communicate with us via e-mail or through our feedback forms, aggregate information on what pages consumers access or visit, and information volunteered by the consumer (such as survey information and/or site registrations). The information we collect is used to improve the content of our Web pages and the quality of our service, and is not shared with or sold to other organizations for commercial purposes, except to provide products or services you’ve requested, when we have your permission, or under the following circumstances: + +* It is necessary to share information in order to investigate, prevent, or take action regarding illegal activities, suspected fraud, situations involving potential threats to the physical safety of any person, violations of [Terms of Service](/terms), or as otherwise required by law. +* We transfer information about you if Exceptionless is acquired by or merged with another company. In this event, Exceptionless will notify you before information about you is transferred and becomes subject to a different privacy policy. + +## The information we gather, and what we do with it + +* When you register for Exceptionless we ask for information such as your email address, and for paying accounts your billing address and credit card information. Members who sign up for the free account are not required to enter a credit card. +* Exceptionless uses collected information for the following general purposes: products and services provision, billing, identification and authentication, services improvement, contact, and research. + +## What we do with cookies + +* A cookie is a small amount of data, which often includes an anonymous unique identifier, that is sent to your browser from a web site’s computers and stored on your computer’s hard drive. +* Cookies are required to use the Exceptionless service fully +* When users choose the "remember me" option during log in, we use cookies to keep them logged in. This cookie is **not permanent**, it will expire after a fixed period of time. +* If users do not select remember me, cookies are destroyed at the end of session (typically when the browser is closed) + +## Data storage + +* Exceptionless uses third party vendors and hosting partners to provide the necessary hardware, software, networking, storage, and related technology required to run Exceptionless. Although Exceptionless owns the code, databases, and all rights to the Exceptionless application, you retain all rights to your data. +* You can delete your personal data at any time by visiting the my account page and clicking the delete account button. + +## Disclosure + +* Exceptionless may disclose personally identifiable information under special circumstances, such as to comply with requests from legal bodies or when your actions violate the [Terms of Service](/terms). + +## Changes + +* Exceptionless may periodically update this policy. We will notify you about significant changes in the way we treat personal information by sending a notice to the primary email address specified in your Exceptionless primary account holder account or by placing a prominent notice on the Exceptionless website. + +## Questions and Comments + +* Any questions regarding our Privacy Policy should be addressed to [support@exceptionless.com](mailto:support@exceptionless.com). diff --git a/docs/public/assets/Working-Space.mp4 b/docs/public/assets/Working-Space.mp4 new file mode 100644 index 0000000000..90e5334645 Binary files /dev/null and b/docs/public/assets/Working-Space.mp4 differ diff --git a/docs/public/assets/css/custom.css b/docs/public/assets/css/custom.css new file mode 100644 index 0000000000..54cfd80f5b --- /dev/null +++ b/docs/public/assets/css/custom.css @@ -0,0 +1,451 @@ +body { + background-image: url("/assets/img/body-bg2.png"); + background-position: left top; + background-size: auto; + background-repeat: repeat; + background-attachment: fixed; +} + +.home h1 { + font-size: 31.5px; +} + +a, a.active, a:hover, a.hover, a.visited, a:visited, a.link, a:link{ color: #0088cc;}#wrap{ color: #333333; } +body, input, button, select, textarea, .search-query {font-family: Open Sans;} +.btn-primary, a.btn-primary{color: #ffffff;background-color: #598e0e;background-image: -moz-linear-gradient(top, #73a818, #346900); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#73a818), to(#346900));background-image: -webkit-linear-gradient(top, #73a818, #346900);background-image: -o-linear-gradient(top, #73a818, #346900);background-image: linear-gradient(to bottom, #73a818, #346900);background-repeat: repeat-x;*background-color: #346900;}.btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] {color: #ffffff;background-color: #346900;*background-color: #285d00;}a.btn-success, a.btn-info, a.btn-warning, a.btn-error, a.btn-inverse{color: #fff;} +
+
+
RETAIN
INNOVATE
EVOLVE
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
Exceptionless Customers & Users
+
Exceptionless Users & Customers
+
+

Why Exceptionless?

+

You’re Losing Users, Leads, and Customers

+

Chances are, you’re losing users every day because of minor or major bugs or errors that aren’t being reported in your app or website. Exceptionless catches these bugs and notifies you, allowing you to fix them quickly and retain those users.

+

Innovate, Don’t Get Stuck Fixing Bugs!

+

Developers should be building the next big thing or adding that revenue-doubling feature, not wasting their time tracking down bugs that could have been caught right away and fixed during the development process. Progress, not regress.

+

Be That Company

+

You know that company. The one everyone loves because their systems, website, applications, tools, etc just work! You want to be those guys, and Exceptionless can help you get there by helping make sure the code powering your services is error free!

+
+
"Exceptionless is awesome. I’ve STOPPED worrying about whether I’m losing customers to bugs I don’t know about." – Eric B
+
+
3,711,629,930 EVENTS, AND COUNTING… // 9700+ ACTIVE PROJECTS
+
"Exceptionless allows us to prioritize fixes smarter by showing frequently occurring errors. In real time!"
+ – Ryan H.
+
+

Make Developer Life Easier

+

Simply put, Exceptionless makes developer life easier by reporting, logging, tracking, and providing the important details about bugs in real time so action can be taken and the developer can move on to important things, like working on actual features.

+

Unique Features

+
    +
  • Detailed Dashboard
  • +
  • Unlimited Users per Organization
  • +
  • Easy & Fast Setup
  • +
  • Event Notifications
  • +
  • Mark Events as Fixed or Critical
  • +
  • Monitor Fixed Events for Regression
  • +
  • Detailed Error Reports
  • +
  • Real-time View as Events Occur
  • +
  • Open Source – Self Host for Free! (affordable hosting available)
  • +
+
+
+ +
+ +
+
diff --git a/src/Exceptionless.Core/Configuration/EmailOptions.cs b/src/Exceptionless.Core/Configuration/EmailOptions.cs index 396290002c..24e3f9268c 100644 --- a/src/Exceptionless.Core/Configuration/EmailOptions.cs +++ b/src/Exceptionless.Core/Configuration/EmailOptions.cs @@ -14,6 +14,8 @@ public class EmailOptions /// public string? TestEmailAddress { get; internal set; } + public string? ContactEmailAddress { get; internal set; } + /// /// Email addresses that match this comma-delimited list of domains and email addresses will be allowed to be sent out in QA mode /// @@ -39,6 +41,7 @@ public static EmailOptions ReadFromConfiguration(IConfiguration config, AppOptio options.EnableDailySummary = config.GetValue(nameof(options.EnableDailySummary), appOptions.AppMode == AppMode.Production); options.AllowedOutboundAddresses = config.GetValueList(nameof(options.AllowedOutboundAddresses)).Select(v => v.ToLowerInvariant()).ToList(); options.TestEmailAddress = config.GetValue(nameof(options.TestEmailAddress), appOptions.AppMode == AppMode.Development ? "admin@exceptionless.test" : null); + options.ContactEmailAddress = config.GetValue(nameof(options.ContactEmailAddress)); string? emailConnectionString = config.GetConnectionString("Email"); if (!String.IsNullOrEmpty(emailConnectionString)) diff --git a/src/Exceptionless.Core/Exceptionless.Core.csproj b/src/Exceptionless.Core/Exceptionless.Core.csproj index 418e273ac3..ddb49ddf2c 100644 --- a/src/Exceptionless.Core/Exceptionless.Core.csproj +++ b/src/Exceptionless.Core/Exceptionless.Core.csproj @@ -1,5 +1,6 @@ + @@ -10,6 +11,7 @@ + diff --git a/src/Exceptionless.Core/Mail/IMailer.cs b/src/Exceptionless.Core/Mail/IMailer.cs index 79b3b7f39e..6e8905cab5 100644 --- a/src/Exceptionless.Core/Mail/IMailer.cs +++ b/src/Exceptionless.Core/Mail/IMailer.cs @@ -4,6 +4,7 @@ namespace Exceptionless.Core.Mail; public interface IMailer { + Task SendContactRequestAsync(string name, string emailAddress, string? company, string? subject, string message, string? clientIpAddress, string? userAgent, string? referrer); Task SendEventNoticeAsync(User user, PersistentEvent ev, Project project, bool isNew, bool isRegression, int totalOccurrences); Task SendOrganizationAddedAsync(User sender, Organization organization, User user); Task SendOrganizationInviteAsync(User sender, Organization organization, Invite invite); diff --git a/src/Exceptionless.Core/Mail/Mailer.cs b/src/Exceptionless.Core/Mail/Mailer.cs index da1c232a12..16394cca4d 100644 --- a/src/Exceptionless.Core/Mail/Mailer.cs +++ b/src/Exceptionless.Core/Mail/Mailer.cs @@ -31,6 +31,42 @@ public Mailer(IQueue queue, FormattingPluginManager pluginManager, _logger = logger; } + public async Task SendContactRequestAsync(string name, string emailAddress, string? company, string? subject, string message, string? clientIpAddress, string? userAgent, string? referrer) + { + string? contactEmailAddress = _appOptions.EmailOptions.ContactEmailAddress; + if (String.IsNullOrWhiteSpace(contactEmailAddress)) + { + _logger.LogWarning("Contact request mail was not sent: ContactEmailAddress is not configured"); + return false; + } + + string requestSubject = String.IsNullOrWhiteSpace(subject) + ? "Website contact request" + : subject.Trim().StripInvisible().Truncate(100); + string mailSubject = $"[Contact] {requestSubject}"; + const string template = "contact-request"; + var data = new Dictionary { + { "Subject", mailSubject }, + { "Name", name.Trim() }, + { "EmailAddress", emailAddress.Trim() }, + { "Company", company?.Trim() }, + { "RequestSubject", requestSubject }, + { "MessageLines", message.SplitLines().ToArray() }, + { "ClientIpAddress", clientIpAddress }, + { "UserAgent", userAgent }, + { "Referrer", referrer } + }; + + string? messageId = await QueueMessageAsync(new MailMessage + { + To = contactEmailAddress, + ReplyTo = emailAddress.Trim(), + Subject = mailSubject, + Body = RenderTemplate(template, data) + }, template); + return !String.IsNullOrEmpty(messageId); + } + public async Task SendEventNoticeAsync(User user, PersistentEvent ev, Project project, bool isNew, bool isRegression, int totalOccurrences) { bool isCritical = ev.IsCritical(); diff --git a/src/Exceptionless.Core/Mail/Templates/contact-request.html b/src/Exceptionless.Core/Mail/Templates/contact-request.html new file mode 100644 index 0000000000..3fb8bcaca2 --- /dev/null +++ b/src/Exceptionless.Core/Mail/Templates/contact-request.html @@ -0,0 +1,43 @@ + + + + + {{Subject}} + + +

{{Subject}}

+
+
Name
+
{{Name}}
+
Email
+
{{EmailAddress}}
+ {{#if Company}} +
Company
+
{{Company}}
+ {{/if}} +
Subject
+
{{RequestSubject}}
+
+ +

Message

+ {{#each MessageLines}} +

{{this}}

+ {{/each}} + +
+
+ {{#if ClientIpAddress}} +
IP address
+
{{ClientIpAddress}}
+ {{/if}} + {{#if UserAgent}} +
User agent
+
{{UserAgent}}
+ {{/if}} + {{#if Referrer}} +
Referrer
+
{{Referrer}}
+ {{/if}} +
+ + diff --git a/src/Exceptionless.Core/Models/Queues/MailMessage.cs b/src/Exceptionless.Core/Models/Queues/MailMessage.cs index 0ee31f66b4..6e79f1adcd 100644 --- a/src/Exceptionless.Core/Models/Queues/MailMessage.cs +++ b/src/Exceptionless.Core/Models/Queues/MailMessage.cs @@ -4,6 +4,7 @@ public record MailMessage { public required string To { get; set; } public string? From { get; set; } + public string? ReplyTo { get; set; } public required string Subject { get; set; } public required string Body { get; set; } } diff --git a/src/Exceptionless.Insulation/Mail/MailKitMailSender.cs b/src/Exceptionless.Insulation/Mail/MailKitMailSender.cs index 003355d19c..517b896fc4 100644 --- a/src/Exceptionless.Insulation/Mail/MailKitMailSender.cs +++ b/src/Exceptionless.Insulation/Mail/MailKitMailSender.cs @@ -96,6 +96,9 @@ private MimeMessage CreateMailMessage(MailMessage notification) else throw new ArgumentException("Email SmtpFrom not configured", nameof(notification)); + if (!String.IsNullOrEmpty(notification.ReplyTo)) + message.ReplyTo.AddRange(InternetAddressList.Parse(notification.ReplyTo)); + if (!String.IsNullOrEmpty(notification.Body)) builder.HtmlBody = notification.Body; diff --git a/src/Exceptionless.Web/Controllers/ContactController.cs b/src/Exceptionless.Web/Controllers/ContactController.cs new file mode 100644 index 0000000000..e3862a8e78 --- /dev/null +++ b/src/Exceptionless.Web/Controllers/ContactController.cs @@ -0,0 +1,84 @@ +using Exceptionless.Core.Configuration; +using Exceptionless.Core.Extensions; +using Exceptionless.Core.Mail; +using Exceptionless.DateTimeExtensions; +using Exceptionless.Web.Extensions; +using Exceptionless.Web.Models; +using Foundatio.Caching; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Exceptionless.Web.Controllers; + +[ApiExplorerSettings(IgnoreApi = true)] +[Route(API_PREFIX + "/contact")] +[AllowAnonymous] +public class ContactController : ExceptionlessApiController +{ + private const int ContactRequestLimit = 3; + private readonly EmailOptions _emailOptions; + private readonly IMailer _mailer; + private readonly ScopedCacheClient _cache; + private readonly ILogger _logger; + + public ContactController(EmailOptions emailOptions, IMailer mailer, ICacheClient cacheClient, TimeProvider timeProvider, ILogger logger) : base(timeProvider) + { + _emailOptions = emailOptions; + _mailer = mailer; + _cache = new ScopedCacheClient(cacheClient, "Contact"); + _logger = logger; + } + + [HttpPost] + [Consumes("application/json")] + public Task PostJsonAsync([FromBody] ContactRequest request) + { + return SubmitAsync(request); + } + + [HttpPost] + [Consumes("application/x-www-form-urlencoded", "multipart/form-data")] + public Task PostFormAsync([FromForm] ContactRequest request) + { + return SubmitAsync(request); + } + + private async Task SubmitAsync(ContactRequest request) + { + if (!String.IsNullOrWhiteSpace(request.Website)) + { + _logger.LogInformation("Contact request ignored because honeypot field was populated from {ClientIpAddress}", Request.GetClientIpAddress()); + return Accepted(); + } + + if (String.IsNullOrWhiteSpace(_emailOptions.ContactEmailAddress)) + return Problem(statusCode: StatusCodes.Status503ServiceUnavailable, title: "Contact form is not configured."); + + if (await IsRateLimitedAsync()) + return TooManyRequests("Too many contact requests. Please try later."); + + bool queued = await _mailer.SendContactRequestAsync( + request.Name!.Trim(), + request.EmailAddress!.Trim(), + request.Company?.Trim(), + request.Subject?.Trim(), + request.Message!.Trim(), + Request.GetClientIpAddress(), + Request.Headers["User-Agent"].ToString().Truncate(500), + Request.Headers["Referer"].ToString().Truncate(500)); + + if (!queued) + return Problem(statusCode: StatusCodes.Status503ServiceUnavailable, title: "Contact request could not be queued."); + + _logger.LogInformation("Contact request queued from {ClientIpAddress}", Request.GetClientIpAddress()); + return Accepted(); + } + + private async Task IsRateLimitedAsync() + { + string clientIpAddress = Request.GetClientIpAddress() ?? "unknown"; + string cacheKey = $"ip:{clientIpAddress}:attempts"; + long attempts = await _cache.IncrementAsync(cacheKey, 1, _timeProvider.GetUtcNow().UtcDateTime.Ceiling(TimeSpan.FromHours(1))); + return attempts > ContactRequestLimit; + } +} diff --git a/src/Exceptionless.Web/Models/ContactRequest.cs b/src/Exceptionless.Web/Models/ContactRequest.cs new file mode 100644 index 0000000000..f70bf05559 --- /dev/null +++ b/src/Exceptionless.Web/Models/ContactRequest.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; + +namespace Exceptionless.Web.Models; + +public record ContactRequest +{ + [Required, StringLength(100)] + public string? Name { get; init; } + + [Required, EmailAddress, StringLength(254)] + public string? EmailAddress { get; init; } + + [StringLength(120)] + public string? Subject { get; init; } + + [StringLength(120)] + public string? Company { get; init; } + + [Required, StringLength(4000, MinimumLength = 10)] + public string? Message { get; init; } + + [StringLength(200)] + public string? Website { get; init; } +} diff --git a/tests/Exceptionless.Tests/Controllers/ContactControllerTests.cs b/tests/Exceptionless.Tests/Controllers/ContactControllerTests.cs new file mode 100644 index 0000000000..5a6445d784 --- /dev/null +++ b/tests/Exceptionless.Tests/Controllers/ContactControllerTests.cs @@ -0,0 +1,173 @@ +using System.Net; +using System.Net.Http.Json; +using System.Text.Json; +using Exceptionless.Core.Extensions; +using Exceptionless.Core.Mail; +using Exceptionless.Core.Models; +using Exceptionless.Web.Models; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Exceptionless.Tests.Controllers; + +public sealed class ContactControllerTests : IntegrationTestsBase +{ + public ContactControllerTests(ITestOutputHelper output, AppWebHostFactory factory) : base(output, factory) { } + + private RecordingContactMailer Mailer => GetService(); + private JsonSerializerOptions JsonOptions => GetService(); + + protected override void RegisterServices(IServiceCollection services) + { + base.RegisterServices(services); + services.AddSingleton(); + services.ReplaceSingleton(sp => sp.GetRequiredService()); + } + + protected override async Task ResetDataAsync() + { + await base.ResetDataAsync(); + Mailer.Reset(); + } + + [Fact] + public async Task PostJsonAsync_WithValidRequest_ReturnsAcceptedAndSendsContactRequest() + { + using var client = CreateHttpClient(); + + var response = await client.PostAsJsonAsync("contact", new ContactRequest + { + Name = "Ada Lovelace", + EmailAddress = "ada@example.com", + Company = "Analytical Engines", + Subject = "Self hosted question", + Message = "Can you help us understand self hosted deployment options?" + }, JsonOptions, TestContext.Current.CancellationToken); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + var call = Assert.Single(Mailer.ContactRequests); + Assert.Equal("Ada Lovelace", call.Name); + Assert.Equal("ada@example.com", call.EmailAddress); + Assert.Equal("Analytical Engines", call.Company); + Assert.Equal("Self hosted question", call.Subject); + } + + [Fact] + public async Task PostJsonAsync_WithHoneypot_ReturnsAcceptedWithoutSendingContactRequest() + { + using var client = CreateHttpClient(); + + var response = await client.PostAsJsonAsync("contact", new ContactRequest + { + Name = "Spam Bot", + EmailAddress = "spam@example.com", + Message = "This message should be ignored by the honeypot field.", + Website = "https://spam.example" + }, JsonOptions, TestContext.Current.CancellationToken); + + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + Assert.Empty(Mailer.ContactRequests); + } + + [Fact] + public async Task PostJsonAsync_WithInvalidEmailAddress_ReturnsUnprocessableEntity() + { + using var client = CreateHttpClient(); + + var response = await client.PostAsJsonAsync("contact", new ContactRequest + { + Name = "Ada Lovelace", + EmailAddress = "not an email address", + Message = "This message has enough characters." + }, JsonOptions, TestContext.Current.CancellationToken); + + Assert.Equal(HttpStatusCode.UnprocessableEntity, response.StatusCode); + Assert.Empty(Mailer.ContactRequests); + } + + [Fact] + public async Task PostJsonAsync_WithTooManyRequests_ReturnsTooManyRequests() + { + using var client = CreateHttpClient(); + + for (int i = 0; i < 3; i++) + { + var allowedResponse = await client.PostAsJsonAsync("contact", CreateValidRequest(i), JsonOptions, TestContext.Current.CancellationToken); + Assert.Equal(HttpStatusCode.Accepted, allowedResponse.StatusCode); + } + + var limitedResponse = await client.PostAsJsonAsync("contact", CreateValidRequest(4), JsonOptions, TestContext.Current.CancellationToken); + + Assert.Equal(HttpStatusCode.TooManyRequests, limitedResponse.StatusCode); + Assert.Equal(3, Mailer.ContactRequests.Count); + } + + private static ContactRequest CreateValidRequest(int index) + { + return new ContactRequest + { + Name = $"Person {index}", + EmailAddress = $"person{index}@example.com", + Subject = "Question", + Message = "This is a contact request with enough characters." + }; + } + + private sealed class RecordingContactMailer : IMailer + { + public List ContactRequests { get; } = []; + + public Task SendContactRequestAsync(string name, string emailAddress, string? company, string? subject, string message, string? clientIpAddress, string? userAgent, string? referrer) + { + ContactRequests.Add(new ContactRequestCall(name, emailAddress, company, subject, message, clientIpAddress, userAgent, referrer)); + return Task.FromResult(true); + } + + public Task SendEventNoticeAsync(User user, PersistentEvent ev, Project project, bool isNew, bool isRegression, int totalOccurrences) + { + return Task.FromResult(true); + } + + public Task SendOrganizationAddedAsync(User sender, Organization organization, User user) + { + return Task.CompletedTask; + } + + public Task SendOrganizationInviteAsync(User sender, Organization organization, Invite invite) + { + return Task.CompletedTask; + } + + public Task SendOrganizationNoticeAsync(User user, Organization organization, bool isOverMonthlyLimit, bool isOverHourlyLimit) + { + return Task.CompletedTask; + } + + public Task SendOrganizationPaymentFailedAsync(User owner, Organization organization) + { + return Task.CompletedTask; + } + + public Task SendProjectDailySummaryAsync(User user, Project project, IEnumerable? mostFrequent, IEnumerable? newest, DateTime startDate, bool hasSubmittedEvents, double count, double uniqueCount, double newCount, double fixedCount, int blockedCount, int tooBigCount, bool isFreePlan) + { + return Task.CompletedTask; + } + + public Task SendUserEmailVerifyAsync(User user) + { + return Task.CompletedTask; + } + + public Task SendUserPasswordResetAsync(User user) + { + return Task.CompletedTask; + } + + public void Reset() + { + ContactRequests.Clear(); + } + } + + private sealed record ContactRequestCall(string Name, string EmailAddress, string? Company, string? Subject, string Message, string? ClientIpAddress, string? UserAgent, string? Referrer); +} diff --git a/tests/Exceptionless.Tests/Controllers/Data/controller-manifest.json b/tests/Exceptionless.Tests/Controllers/Data/controller-manifest.json index 0201800ef1..f6c58c2d7c 100644 --- a/tests/Exceptionless.Tests/Controllers/Data/controller-manifest.json +++ b/tests/Exceptionless.Tests/Controllers/Data/controller-manifest.json @@ -826,6 +826,41 @@ ], "ExcludeFromDescription": false }, + { + "Controller": "ContactController", + "Action": "PostFormAsync", + "HttpMethod": "POST", + "Route": "/api/v2/contact", + "Authorization": [ + "AllowAnonymous" + ], + "Consumes": [ + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "Produces": [ + "application/json", + "application/problem\u002Bjson" + ], + "ExcludeFromDescription": true + }, + { + "Controller": "ContactController", + "Action": "PostJsonAsync", + "HttpMethod": "POST", + "Route": "/api/v2/contact", + "Authorization": [ + "AllowAnonymous" + ], + "Consumes": [ + "application/json" + ], + "Produces": [ + "application/json", + "application/problem\u002Bjson" + ], + "ExcludeFromDescription": true + }, { "Controller": "EventController", "Action": "GetAllAsync", diff --git a/tests/Exceptionless.Tests/Mail/CountingMailer.cs b/tests/Exceptionless.Tests/Mail/CountingMailer.cs index 96d5671c3f..2967a84886 100644 --- a/tests/Exceptionless.Tests/Mail/CountingMailer.cs +++ b/tests/Exceptionless.Tests/Mail/CountingMailer.cs @@ -17,6 +17,11 @@ public class CountingMailer : IMailer /// public bool ShouldThrow { get; set; } + public Task SendContactRequestAsync(string name, string emailAddress, string? company, string? subject, string message, string? clientIpAddress, string? userAgent, string? referrer) + { + return Task.FromResult(true); + } + public Task SendEventNoticeAsync(User user, PersistentEvent ev, Project project, bool isNew, bool isRegression, int totalOccurrences) { return Task.FromResult(true); diff --git a/tests/Exceptionless.Tests/Mail/NullMailer.cs b/tests/Exceptionless.Tests/Mail/NullMailer.cs index 826be1324d..7ce54fcde6 100644 --- a/tests/Exceptionless.Tests/Mail/NullMailer.cs +++ b/tests/Exceptionless.Tests/Mail/NullMailer.cs @@ -5,6 +5,11 @@ namespace Exceptionless.Tests.Mail; public class NullMailer : IMailer { + public Task SendContactRequestAsync(string name, string emailAddress, string? company, string? subject, string message, string? clientIpAddress, string? userAgent, string? referrer) + { + return Task.FromResult(true); + } + public Task SendEventNoticeAsync(User user, PersistentEvent ev, Project project, bool isNew, bool isRegression, int totalOccurrences) { return Task.FromResult(true); diff --git a/tests/Exceptionless.Tests/appsettings.yml b/tests/Exceptionless.Tests/appsettings.yml index 5bdb00cb6a..5914619e15 100644 --- a/tests/Exceptionless.Tests/appsettings.yml +++ b/tests/Exceptionless.Tests/appsettings.yml @@ -17,6 +17,7 @@ MaximumRetentionDays: 3650 # Controls whether daily summary emails are sent EnableDailySummary: false +ContactEmailAddress: "contact@exceptionless.test" # Runs the jobs in the current website process RunJobsInProcess: false