{"_id":"59a88afb6fcf1d000f430c9e","project":"56ba46e2ce5d540d00e2d7a7","version":{"_id":"56ba46e2ce5d540d00e2d7aa","project":"56ba46e2ce5d540d00e2d7a7","__v":13,"createdAt":"2016-02-09T20:06:58.727Z","releaseDate":"2016-02-09T20:06:58.727Z","categories":["56ba46e3ce5d540d00e2d7ab","5771a6b145c7080e0072927f","5771a72eb0ea6b0e006a5221","5772e5b20a6d610e00dea073","577c3006b20f211700593629","57ae587bca3e310e00538155","57ae593a7c93fa0e001e6b50","57b1f8263ff6c519005cf074","582601f155b1060f00ec4173","582a62857a96051b0070b011","58ebfae58d5a860f00851fb9","590a75a1ec0d5e190095ab38","59e5253fd460b50010237bed"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"category":{"_id":"582601f155b1060f00ec4173","project":"56ba46e2ce5d540d00e2d7a7","__v":0,"version":"56ba46e2ce5d540d00e2d7aa","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-11-11T17:37:53.355Z","from_sync":false,"order":1,"slug":"guides","title":"Guides"},"user":"5732062ad720220e008ea1d2","__v":3,"parentDoc":null,"updates":["59c1097b55166d00301e5ce4","59c10a0e55166d00301e5ce5","59c1159b90de33001076c2be"],"next":{"pages":[],"description":""},"createdAt":"2017-08-31T22:17:31.434Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"## Overview\n\nEmbedding a view allows users outside of your LogDNA organization to view a specific portion of your logs. You can embed views to showcase your product, create custom internal dashboards, or even provide user-specific event logs to your customers.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/2351a3a-embedded-views.gif\",\n        \"embedded-views.gif\",\n        800,\n        450,\n        \"#363636\"\n      ]\n    }\n  ]\n}\n[/block]\n## How it works\n\nEach [view](doc:views) you create inside LogDNA can be configured to be embeddable. As part of the embed options, you can choose to mirror that view exactly, or allow it to accept a refined query that you can specify from your web page. \n\nFor example, if Susie logs into your website, you could show Susie logs only related to her activity by passing her user identifier as a refined query. Once the embed options are set, we automatically generate the embed code for you to copy and paste into your website.\n\n## Getting started\n\nAs a prerequisite, **you must whitelist your website domain** to authorize hosting your embedded view. You can add your domain to the whitelist on the [Manage Account Profile](https://app.logdna.com/manage/profile) page in the LogDNA web app.\n\nEmbedded views first require [creating a view](doc:views#section-creating-a-view) inside LogDNA. After the view is created, click on the view drop-down in the top left and select Embed this View. This will open a pane prompting you to to choose whether to use a static or dynamic embedded view. \n\n### Static vs dynamic\n\nA static embed only shows log lines from the view and it will not accept any query refinement made from the web page using the embed. This is useful for showing the view's logs to other users outside of your LogDNA organization.\n\nA dynamic embed only shows a subset of log lines from the view that match a refined query. This is useful for showing a specific subset of the view's logs to a particular user or group of users outside of your LogDNA organization.\n\nImportant considerations to keep in mind when choosing a static or dynamic embed are displayed in the table below.\n[block:parameters]\n{\n  \"data\": {\n    \"h-1\": \"Static\",\n    \"h-2\": \"Dynamic\",\n    \"h-0\": \"\",\n    \"0-0\": \"Behavior\",\n    \"0-1\": \"Mirrors view exactly\",\n    \"0-2\": \"Shows a subset of lines matching a refined query\",\n    \"1-0\": \"Effort\",\n    \"1-1\": \"No server-side work required\",\n    \"1-2\": \"Server-side work required\",\n    \"2-0\": \"Security\",\n    \"2-1\": \"Basic CORS security\",\n    \"2-2\": \"CORS and HMAC validation\"\n  },\n  \"cols\": 3,\n  \"rows\": 3\n}\n[/block]\n## Embed code\n\nOnce you have chosen an embed type, the last step is to copy the embed code into your website. For static embeds, this process is as easy as copying and pasting the generated snippet in the configuration pane. However, for dynamic embeds, you will also need to use server-side code to securely perform query refinement.\n\n## Query refinement (dynamic only)\n\nIf you selected the dynamic embed option, a query parameter is **required** for the embedded view. The query parameter for a dynamic embed is identical to a [search query](doc:search) in the web app. For security reasons, it is not possible to show a dynamic embed without a query parameter to refine the embedded view's contents.\n\nFor security, the query parameter **MUST** be hashed via HMAC-SHA256. This requires a **shared secret**, which you can specify or generate in the configuration pane. For hashing, we allow two different methods to generate a signature: a traditional query string based HMAC signature, and JSON Web Token (JWT). \n\n### Query string\n\nThe query string is your refined query for the embed, which is then hashed using the HMAC-SHA256 algorithm. Example code snippets in a few popular languages are available below.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import javax.crypto.Mac;\\nimport javax.crypto.spec.SecretKeySpec;\\nimport org.apache.commons.codec.binary.Base64;\\n\\nString secret = \\\"secret\\\";\\nString query = \\\"query\\\";\\n\\ntry {\\n    Mac sha256_HMAC = Mac.getInstance(\\\"HmacSHA256\\\");\\n    SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), \\\"HmacSHA256\\\");\\n    sha256_HMAC.init(secret_key);\\n    String signature = Base64.encodeBase64String(sha256_HMAC.doFinal(query.getBytes()));\\n} catch (Exception e){\\n  //Catch exceptions\\n}\",\n      \"language\": \"java\",\n      \"name\": \"Java\"\n    },\n    {\n      \"code\": \"var crypto = require('crypto')\\n  , query = 'query'\\n  , secret = 'secret'\\n  , signature;\\n\\nsignature = crypto.createHmac('sha256', secret).update(query).digest('hex');\",\n      \"language\": \"javascript\",\n      \"name\": \"Node\"\n    },\n    {\n      \"code\": \"$signature = hash_hmac('sha256', 'query', 'secret', true);\",\n      \"language\": \"php\",\n      \"name\": \"PHP\"\n    },\n    {\n      \"code\": \"import hashlib\\nimport hmac\\nimport base64\\n\\nquery = bytes(\\\"query\\\").encode('utf-8')\\nsecret = bytes(\\\"secret\\\").encode('utf-8')\\n\\nsignature = base64.b64encode(hmac.new(secret, query, digestmod=hashlib.sha256).digest())\",\n      \"language\": \"python\",\n      \"name\": \"Python\"\n    },\n    {\n      \"code\": \"require 'openssl'\\nrequire \\\"base64\\\"\\n\\nhash = OpenSSL::HMAC.digest('sha256', \\\"secret\\\", \\\"query\\\")\\nsignature = Base64.encode64(hash)\",\n      \"language\": \"ruby\",\n      \"name\": \"Ruby\"\n    }\n  ]\n}\n[/block]\n### JSON Web Token (JWT)\n\nJWT is a [JSON-based open standard](https://tools.ietf.org/html/rfc7519) used to create access tokens that can securely assert a particular claim. In this case, the claim is q, the query parameter, which contains your refined query for the embed. Example code snippets in a few popular languages are available below.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Library documentation: https://github.com/auth0/java-jwt\\nimport com.auth0.jwt.algorithms.Algorithm;\\nimport com.auth0.jwt.exceptions.JWTCreationException;\\nimport com.auth0.jwt.JWT;\\nimport java.io.UnsupportedEncodingException\\n\\nString secret =\\\"secret\\\";\\nString query = \\\"query\\\";\\n  \\ntry {\\n    Algorithm algorithm = Algorithm.HMAC256(\\\"secret\\\");\\n    String token = JWT.create()\\n\\t\\t\\t.withClaim(\\\"q\\\", query)\\n      .sign(algorithm);\\n} catch (UnsupportedEncodingException exception) {\\n    //UTF-8 encoding not supported\\n} catch (JWTCreationException exception) {\\n    //Invalid Signing configuration\\n}\",\n      \"language\": \"java\",\n      \"name\": null\n    },\n    {\n      \"code\": \"// Library documentation: https://www.npmjs.com/package/jsonwebtoken\\nvar jwt = require('jsonwebtoken')\\n\\t, secret = 'secret'\\n  , signature;\\n\\nsignature = jwt.sign({ q: 'query' }, secret);\",\n      \"language\": \"javascript\",\n      \"name\": \"Node\"\n    },\n    {\n      \"code\": \"<?php\\n// Library documentation: https://github.com/firebase/php-jwt\\nuse \\\\Firebase\\\\JWT\\\\JWT;\\n\\n$query = \\\"query\\\";\\n$secret = \\\"secret\\\";\\n\\n$signature = JWT::encode(array(\\\"q\\\" => $query), $secret, array('HS256'));\",\n      \"language\": \"php\",\n      \"name\": \"PHP\"\n    },\n    {\n      \"code\": \"# Library documentation: https://github.com/jpadilla/pyjwt/\\nimport jwt\\n\\nsecret = 'secret'\\nquery = 'query'\\n\\nsignature = jwt.encode({'q': query}, secret, algorithm='HS256')\",\n      \"language\": \"python\",\n      \"name\": \"Python\"\n    },\n    {\n      \"code\": \"# Library documentation: https://github.com/jwt/ruby-jwt\\nrequire 'jwt'\\n\\nquery = 'query'\\nsecret = 'secret'\\n\\nsignature = JWT.encode {:q => query}, secret, 'HS256'\",\n      \"language\": \"ruby\",\n      \"name\": \"Ruby\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"embedded-views","type":"basic","title":"Embedded Views"}
## Overview Embedding a view allows users outside of your LogDNA organization to view a specific portion of your logs. You can embed views to showcase your product, create custom internal dashboards, or even provide user-specific event logs to your customers. [block:image] { "images": [ { "image": [ "https://files.readme.io/2351a3a-embedded-views.gif", "embedded-views.gif", 800, 450, "#363636" ] } ] } [/block] ## How it works Each [view](doc:views) you create inside LogDNA can be configured to be embeddable. As part of the embed options, you can choose to mirror that view exactly, or allow it to accept a refined query that you can specify from your web page. For example, if Susie logs into your website, you could show Susie logs only related to her activity by passing her user identifier as a refined query. Once the embed options are set, we automatically generate the embed code for you to copy and paste into your website. ## Getting started As a prerequisite, **you must whitelist your website domain** to authorize hosting your embedded view. You can add your domain to the whitelist on the [Manage Account Profile](https://app.logdna.com/manage/profile) page in the LogDNA web app. Embedded views first require [creating a view](doc:views#section-creating-a-view) inside LogDNA. After the view is created, click on the view drop-down in the top left and select Embed this View. This will open a pane prompting you to to choose whether to use a static or dynamic embedded view. ### Static vs dynamic A static embed only shows log lines from the view and it will not accept any query refinement made from the web page using the embed. This is useful for showing the view's logs to other users outside of your LogDNA organization. A dynamic embed only shows a subset of log lines from the view that match a refined query. This is useful for showing a specific subset of the view's logs to a particular user or group of users outside of your LogDNA organization. Important considerations to keep in mind when choosing a static or dynamic embed are displayed in the table below. [block:parameters] { "data": { "h-1": "Static", "h-2": "Dynamic", "h-0": "", "0-0": "Behavior", "0-1": "Mirrors view exactly", "0-2": "Shows a subset of lines matching a refined query", "1-0": "Effort", "1-1": "No server-side work required", "1-2": "Server-side work required", "2-0": "Security", "2-1": "Basic CORS security", "2-2": "CORS and HMAC validation" }, "cols": 3, "rows": 3 } [/block] ## Embed code Once you have chosen an embed type, the last step is to copy the embed code into your website. For static embeds, this process is as easy as copying and pasting the generated snippet in the configuration pane. However, for dynamic embeds, you will also need to use server-side code to securely perform query refinement. ## Query refinement (dynamic only) If you selected the dynamic embed option, a query parameter is **required** for the embedded view. The query parameter for a dynamic embed is identical to a [search query](doc:search) in the web app. For security reasons, it is not possible to show a dynamic embed without a query parameter to refine the embedded view's contents. For security, the query parameter **MUST** be hashed via HMAC-SHA256. This requires a **shared secret**, which you can specify or generate in the configuration pane. For hashing, we allow two different methods to generate a signature: a traditional query string based HMAC signature, and JSON Web Token (JWT). ### Query string The query string is your refined query for the embed, which is then hashed using the HMAC-SHA256 algorithm. Example code snippets in a few popular languages are available below. [block:code] { "codes": [ { "code": "import javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\nimport org.apache.commons.codec.binary.Base64;\n\nString secret = \"secret\";\nString query = \"query\";\n\ntry {\n Mac sha256_HMAC = Mac.getInstance(\"HmacSHA256\");\n SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), \"HmacSHA256\");\n sha256_HMAC.init(secret_key);\n String signature = Base64.encodeBase64String(sha256_HMAC.doFinal(query.getBytes()));\n} catch (Exception e){\n //Catch exceptions\n}", "language": "java", "name": "Java" }, { "code": "var crypto = require('crypto')\n , query = 'query'\n , secret = 'secret'\n , signature;\n\nsignature = crypto.createHmac('sha256', secret).update(query).digest('hex');", "language": "javascript", "name": "Node" }, { "code": "$signature = hash_hmac('sha256', 'query', 'secret', true);", "language": "php", "name": "PHP" }, { "code": "import hashlib\nimport hmac\nimport base64\n\nquery = bytes(\"query\").encode('utf-8')\nsecret = bytes(\"secret\").encode('utf-8')\n\nsignature = base64.b64encode(hmac.new(secret, query, digestmod=hashlib.sha256).digest())", "language": "python", "name": "Python" }, { "code": "require 'openssl'\nrequire \"base64\"\n\nhash = OpenSSL::HMAC.digest('sha256', \"secret\", \"query\")\nsignature = Base64.encode64(hash)", "language": "ruby", "name": "Ruby" } ] } [/block] ### JSON Web Token (JWT) JWT is a [JSON-based open standard](https://tools.ietf.org/html/rfc7519) used to create access tokens that can securely assert a particular claim. In this case, the claim is q, the query parameter, which contains your refined query for the embed. Example code snippets in a few popular languages are available below. [block:code] { "codes": [ { "code": "// Library documentation: https://github.com/auth0/java-jwt\nimport com.auth0.jwt.algorithms.Algorithm;\nimport com.auth0.jwt.exceptions.JWTCreationException;\nimport com.auth0.jwt.JWT;\nimport java.io.UnsupportedEncodingException\n\nString secret =\"secret\";\nString query = \"query\";\n \ntry {\n Algorithm algorithm = Algorithm.HMAC256(\"secret\");\n String token = JWT.create()\n\t\t\t.withClaim(\"q\", query)\n .sign(algorithm);\n} catch (UnsupportedEncodingException exception) {\n //UTF-8 encoding not supported\n} catch (JWTCreationException exception) {\n //Invalid Signing configuration\n}", "language": "java", "name": null }, { "code": "// Library documentation: https://www.npmjs.com/package/jsonwebtoken\nvar jwt = require('jsonwebtoken')\n\t, secret = 'secret'\n , signature;\n\nsignature = jwt.sign({ q: 'query' }, secret);", "language": "javascript", "name": "Node" }, { "code": "<?php\n// Library documentation: https://github.com/firebase/php-jwt\nuse \\Firebase\\JWT\\JWT;\n\n$query = \"query\";\n$secret = \"secret\";\n\n$signature = JWT::encode(array(\"q\" => $query), $secret, array('HS256'));", "language": "php", "name": "PHP" }, { "code": "# Library documentation: https://github.com/jpadilla/pyjwt/\nimport jwt\n\nsecret = 'secret'\nquery = 'query'\n\nsignature = jwt.encode({'q': query}, secret, algorithm='HS256')", "language": "python", "name": "Python" }, { "code": "# Library documentation: https://github.com/jwt/ruby-jwt\nrequire 'jwt'\n\nquery = 'query'\nsecret = 'secret'\n\nsignature = JWT.encode {:q => query}, secret, 'HS256'", "language": "ruby", "name": "Ruby" } ] } [/block]