Skip to content

Commit ae8cf96

Browse files
committed
First working iteration
1 parent 13fc3c2 commit ae8cf96

File tree

6 files changed

+154
-0
lines changed

6 files changed

+154
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.hi
2+
*.o
3+
*.exe
4+
dist/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) <year> <copyright holders>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,26 @@ log2sql
22
=======
33

44
Parses a log file and writes it to a [SQLite] database for better querying
5+
6+
Usage
7+
-----
8+
9+
Currently `log2sql` only supports [decrypted] Windows client log files.
10+
11+
`log2sql myfile.log` will create `test.db` with your log's data as columns of the table `test`.
12+
13+
14+
Building
15+
--------
16+
17+
You must have
18+
19+
* [Glasgow Haskell Compiler](http://www.haskell.org/ghc/)
20+
* [Cabal](http://www.haskell.org/cabal/) (which comes with the [Haskell Platform](http://www.haskell.org/platform/))
21+
22+
Then you can
23+
24+
```bash
25+
$ cd log2sql
26+
$ cabal install
27+
```

Setup.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

log2sql.cabal

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-- Initial log2sql.cabal generated by cabal init. For further
2+
-- documentation, see http://haskell.org/cabal/users-guide/
3+
4+
name: log2sql
5+
version: 0.1.0.0
6+
synopsis: Places program logs into SQL for better querying
7+
-- description:
8+
license: MIT
9+
license-file: LICENSE
10+
author: Elliot Cameron
11+
maintainer: [email protected]
12+
-- copyright:
13+
category: Development
14+
build-type: Simple
15+
-- extra-source-files:
16+
cabal-version: >=1.10
17+
18+
executable log2sql
19+
main-is: Main.hs
20+
-- other-modules:
21+
-- other-extensions:
22+
build-depends: base >=4.6 && <4.7,
23+
bytestring,
24+
optparse-applicative,
25+
sqlite-simple,
26+
text
27+
hs-source-dirs: src
28+
default-language: Haskell2010

src/Main.hs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
3+
module Main where
4+
5+
import Control.Applicative
6+
import Control.Category ((>>>))
7+
import Control.Monad (forM_)
8+
import Data.Text.Lazy (Text)
9+
import qualified Data.Text.Lazy as T
10+
import qualified Data.Text.Lazy.IO as Tio
11+
import Data.Monoid
12+
import Data.String
13+
import Database.SQLite.Simple
14+
import System.Environment (getArgs)
15+
16+
data TestField = TestField Int String String deriving (Show)
17+
18+
instance FromRow TestField where
19+
fromRow = TestField <$> field <*> field <*> field
20+
21+
data Options = Options
22+
{ opName :: Text
23+
, opFields :: [Text]
24+
, opDelim :: Text
25+
}
26+
27+
defaults :: Options
28+
defaults = Options "test" ["timestamp", "thread_id", "line_no", "file", "func", "message"] ","
29+
30+
encloseWithLR :: Monoid a => a -> a -> a -> a
31+
encloseWithLR left right inner = left <> inner <> right
32+
33+
encloseWith :: Monoid a => a -> a -> a
34+
encloseWith x = encloseWithLR x x
35+
36+
enclosedBy :: Monoid a => a -> a -> a
37+
enclosedBy = flip encloseWith
38+
39+
sqlColumns :: [Text] -> [Text]
40+
sqlColumns = map $ encloseWith "\"" >>> (<> " TEXT")
41+
42+
limitedSplitOn :: Int -> Text -> Text -> [Text]
43+
limitedSplitOn 0 _ x = [x]
44+
limitedSplitOn limit delim x = if length pieces > limit
45+
then take (limit - 1) pieces ++ [T.concat (drop limit pieces)]
46+
else pieces
47+
where pieces = T.splitOn delim x
48+
49+
runWith :: Options -> [Text] -> IO ()
50+
runWith (Options name fields delim) xs = withConnection (fileName) $ \c -> do
51+
execute_ c $ fromString (T.unpack $ "CREATE TABLE IF NOT EXISTS " <> tableName <> " " <> columnDef)
52+
execute_ c "BEGIN TRANSACTION"
53+
forM_ xs $ \x -> do
54+
execute c (fromString (T.unpack insertQuery)) (parseLine x)
55+
execute_ c "COMMIT"
56+
where
57+
fileName = T.unpack $ name <> ".db"
58+
tableName = name `enclosedBy` "\""
59+
columnDef = "(id INTEGER PRIMARY KEY, " <> (T.intercalate ", " (sqlColumns fields)) <> ")"
60+
insertQuery = "INSERT INTO " <> tableName <> " ("
61+
<> T.intercalate ", " fields
62+
<> ") VALUES ("
63+
<> T.intercalate ", " (replicate (length fields) "?")
64+
<> ")"
65+
66+
parseLine :: Text -> [Text]
67+
parseLine x = clean <$> limitedSplitOn numFields delim x
68+
where
69+
numFields = length fields
70+
clean = T.dropAround (`elem` " \"")
71+
72+
main :: IO ()
73+
main = do
74+
(fileName:_) <- getArgs
75+
Tio.readFile fileName >>= (T.lines >>> runWith defaults)
76+

0 commit comments

Comments
 (0)