{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Log Analysis with Regex\n",
    "\n",
    "*Logs* describe a series of events happening in time.  When you run a flask application, capturing the output will be a log of requests.  At the beginning of the semester, analyzed a log of git commits.  When logs contain text, regular expressions can help us extract useful information.\n",
    "\n",
    "In this reading, we'll use regular expressions to analyze the git history of this repo: https://github.com/tylerharter/cs320.  After checking out the repo, we ran `git log > git-log.txt` to produce the \"git-log.txt\" file we'll be using here.\n",
    "\n",
    "We'll use regular expressions to extract the following:\n",
    "\n",
    "1. all commit numbers\n",
    "2. email addresses\n",
    "3. forks from which pull requests were made\n",
    "4. all dates "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Commit Numbers\n",
    "\n",
    "`b046b85da7f5d65ef2131eefe72a8c1a39c5d139` is an example of a valid commit number.  It is 40 characters long, and contains only the 16 hexidecimal digits (0-9 and a-f).  For test cases, we'll put that example as the first line is a valid commit, and the following ones are not (because they are too long, contain invalid characters, or are too short -- in that order)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "tests = \"\"\"\n",
    "b046b85da7f5d65ef2131eefe72a8c1a39c5d139\n",
    "0000000000000000000000000000000000000001234\n",
    "b046b85da7f5d65ef2131eefe72a8c1a39c5dzzz\n",
    "b046b85da7f5d65ef2131eefe72a8c1a39c5d\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The character class that matches a digit is `[0-9a-fA-F]`.  Let's try matching 40 of those."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b046b85da7f5d65ef2131eefe72a8c1a39c5d139\n",
      "0000000000000000000000000000000000000001\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "for match in re.findall(r\"[0-9a-fA-F]{40}\", tests):\n",
    "    print(match)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Do you see what happened?  Although `0000000000000000000000000000000000000001234` is not a valid commit number, as it is 43 characters instead of 40, the regex is recognizing the first 40 characters as a valid regex.  This probably isn't what we want.\n",
    "\n",
    "To fix it, we'll use a new metacharacter, `\\b`.  According to the Python docs, this \"matches the empty string, but only at the beginning or end of a word. A word is defined as a sequence of word characters.\"  (word characters are `[a-zA-Z0-9_]`, so commit numbers conveniently consist of word characters)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b046b85da7f5d65ef2131eefe72a8c1a39c5d139\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "\n",
    "for match in re.findall(r\"\\b[0-9a-fA-F]{40}\\b\", tests):\n",
    "    print(match)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nice!  Now that we have developed and tested the regex we want, we can use on our big log file from the git repo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "commit 24c509d20afed69592442f9d1de97131dab6bd3a\n",
      "Author: tylerharter <tylerharter@gmail.com>\n",
      "Date:   Mon Mar 1 15:59:16 2021 -0600\n",
      "\n",
      "    debug 5\n",
      "\n",
      "commit 0d5316187148c72fd65439f7aec5da6859cc8913\n",
      "Author: Peyman <payman.pm@gmail.com>\n",
      "Date:   Mon Mar 1 15:26:45 2021 +0000\n",
      "\n",
      "    updated README\n",
      "\n",
      "commit 79a3058f59e43953f5036e3980b47eec9a7ede62\n",
      "Merge: 44c1e8a 41fd923\n",
      "Author: Peyman <payman.pm@gmail.com>\n",
      "Date:   Mon Mar 1 15:23:18 2021 +0000\n",
      "\n",
      "    Merge branch 'master' of https://github.com/tylerharter/cs320...\n"
     ]
    }
   ],
   "source": [
    "with open(\"git-log.txt\") as f:\n",
    "    log = f.read()\n",
    "print(log[:500] + \"...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 524 commits.  Here are the first 10:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['24c509d20afed69592442f9d1de97131dab6bd3a',\n",
       " '0d5316187148c72fd65439f7aec5da6859cc8913',\n",
       " '79a3058f59e43953f5036e3980b47eec9a7ede62',\n",
       " '44c1e8a1f57ff854a130a162922a4a97c7fc6991',\n",
       " '41fd92391f01969eca8d11a6e3462c3025355b03',\n",
       " '2b0846b3830a2c0a61477c968a5abd6303d9ba84',\n",
       " 'fc44fd584eb807622f516f929c2bfd4e646c6520',\n",
       " '5dbe4ed8b6da984a78e38bc9f3a347b739373f13',\n",
       " '546a37d6c9fd92120f8bd6608ce05a66597ca2e9',\n",
       " '07971e14d6afd534de889a53ac5517472be03e1c']"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "commits = re.findall(r\"\\b[0-9a-fA-F]{40}\\b\", log)\n",
    "print(f\"Found {len(commits)} commits.  Here are the first 10:\")\n",
    "commits[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Email Addresses\n",
    "\n",
    "We see email address in the log, like this:\n",
    "\n",
    "```\n",
    "commit 24c509d20afed69592442f9d1de97131dab6bd3a\n",
    "Author: tylerharter <tylerharter@gmail.com>\n",
    "Date:   Mon Mar 1 15:59:16 2021 -0600\n",
    "\n",
    "    debug 5\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It looks like we want everything between `<` and `>`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['<tylerharter@gmail.com>',\n",
       " '<payman.pm@gmail.com>',\n",
       " '<payman.pm@gmail.com>',\n",
       " '<payman.pm@gmail.com>',\n",
       " '<tylerharter@gmail.com>',\n",
       " '<tylerharter@gmail.com>',\n",
       " '<payman.pm@gmail.com>',\n",
       " '<payman.pm@gmail.com>',\n",
       " '<payman.pm@gmail.com>',\n",
       " '<payman.pm@gmail.com>']"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "emails = re.findall(r\"<.*>\", log)\n",
    "emails[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Oops, we don't want to include those angle brackets (`<` and `>`).  Let's put parentheses (`(` and `)`) around just the email part, with `r\"<(.*)>\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 525 emails.  Here are the first 10:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['tylerharter@gmail.com',\n",
       " 'payman.pm@gmail.com',\n",
       " 'payman.pm@gmail.com',\n",
       " 'payman.pm@gmail.com',\n",
       " 'tylerharter@gmail.com',\n",
       " 'tylerharter@gmail.com',\n",
       " 'payman.pm@gmail.com',\n",
       " 'payman.pm@gmail.com',\n",
       " 'payman.pm@gmail.com',\n",
       " 'payman.pm@gmail.com']"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "emails = re.findall(r\"<(.*)>\", log)\n",
    "print(f\"Found {len(emails)} emails.  Here are the first 10:\")\n",
    "emails[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we want, we can throw these in a pandas Series, allowing us to count occurrences, plotting the result in a bar plot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7fe005c42e80>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "pd.Series(emails).value_counts().plot.barh()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that some commits look like this:\n",
    "\n",
    "```\n",
    "commit 6f331b977075991eaafc892e2b551e1346cfb396\n",
    "Merge: bdc058d dee374a\n",
    "Author: Tyler Caraza-Harter <tylerharter@users.noreply.github.com>\n",
    "Date:   Wed Feb 10 08:29:15 2021 -0600\n",
    "\n",
    "    Merge pull request #25 from ch-shin/master\n",
    "    \n",
    "    mini.zip update\n",
    "```\n",
    "\n",
    "The \"Author\" email address sometimes corresponds to the person who merged a pull request, not the original author.  Can we find the actual git users behind the pull requests?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Pull Requests"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Can we extract `ch-shin/master` from text like `Merge pull request #25 from ch-shin/master`, as in the last example of the above section?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Merge pull request #28 from GAInTheHouse/master',\n",
       " 'Merge pull request #1 from emmabrostrom/patch',\n",
       " 'Merge pull request #23 from varun19299/master',\n",
       " 'Merge pull request #22 from jaimericart/patch',\n",
       " 'Merge pull request #21 from jaimericart/patch',\n",
       " 'Merge pull request #19 from Cyrannosaurus/patch',\n",
       " 'Merge pull request #18 from tylerharter/newbranch',\n",
       " 'Merge pull request #16 from beninato8/master',\n",
       " 'Merge pull request #13 from tylerharter/p3_handin',\n",
       " 'Merge pull request #15 from beninato8/master',\n",
       " 'Merge pull request #14 from beninato8/master',\n",
       " 'Merge pull request #11 from vmpatil/master',\n",
       " 'Merge pull request #12 from beninato8/master',\n",
       " 'Merge pull request #10 from beninato8/master',\n",
       " 'Merge pull request #8 from beninato8/master',\n",
       " 'Merge pull request #6 from beninato8/master',\n",
       " 'Merge pull request #5 from beninato8/master',\n",
       " 'Merge pull request #2 from beninato8/master',\n",
       " 'Merge pull request #1 from jungerm2/master']"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "re.findall(r\"Merge pull request #\\d+ from \\w+/\\w+\", log)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That looks promising!  Let's put some parentheses around key parts, to extract what we want:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('28', 'GAInTheHouse', 'master')\n",
      "('1', 'emmabrostrom', 'patch')\n",
      "('23', 'varun19299', 'master')\n",
      "('22', 'jaimericart', 'patch')\n",
      "('21', 'jaimericart', 'patch')\n",
      "('19', 'Cyrannosaurus', 'patch')\n",
      "('18', 'tylerharter', 'newbranch')\n",
      "('16', 'beninato8', 'master')\n",
      "('13', 'tylerharter', 'p3_handin')\n",
      "('15', 'beninato8', 'master')\n",
      "('14', 'beninato8', 'master')\n",
      "('11', 'vmpatil', 'master')\n",
      "('12', 'beninato8', 'master')\n",
      "('10', 'beninato8', 'master')\n",
      "('8', 'beninato8', 'master')\n",
      "('6', 'beninato8', 'master')\n",
      "('5', 'beninato8', 'master')\n",
      "('2', 'beninato8', 'master')\n",
      "('1', 'jungerm2', 'master')\n"
     ]
    }
   ],
   "source": [
    "matches = re.findall(r\"Merge pull request #(\\d+) from (\\w+)/(\\w+)\", log)\n",
    "for match in matches:\n",
    "    print(match)\n",
    "    pr = match[0]\n",
    "    user = match[1]\n",
    "    branch = match[2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We're looping over tuples with the three pieces of info we want: commit number, github user, and branch.  We could pull that out with `pr = match[0]` and similar, as in the above example.  Alternatively, Python has a feature called *unpacking* that is useful in such cases.  Instead of `match` on the line we define our `for` loop, we can list the three variables we want to fill from the tuple we are currently looping over."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "GAInTheHouse\n",
      "emmabrostrom\n",
      "varun19299\n",
      "jaimericart\n",
      "jaimericart\n",
      "Cyrannosaurus\n",
      "tylerharter\n",
      "beninato8\n",
      "tylerharter\n",
      "beninato8\n",
      "beninato8\n",
      "vmpatil\n",
      "beninato8\n",
      "beninato8\n",
      "beninato8\n",
      "beninato8\n",
      "beninato8\n",
      "beninato8\n",
      "jungerm2\n"
     ]
    }
   ],
   "source": [
    "for pr, user, branch in matches:\n",
    "    print(user)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Dates"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Look at the date line of a commit entry in the log:\n",
    "    \n",
    "```\n",
    "commit 24c509d20afed69592442f9d1de97131dab6bd3a\n",
    "Author: tylerharter <tylerharter@gmail.com>\n",
    "Date:   Mon Mar 1 15:59:16 2021 -0600\n",
    "\n",
    "    debug 5\n",
    "```\n",
    "\n",
    "We see a date starts with \"Date:\" and some spaces (excluded) and ends with a four digit number, such as \"2021\" (included).  Let's try the match."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Mon Mar 1 15:59:16 2021 -0600']"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = \"Date:   Mon Mar 1 15:59:16 2021 -0600\"\n",
    "re.findall(r\"Date:\\s+(.*\\d{4})\", text)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Do you see the problem?  Both `Date:   Mon Mar 1 15:59:16 2021` and `Date:   Mon Mar 1 15:59:16 2021 -0600` could theoretically match (depending on how many characters `.*` matches), as both end in four digits.  `0600` is timezone info, and let's assume we don't want that.\n",
    "\n",
    "By default, the `*` is greedy, meaning it prefers to match more characters.  That's why we got the longer option.  If we use `*?` instead, it will no longer be greedy, and we'll get the shorter version, ending in the four digits of the year."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Mon Mar 1 15:59:16 2021']"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text = \"Date:   Mon Mar 1 15:59:16 2021 -0600\"\n",
    "re.findall(r\"Date:\\s+(.*?\\d{4})\", text)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great, now we can test on the original data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 524 dates.  Here are the first 10:\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['Mon Mar 1 15:59:16 2021',\n",
       " 'Mon Mar 1 15:26:45 2021',\n",
       " 'Mon Mar 1 15:23:18 2021',\n",
       " 'Mon Mar 1 15:21:34 2021',\n",
       " 'Mon Mar 1 08:44:41 2021',\n",
       " 'Mon Mar 1 08:42:30 2021',\n",
       " 'Mon Mar 1 04:05:58 2021',\n",
       " 'Mon Mar 1 04:03:36 2021',\n",
       " 'Sun Feb 28 00:08:27 2021',\n",
       " 'Sun Feb 28 00:05:01 2021']"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dates = re.findall(r\"Date:\\s+(.*?\\d{4})\", log)\n",
    "print(f\"Found {len(dates)} dates.  Here are the first 10:\")\n",
    "dates[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "Regular expressions are very helpful for analyzing logs and other text-based data.  Unfortunately, it's difficult to get a regular expression correct on the first attempt; we made several intuitive mistakes along the way in this reading before arriving at the correct expression.  In such cases, it's difficult to troubleshoot when running on the big dataset, so do what we did here: create some simple examples and revise your regular expression until it works with those.  Then go back and use it on your full dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
