Skip to content

Instantly share code, notes, and snippets.

@zouppen
Created October 12, 2011 21:14
Show Gist options
  • Save zouppen/1282608 to your computer and use it in GitHub Desktop.
Save zouppen/1282608 to your computer and use it in GitHub Desktop.
I accidentally collected information of electricity switch state... :-)
-- |Parses log file for network card ups and downs. In Liittovaltio we
-- have a switch which shuts down all electric equipments in our
-- living room, including our network switch. I accidentally
-- discovered that when this button is pressed, the intranet interface
-- of Moskova is put offline, too. Moskova writes it to kernel log as
-- any good server should. The reverse happens when the power is
-- resumed. Some example log lines:
--
-- > 2011-10-04T23:46:04+0300 eth0: link up, 1000 Mb/s, full duplex, ...
-- > 2011-10-05T02:20:42+0300 eth0: link down
module PowerParser where
import Text.Parsec
import Text.Parsec.String
import Data.Time.Format
import System.Locale
import Data.Time.Clock
import Data.List (groupBy)
import Data.Function (on)
data Direction = Up | Down deriving (Show, Eq)
-- The next ones are very specific to Moskova.
isoTimestamp = many $ noneOf " "
common = string " eth0: link "
linkUp = string "up" >> return Up
linkDown = string "down" >> return Down
-- |Parses ISO 8601 date. Returns error in any monad.
isoParser str = case parseTime defaultTimeLocale "%Y-%m-%dT%H:%M:%S%z" str of
Just stamp -> return stamp
Nothing -> fail "Invalid date format"
-- |Parses a single line.
parseLine :: Parser (UTCTime,Direction)
parseLine = do
stamp <- isoTimestamp >>= isoParser
common
value <- choice [linkUp,linkDown]
throwLineAway
return (stamp,value)
-- |Tries to parse input line by line until match.
parseNextValid :: Parser (UTCTime,Direction)
parseNextValid = try parseLine <|> (throwLineAway >> parseNextValid)
-- |Skips the end of the line.
throwLineAway = do
skipMany $ noneOf "\n"
char '\n'
-- |Parses the whole input to a list.
parseAll = manyTill parseNextValid eof
-- |Converts a list of actions into list of pairs (up,down).
upDownPairs ((_,Down):xs) = upDownPairs xs
upDownPairs ((up,Up):(down,Down):xs) = (up,down):upDownPairs xs
upDownPairs [(_,Up)] = [] -- End of the list, powers still up.
upDownPairs [] = []
upDownPairs _ = error "List is errorneous"
-- |Removes successive ups and downs from a list.
removeGarbage xs = map head $ groupBy (on (==) snd) xs
-- |Converts (up,down) pair to a CSV line with UNIX timestamps.
toTimestamps :: (FormatTime t) => (t, t) -> String
toTimestamps (up,down) = formatter up ++ "," ++ formatter down
where formatter = formatTime defaultTimeLocale "%s"
-- |Parses a log file and writes output as CSV.
kernelLogToCSV :: FilePath -> FilePath -> IO ()
kernelLogToCSV from to = do
parsed <- parseFromFile parseAll from
case parsed of
Left e -> fail $ "Parse error: " ++ show e
Right x -> writeStamps $ upDownPairs $ removeGarbage x
where writeStamps xs = writeFile to $ unlines $ legend : map toTimestamps xs
legend = "up,down"
We can make this file beautiful and searchable if this error is corrected: It looks like row 2 should actually have 1 column, instead of 2. in line 1.
; Timestamps of when our living room electricity were switched on and off. Format: Seconds since UNIX epoch.
up,down
1300234163,1300267202
1300296417,1300318226
1300354059,1300404154
1300433280,1300502719
1300524418,1300527665
1300529778,1300587046
1300619467,1300671503
1300734461,1300754052
1300781804,1300841447
1300901657,1300922516
1300956492,1301296883
1301327563,1301353903
1301421773,1301438238
1301551598,1301612855
1301637788,1301692498
1301755987,1301769076
1301785907,1301788306
1301828604,1301940842
1301941094,1302043098
1302045694,1302120312
1302190497,1302211599
1302294471,1302298539
1302351283,1302396260
1302427541,1302473006
1302536360,1302557840
1302621114,1302642666
1302718068,1302731746
1302768698,1302794524
1302794533,1302818668
1302857219,1302916149
1302916154,1302933985
1302949065,1302978796
1303023956,1303079969
1303138359,1303166446
1303231413,1303245669
1303342625,1303346593
1303367100,1303390614
1303390625,1303395001
1303667098,1303855105
1303917441,1303940696
1303971434,1303973780
1304003153,1304032802
1304172162,1304173491
1304256013,1304319897
1304363609,1304383593
1304412339,1304460549
1305032653,1305092549
1305101678,1305104167
1305134668,1305158664
1305192075,1305194217
1305214987,1305270316
1305335723,1305339395
1305380013,1305380379
1305445960,1305497065
1305553740,1305576099
1305607319,1305697345
1305733260,1305762217
1305791200,1305793916
1305840320,1305840817
1305916557,1305924710
1305966660,1305974633
1306021072,1306024834
1306026133,1306028154
1306060007,1306152360
1306168358,1306183491
1306250671,1306259079
1306270170,1306272363
1306272993,1306277249
1306417533,1306454747
1306702842,1306708074
1306780425,1306802076
1306823477,1306824070
1306829827,1306832247
1306860502,1306883905
1306945340,1306966052
1306998331,1307078151
1307106084,1307108991
1307269894,1307309315
1307385316,1307403169
1307430005,1307440903
1307476623,1307490132
1307551290,1307558479
1307632214,1307651336
1307722730,1307741938
1307782443,1307790928
1307807419,1307826288
1307863157,1307884177
1307898106,1307915300
1307988936,1308001026
1308035462,1308041600
1308042493,1308046171
1308062002,1308094765
1308122282,1308178842
1308240842,1308258042
1308291211,1308303914
1308318929,1308330586
1308354869,1308356690
1308361458,1308364080
1308393036,1308443270
1308471413,1308524840
1308583978,1308612608
1308631950,1308697582
1308757243,1308788335
1309116483,1309169286
1309191843,1309195388
1309202882,1309219477
1309396754,1309398719
1309431741,1309501929
1309509388,1309518013
1309718259,1309733027
1309799580,1309810216
1309856932,1309899233
1309936325,1309986236
1310047796,1310078244
1310132875,1310136710
1310151665,1310168668
1310207983,1310211224
1310235142,1310235962
1310291773,1310330093
1310415978,1310419192
1310505965,1310516786
1310582552,1310601735
1310667279,1310723066
1310739307,1310741184
1310758190,1310765621
1310918363,1310936943
1311006408,1311031505
1311095571,1311113121
1311180768,1311200055
1311261203,1311286992
1311354978,1311365913
1311621584,1311627834
1311691050,1311718169
1311779879,1311810340
1311881136,1311988318
1312014732,1312074535
1312102299,1312157643
1312164256,1312175858
1312226093,1312246409
1312286588,1312299027
1312324185,1312331024
1312380041,1312503693
1312542444,1312549126
1312746466,1312759731
1312792549,1312849065
1312879326,1312935323
1312966059,1313023061
1313063469,1313094846
1313130002,1313133310
1313224138,1313238606
1313258369,1313288192
1313316668,1313363468
1313417289,1313450419
1313486822,1313491270
1313558604,1313619552
1313693193,1313714835
1313769360,1313794458
1313829635,1313841819
1313858262,1313885023
1313917584,1313964252
1314034856,1314050474
1314105519,1314166672
1314199170,1314224167
1314224899,1314256599
1314286549,1314287106
1314368195,1314444940
1314458227,1314488622
1314537776,1314568179
1314624844,1314660869
1314708075,1314745315
1314807236,1314837365
1314902605,1314913691
1314980996,1315015952
1315057195,1315096580
1315099691,1315104988
1315125547,1315207639
1315237333,1315249865
1315289234,1315291317
1315328713,1315348797
1315417330,1315437518
1315507118,1315523315
1315763559,1315788794
1315852574,1315857310
1315944105,1315954969
1316019858,1316035736
1316118222,1316123491
1316195876,1316309072
1316341763,1316483909
1316540664,1316564547
1316620847,1316641569
1316713916,1316733350
1316764477,1316764826
1316786009,1316825882
1316862802,1316913294
1316952016,1316997472
1317056906,1317075633
1317147208,1317160327
1317240881,1317248272
1317285424,1317289285
1317395396,1317409341
1317477647,1317508028
1317537573,1317597828
1317627532,1317685461
1317740908,1317749259
1317761164,1317770442
1317837830,1317853407
1317916420,1317944896
1317980478,1318035767
1318076979,1318084803
1318185594,1318201742
1318277693,1318291570
1318356740,1318376565
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment