{"id":1170,"date":"2023-03-30T21:54:34","date_gmt":"2023-03-30T12:54:34","guid":{"rendered":"https:\/\/www.gyuroot.com\/wordpress\/?p=1170"},"modified":"2023-07-04T22:12:28","modified_gmt":"2023-07-04T13:12:28","slug":"sprint-%eb%a1%9c%ea%b7%b8-%ed%8c%8c%ec%9d%b4%ed%94%84%eb%9d%bc%ec%9d%b8","status":"publish","type":"post","link":"https:\/\/www.gyuroot.com\/wordpress\/?p=1170","title":{"rendered":"[Sprint] \ub85c\uadf8 \ud30c\uc774\ud504\ub77c\uc778"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_63 counter-hierarchy ez-toc-counter ez-toc-white ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title \" >\ubaa9\ucc28<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.gyuroot.com\/wordpress\/?p=1170\/#1_%ED%8C%8C%EC%84%9Cparser_%EC%9E%91%EC%84%B1\" title=\"1. \ud30c\uc11c(parser) \uc791\uc131\">1. \ud30c\uc11c(parser) \uc791\uc131<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.gyuroot.com\/wordpress\/?p=1170\/#2_%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4_%EC%97%B0%EA%B2%B0_%ED%85%8C%EC%8A%A4%ED%8A%B8\" title=\"2. \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\uacb0 \ud14c\uc2a4\ud2b8\">2. \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\uacb0 \ud14c\uc2a4\ud2b8<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.gyuroot.com\/wordpress\/?p=1170\/#3_%EC%88%98%EC%A7%91%EA%B8%B0collector_%EC%9E%91%EC%84%B1\" title=\"3. \uc218\uc9d1\uae30(collector) \uc791\uc131\">3. \uc218\uc9d1\uae30(collector) \uc791\uc131<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.gyuroot.com\/wordpress\/?p=1170\/#4_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EC%9A%B0%EA%B8%B0\" title=\"4. \ub370\uc774\ud130 \uc9c0\uc6b0\uae30\">4. \ub370\uc774\ud130 \uc9c0\uc6b0\uae30<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.gyuroot.com\/wordpress\/?p=1170\/#5_%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8_%EC%99%84%EC%84%B1\" title=\"5. \ud30c\uc774\ud504\ub77c\uc778 \uc644\uc131\">5. \ud30c\uc774\ud504\ub77c\uc778 \uc644\uc131<\/a><\/li><\/ul><\/nav><\/div>\n\n<p class=\"has-background\" style=\"background-color: rgb(241, 241, 239)\">&#x1f4a1; <strong>Bare Minimum Requirements<\/strong><\/p>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"1_%ED%8C%8C%EC%84%9Cparser_%EC%9E%91%EC%84%B1\"><\/span>1. \ud30c\uc11c(parser) \uc791\uc131<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/env node\n\nconst dayjs = require(&#039;dayjs&#039;)\nconst customParseFormat = require(&#039;dayjs\/plugin\/customParseFormat&#039;)\ndayjs.extend(customParseFormat)\n\nprocess.stdin.on(&quot;data&quot;, data =&gt; {\n  let raw = data.toString()\n\t\/\/\ubc15\ucc2c\uaddc \uc815\uaddc \ud45c\ud604\uc2dd\n <strong> let regex = \/^(S+) S+ S+ [([w:\/]+s[+-]d{4})] &quot;(S+) S+s*S*&quot; (d{3}) (d+) &quot;([^&quot;]*)&quot; &quot;([^&quot;]*)&quot;\/\n  <\/strong>\/\/\uc624\ud0dc\uacbd \uc815\uaddc \ud45c\ud604\uc2dd<strong>\n  let regex = \/^([d.]+) .+ [(.+)] &quot;(w+) (.+) .+&quot; (d+) (d+) &quot;([^&quot;]+)&quot; &quot;([^&quot;]+)&quot;\/\n\n  let source_ip = regex.exec(raw)[1]\n  let method = regex.exec(3)\n  let status_code = regex.exec(5)\n  let path = regex.exec(4)\n  let timestamp = regex.exec(2)\n\n  let accessTime = dayjs(timestamp, &#039;DD\/MMM\/YYYY:hh:mm:ss +ZZ&#039;).toISOString()<\/strong>\n\n  let jsonString = `\n{\n  &quot;source_ip&quot;: &quot;${source_ip}&quot;,\n  &quot;method&quot;: &quot;${method}&quot;,\n  &quot;status_code&quot;: ${status_code},\n  &quot;path&quot;: &quot;${path}&quot;,\n  &quot;timestamp&quot;: &quot;${<strong>accessTime<\/strong>}&quot;\n}`\n\n  process.stdout.write(jsonString)\n})<\/code><\/pre>\n\n\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"2_%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4_%EC%97%B0%EA%B2%B0_%ED%85%8C%EC%8A%A4%ED%8A%B8\"><\/span>2. \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\uacb0 \ud14c\uc2a4\ud2b8<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n<blockquote class=\"wp-block-quote has-text-color\" style=\"color: rgb(0, 0, 0)\">\n<p><strong>.env \ud30c\uc77c \uc0dd\uc131<\/strong><\/p>\n\n<\/blockquote>\n\n\n<pre class=\"wp-block-code\"><code><strong>HOSTNAME=ruby.db.elephantsql.com\nUSERNAME=ztwarhqq\nPASSWORD=iNdkZVP1ODKWDDr5_tvC39JmMmKrBqqj\nDATABASE=ztwarhqq<\/strong><\/code><\/pre>\n\n\n<blockquote class=\"wp-block-quote has-text-color\" style=\"color: rgb(0, 0, 0)\">\n<p><strong>SQL Test<\/strong><\/p>\n\n<\/blockquote>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.gyuroot.com\/wordpress\/wp-content\/uploads\/image-183.png?v=1688456282\" alt=\"\"\/><\/figure>\n\n\n<p class=\"has-background\" style=\"background-color: rgb(241, 241, 239)\">&#x2b50; <strong>Trouble Shooting\n<\/strong>\n<strong>.env \uc124\uc815\uc2dc OS \ud658\uacbd \ubcc0\uc218\uc640 KEY \uc911\ubcf5\uc774 \ub418\uc9c0 \uc54a\ub294\uc9c0 \ud655\uc778 \ud544\uc218<\/strong><\/p>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"3_%EC%88%98%EC%A7%91%EA%B8%B0collector_%EC%9E%91%EC%84%B1\"><\/span>3. \uc218\uc9d1\uae30(collector) \uc791\uc131<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/env node\n\nconst dotenv = require(&#039;dotenv&#039;)\nconst { Client } = require(&#039;pg&#039;)\ndotenv.config()\n\nconst { HOSTNAME, USERNAME, PASSWORD, DATABASE } = process.env\nconst client = new Client({\n  host: HOSTNAME,\n  user: USERNAME,\n  password: PASSWORD,\n  database: DATABASE\n})\n\nclient.connect().then(() =&gt; {\n\n  process.stdin.on(&quot;data&quot;, async data =&gt; {\n    let raw = data.toString()\n    let json = JSON.parse(raw)\n\n    let queryString = `\n      <strong>INSERT INTO public.nginx (source_ip, method, status_code, path, timestamp)\n      VALUES (\n        &#039;${json.source_ip}&#039;,\n        &#039;${json.method}&#039;,\n        &#039;${json.status_code}&#039;,\n        &#039;${json.path}&#039;,\n        &#039;${json.timestamp}&#039;\n      );<\/strong>\n    `\n\n    console.log(queryString)\n    try {\n      await client.query(queryString)\n    }\n    catch(e) {\n      console.log(e)\n    }\n  })\n\n}).catch(err =&gt; console.log(&#039;\uc5f0\uacb0 \uc624\ub958&#039;, err.stack))\n\n\n\/\/ Ctrl+C\uac00 \uc785\ub825\ub418\uba74, \ub370\uc774\ud130\ubca0\uc774\uc2a4\ub97c \ub2eb\uc2b5\ub2c8\ub2e4\nprocess.on(&#039;SIGINT&#039;, async (sig) =&gt; {\n  console.log(&#039;n\ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\uacb0 \ub2eb\ub294 \uc911...&#039;)\n  await client.end()\n  console.log(&#039;\ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\uacb0 \uc885\ub8cc&#039;)\n  process.exit(1)\n})<\/code><\/pre>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"4_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EC%9A%B0%EA%B8%B0\"><\/span>4. \ub370\uc774\ud130 \uc9c0\uc6b0\uae30<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n<blockquote class=\"wp-block-quote has-text-color\" style=\"color: rgb(0, 0, 0)\">\n<p><strong>\ub370\uc774\ud130 \uc0ad\uc81c \ucffc\ub9ac \uc791\uc131<\/strong><\/p>\n\n<\/blockquote>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.gyuroot.com\/wordpress\/wp-content\/uploads\/image-184.png?v=1688456284\" alt=\"\"\/><\/figure>\n\n\n<blockquote class=\"wp-block-quote has-text-color\" style=\"color: rgb(0, 0, 0)\">\n<p><strong>SQL Test<\/strong><\/p>\n\n<\/blockquote>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.gyuroot.com\/wordpress\/wp-content\/uploads\/image-185.png?v=1688456288\" alt=\"\"\/><\/figure>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"5_%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8_%EC%99%84%EC%84%B1\"><\/span>5. \ud30c\uc774\ud504\ub77c\uc778 \uc644\uc131<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n<blockquote class=\"wp-block-quote has-text-color\" style=\"color: rgb(0, 0, 0)\">\n<p><strong>ETL \ud30c\uc774\ud504\ub77c\uc778<\/strong><\/p>\n\n<\/blockquote>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.gyuroot.com\/wordpress\/wp-content\/uploads\/image-186-1024x222.png?v=1688456291\" alt=\"\"\/><\/figure>\n\n\n<ol>\n<li>\uba3c\uc800 nginx\uac00 \uc2e4\ud589\uc911\uc774\uc5b4\uc57c \ud569\ub2c8\ub2e4.<\/li>\n\n<\/ol>\n\n\n<ol>\n<li>access.log \ud30c\uc77c\uc744 \uad00\ucc30\ud569\ub2c8\ub2e4. <code>tail -f<\/code> \uba85\ub839\uc5b4\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<\/li>\n\n<\/ol>\n\n\n<ol>\n<li>\uc6f9 \uc11c\ubc84\uc5d0 \ub2e4\uc591\ud55c \uc811\uc18d \uae30\ub85d\uc744 \uc0dd\uc131\ud569\ub2c8\ub2e4. Postman\uc774\ub4e0 curl\uc774\ub4e0 \uc6f9 \ube0c\ub77c\uc6b0\uc800\ub4e0 \uc0c1\uad00\uc5c6\uc2b5\ub2c8\ub2e4.<\/li>\n\n<\/ol>\n\n\n<ol>\n<li>\uc811\uc18d \uc2dc, access.log \ud30c\uc77c\uc5d0 \uc0c8\ub85c\uc6b4 \ub85c\uadf8\uac00 \ucd9c\ub825\ub418\ub294 \uc9c0 \ud655\uc778\ud569\ub2c8\ub2e4.<\/li>\n\n<\/ol>\n\n\n<ol>\n<li>4\ubc88\uc5d0 \uc131\uacf5\ud588\ub2e4\uba74, <code>tail -f access.log<\/code> \uc758 \ud45c\uc900 \ucd9c\ub825(stdout)\uc774 \ud30c\uc11c\uc758 \ud45c\uc900 \uc785\ub825(stdin)\uc774 \ub418\ub3c4\ub85d \ud30c\uc774\ud504(<code>|<\/code>)\ub97c \uc774\uc6a9\ud574 \uc5f0\uacb0\ud569\ub2c8\ub2e4.<\/li>\n\n<\/ol>\n\n\n<blockquote class=\"wp-block-quote has-text-color\" style=\"color: rgb(0, 0, 0)\">\n<p><strong>\ud30c\uc774\ud504\ub77c\uc778 \uba85\ub839\uc5b4<\/strong><\/p>\n\n<\/blockquote>\n\n\n<pre class=\"wp-block-code\"><code>$ tail -0f \/var\/log\/nginx\/access.log | .\/parser.js | .\/collector.js<\/code><\/pre>\n\n\n<blockquote class=\"wp-block-quote has-text-color\" style=\"color: rgb(0, 0, 0)\">\n<p><strong>\uc801\uc7ac \uacb0\uacfc \ud655\uc778<\/strong><\/p>\n\n<\/blockquote>\n\n\n<pre class=\"wp-block-code\"><code>$ .\/sql-runner.js &lt; sql\/3_display_table_data.sql<\/code><\/pre>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/www.gyuroot.com\/wordpress\/wp-content\/uploads\/image-187.png?v=1688456294\" alt=\"\"\/><\/figure>\n\n<script type=\"text\/javascript\"> toolTips('.classtoolTips11','<span class=\"notion-enable-hover\" data-token-index=\"0\">Uniform Resource Locator<br\/><\/span><br\/><br\/><a href=\"\/wordpress\/?p=65\">Detail<\/a>'); <\/script>","protected":false},"excerpt":{"rendered":"<p>&#x1f4a1; Bare Minimum Requirements 1. \ud30c\uc11c(parser) \uc791\uc131 2. \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\uacb0 \ud14c\uc2a4\ud2b8 .env \ud30c\uc77c \uc0dd\uc131 SQL Test &#x2b50; Trouble Shooting .env \uc124\uc815\uc2dc OS \ud658\uacbd \ubcc0\uc218\uc640 KEY \uc911\ubcf5\uc774 \ub418\uc9c0 \uc54a\ub294\uc9c0 \ud655\uc778 \ud544\uc218 3. \uc218\uc9d1\uae30(collector) \uc791\uc131 4. \ub370\uc774\ud130 \uc9c0\uc6b0\uae30 \ub370\uc774\ud130 \uc0ad\uc81c \ucffc\ub9ac \uc791\uc131 SQL Test 5. \ud30c\uc774\ud504\ub77c\uc778 \uc644\uc131 ETL \ud30c\uc774\ud504\ub77c\uc778 \ud30c\uc774\ud504\ub77c\uc778 \uba85\ub839\uc5b4 \uc801\uc7ac \uacb0\uacfc \ud655\uc778<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_eb_attr":""},"categories":[45],"tags":[],"_links":{"self":[{"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1170"}],"collection":[{"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1170"}],"version-history":[{"count":1,"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1170\/revisions"}],"predecessor-version":[{"id":1190,"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1170\/revisions\/1190"}],"wp:attachment":[{"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gyuroot.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}