logzero-1.5.0/0000755000372000037200000000000013250015612014031 5ustar travistravis00000000000000logzero-1.5.0/docs/0000755000372000037200000000000013250015612014761 5ustar travistravis00000000000000logzero-1.5.0/docs/_static/0000755000372000037200000000000013250015612016407 5ustar travistravis00000000000000logzero-1.5.0/docs/_static/demo_output.png0000644000372000037200000002545413250015553021477 0ustar travistravis00000000000000PNG  IHDR/}PLTE)3(3)45VFӱ9(4(Tw`8/XUʠo#;1A\}mO-ٵZ'2Q*I&2נrp52ȁ:2sL*n"tѩwQ$)4[CubͿྏ͡",fyo'2g&pMaBrťn&$1b%.ut`)(WdcOP.OtG1441%;H[_S+*fs{8>1#)O/kb =m%b{A}V;1pyz(_)[a(N-br!Zm#wxzs!X}h$ l us ~x632.&.0/02`)jIDATx{Jwn'섎{{Ojuؖ^hgU2Xkk*Wl߱Rxf*]vgYi)*WlCg+6֐kےwb|Km\?ǯxd}E׬ KF+ֿoHb;bn%~l% +ۆ!ߐ?ŴR+&::n۩SXJf`Z*;b]ClܲnE7ߟ_1WK.3d !/ n8=㮲S} Z9o;~!-s)'A<"#L2H/+^xK~U»@ix=lWE|_>Mg|9ecAK&׳+&i.J-;;TnSIfk佨e{-G rGNc]|}9HcY9;|25BL`/:2NQJ~(g`o5E] 4IT5}imI7=yG9u [lβǚ̟G'O0>+y%O"i#?'rnheGd_yi)q1ZTM2m?T'v[{}JD'ȰO0>p^y"³h[ HG!G]BxSТO}V:<֌u߲Wg2IyDƶEHSWie'ӯo^ɓx w6[\ VxoS ȞPc<ƓXC+&f< wI}.ڼkaN,j$೶?/tP+vM#ТOɗ" oA/WHǚ>xWcr+_t,C<&wx!e 䎿`:5C`H8ʿ%YtD"#\hʎH<UDOYEFm0ǼТ#]u$!_Ld~jf%e>}WnUdr#B~FkTǙQ|zW*y1ڇ4 gU2_kv!vC6nzee}0_2OQZoni~dz^Yk8RAE+ 1voL+ӷ|ٔ ?{䕩<=م~,0=h7/d?%|._J` 'v7sXWKbw2<(ih4dW*F?Sn(lVpQj(xĢ7B^ؔC}-G!rf'UެZ& \$#l\E,v+s'Tk D{td%bY)6wrhϙ6ڕv,?4̻/f-Zݧ(wE8E7-qB|4cs|ANU!Ԋ[;}Y6ݐcծ4xr=+]Q F@.Sl=9 3_zӅ4ďٔ1uJqx2iD?z& Rq,ϟ4M3m=] <@MJIL}4%80<3ڕ%V.|^7{D=VtJn4 Ǘ[XJ^'XJi<:ul? Olgq+/l:htW"O?1p4qb$]ǯeyrXw&_W`ߤ0<0윿dw&?YWc;JR8 6ʱJhxr(ϏiOux"wPSZ0ѵcw=5JڋE? p-ݬ?CXTcvrfY\ϯ}WЕtz& ^y/h bsV?L[D-U[P0?Tl8ϸ8lK YË`xi O|޹h'vꏚҸio}֝ 5,h~H_<[ ?&"ʛPZSF9jSX?WX-,E%ƞ3/w^50AnrH]n)nfOf.NNMLW{ [Px1?F)?~Sׯ%_^>^`ٕ6&ry!Egچ?2'7@Ie|%na e=5;Dgiu볔NNy:'7+;F)ɿ+sQ4[3o'A)1wǟxwHٮz޻qF0<{cKbP>c~a*B`g+.7JH})bQNM?6e89+D/ A(g"j$jnh#ޏm[:wspz.S}wYOR_g>F*}5dKs^kh;N2~+gb(m2&ol׃1|7!iZKLٓ._-MlOK!t|Elj4E+@A1|->eo|Gw޵񎳞z%OĠ2Z#ZdBNRTس ).(L8RDK~sK~rjZK+Z 6GtɃowq)//27ª7n~/|{"{ #>^땠үh}LnJ? ku>Nf8%MLR a-ҙ2Nv:gA=o{8'2 LJD=ǗFXFx&Ud>Jmĸk ZRT/) &6ָGbQ^ JL&],oE/8X>WewJU]o)cb`Ox(ϫWiE>ĸ"kٻby/)x/. uIoV5?b⥩X|i4= *TѳRY n^%w>?ȕJ`{3ٻRyHõ\s9A@9(W&Ri3D/.>h,n#Ff 0R15UysU a$8H$I$$&gXD~?"RH%1? o$ Gʗzpg*{/{2uF^@mX+NU+]0>dx+2v=SU9T oTFY~$W%J%yiJ׿DcJXs+sHr08[~`P&OV(K۴ׅ9L`|qurDNn_d^㬑+VwػSD5nBD ٴɷ"g=m!j{ߌ'$YjXs^|s2A~Z/JdB?jkDط 4 +a]t oBdȕ ߭l4rRI}w^YJ 5X|VӔ{ErjJs[Ho֋WwF?ڻS-2+kYU-eL? Mm*0޸/2wk RTZ}׻_,I@}ʲ?Ҭt6MGxt:(84Wǣ_nR20ouÏgهxI߫WJQgGte}s>Ígh|-_9ࡿrC倇D⡿rw#YԊ:B5O Ф}b0;bv*1Q {v('S 9ܭ*seMRWiZEMAu:^cxTk/gybQi,yz_I 8_;vZ4j7}g=Ǚ^9.%zbgCTSoʎDX~ކY8D|w#԰Z^9^kCq d9}=*oߺ=`*^Tէھ>6!hT˰ڇ8^qw-ax}iZ !.3fSy0F#0#臫qySN+?&!gg*Id*T$v.+)G-_xRg8d/M`,ku±;:-.@iB'q^8l)(x%[1ZNJⴂx^+ϧvP덿~rl4_y7b2KoI1cwL_LeȧzV] eQKnҮw1_ψ2sbYl fԎSc׿nKŹ'yΚ/{?\@D)Q0RCN~y~+}e1?]f)hT {zvy]WJӿ}`Ja {@yJ .^XM]β`l$f?mX,v֍k-@r g5;HWc'F]J\[z6scBeSA +ϲ+m@땠2ӿ*04H*Ƥ)90YŠ S] -Y0-+M|-ck6t^ k\z/0'HB\y]h\zr}Y^4 yq-t[?ߑ9?W EZR&cBRpUG pZ ۂ)[#{\>6%z]wy b=SAðypQ,881㌬^C]nWcw% 9P 7+u q1&C>*ƠT(JRWh>dU˯YɢNۺRX#*}ca1 J(#)rWAVWƯ}k~>VzP5QXsB%~zRAI ~ǔq!OoO)bǂX`RAҌv??X<fΨX*F/qlT©.? 4.go/׿#1G3蕠RV#"} Tfݨj]F !޶-f*-b$^S'T$XcJ T96pq{v!Ol[Vg#`]PwTwQto?JzVk_'XY+Nӿ aV2ofuD~#wŶn]zΘ _ r]^ʸ_}E3n |}lk!;~ +);PGץXo%* W﮳$]aV5fb'M9\D>*גԫ=B_sWr ֯4WON+mg'> zͫqqfڵaxf]v4}$]>\O0+ze܉_,_ys_4N ʽGa?]Y@Uv4Of#k0.7,hdQ` ~TWuNj};{wD7 瞪StOʣ>+|W>+|W<+'/w\+'8 F솼SQÌR5cJcsԧ 1/C[0j=Ax{!5N*+'Y*~[|/^pi!w}U|>:~u=/?k~EKg;V?>u~u}ΔLS?w#ڛ44pJi-D%C]kp]w0Ҽ7s}oo]ϳ%\#pۯ!y#HS+ʥuWD5$⮒ '//?l#7jaWEn SRz%f%x`n},%G~N'%~=Tj &>TM󖁦?5"a#ft>o=>Ki#9Y*3>'p uU+1+ycrÇ͇8vF52 Ps^ERgFҏ<-]׼KSaʿIۈj@*ѿuTxGLtd+.gjPw%g=zaJ^0-nUt4JsA-BTsjn6<qVS9Zui0{  8 pGy<+-^qd?q]ѦwNz]⿲?ݧyzt_6E ~w_7WL$inc3YY=?^~?y|@g88-}TJ݈ITn݇~o}Vf(\__"6n^y1<_JD `(r\Ѷv/ u[`^~?jK$r\܊Izx?|{ e\~Ϭ+ж] ;xZ˼f跫?݂xn_?_3>^مw?^vuQO;pI;px]!xIENDB`logzero-1.5.0/docs/_static/demo_output_with_exception.png0000644000372000037200000002374213250015553024606 0ustar travistravis00000000000000PNG  IHDRy<'IDATxہgZ_ (j ܍BY)ZFRRR[64V5XТECC9]]3!wrrpп!f B!FR"-Dx3ԯ!􎳆?oU[ysgUB{WDLoo$8뇥"%;0kW!He`ufٍBOL CJlњ$5c8zcW95= ֎bdܞMKknO/Xy8h6wﮒw Y n; <3CKF5qY2;EJk׎bk8R \sG-q R'zr6^o١wM"'}ᓯYXyʽRdpv §R`97VlodwƸk4k~CMžm/W=BC^ąK@$$7K $ (1H(bW!>M[9HJeo5 ׎П=*k!%B@uq4I3k)ױE1 }R(U.[(K%K(v`mݷo֚*sޜs{3}%?B${A/T[߽E5Be?BUfDt6W`tiIrW.gra?-YuPD iAKLkncF[:-䓾ᔍؑpv6;E[>r}LRкh6ѻe"'WvfM6֔|AܒExF%/p|rJԓ!mLJR{+ʳc*&M'*ˤ-6iQXa>FgX= +7v_V`#X ZcL\]J \|+΁:O%>dW1ms $TN6% Fl&$Ե;&L|Vtέdt|qo Wg:\$rk-6S<agX@k}ž@k"9c&<\p<$k)ԑ,#ӚBSKշM Vic$aa;OTz>_3arzT)mwǔ2r/~9 !j'PUδCZxNv+,d-1MĄ'-u uF[2{>[{3#Q 1&PnN|y3 wYש,kM kkMj h @aQZ׬Z4!6GУ?=+yA_^D$/R(O}`NGo9\wÄ9:8lWM{Qs2KgjWζ71FʕPz/@9('vh/wvISaoa#\v 5gxHx'}A=T@@@5wcax1LIC8ňԅںZ{3\Ԍn J)+B9,r8,,p.I_ݿ{}sqH罯//<5I+l.="&tM3͠wʫ2_;_[E> x/߾@JQR/(h7)8>]|%M:@^mEs^TnXW˺_"@%5>;VDڏ+3t*fȽ2{}6y!充 +igO;Şw͋ZK'߾ yxtm"FzW[d_wI7>9yI\*U"+3 sx$ n bV'Qt.& ?v3ea&m +RaΝs я0$q\jmj+93Ǝyis:LF"? i7(()cH@rkYáͤ@{k|^&۽xMӺh#몠'UU!5An QV˰q_tvLNp˗t5e s|ZZ*_Mk >[E@@@@x fj@ȶdfw/)@"l@O`݂d A 6KUТd԰֒VJ T`}w;g_-s~ 2srn[Bl$vMѸ n vÅ5}Ii x}"b}@;7rVZzB.P FB #j<ԍ򾕼F]-R s; CpA-D+Ry__ NFa4{FςӅ5rG3A'Gf! wtr%CGo ˟މ(d| )21۹Ęgm\6Dp0>fՀӴf 3 MPlƅ[XZcpVF+yO :Èw9+y1j9Ù%BNB#+qߍ #HMKVQư;HihB^)sJkV}|hLmPUwڪ۪#b4hMg~Ŧ{u?\b;忯O )7|?qNm,.NW8Z30Т;i#0GL?zKwJNc>gdvܳG1+911ur0 &N+%Dp "xe?w^אo_rNYjUごݫ@*6頮_].M??״W;\^6~ z4ךo={fA ?p&lF(%;bÎ{H^0tJYGޡeWaLkzPu<4`&ձ`)cpmiˆ'rc6MAVDž>2<$,Q;Ʌ` ;ߍ_g՞Oe/skSIM-/~ybImj}=o9+%\a}~XX]HShML6k~C3JuWJAsҵ~VsrxVȞ#B!К#&+8Է8К5 )r ZDk.7~> .k}?~^9|jM0)}javdr$z+ښSMőeW2K[j9j?,=-DQS2þ$a"8Mmۇ+|BZi"95tWռ M'sÝ<ٚԴo Y\7m>95j Wk<1}o(㭼 MJ#j[ 2rZ'tf+Wa}(ȒZyoe$4?y0$>25͞]{Yq;L cfp52* aۯ_a4fhduHm";KӁְ)WͧWkl샐x7=eW#T{jNB& {@0;=evgOKW.w\ZՋfٌ09j.-bFM >.P.\pƅ ָpŇӚ!KHa]j.*3|hF,雚\8IaB&M)r3 ׂvPi TYDhJ- ߠ `~5-2j\f$$ lL0QRQ~ᗶ$54Ol *˒ fF\Z%GZpw:v+ JBG TNMUTCԩ% iEH=6DTmicw.$ma {DpF R Juf\qPk:q hV>0CP",ZpR!&iO(h#x0Q@.;Li촉^aFdzM} 7G-mh^ߕ&{-v5_^/yÖ.΁i7h3ӧ՚bX-a5BF'5G)gt#QNg㐘^1Un `Lc,I&ӄAT4L#EnI|PCTF3X!U @Y7jtO#y/i,(sbVcI?x_@tn\taKa *I4vJ[>t1UտNwhTIG,$4=rjLD闷YvpmiHbaYc(y9!e]Jl, S;yGĘ4Jđ/)~T\^zqKF}ހ95\kx-`)ȡNͻCKӆRNB%6z툻~d_E(M轛&ӴњMLҚ.ַB#G&yHk=t\d->F9/KF}ް |MX8́9:"qd#hv c8jOHV o'JP8#HL`wN=/ .&lA-W ]|8f'lf9pᄣoΉǯ_ts^ 5,\ϼ$4[̅ufT?jvPC 'DI>^,8 K@'ߚ^18ȦO6V#0&(Q@Ֆ/KO̳5` !Pӫ_W.0NkgG?㕖TUmO|}ǵn~7lNk>3$Q{GX H 4Aa @ȑc3LI;8{}jMLU6Ķ5D4 hK7{gʖq}ؽu,&@h(HAS ZH4 )R khH+2H !ABB^r7v&7t ܜs$s>'}X,P,bװX,sy VڍTAnš'sySOv*Ȇ׈u,H:~ }y)+*Fד9oqQ})+}|\i+sFQ¯ (Bbç^U1͜7п~5[pTYCRnA Aoxa8*$&ldIEĮ"6ǹXG_\Qm:+'z3mwoFi '6)ܼwcш//r<+⸹~~_l|GUFp v漙U߬[K}McZҮߍ

,$_kD*^kaص|q떼Ե`/қSH=)[{1kt>1( g!q4p<HhN"pTqF.|֌[ɚO$Yi}zM ~[S]Xt `2%<މ"YI>:h`ks1qK$Y¢÷$+O^ nށ*~[y+l^ c2P:wk@"'S}sq,{ Lk-d@u}r8v3>7e h/@i^J B(v SBʻ5x jw2w]p^Қqd%/q7$!A&z (,ʻ5x jZ`}Tl@ܒH[Чl>>:'Whh/F1q J B(”@؛4kы|\oi+ζ_^\gLIVk{P Y#ڧp*7$co^Qt(h/F1q J B(”@FEֲFo jO@bA!s*P:*R;@" ֟kXV2 ?x|̋^bkX,b8Lv* DuӚCհ~[wO7.2/^# tPlwnԖLv/Zf;%tm yL'v;9ǓҤToyҭnkH}{WcV+'5:.LV0iVRB >8OWDÃmٞ}FihLx'^³Bf Y9_SO*."cJ&Nkdר}yz +x$*zΛVO)my>M1E'"I 7'ե.=oEΛ~es/^`7yͅipq 2ݏiB'NkFʉ1ht5&8SݫrR$IJyM2Ϫ[$'^3jfHhVVq%,> v%qUI[q7UN5 (^f Ӛ&+R"ZBn{ Ȇ<1s!-~1P4lJEV|\/? {+`(n3{5\x}rWw7axȆT4o^OM/1:R_>'ӼK=U͠gK6yp?6ĭ6FEn{a cX pa,`ܒ?O- Uôz]\ά (~ ܌"7Ϊ1]?4)VTx_}Z3LV\OwDz*ǓXhf lEʁݓ]y7Li ?ȳɳk8Y9O ٰ&6v,>&baX5,^pa"FrBh:}J6p9{Xà=;(bDm|E0r q9}J=7H=wkXz'7Q)J@Pޣ>!x358p g֜x#%~=+-CшAXR xtyI(2`݁}g̀S?!. Þ XQcV6sf~VgWB9+?wBraR xtzȃ>7(2`݁}iR?1Vž X\ݯÝa8,ds%%j$|E2T4£GrmEr(??; |!āðgּ>e' )a䄝)sL9'HNu}j`58p~ \5rfj2&jO+”9I  $isc>C@B8…a3ϼ3o kVJV^j;O #G7ȟW`e 0 $isc>}C@9?@ 6o?M)aE7(?݁AFJQ *"}րܭ#Bo^l {* YgkT#UtbkTTUt?[]E_7F޿=޷akګx=i=UфlMu=SEؚ*8ȭVEۚiܪhUyUE ؚ[y 5(FupcBIENDB`logzero-1.5.0/docs/_static/logo-small.png0000644000372000037200000002006713250015553021174 0ustar travistravis00000000000000PNG  IHDR,pPLTEɦƳ|q=r zeiR/̰8%{ǙߜƎLڽBuV 1ͧbmBo`j`._B%a[ERF:BBBOOOYXX;;:Y="a9e=iE'T(_1bJ48$CZ.c2óygvR2W.W+ ]GǺonnaaaL3 oAI% PTtT' G-tss[4w?o9N$tN*wEi3p?~Im=c5\/\+mS$ʌ.^vޣ `svHKſ]ă{A}Iz3E)iDlh: \ׯ[쮍ifvnR.-,.ʕ !QJ#XZBČIA^_9I؟Șv+Rq )I:IAwFէL$%>`eL@,ꔐ)Yz·rycA0WXzpRH(5,kDQƢ76[ײYOL 52SuYz4WQ%R# nC_Poߦ׮Z$)J@-.}_tpyQB}S7Xr .Uܑ!Ӓ)Z"LD(Dȷ ;tupX>nCgyY̴PB|cWaCZʮ*GjZ- l *t^jJ;X UɾA<[kS?_Yy?g-e +*łHu΀'q{Sę?|dO QEa宄RBI@*ʬ_=PuTiBJ3Nog E@{I "Z@(QizĦ}c X!Նo ,䏲Bc} _ĸOxisE@uTD:+R฾y3]~ *pDcY ud Ul\'7WHD*<߂K&m XVBu巈Š37\MëAƾ)X3K {RƘ4*p8XLbc!C6E/e( )&Sx#`c ƪ[h,TCby2Tk^RH=* !fz-4h1o!+TuBGH-[-IqN3eIkĘ7plDBĢE \oϑɜysoiJB2 Z!=i&p4ƈٜ9VNXMnez>Ȯ7uieU&@!Cwāq]#p] ss,XE`qxاΫfE|!_~p fop97j 49<1>f|a)/1`k0֥MVNXM.bٳgÞߎ$ VEa1K1O/ovۦMHXvO `|w8;g\PL2p5w;S X [iq XnK;LS" +A O`6҆4ti^dlN' %ʄmߥ!OA΂pRhf8[n!mpw/@9]'TpaoD-3VXmSVs;O,qx>H|AvN:hޗ'i"l7PXYa6|6@FʊDQg݋G_&Xg!dt]]n %lz [avR*:1/3{9kJOQ@j*_CK3[THJPlQۚ'B"V+*G"I5Y9wdvw.hCQIк!v>CrI|UcEpOA5Te{XE0DR'˂*[X,LV{þ'X>6=,6% -H0 | j9!m7VJEWάYuKɲߖ<΃/m]t|e|, TmƽtMUh Iju%5tBZ"Wd),~0~9ۛ9FF$Z'f:h]ڣ~-dUTjW[%עb̕p"XZ@[xF+mhorr /N4ΓKmxYՎRZR B\ l\>!5UP@OiX(E<%^HnTتCA,M-rV zϲ݄^G;RZڟr2zQ&Ft a~LPJ jj h!ŪzǓ۴GcYG |jރ3\F:) F?Y #+bdE1d)h4EXPo_'Vï9R2GTT!0N Њ'djn0HKU˜zUjZT/h*_ AU *YJ!X]ѻ3ƪT-".Uˮ RN Wh]sMT@ 'J$RJtδC0k&q1XvX e `R QDJ߅2Keg4ëF+YUV"W7J_ M E*yc5> c`5r" X^5oD`e`r#目6VÊDdF>`"]cR IʆíEJ_/1 aY,[tQT)e*IE0W0μ1 WVa E串r] !G. !591}wBs #˒gRb*T-B+z캠=Z+6] W>[DA1兢ժHT z 0 /ҟ詑hÏN QubٚJ[yqvW! OC ID,!t(XZRDca2pBN R}^~bNqIX;fʍ⪕vtNs:P]*? L4̓KCmHᗙm\ bt$i;=<8wx:M` X򺴭yX1jkQkQ*295@Rvb؊wyp{yVX`o(ӯLX3+[X1h:f5<+.aufkH y{OjιoǬ˩T)ˮ+Jkީifv; wRuiD9ȪI4be?y&"/ALqΔi`}5:8Hwa"K)  U"`5ٴ۩6'+tZ(Sgε-{M5Jp9eW$:89&8c]P𚇙Wj^>{8X<OT\}k5RA)p$NukMVP l M *rÛ 1+* y%$YU$9*UZDP^Xc"lͭˏ¤ ^V3IѝN9(%+*Qg}[ֳ{ׇüv`0>D+?,\žN^%XSHn";soo+vDvKRz M\Ej`G5B} M]'Y1#3?]"R[y׵zeqZ"1#X k+df `c5 E+Gtѧ,E8IcUa)*y;v:,W $Q4͞Y!&f"FusyeӴV+,D8zbMEi" !7WFZѽg:~)B4[*^!BydsݢbR@\ cU0SʬB)Bn֍嚛bleRx\ӡrklAnm-b =JyaALV[R^6NyTE\񯳒՛Nv z+FmXֶL!.7OAYUu^/:nBccLwĴ" A4p/0%:ysy +ߎȜ FojNLVz Qf 6YHk~vVRX%~{X7=x8X}p=br$fh,z4("HHmkA y QBiKXqy Zb,bB(Z3bCUo9b=t̞\[Нc҄E f4}@d%ae A BY"jVz2oSfb\!̽ /-8jCTo#C/J`?,IPP ϫuQD_{糣(qՓ<ޅ9f@l>,A$.RL2Vc9y\,:anG{ CVhn(R:aUH[R۪,|+.;ΎyrQܞ4y8ĩ$39DFQ+U* ?w\rL7j eC=1p8p8~eIIENDB`logzero-1.5.0/docs/_static/logo.png0000644000372000037200000006315013250015553020066 0ustar travistravis00000000000000PNG  IHDR0~PLTEƳ|q=r zeɦ%̰8/{LڽBƎߜǙͧ1o`j`.a[EYXX;;:Y="T(Z._1bvR2N$tN*OOO8$bJ4PTL3 BBBe=a9W.iE'iRRF:CT' ^6oAI% |||onnZ3aaat]Gygҽ[4~IG-c2lUo9w?i3wE_B%m=uV ǺW+ \+\/c5p?a2mSכ^z=Jc-"gN uaQV_Of-7~ˈi0"ݢ,Rn7 aX/+#*? Gw`˗at:͠m; B7L~[5Ͱ4HJ7lLUh븛LtkuZ孓\}V d06$KN0a9{a&}I"ìLw(};8S$lxQ~Kt O8gR k_J26\GKBrљ_{=ϧLLa'LSC`{̻ 6;uM;>w$N`C6GoQp>_' s6G  d# v4GNM7B ?F!pNT0 Kškǘ}wIqJo9o@F<)ski2\F9^?+)o0>[b;C4'd6 0q밂9X!Y30m:`sm-NGW0_ps]H N /;z?&gxL ~eMSm]!]L_9(a`sz ѴTAЯ\I[DTʺ !:]0LbɄwV_0c X> `^' Y!LQtݒy .HLpl;Dӧ{肻J"1L<|h:f-c$053Dg,;`{7b- 5- ؕקN{aDKp:KbrU^p%xz 01 8'KDǓ ,Tg vk34`ݘKp<0C ލZ0K+ A9ˏ^q1tVиw %1C dcdo9\:{7v1"Z|{h]|Qλ[1nr'%?"~ d)Lй(Ɋgt:I :u`~CQ`:gУ4$UH<#̏7IyL" bՍI"\$p/)xcIgh8%Ld l0;Ʋ l6?160-\vZtLjbލ=ƒ [lagX{>+nK, v}&]{FT2C{rxClY5|`~M0@C\fh)6o?Uo0g.$X/ vq-4ӕW\3 i&]'tt@tu&8yM0N(`ocxw e mozUz#% {={ +XS.Xo uθf C, XK/ oYK,7]$ݐCGj,5oA}\nx oڕG4\ptZ&` xkjQXk ݲ&Xz =W,.[ӄlh;n72 EU6iiz`@xr3 [VVrM0 `~l&ING&X{7e=6 kAe׃)+l[?gs4ogVaІoW FPe7l30{$PpfI\ataw>?`R 83DGp)Vuk>f `Ua_9Smĺ^ ]\tOMQP4I7LPu bx%Q'N;~Ĭu6&q|T񆽶1ƞ&NIwE72[66/$c=.[XwQ4`;zØc}s,w|UUfUU 1m]-a;?oU\G!(7@/ ߡdk7ptP/loNlVQuIYo6`ԕMĴi VR0Qm.F|!4ីDŰQuz"U@fG}/.腑$d8t8ۊ~M&3Wq]t G"c(Rd^?GE&doo}g<~؆~g\3[%٘MΜvTQBać2l9[l4Q*.wo\÷YӫsJ ̧ r#OyδK#B0s]O4W;f!,\5g"]uЎ`Q Y/;t3=T@昐PvobwQUyXveWLfž41|k([0:;;ip9!TtY(Kfؙ~-q j$Mk쒺l_jnBF 95vf~C&rpJ]Sq9h1C4C$_fR_$ـo>m90xQ 5myӡMH)vG=> ?tȌ؟q6pP XƢ],S/QM?\onW2g&8 f>`AAZ~˳ |kb <\0(͝Ǘ-c4؝QE a'iX  k&24<Ʉ-,qj/yIc}4x8* b7QLSϟ:b[(.1.N>4CGWPo Jt:@S/gX7eח%m &5ѴƢ|ITGOz<`xuiDiai ОŰؠ7p$dZ=a; QM[ Ÿja 1,-9`9_06- `~ S|"RkAI!>$`СzS=a+٠ UZ\~["`ШpWzv0T BƁ :jx 1[G0GF4q@ &'D1s$\V~$Xl;~{QB(>T.0 R_ޡ{I)cBff0&dl2a g\7L%"a1IҴOEѧYr (c0?FNg\׶ 3ɟa j_@+@p%-ݡʼ14} wj~um} knЛ8_ErTXoYw>>mcS$'(l2l=3(r l)d5!GLI@BkkKM5sϽ$BME KMrI,g SXFX%=ݻb )pMeeweEpADpmH8ǠހhBxCOjpX}Ô~z㰵o ^-+EW0 - 712 _?#A{YW#i,8%Ec2Z+C`lL2+zB~0q;%oP >C9X`m>hIѹ|#XP'6}msø̹rۺww!FPc  `&xεW >6i //s$w=/oc)o2 d  -x{Og\׸ ݉‰Sεe ސ$+?D0t={H%o%46}50Ŋի 826+Y IBW"f|KМ9F>҅!pl^-$Vn՗-x"JD"XacA~7i+YbSrw`p}UJYѸ^R՗.x#[I0YԻ*ATꢒG=> [a>Zk)p~m-owNUS +i+O`YOhC,2&6L+78-D}̊hB6;AB>K =^a\ЖS)p.xͷfE4:7Q0{Ѭ;[b <2V^k)pN[BG05w3 ͹_Fh #oaLiЗSX^!] =;לe)_s574F0O1^ +-IyCVE543&j'яX/1%Wg"j'#0o=u>N' o[2[krЊs'RwR/ -?)~}3xM`ZB`:?F&>Mҗ 0[XlQ(_'m U)QA%tE4ADH`иni"8#W`j2奔(z*Z\+puMq hM_jK,lMc{XVy-"]!pL$ J1I p%0 -,y?/t=_Pxt#ҁjX$.%`y)q+"+Ba!8LW ۷ aǛH=,'FiLü"dd Xˊ0lX S:v+ZFNyO @ S@V3[`( "xQ.ćuX#\sHrk8Ŭ `(Ä~n/]Wx_`VA\,3t V'CÔXͶ m.ȯfaNZ-Ve3@au,>xk4C `TɠPXҠ@;hz'څ:F3}dUz!VڜÛ8&{Ck# < x@ɔ#)[ttie"1H"{y/Jbm2@rS62jhxO,:YSkBU>5uE lӪ(d+b6Q@qr+ٖ1WCI' x1Wa>j+OuR Qr/f;{$>_M%;\p-?}f0)Cjh

Qj{hB`w"99飷mLT>R٬_,gаwM_ `yL@O-Q>!kH&:Ɍ6&kfl+_䭀diV0{ۈax5_yʟ*&Nj,u21G̬9J h3ԗERb%`k`0_i ,q/Lhc{H |먌 MWeS^*+mcՄ-rT +L[HPDҩc]R"'ia08*mH⮳0Hc y6V}UIJmZ߉Z,g{BS#̵q?7!V hD0XmWI\Aw;)"M<'v9bpi;sYocQ+:ZK(MXB#ǫ5,ڻIY{Hz͞ϬY;IVUyۢ'p= q`Vq#|33%s/\lEVE nf7`p) ߩmHc73MyƲٱ}X$}tNfl W c'`+2 (+`q;IoN]֓P7Z|}AH[H e80c<^GV$琊 `$Մgv%4ұ[ +eN Ж$iCʥMkW^.|NVdpDVvM=O0la䴀%䯨z ";IO׾L00Νm $J]vzNh/zwE'R8QBt}/y29sI^:ZSXݼ08KS=_k[-*Gw?}AdWe':mY wRoJyc)wR)52DhCv, +++[+(x.7[\kdbCj_ts"QG:4G*ز _P@3FJ4D gbRnHm_b>οFpCS+)ǪiJu*k,4bbg37}sٱ;Vno~l2TqtjVlB`A0#d4,عmQvq* L\PfuU ?=|xW~ }n%p=,0 C[p\5Գ} +_E/m#9[_Z4o._* F眹1V?EwY ~_%H압{ieҧn8Luh`3]e= y% lm RR?:*  b'9@VН0}o[Uvf p{C-]`VA&8 f -+`n}0+EC|TC^uָC\>=IU>k3`e{_M+ڙ G7&{N1XQ.TEiO`4\`}/%!6氬[@o{ߞ<ޝ,V+7 H,YY;Z\nerj@ga! *:+9\9sw}qFBaQ(s+!0tx;~Cp_;kGu3>ݔpf(N=Q+V:?|QbE0pƏp w1睐o e7Q+[2IVZ ?wcZz@!åa dO:[wq `A$p! -}!g̏ SCڔ 4bWޮCI >ko;^Gd7M `gc|! XAo=!q,%As:2(moP^0#]R ހɢ`bp&ܚ?6i<w[!ע;@PhBBdҶ{Rn >,~WnO3ߙv*! *A[>u{`oI|4}>kL<4!޲~nVf2DN4ad /:p,qT #Ow.4Rc@MN==+f[~a\F x١jlԸ\nen! jZ- pq% %xi]zkË!pA,Gڀ`?);kEw9NaM|v:fnM6 Da]ꛔZ3w/ֆJWV us?)fmdk\1`U kRP9{[hZ>0 ~X`CW3dn8HrL@l_R=C(aK>-JزBbWU7a_)Kiw|-0`Ć P'CgA\ecE'p%+qu4 (+z1n6{,Zmo&7Or bla|Ru_#\= WӒIԂ qF4\E#U&-2]z9-̀ f5_ jh&hY8//ONη{*R!4.)"4'7G e[77S6BVK-5d &܄9¾#mtZ)P;qF( f^ t6Ml[^[+ ;WtDՌl<ޤX`ʎ aVe*݌P̐p*4Y/"V?OF}LhBa| L܀7yTރ5H^B  s-b[2KŅʥa +T>`97`Mۇ e ]'jh_\ Ar逖 ׹ri]1#gp~mS bdGC@i"G@7e mFS,>Ltn쫪"^ݗw X|>#xQ\sWOzk>`_+ P:.DjhuPUB  EҡWjclՅ"EsAn7g/Ur2Ʋ%geeJ0ibp l0 k)1S3~F`!$ⷂo}> S8Kg@F1&ѧ0XG3~FrQl,XlCfLf`VE8쭵W^'2C}E'Bk+hp hHU%i_]ACW> "<ۇb8f2V#az@ `z3`GZ04/!:~e,ZC+@j+Uυi6\--15f m ̿`0}1LF=m.ṇbv[  N;6eyZAZ1\7 --=a]8E[(÷~~Nv|K2}6y7 떺KZ7=!TCsLh)c\aA/!wI>.ަ7CQczw돛OxK{7` Ƌvb+Y0e[tDt<|dtW¯/:ze_1) 2v3yw*lQlb WG싄|JABMܵ3tUz%ȓ?}1}pKM7Q fcVKlPVA[| +h|5bzb)8b~f,RV5 pA?㓤*"Z{s>#zG/3b? \~KR1Xe/f­gXxPDkX͵/N຤wuH cӋJ͞aY_PҮ5MAEӊ,تGd*.'w%-zkm)p\pUȲRzKxF`b.E7~FAѲKR%xڙWҙxKL U+9B.{2z(=p#go׋~RHQ 2?kgn\v;Ho/-Ipl }LaLިcJ7ODSG,o҉菰F2'-R;#|tnE+겿Fh0i͗jo N0E0E?Sڋ;uW_'fQ딾3VIu;{zA<7BO_p,Vb/~ uKmBsߩ>j [/WGF?qWߴ 6·_݋l'p(9f0 N^-}~S?L[BsK#цs[_;|vN?p;o?X9"Ze`Jӫ/MV)aE1 ޝj;ɛ ~A?DHK߄ ^Oƙ~)~0`,r@طXzYV }lN:PjgՏ Z~TxHEFar ma]_}!_0mִ)LJ"RSMW ߯o*F;l Ie}(|úr;R{}/;%,snj9{X˽"qg?`[tV"K/KBµ3Λρ<‘K1n/y`n`^sƎux*n(=AJL$m܆HN/?mF <>O\y7[re_D& oQ\zCJ.:tLY/>c@V9p*p(s:a ܓ]*c)_dN,j@~,𞰤\;KM*5!Y|>b{*v1.}1un?t/4K`R'_ߚǨ! $/%s;hD١4+Qd0;%"Z[,PE盯^B*5{|Rr^CV f: CXv! L͠Y_,%f_˹J ОJ]! h"WٖьT:zs`v [B%3zS+lV:%By,?#;H$pgS=e#",tӄF_Sf0+* NXG?&ص7Z"&7 O[xXJm3k^Ck_``fކ6vvT=-SQ Qb{%'g/ns`p evD*/l8+ d JW_ N#e yXi뷨e*Lǔ"9kE[ץ OJUn$Ih" [ʞӆ@`ףXsoCwEH ,~~ѻHc9y 5vP_9,(JMrGi,Rp%p6oe1Dui3La`/(=_$z #j7l:BRO|:>@~Dž3rveT. 4o5جoxL)Yy]$ D&k3V=Է黫*^.U|vKV uiĒ &,ׯ9}ƶTEIZC-ǭCMtg{ (.hRLX:+7‹*?ք>ZX & u%b v# ߊc,u1&]{.x5)H_?o̮3W&\hM;| ^*GɻVaTl&Ce^q!G!j2Z%j 6f^ ~U-hH‹hB-0a:Fܢ`p%8' a\ p`#0Аm,C%1|>؆- AS-0 h#BV!PbղNK-!XsD+\v9CLNY &}%AaA  WDlp`݆/h']AtUY1SBTK RЋ|mrDi'#nō_00Ʋ8x\4J9 zVU nklѿ*MTxxGN:y_m@G?"B/N?wj. +%?&ɳSu;a1c¢Մ>s s d549y+F[Fa'쮀g|t؟ F+Fpo:NSq|sK^`^K9*vJG)ݫ+קsqqy6t0l]ֶ[0Ty2q{S%^__rGn[Au[0XW~@&~fHfJ|N!TlT3lBk>xxKtݚJgnY%鰳&1|WRa_<Иz:9\Rh,m*,?g?jh5wY9d-*iX$o[pQل÷}H\~ 0jfy`σ,|z̺\Mk 3SCWņ͈WU Zz,xaZ wWYK +npI(l#OI^mBN_ LZvq9an_%rxwBj`; ZZ 7NL\$߹?BsY؂-+e;#֒dwص< f9}Câ]/V]٭z0aw8J0x 4r8 'ڤQLԶeiG-G0M?R}dI qe\+h t1) kg`3-P'/h a$YE`Qme"bp6^i/g1EHCj:W#F9}$y`YPp!5w2`nJ)~i!,HZ0͑y 3o4f&*:0[{í]jxRTڒFy{_ ^4; ^w9_`%u8~6{*x(,M6!r00$&4_s"t44,zy5107жhaMkicdpܮ0Fe4BؗЀ j_1F0K|:2HYݟ@8<#f\#L+ `_K~%7*J/lsjhy;0x|(BEP/U_Q_}7?JZz':kk:XV QKqUVþYQ6|N)T ޽_rlR_zr ŀ[?J;eحT*WHSG;2Y:<1\8V ˂Czz7"LjX3\>OT|>OfbٕX_wkؖ )D.eZ(H}, ժ:jϽe  7a And=Gza9<\Qc?`z\+ϧN/NPTPi>i/ޘg QB5Ft.7fy%Ӻt“vfBg-H ~qpos`r}7]jMpZ?-=p ?Cz{`hB:UPhS &igS $~1Yl}NLvDF5[h{/ncR_1;77o߾\#e`)gŹ1ÆP؝_ l◗fԀ>;2l]>z[:{Wd'۷oopd;iTG'+8__Lč"`՗~8Ywgv i'^0 R2Age99M-R8uA% #j%n5RXڎHŮBޒ6Ck!_.s#Wk:pdZJg|O$YbԦח |_NFH)ȶM{F/p^:)gB;J[4ng*hUg6M^+,!qv+}YY.9~wfLp{XnCࡒ]]2qheM Xa/[qLa;'WOjj}(+0 ԑɐ.v}ˆ/fѾI5J` q0ۛ.oS/j>srL0y VC`¦_*_P64l$ ~@|ޚL${t 4)0^?|̱TVX|l ,_#b/GƵIzkޗDM[@3 ܲ sC] < 1,q`v+vW’ {FpEH _`Рg 0w ~/x.OSY8+;49qGVV~z^?a&%__IDf~aYsxow9@tݒ zy:GdpX SK/$0h:a5棹Kœ# 胘Β%'R@/Ǎӿ50+ lMCKwx_dt8?RT@3g֒gPhB{qX7E@ ;(|5'TN+$˺Wqy;anwB]Pά#B*M'a e[<1|߾U w܀eؓP{R`AΪ/T5ǰJ `i"a&Ujao|vK8m1¼|;LbOI9 wޘ 2:ё7;z}Ar kގsM9k80?E3 er[y^(ͅT!"ZTm*Y)Lmh44L× z{Hhz9SZ MYnt뾼] ㌡ P*v¾/~Y+%sÌ"/:ѥ;m?#.|Xoeedz:Qq|cx! ,0K--ƁĔߛb1`*eHoqєΥ{^wEU!9#kd=5 6LJ?RMOUB#1)J-Kgngok(o!.p3= 鎲ą~ w5E)֗NbٺvÉ,ďtmG `TпX܆;g9psQ vh O`(>%92n1L\6W_i^DpD`^ Օ!6$X6)c+b?P&U,y=qVߒb |H.3tb7_ac &܋NV_⭰fkh%MG a ]xBYnE8;F2Գs\yq? 2ө 58_/z!r 06`{/LhB?\ JwmV;7#=/28 dM8fQlO)8Hhfd0֮c VD?z3eC`rWbin_DS(/PKjEVyr?MJ4|ϛƓs r8]/W߂"qe$ݩs_n^lWeT~56z= cS7T@jY&]j.J:Ok(,%R5"w]@${m6W{=|Ľů,d<8mI)-azv=* oǬeO\BqTX5ҥp,1k# 4l;| ,HՒ Ҫe t\?gbmKs[duGО' L֗ e]'(paVI|C%QQJĿ0BOEEk<viX^l(p!c]jS%$[?4tx"RIMjuG^`kSػV} yavF ObX$Hy7U8]ѿ:Jս16 /rpRG\{_#gif>>+ ]v{!czqAA^h!MxƑ:/ض};Enci _A sAg7h .Q>ݼ/ø*RJ/}ҡG>x%YfwRtm^ lfm/|ˣ(DhZ) %j,V3CnS gfjʲtPJi|oc? O6O`D5ƪ堢#Ouзy`(ZcOx ^6shLj'A61ǝ_QmcS巖W_o]qY N]eW_4.Q}_'~E=~lߧ^6NW`@FO-C(B-Ty6VYjq){~iT/F7_q$C4<smy1^wQ^1Omc?arYej8iMt1{|o3ϏCCv 1STJJ1]hYk)yt ׸bU;[ӳ>J"،o V7v[+9׃%$>7Vt 2KhqߌԦiN诫b,n>UX܉Q)QY}<6oO\|u[̡ҍ=8XSHZLLq-E~df:IWҧ\{L/Jqf+xK/Wmd+OJʻcxgùwTZIrﲬP tsg݉M>nUNU{!2|8."LrY>sm:5$ ReXmG7cf>!>G;{ `~@%X_d,Û^ZK 0b,^&8w旨[~]{_( WJ6C=p}[qEV>7"D4"?C;t","累u}?YGDKq8' l&BD7פ'?^ODnJ7VenmM=pQCeMcN™oFNjW9Q<4G쀾'NDꃤꆐ8ì(JQ[X8R!"C|GtlDDe,+ "R53"ZeD{5?"*1‡݅:ue*NRWCDѧ׏/9Xn_\2>qJ𪦦eAښB+(/*h1\"Rr\+"Z(6)"Z+ZJ-ײ"e'T-(g_o<`"R IENDB`logzero-1.5.0/docs/Makefile0000644000372000037200000001515613250015553016435 0ustar travistravis00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/logzero.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/logzero.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/logzero" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/logzero" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." logzero-1.5.0/docs/authors.rst0000644000372000037200000000003413250015553017201 0ustar travistravis00000000000000.. include:: ../AUTHORS.rst logzero-1.5.0/docs/conf.py0000755000372000037200000002027713250015553016277 0ustar travistravis00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # # logzero documentation build configuration file, created by # sphinx-quickstart on Tue Jul 9 22:26:36 2013. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another # directory, add these directories to sys.path here. If the directory is # relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # Get the project root dir, which is the parent dir of this cwd = os.getcwd() project_root = os.path.dirname(cwd) # Insert the project root dir as the first element in the PYTHONPATH. # This lets us ensure that the source package is imported, and that its # version is used. sys.path.insert(0, project_root) import logzero # -- General configuration --------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'logzero' copyright = u"2017, Chris Hager" # The version info for the project you're documenting, acts as replacement # for |version| and |release|, also used in various other places throughout # the built documents. # # The short X.Y version. version = logzero.__version__ # The full version, including alpha/beta/rc tags. release = logzero.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to # some non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built # documents. #keep_warnings = False # -- Options for HTML output ------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a # theme further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as # html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the # top of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon # of the docs. This file should be a Windows icon file (.ico) being # 16x16 or 32x32 pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) # here, relative to this directory. They are copied after the builtin # static files, so a file named "default.css" will overwrite the builtin # "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names # to template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. # Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. # Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages # will contain a tag referring to it. The value of this option # must be the base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'logzerodoc' # -- Options for LaTeX output ------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ ('index', 'logzero.tex', u'logzero Documentation', u'Chris Hager', 'manual'), ] # The name of an image file (relative to this directory) to place at # the top of the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings # are parts, not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output ------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'logzero', u'logzero Documentation', [u'Chris Hager'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ---------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'logzero', u'logzero Documentation', u'Chris Hager', 'logzero', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False logzero-1.5.0/docs/contributing.rst0000644000372000037200000000004113250015553020221 0ustar travistravis00000000000000.. include:: ../CONTRIBUTING.rst logzero-1.5.0/docs/history.rst0000644000372000037200000000003413250015553017215 0ustar travistravis00000000000000.. include:: ../HISTORY.rst logzero-1.5.0/docs/index.rst0000644000372000037200000002601713250015553016634 0ustar travistravis00000000000000.. highlight:: shell .. _index: =================================== `logzero`: Python logging made easy =================================== Robust and effective logging for Python 2 and 3. .. image:: _static/logo-small.png :alt: Logo :width: 300px **Features** * Easy logging to console and/or (rotating) file. * Provides a fully configured standard `Python logger object `_. * Pretty formatting, including level-specific colors in the console. * Windows color output supported by `colorama`_ * Robust against str/bytes encoding problems, works with all kinds of character encodings and special characters. * Multiple loggers can write to the same logfile (also works across multiple Python files). * Global default logger with `logzero.logger <#i-logzero-logger>`_ and custom loggers with `logzero.setup_logger(..) <#i-logzero-setup-logger>`_. * Compatible with Python 2 and 3. * All contained in a `single file`_. * Licensed under the MIT license. * Heavily inspired by the `Tornado web framework`_. * Hosted on GitHub: https://github.com/metachris/logzero .. image:: _static/demo_output.png :alt: Demo output in color :width: 300px Installation ============ Install `logzero` with `pip`_: .. code-block:: console $ pip install -U logzero If you don't have `pip`_ installed, this `Python installation guide`_ can guide you through the process. You can also install `logzero` from the public `Github repo`_: .. code-block:: console $ git clone https://github.com/metachris/logzero.git $ cd logzero $ python setup.py install On openSUSE you can install the current version from repos: `python2-logzero `_, `python3-logzero `_. In the newest openSUSE release you can install it with zypper: ``sudo zypper in python2-logzero``. .. _pip: https://pip.pypa.io .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ .. _Github repo: https://github.com/metachris/logzero .. _tarball: https://github.com/metachris/logzero/tarball/master .. _single file: https://github.com/metachris/logzero/blob/master/logzero/__init__.py .. _Tornado web framework: https://github.com/tornadoweb/tornado .. _colorama: https://github.com/tartley/colorama Example Usage ============= You can use `logzero` like this (logs only to the console by default): .. code-block:: python from logzero import logger # These log messages are sent to the console logger.debug("hello") logger.info("info") logger.warning("warning") logger.error("error") # This is how you'd log an exception try: raise Exception("this is a demo exception") except Exception as e: logger.exception(e) If this was a file called ``demo.py``, the output will look like this: .. image:: _static/demo_output_with_exception.png :alt: Demo output in color .. code-block:: console [D 170705 14:59:47 demo:3] hello [I 170705 14:59:47 demo:4] info [W 170705 14:59:47 demo:5] warn [E 170705 14:59:47 demo:6] error [E 170705 14:59:47 demo:12] this is a demo exception Traceback (most recent call last): File "demo.py", line 10, in raise Exception("this is a demo exception") Exception: this is a demo exception Rotating Logfile ---------------- Adding a rotating logfile is that easy: .. code-block:: python import logzero from logzero import logger # Setup rotating logfile with 3 rotations, each with a maximum filesize of 1MB: logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1e6, backupCount=3) # Log messages logger.info("This log message goes to the console and the logfile") Advanced Usage Examples ----------------------- Here are more examples which show how to use logfiles, custom formatters and setting a minimum loglevel. +-----------------------------------------+--------------------------------------------------+ | Outcome | Method | +=========================================+==================================================+ | Set a minimum log level | `logzero.loglevel(..) <#i-logzero-loglevel>`_ | +-----------------------------------------+--------------------------------------------------+ | Add logging to a logfile | `logzero.logfile(..) <#i-logzero-logfile>`_ | +-----------------------------------------+--------------------------------------------------+ | Setup a rotating logfile | `logzero.logfile(..) <#i-logzero-logfile>`_ | +-----------------------------------------+--------------------------------------------------+ | Disable logging to a logfile | `logzero.logfile(None) <#i-logzero-logfile>`_ | +-----------------------------------------+--------------------------------------------------+ | Log to syslog | `logzero.syslog(...) <#i-logzero-logfile>`_ | +-----------------------------------------+--------------------------------------------------+ | Use a custom formatter | `logzero.formatter(..) <#i-logzero-formatter>`_ | +-----------------------------------------+--------------------------------------------------+ .. code-block:: python import logging import logzero from logzero import logger # This log message goes to the console logger.debug("hello") # Set a minimum log level logzero.loglevel(logging.INFO) # Set a logfile (all future log messages are also saved there) logzero.logfile("/tmp/logfile.log") # Set a logfile (all future log messages are also saved there), but disable the default stderr logging logzero.logfile("/tmp/logfile.log", disableStderrLogger=True) # You can also set a different loglevel for the file handler logzero.logfile("/tmp/logfile.log", loglevel=logging.ERROR) # Set a rotating logfile (replaces the previous logfile handler) logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3) # Disable logging to a file logzero.logfile(None) # Log to syslog, using default logzero logger and 'user' syslog facility logzero.syslog() # Log to syslog, using default logzero logger and 'local0' syslog facility logzero.syslog(facility=SysLogHandler.LOG_LOCAL0) # Set a custom formatter formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s'); logzero.formatter(formatter) # Log some variables logger.info("var1: %s, var2: %s", var1, var2) Custom Logger Instances ----------------------- Instead of using the default logger you can also setup specific logger instances with `logzero.setup_logger(..) <#i-logzero-setup-logger>`_: .. code-block:: python from logzero import setup_logger logger1 = setup_logger(name="mylogger1", logfile="/tmp/test-logger1.log", level=logging.INFO) logger2 = setup_logger(name="mylogger2", logfile="/tmp/test-logger2.log", level=logging.INFO) logger3 = setup_logger(name="mylogger3", logfile="/tmp/test-logger3.log", level=logging.INFO, disableStderrLogger=True) # By default, logging logger1.info("info for logger 1") logger2.info("info for logger 2") # log to a file only, excluding the default stderr logger logger3.info("info for logger 3") Adding custom handlers (eg. SocketHandler) ------------------------------------------ Since `logzero` uses the standard `Python logger object `_, you can attach any `Python logging handlers `_ you can imagine! This is how you add a `SocketHandler `_: .. code-block:: python import logzero import logging from logging.handlers import SocketHandler # Setup the SocketHandler socket_handler = SocketHandler(address=('localhost', logging.DEFAULT_TCP_LOGGING_PORT)) socket_handler.setLevel(logging.DEBUG) socket_handler.setFormatter(logzero.LogFormatter(color=False)) # Attach it to the logzero default logger logzero.logger.addHandler(socket_handler) # Log messages logzero.logger.info("this is a test") Documentation ============= .. _i-logzero-logger: `logzero.logger` ---------------- `logzero.logger` is an already set up standard `Python logger instance `_ for your convenience. You can use it from all your files and modules directly like this: .. code-block:: python from logzero import logger logger.debug("hello") logger.info("info") logger.warning("warning") logger.error("error") You can reconfigure the default logger globally with `logzero.setup_default_logger(..) <#i-logzero-setup-default-logger>`_. See the documentation for the `Python logger instance `_ for more information about how you can use it. .. _i-logzero-loglevel: `logzero.loglevel(..)` -------------------------- .. autofunction:: logzero.loglevel .. _i-logzero-logfile: `logzero.logfile(..)` -------------------------- .. autofunction:: logzero.logfile .. _i-logzero-formatter: `logzero.formatter(..)` -------------------------- .. autofunction:: logzero.formatter .. _i-logzero-setup-logger: `logzero.setup_logger(..)` -------------------------- .. autofunction:: logzero.setup_logger .. _i-logzero-setup-default-logger: Default Log Format ------------------ This is the default log format string: .. code-block:: python DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s' See also the `Python LogRecord attributes `_ you can use. Custom Formatting ----------------- It is easy to use a custom formatter / a custom log format string: * Define your log format string (you can use any of the `LogRecord attributes `_). * Create a `Formatter object `_ (based on `logzero.LogFormatter` to get all the encoding helpers). * Supply the formatter object to the `formatter` argument in the `setup_logger(..)` method. This is a working example on how to setup logging with a custom format: .. code-block:: python import logzero log_format = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s' formatter = logzero.LogFormatter(fmt=log_format) logzero.setup_default_logger(formatter=formatter) Issues, Feedback & Contributions ================================ All kinds of feedback and contributions are welcome. * `Create an issue `_ * Create a pull request * https://github.com/metachris/logzero * chris@linuxuser.at // `@metachris `_ logzero-1.5.0/docs/make.bat0000644000372000037200000001447513250015553016405 0ustar travistravis00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\logzero.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\logzero.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end logzero-1.5.0/docs/readme.rst0000644000372000037200000000003313250015553016750 0ustar travistravis00000000000000.. include:: ../README.rst logzero-1.5.0/logzero/0000755000372000037200000000000013250015612015512 5ustar travistravis00000000000000logzero-1.5.0/logzero/__init__.py0000644000372000037200000005010313250015553017626 0ustar travistravis00000000000000# -*- coding: utf-8 -*- """ This helper provides a versatile yet easy to use and beautiful logging setup. You can use it to log to the console and optionally to a logfile. This project is heavily inspired by the Tornado web framework. * https://logzero.readthedocs.io * https://github.com/metachris/logzero The call `logger.info("hello")` prints log messages in this format: [I 170213 15:02:00 test:203] hello Usage: from logzero import logger logger.debug("hello") logger.info("info") logger.warn("warn") logger.error("error") In order to also log to a file, just use `logzero.logfile(..)`: logzero.logfile("/tmp/test.log") If you want to use specific loggers instead of the global default logger, use `setup_logger(..)`: logger = logzero.setup_logger(logfile="/tmp/test.log") The default loglevel is `logging.DEBUG`. You can set it with the parameter `level`. See the documentation for more information: https://logzero.readthedocs.io """ import functools import os import sys import logging from logzero.colors import Fore as ForegroundColors from logging.handlers import RotatingFileHandler, SysLogHandler try: import curses # type: ignore except ImportError: curses = None __author__ = """Chris Hager""" __email__ = 'chris@linuxuser.at' __version__ = '1.5.0' # Python 2+3 compatibility settings for logger bytes_type = bytes if sys.version_info >= (3, ): unicode_type = str basestring_type = str xrange = range else: # The names unicode and basestring don't exist in py3 so silence flake8. unicode_type = unicode # noqa basestring_type = basestring # noqa # Name of the internal default logger LOGZERO_DEFAULT_LOGGER = "logzero_default" # Attribute which all internal loggers carry LOGZERO_INTERNAL_LOGGER_ATTR = "_is_logzero_internal" # Attribute signalling whether the handler has a custom loglevel LOGZERO_INTERNAL_HANDLER_IS_CUSTOM_LOGLEVEL = "_is_logzero_internal_handler_custom_loglevel" # Logzero default logger logger = None # Current state of the internal logging settings _loglevel = logging.DEBUG _logfile = None _formatter = None # Setup colorama on Windows if os.name == 'nt': from colorama import init as colorama_init colorama_init() def setup_logger(name=None, logfile=None, level=logging.DEBUG, formatter=None, maxBytes=0, backupCount=0, fileLoglevel=None, disableStderrLogger=False): """ Configures and returns a fully configured logger instance, no hassles. If a logger with the specified name already exists, it returns the existing instance, else creates a new one. If you set the ``logfile`` parameter with a filename, the logger will save the messages to the logfile, but does not rotate by default. If you want to enable log rotation, set both ``maxBytes`` and ``backupCount``. Usage: .. code-block:: python from logzero import setup_logger logger = setup_logger() logger.info("hello") :arg string name: Name of the `Logger object `_. Multiple calls to ``setup_logger()`` with the same name will always return a reference to the same Logger object. (default: ``__name__``) :arg string logfile: If set, also write logs to the specified filename. :arg int level: Minimum `logging-level `_ to display (default: ``logging.DEBUG``). :arg Formatter formatter: `Python logging Formatter object `_ (by default uses the internal LogFormatter). :arg int maxBytes: Size of the logfile when rollover should occur. Defaults to 0, rollover never occurs. :arg int backupCount: Number of backups to keep. Defaults to 0, rollover never occurs. :arg int fileLoglevel: Minimum `logging-level `_ for the file logger (is not set, it will use the loglevel from the ``level`` argument) :arg bool disableStderrLogger: Should the default stderr logger be disabled. Defaults to False. :return: A fully configured Python logging `Logger object `_ you can use with ``.debug("msg")``, etc. """ _logger = logging.getLogger(name or __name__) _logger.propagate = False _logger.setLevel(level) # Reconfigure existing handlers stderr_stream_handler = None for handler in list(_logger.handlers): if hasattr(handler, LOGZERO_INTERNAL_LOGGER_ATTR): if isinstance(handler, logging.FileHandler): # Internal FileHandler needs to be removed and re-setup to be able # to set a new logfile. _logger.removeHandler(handler) continue elif isinstance(handler, logging.StreamHandler): stderr_stream_handler = handler # reconfigure handler handler.setLevel(level) handler.setFormatter(formatter or LogFormatter()) # remove the stderr handler (stream_handler) if disabled if disableStderrLogger: if stderr_stream_handler is not None: _logger.removeHandler(stderr_stream_handler) elif stderr_stream_handler is None: stderr_stream_handler = logging.StreamHandler() setattr(stderr_stream_handler, LOGZERO_INTERNAL_LOGGER_ATTR, True) stderr_stream_handler.setLevel(level) stderr_stream_handler.setFormatter(formatter or LogFormatter()) _logger.addHandler(stderr_stream_handler) if logfile: rotating_filehandler = RotatingFileHandler(filename=logfile, maxBytes=maxBytes, backupCount=backupCount) setattr(rotating_filehandler, LOGZERO_INTERNAL_LOGGER_ATTR, True) rotating_filehandler.setLevel(fileLoglevel or level) rotating_filehandler.setFormatter(formatter or LogFormatter(color=False)) _logger.addHandler(rotating_filehandler) return _logger class LogFormatter(logging.Formatter): """ Log formatter used in Tornado. Key features of this formatter are: * Color support when logging to a terminal that supports it. * Timestamps on every log line. * Robust against str/bytes encoding problems. """ DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s' DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S' DEFAULT_COLORS = { logging.DEBUG: ForegroundColors.CYAN, logging.INFO: ForegroundColors.GREEN, logging.WARNING: ForegroundColors.YELLOW, logging.ERROR: ForegroundColors.RED } def __init__(self, color=True, fmt=DEFAULT_FORMAT, datefmt=DEFAULT_DATE_FORMAT, colors=DEFAULT_COLORS): r""" :arg bool color: Enables color support. :arg string fmt: Log message format. It will be applied to the attributes dict of log records. The text between ``%(color)s`` and ``%(end_color)s`` will be colored depending on the level if color support is on. :arg dict colors: color mappings from logging level to terminal color code :arg string datefmt: Datetime format. Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``. .. versionchanged:: 3.2 Added ``fmt`` and ``datefmt`` arguments. """ logging.Formatter.__init__(self, datefmt=datefmt) self._fmt = fmt self._colors = {} self._normal = '' if color and _stderr_supports_color(): self._colors = colors self._normal = ForegroundColors.RESET def format(self, record): try: message = record.getMessage() assert isinstance(message, basestring_type) # guaranteed by logging # Encoding notes: The logging module prefers to work with character # strings, but only enforces that log messages are instances of # basestring. In python 2, non-ascii bytestrings will make # their way through the logging framework until they blow up with # an unhelpful decoding error (with this formatter it happens # when we attach the prefix, but there are other opportunities for # exceptions further along in the framework). # # If a byte string makes it this far, convert it to unicode to # ensure it will make it out to the logs. Use repr() as a fallback # to ensure that all byte strings can be converted successfully, # but don't do it by default so we don't add extra quotes to ascii # bytestrings. This is a bit of a hacky place to do this, but # it's worth it since the encoding errors that would otherwise # result are so useless (and tornado is fond of using utf8-encoded # byte strings wherever possible). record.message = _safe_unicode(message) except Exception as e: record.message = "Bad message (%r): %r" % (e, record.__dict__) record.asctime = self.formatTime(record, self.datefmt) if record.levelno in self._colors: record.color = self._colors[record.levelno] record.end_color = self._normal else: record.color = record.end_color = '' formatted = self._fmt % record.__dict__ if record.exc_info: if not record.exc_text: record.exc_text = self.formatException(record.exc_info) if record.exc_text: # exc_text contains multiple lines. We need to _safe_unicode # each line separately so that non-utf8 bytes don't cause # all the newlines to turn into '\n'. lines = [formatted.rstrip()] lines.extend( _safe_unicode(ln) for ln in record.exc_text.split('\n')) formatted = '\n'.join(lines) return formatted.replace("\n", "\n ") def _stderr_supports_color(): # Colors can be forced with an env variable if os.getenv('LOGZERO_FORCE_COLOR') == '1': return True # Windows supports colors with colorama if os.name == 'nt': return True # Detect color support of stderr with curses (Linux/macOS) if curses and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty(): try: curses.setupterm() if curses.tigetnum("colors") > 0: return True except Exception: pass return False _TO_UNICODE_TYPES = (unicode_type, type(None)) def to_unicode(value): """ Converts a string argument to a unicode string. If the argument is already a unicode string or None, it is returned unchanged. Otherwise it must be a byte string and is decoded as utf8. """ if isinstance(value, _TO_UNICODE_TYPES): return value if not isinstance(value, bytes): raise TypeError( "Expected bytes, unicode, or None; got %r" % type(value)) return value.decode("utf-8") def _safe_unicode(s): try: return to_unicode(s) except UnicodeDecodeError: return repr(s) def setup_default_logger(logfile=None, level=logging.DEBUG, formatter=None, maxBytes=0, backupCount=0, disableStderrLogger=False): """ Deprecated. Use `logzero.loglevel(..)`, `logzero.logfile(..)`, etc. Globally reconfigures the default `logzero.logger` instance. Usage: .. code-block:: python from logzero import logger, setup_default_logger setup_default_logger(level=logging.WARN) logger.info("hello") # this will not be displayed anymore because minimum loglevel was set to WARN :arg string logfile: If set, also write logs to the specified filename. :arg int level: Minimum `logging-level `_ to display (default: `logging.DEBUG`). :arg Formatter formatter: `Python logging Formatter object `_ (by default uses the internal LogFormatter). :arg int maxBytes: Size of the logfile when rollover should occur. Defaults to 0, rollover never occurs. :arg int backupCount: Number of backups to keep. Defaults to 0, rollover never occurs. :arg bool disableStderrLogger: Should the default stderr logger be disabled. Defaults to False. """ global logger logger = setup_logger(name=LOGZERO_DEFAULT_LOGGER, logfile=logfile, level=level, formatter=formatter, disableStderrLogger=disableStderrLogger) return logger def reset_default_logger(): """ Resets the internal default logger to the initial configuration """ global logger global _loglevel global _logfile global _formatter _loglevel = logging.DEBUG _logfile = None _formatter = None logger = setup_logger(name=LOGZERO_DEFAULT_LOGGER, logfile=_logfile, level=_loglevel, formatter=_formatter) # Initially setup the default logger reset_default_logger() def loglevel(level=logging.DEBUG, update_custom_handlers=False): """ Set the minimum loglevel for the default logger (`logzero.logger`). This reconfigures only the internal handlers of the default logger (eg. stream and logfile). You can also update the loglevel for custom handlers by using `update_custom_handlers=True`. :arg int level: Minimum `logging-level `_ to display (default: `logging.DEBUG`). :arg bool update_custom_handlers: If you added custom handlers to this logger and want this to update them too, you need to set `update_custom_handlers` to `True` """ logger.setLevel(level) # Reconfigure existing internal handlers for handler in list(logger.handlers): if hasattr(handler, LOGZERO_INTERNAL_LOGGER_ATTR) or update_custom_handlers: # Don't update the loglevel if this handler uses a custom one if hasattr(handler, LOGZERO_INTERNAL_HANDLER_IS_CUSTOM_LOGLEVEL): continue # Update the loglevel for all default handlers handler.setLevel(level) global _loglevel _loglevel = level def formatter(formatter, update_custom_handlers=False): """ Set the formatter for all handlers of the default logger (``logzero.logger``). This reconfigures only the logzero internal handlers by default, but you can also reconfigure custom handlers by using ``update_custom_handlers=True``. Beware that setting a formatter which uses colors also may write the color codes to logfiles. :arg Formatter formatter: `Python logging Formatter object `_ (by default uses the internal LogFormatter). :arg bool update_custom_handlers: If you added custom handlers to this logger and want this to update them too, you need to set ``update_custom_handlers`` to `True` """ for handler in list(logger.handlers): if hasattr(handler, LOGZERO_INTERNAL_LOGGER_ATTR) or update_custom_handlers: handler.setFormatter(formatter) global _formatter _formatter = formatter def logfile(filename, formatter=None, mode='a', maxBytes=0, backupCount=0, encoding=None, loglevel=None, disableStderrLogger=False): """ Setup logging to file (using a `RotatingFileHandler `_ internally). By default, the file grows indefinitely (no rotation). You can use the ``maxBytes`` and ``backupCount`` values to allow the file to rollover at a predetermined size. When the size is about to be exceeded, the file is closed and a new file is silently opened for output. Rollover occurs whenever the current log file is nearly ``maxBytes`` in length; if either of ``maxBytes`` or ``backupCount`` is zero, rollover never occurs. If ``backupCount`` is non-zero, the system will save old log files by appending the extensions ‘.1’, ‘.2’ etc., to the filename. For example, with a ``backupCount`` of 5 and a base file name of app.log, you would get app.log, app.log.1, app.log.2, up to app.log.5. The file being written to is always app.log. When this file is filled, it is closed and renamed to app.log.1, and if files app.log.1, app.log.2, etc. exist, then they are renamed to app.log.2, app.log.3 etc. respectively. :arg string filename: Filename of the logfile. Set to `None` to disable logging to the logfile. :arg Formatter formatter: `Python logging Formatter object `_ (by default uses the internal LogFormatter). :arg string mode: mode to open the file with. Defaults to ``a`` :arg int maxBytes: Size of the logfile when rollover should occur. Defaults to 0, rollover never occurs. :arg int backupCount: Number of backups to keep. Defaults to 0, rollover never occurs. :arg string encoding: Used to open the file with that encoding. :arg int loglevel: Set a custom loglevel for the file logger, else uses the current global loglevel. :arg bool disableStderrLogger: Should the default stderr logger be disabled. Defaults to False. """ # Step 1: If an internal RotatingFileHandler already exists, remove it __remove_internal_loggers(logger, disableStderrLogger) # Step 2: If wanted, add the RotatingFileHandler now if filename: rotating_filehandler = RotatingFileHandler(filename, mode=mode, maxBytes=maxBytes, backupCount=backupCount, encoding=encoding) # Set internal attributes on this handler setattr(rotating_filehandler, LOGZERO_INTERNAL_LOGGER_ATTR, True) if loglevel: setattr(rotating_filehandler, LOGZERO_INTERNAL_HANDLER_IS_CUSTOM_LOGLEVEL, True) # Configure the handler and add it to the logger rotating_filehandler.setLevel(loglevel or _loglevel) rotating_filehandler.setFormatter(formatter or _formatter or LogFormatter(color=False)) logger.addHandler(rotating_filehandler) def __remove_internal_loggers(logger_to_update, disableStderrLogger=True): """ Remove the internal loggers (e.g. stderr logger and file logger) from the specific logger :param logger_to_update: the logger to remove internal loggers from :param disableStderrLogger: should the default stderr logger be disabled? defaults to True """ for handler in list(logger_to_update.handlers): if hasattr(handler, LOGZERO_INTERNAL_LOGGER_ATTR): if isinstance(handler, RotatingFileHandler): logger_to_update.removeHandler(handler) elif isinstance(handler, SysLogHandler): logger_to_update.removeHandler(handler) elif isinstance(handler, logging.StreamHandler) and disableStderrLogger: logger_to_update.removeHandler(handler) def syslog(logger_to_update=logger, facility=SysLogHandler.LOG_USER, disableStderrLogger=True): """ Setup logging to syslog and disable other internal loggers :param logger_to_update: the logger to enable syslog logging for :param facility: syslog facility to log to :param disableStderrLogger: should the default stderr logger be disabled? defaults to True :return the new SysLogHandler, which can be modified externally (e.g. for custom log level) """ # remove internal loggers __remove_internal_loggers(logger_to_update, disableStderrLogger) # Setup logzero to only use the syslog handler with the specified facility syslog_handler = SysLogHandler(facility=facility) setattr(syslog_handler, LOGZERO_INTERNAL_LOGGER_ATTR, True) logger_to_update.addHandler(syslog_handler) return syslog_handler def log_function_call(func): @functools.wraps(func) def wrap(*args, **kwargs): args_str = ", ".join([str(arg) for arg in args]) kwargs_str = ", ".join(["%s=%s" % (key, kwargs[key]) for key in kwargs]) if args_str and kwargs_str: all_args_str = ", ".join([args_str, kwargs_str]) else: all_args_str = args_str or kwargs_str logger.debug("%s(%s)", func.__name__, all_args_str) return func(*args, **kwargs) return wrap if __name__ == "__main__": _logger = setup_logger() _logger.info("hello") logzero-1.5.0/logzero/colors.py0000644000372000037200000000426213250015553017375 0ustar travistravis00000000000000""" Source: https://github.com/tartley/colorama/blob/master/colorama/ansi.py Copyright: Jonathan Hartley 2013. BSD 3-Clause license. """ CSI = '\033[' OSC = '\033]' BEL = '\007' def code_to_chars(code): return CSI + str(code) + 'm' def set_title(title): return OSC + '2;' + title + BEL def clear_screen(mode=2): return CSI + str(mode) + 'J' def clear_line(mode=2): return CSI + str(mode) + 'K' class AnsiCodes(object): def __init__(self): # the subclasses declare class attributes which are numbers. # Upon instantiation we define instance attributes, which are the same # as the class attributes but wrapped with the ANSI escape sequence for name in dir(self): if not name.startswith('_'): value = getattr(self, name) setattr(self, name, code_to_chars(value)) class AnsiCursor(object): def UP(self, n=1): return CSI + str(n) + 'A' def DOWN(self, n=1): return CSI + str(n) + 'B' def FORWARD(self, n=1): return CSI + str(n) + 'C' def BACK(self, n=1): return CSI + str(n) + 'D' def POS(self, x=1, y=1): return CSI + str(y) + ';' + str(x) + 'H' class AnsiFore(AnsiCodes): BLACK = 30 RED = 31 GREEN = 32 YELLOW = 33 BLUE = 34 MAGENTA = 35 CYAN = 36 WHITE = 37 RESET = 39 # These are fairly well supported, but not part of the standard. LIGHTBLACK_EX = 90 LIGHTRED_EX = 91 LIGHTGREEN_EX = 92 LIGHTYELLOW_EX = 93 LIGHTBLUE_EX = 94 LIGHTMAGENTA_EX = 95 LIGHTCYAN_EX = 96 LIGHTWHITE_EX = 97 class AnsiBack(AnsiCodes): BLACK = 40 RED = 41 GREEN = 42 YELLOW = 43 BLUE = 44 MAGENTA = 45 CYAN = 46 WHITE = 47 RESET = 49 # These are fairly well supported, but not part of the standard. LIGHTBLACK_EX = 100 LIGHTRED_EX = 101 LIGHTGREEN_EX = 102 LIGHTYELLOW_EX = 103 LIGHTBLUE_EX = 104 LIGHTMAGENTA_EX = 105 LIGHTCYAN_EX = 106 LIGHTWHITE_EX = 107 class AnsiStyle(AnsiCodes): BRIGHT = 1 DIM = 2 NORMAL = 22 RESET_ALL = 0 Fore = AnsiFore() Back = AnsiBack() Style = AnsiStyle() Cursor = AnsiCursor() logzero-1.5.0/logzero.egg-info/0000755000372000037200000000000013250015612017204 5ustar travistravis00000000000000logzero-1.5.0/logzero.egg-info/PKG-INFO0000644000372000037200000002522513250015612020307 0ustar travistravis00000000000000Metadata-Version: 1.1 Name: logzero Version: 1.5.0 Summary: Robust and effective logging for Python 2 and 3 Home-page: https://github.com/metachris/logzero Author: Chris Hager Author-email: chris@linuxuser.at License: MIT license Description-Content-Type: UNKNOWN Description: ======= logzero ======= .. image:: https://img.shields.io/pypi/v/logzero.svg :target: https://pypi.python.org/pypi/logzero :alt: Latest version on PyPi .. image:: https://travis-ci.org/metachris/logzero.svg?branch=master :target: https://travis-ci.org/metachris/logzero :alt: Build status for master branch .. image:: https://readthedocs.org/projects/logzero/badge/?version=latest :target: https://logzero.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://pyup.io/repos/github/metachris/logzero/shield.svg :target: https://pyup.io/repos/github/metachris/logzero/ :alt: Updates .. image:: https://anaconda.org/conda-forge/logzero/badges/version.svg :target: https://anaconda.org/conda-forge/logzero :alt: Anaconda-Server Badge Robust and effective logging for Python 2 and 3. .. image:: https://raw.githubusercontent.com/metachris/logzero/master/docs/_static/logo-small.png :alt: Logo :width: 300px * Documentation: https://logzero.readthedocs.io * GitHub: https://github.com/metachris/logzero Features -------- * Easy logging to console and/or (rotating) file. * Provides a fully configured standard `Python logger object `_. * Pretty formatting, including level-specific colors in the console. * Windows color output supported by `colorama`_ * Robust against str/bytes encoding problems, works with all kinds of character encodings and special characters. * Multiple loggers can write to the same logfile (also across multiple Python files). * Global default logger with `logzero.logger `_ and custom loggers with `logzero.setup_logger(..) `_. * Compatible with Python 2 and 3. * All contained in a `single file`_. * Licensed under the MIT license. * Heavily inspired by the `Tornado web framework`_. .. image:: https://raw.githubusercontent.com/metachris/logzero/master/docs/_static/demo_output.png :alt: Demo output in color :width: 300px .. _single file: https://github.com/metachris/logzero/blob/master/logzero/__init__.py .. _Tornado web framework: https://github.com/tornadoweb/tornado .. _colorama: https://github.com/tartley/colorama Example Usage ------------- .. code-block:: python from logzero import logger logger.debug("hello") logger.info("info") logger.warn("warn") logger.error("error") # This is how you'd log an exception try: raise Exception("this is a demo exception") except Exception as e: logger.exception(e) Adding a rotating logfile is that easy: .. code-block:: python import logzero from logzero import logger # Setup rotating logfile with 3 rotations, each with a maximum filesize of 1MB: logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1e6, backupCount=3) # Log messages logger.info("This log message goes to the console and the logfile") Here are more examples which show how to use logfiles, custom formatters and setting a minimum loglevel: .. code-block:: python import logging import logzero from logzero import logger # This log message goes to the console logger.debug("hello") # Set a minimum log level logzero.loglevel(logging.INFO) # Set a logfile (all future log messages are also saved there) logzero.logfile("/tmp/logfile.log") # You can also set a different loglevel for the file handler logzero.logfile("/tmp/logfile.log", loglevel=logging.ERROR) # Set a rotating logfile (replaces the previous logfile handler) logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3) # Disable logging to a file logzero.logfile(None) # Set a custom formatter formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s'); logzero.formatter(formatter) # Log some variables logger.info("var1: %s, var2: %s", var1, var2) Take a look at the documentation for more information and examples: * Documentation: https://logzero.readthedocs.io. Installation ------------ Install `logzero` with `pip`_: .. code-block:: console $ pip install -U logzero If you don't have `pip`_ installed, this `Python installation guide`_ can guide you through the process. Alternatively, if you use the `Anaconda distribution `_: .. code-block:: console $ conda config --add channels conda-forge $ conda install logzero You can also install `logzero` from the public `Github repo`_: .. code-block:: console $ git clone https://github.com/metachris/logzero.git $ cd logzero $ python setup.py install On openSUSE you can install the current version from repos: `python2-logzero `_, `python3-logzero `_. In the newest openSUSE release you can install it with zypper: `sudo zypper in python2-logzero`. .. _pip: https://pip.pypa.io .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ .. _Github repo: https://github.com/metachris/logzero Changelog --------- See the changelog here: https://github.com/metachris/logzero/blob/master/HISTORY.rst Feedback -------- All kinds of feedback and contributions are welcome. * `Create an issue `_ * Create a pull request * `@metachris `_ // chris@linuxuser.at ======= History ======= 1.5.0 (2018-03-07) ------------------ * ``logzero.syslog(..)`` (`PR 83 `_) 1.4.0 (2018-03-02) ------------------ * Allow Disabling stderr Output (`PR 83 `_) 1.3.0 (2017-07-19) ------------------ * Color output now works in Windows (supported by colorama) 1.2.1 (2017-07-09) ------------------ * Logfiles with custom loglevels (eg. stream handler with DEBUG and file handler with ERROR). 1.2.0 (2017-07-05) ------------------ * Way better API for configuring the default logger with `logzero.loglevel(..)`, `logzero.logfile(..)`, etc. * Built-in rotating logfile support. .. code-block:: python import logging import logzero from logzero import logger # This log message goes to the console logger.debug("hello") # Set a minimum log level logzero.loglevel(logging.INFO) # Set a logfile (all future log messages are also saved there) logzero.logfile("/tmp/logfile.log") # Set a rotating logfile (replaces the previous logfile handler) logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3) # Disable logging to a file logzero.logfile(None) # Set a custom formatter formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s'); logzero.formatter(formatter) # Log some variables logger.info("var1: %s, var2: %s", var1, var2) 1.1.2 (2017-07-04) ------------------ * Better reconfiguration of handlers, doesn't remove custom handlers anymore 1.1.0 (2017-07-03) ------------------ * Bugfix: Disabled color logging to logfile 1.1.0 (2017-07-02) ------------------ * Global default logger instance (`logzero.logger`) * Ability to reconfigure the default logger with (`logzero.setup_default_logger(..)`) * More tests * More documentation 1.0.0 (2017-06-27) ------------------ * Cleanup and documentation 0.2.0 (2017-06-12) ------------------ * Working logzero package with code and tests 0.1.0 (2017-06-12) ------------------ * First release on PyPI. Keywords: logzero Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 logzero-1.5.0/logzero.egg-info/SOURCES.txt0000644000372000037200000000116113250015612021067 0ustar travistravis00000000000000AUTHORS.rst CONTRIBUTING.rst HISTORY.rst LICENSE MANIFEST.in README.rst setup.cfg setup.py docs/Makefile docs/authors.rst docs/conf.py docs/contributing.rst docs/history.rst docs/index.rst docs/make.bat docs/readme.rst docs/_static/demo_output.png docs/_static/demo_output_with_exception.png docs/_static/logo-small.png docs/_static/logo.png logzero/__init__.py logzero/colors.py logzero.egg-info/PKG-INFO logzero.egg-info/SOURCES.txt logzero.egg-info/dependency_links.txt logzero.egg-info/not-zip-safe logzero.egg-info/requires.txt logzero.egg-info/top_level.txt tests/__init__.py tests/test_logzero.py tests/test_new_api.pylogzero-1.5.0/logzero.egg-info/dependency_links.txt0000644000372000037200000000000113250015612023252 0ustar travistravis00000000000000 logzero-1.5.0/logzero.egg-info/not-zip-safe0000644000372000037200000000000113250015612021432 0ustar travistravis00000000000000 logzero-1.5.0/logzero.egg-info/requires.txt0000644000372000037200000000004313250015612021601 0ustar travistravis00000000000000 [:sys_platform=="win32"] colorama logzero-1.5.0/logzero.egg-info/top_level.txt0000644000372000037200000000001013250015612021725 0ustar travistravis00000000000000logzero logzero-1.5.0/tests/0000755000372000037200000000000013250015612015173 5ustar travistravis00000000000000logzero-1.5.0/tests/__init__.py0000644000372000037200000000007613250015553017313 0ustar travistravis00000000000000# -*- coding: utf-8 -*- """Unit test package for logzero.""" logzero-1.5.0/tests/test_logzero.py0000644000372000037200000002124013250015553020270 0ustar travistravis00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ test_logzero ---------------------------------- Tests for `logzero` module. """ import os import tempfile import logging import logzero import pytest def test_write_to_logfile_and_stderr(capsys): """ Should log to a file. """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logger = logzero.setup_logger(logfile=temp.name) logger.info("test log output") _out, err = capsys.readouterr() assert " test_logzero:" in err assert err.endswith("test log output\n") with open(temp.name) as f: content = f.read() assert " test_logzero:" in content assert content.endswith("test log output\n") finally: temp.close() def test_custom_formatter(): """ Should work with a custom formatter. """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: log_format = '%(color)s[%(levelname)1.1s %(asctime)s customnametest:%(lineno)d]%(end_color)s %(message)s' formatter = logzero.LogFormatter(fmt=log_format) logger = logzero.setup_logger(logfile=temp.name, formatter=formatter) logger.info("test log output") with open(temp.name) as f: content = f.read() assert " customnametest:" in content assert content.endswith("test log output\n") finally: temp.close() def test_loglevel(): """ Should not log any debug messages if minimum level is set to INFO """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logger = logzero.setup_logger(logfile=temp.name, level=logging.INFO) logger.debug("test log output") with open(temp.name) as f: content = f.read() assert len(content.strip()) == 0 finally: temp.close() def test_bytes(): """ Should properly log bytes """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logger = logzero.setup_logger(logfile=temp.name) testbytes = os.urandom(20) logger.debug(testbytes) logger.debug(None) # with open(temp.name) as f: # content = f.read() # # assert str(testbytes) in content finally: temp.close() def test_unicode(): """ Should log unicode """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logger = logzero.setup_logger(logfile=temp.name) logger.debug("😄 😁 😆 😅 😂") with open(temp.name, "rb") as f: content = f.read() assert "\\xf0\\x9f\\x98\\x84 \\xf0\\x9f\\x98\\x81 \\xf0\\x9f\\x98\\x86 \\xf0\\x9f\\x98\\x85 \\xf0\\x9f\\x98\\x82\\n" in repr(content) finally: temp.close() def test_multiple_loggers_one_logfile(): """ Should properly log bytes """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logger1 = logzero.setup_logger(name="logger1", logfile=temp.name) logger2 = logzero.setup_logger(name="logger2", logfile=temp.name) logger3 = logzero.setup_logger(name="logger3", logfile=temp.name) logger1.info("logger1") logger2.info("logger2") logger3.info("logger3") with open(temp.name) as f: content = f.read().strip() assert "logger1" in content assert "logger2" in content assert "logger3" in content assert len(content.split("\n")) == 3 finally: temp.close() def test_default_logger(disableStdErrorLogger=False): """ Default logger should work and be able to be reconfigured. """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logzero.setup_default_logger(logfile=temp.name, disableStderrLogger=disableStdErrorLogger) logzero.logger.debug("debug1") # will be logged # Reconfigure with loglevel INFO logzero.setup_default_logger(logfile=temp.name, level=logging.INFO, disableStderrLogger=disableStdErrorLogger) logzero.logger.debug("debug2") # will not be logged logzero.logger.info("info1") # will be logged # Reconfigure with a different formatter log_format = '%(color)s[xxx]%(end_color)s %(message)s' formatter = logzero.LogFormatter(fmt=log_format) logzero.setup_default_logger(logfile=temp.name, level=logging.INFO, formatter=formatter, disableStderrLogger=disableStdErrorLogger) logzero.logger.info("info2") # will be logged with new formatter logzero.logger.debug("debug3") # will not be logged with open(temp.name) as f: content = f.read() test_default_logger_output(content) finally: temp.close() @pytest.mark.skip(reason="not a standalone test") def test_default_logger_output(content): assert "] debug1" in content assert "] debug2" not in content assert "] info1" in content assert "xxx] info2" in content assert "] debug3" not in content def test_setup_logger_reconfiguration(): """ Should be able to reconfigure without loosing custom handlers """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() temp2 = tempfile.NamedTemporaryFile() try: logzero.setup_default_logger(logfile=temp.name) # Add a custom file handler filehandler = logging.FileHandler(temp2.name) filehandler.setLevel(logging.DEBUG) filehandler.setFormatter(logzero.LogFormatter(color=False)) logzero.logger.addHandler(filehandler) # First debug message goes to both files logzero.logger.debug("debug1") # Reconfigure logger to remove logfile logzero.setup_default_logger() logzero.logger.debug("debug2") # Reconfigure logger to add logfile logzero.setup_default_logger(logfile=temp.name) logzero.logger.debug("debug3") # Reconfigure logger to set minimum loglevel to INFO logzero.setup_default_logger(logfile=temp.name, level=logging.INFO) logzero.logger.debug("debug4") logzero.logger.info("info1") # Reconfigure logger to set minimum loglevel back to DEBUG logzero.setup_default_logger(logfile=temp.name, level=logging.DEBUG) logzero.logger.debug("debug5") with open(temp.name) as f: content = f.read() assert "] debug1" in content assert "] debug2" not in content assert "] debug3" in content assert "] debug4" not in content assert "] info1" in content assert "] debug5" in content with open(temp2.name) as f: content = f.read() assert "] debug1" in content assert "] debug2" in content assert "] debug3" in content assert "] debug4" not in content assert "] info1" in content assert "] debug5" in content finally: temp.close() def test_setup_logger_logfile_custom_loglevel(capsys): """ setup_logger(..) with filelogger and custom loglevel """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logger = logzero.setup_logger(logfile=temp.name, fileLoglevel=logging.WARN) logger.info("info1") logger.warn("warn1") with open(temp.name) as f: content = f.read() assert "] info1" not in content assert "] warn1" in content finally: temp.close() def test_log_function_call(): @logzero.log_function_call def example(): """example doc""" pass assert example.__name__ == "example" assert example.__doc__ == "example doc" def test_default_logger_logfile_only(capsys): """ Run the ``test_default_logger`` with ``disableStdErrorLogger`` set to ``True`` and confirm that no data is written to stderr """ test_default_logger(disableStdErrorLogger=True) out, err = capsys.readouterr() assert err == '' def test_default_logger_stderr_output(capsys): """ Run the ``test_default_logger`` and confirm that the proper data is written to stderr """ test_default_logger() out, err = capsys.readouterr() test_default_logger_output(err) def test_default_logger_syslog_only(capsys): """ Run a test logging to ``syslog`` and confirm that no data is written to stderr. Note that the output in syslog is not currently being captured or checked. """ logzero.reset_default_logger() logzero.syslog() logzero.logger.error('debug') out, err = capsys.readouterr() assert out == '' and err == '' logzero-1.5.0/tests/test_new_api.py0000644000372000037200000000770313250015553020241 0ustar travistravis00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ test_logzero ---------------------------------- Tests for `logzero` module. """ import os import tempfile import logging import logzero def test_api_logfile(capsys): """ logzero.logfile(..) should work as expected """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logzero.logger.info("info1") # Set logfile logzero.logfile(temp.name) logzero.logger.info("info2") # Remove logfile logzero.logfile(None) logzero.logger.info("info3") # Set logfile again logzero.logfile(temp.name) logzero.logger.info("info4") with open(temp.name) as f: content = f.read() assert "] info1" not in content assert "] info2" in content assert "] info3" not in content assert "] info4" in content finally: temp.close() def test_api_loglevel(capsys): """ Should reconfigure the internal logger loglevel """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logzero.logfile(temp.name) logzero.logger.info("info1") logzero.loglevel(logging.WARN) logzero.logger.info("info2") logzero.logger.warn("warn1") with open(temp.name) as f: content = f.read() assert "] info1" in content assert "] info2" not in content assert "] warn1" in content finally: temp.close() def test_api_loglevel_custom_handlers(capsys): """ Should reconfigure the internal logger loglevel and custom handlers """ logzero.reset_default_logger() # TODO pass # temp = tempfile.NamedTemporaryFile() # try: # logzero.logfile(temp.name) # logzero.logger.info("info1") # logzero.loglevel(logging.WARN) # logzero.logger.info("info2") # logzero.logger.warn("warn1") # with open(temp.name) as f: # content = f.read() # assert "] info1" in content # assert "] info2" not in content # assert "] warn1" in content # finally: # temp.close() def test_api_rotating_logfile(capsys): """ logzero.rotating_logfile(..) should work as expected """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: logzero.logger.info("info1") # Set logfile logzero.logfile(temp.name, maxBytes=10, backupCount=3) logzero.logger.info("info2") logzero.logger.info("info3") with open(temp.name) as f: content = f.read() assert "] info1" not in content # logged before setting up logfile assert "] info2" not in content # already rotated out assert "] info3" in content # already rotated out fn_rotated = temp.name + ".1" assert os.path.exists(fn_rotated) with open(fn_rotated) as f: content = f.read() assert "] info2" in content finally: temp.close() def test_api_logfile_custom_loglevel(): """ logzero.logfile(..) should be able to use a custom loglevel """ logzero.reset_default_logger() temp = tempfile.NamedTemporaryFile() try: # Set logfile with custom loglevel logzero.logfile(temp.name, loglevel=logging.WARN) logzero.logger.info("info1") logzero.logger.warn("warn1") # If setting a loglevel with logzero.loglevel(..) it will not overwrite # the custom loglevel of the file handler logzero.loglevel(logging.INFO) logzero.logger.info("info2") logzero.logger.warn("warn2") with open(temp.name) as f: content = f.read() assert "] info1" not in content assert "] warn1" in content assert "] info2" not in content assert "] warn2" in content finally: temp.close() logzero-1.5.0/AUTHORS.rst0000644000372000037200000000023313250015553015712 0ustar travistravis00000000000000======= Credits ======= Development Lead ---------------- * Chris Hager Contributors ------------ None yet. Why not be the first? logzero-1.5.0/CONTRIBUTING.rst0000644000372000037200000000622613250015553016504 0ustar travistravis00000000000000.. highlight:: shell ============ Contributing ============ Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. You can contribute in many ways: Types of Contributions ---------------------- Report Bugs ~~~~~~~~~~~ Report bugs at https://github.com/metachris/logzero/issues. If you are reporting a bug, please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting. * Detailed steps to reproduce the bug. Fix Bugs ~~~~~~~~ Look through the GitHub issues for bugs. Anything tagged with "bug" and "help wanted" is open to whoever wants to implement it. Implement Features ~~~~~~~~~~~~~~~~~~ Look through the GitHub issues for features. Anything tagged with "enhancement" and "help wanted" is open to whoever wants to implement it. Write Documentation ~~~~~~~~~~~~~~~~~~~ logzero could always use more documentation, whether as part of the official logzero docs, in docstrings, or even on the web in blog posts, articles, and such. Submit Feedback ~~~~~~~~~~~~~~~ The best way to send feedback is to file an issue at https://github.com/metachris/logzero/issues. If you are proposing a feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that contributions are welcome :) Get Started! ------------ Ready to contribute? Here's how to set up `logzero` for local development. 1. Fork the `logzero` repo on GitHub. 2. Clone your fork locally:: $ git clone git@github.com:your_name_here/logzero.git 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: $ mkvirtualenv logzero $ cd logzero/ $ python setup.py develop 4. Create a branch for local development:: $ git checkout -b name-of-your-bugfix-or-feature Now you can make your changes locally. 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: $ flake8 logzero tests $ python setup.py test or py.test $ tox To get flake8 and tox, just pip install them into your virtualenv. 6. Commit your changes and push your branch to GitHub:: $ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature 7. Submit a pull request through the GitHub website. Pull Request Guidelines ----------------------- Before you submit a pull request, check that it meets these guidelines: 1. The pull request should include tests. 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst. 3. The pull request should work for Python 2.6, 2.7, 3.3, 3.4 and 3.5, and for PyPy. Check https://travis-ci.org/metachris/logzero/pull_requests and make sure that the tests pass for all supported Python versions. Tips ---- To run a subset of tests:: $ py.test tests.test_logzero logzero-1.5.0/HISTORY.rst0000644000372000037200000000410513250015553015730 0ustar travistravis00000000000000======= History ======= 1.5.0 (2018-03-07) ------------------ * ``logzero.syslog(..)`` (`PR 83 `_) 1.4.0 (2018-03-02) ------------------ * Allow Disabling stderr Output (`PR 83 `_) 1.3.0 (2017-07-19) ------------------ * Color output now works in Windows (supported by colorama) 1.2.1 (2017-07-09) ------------------ * Logfiles with custom loglevels (eg. stream handler with DEBUG and file handler with ERROR). 1.2.0 (2017-07-05) ------------------ * Way better API for configuring the default logger with `logzero.loglevel(..)`, `logzero.logfile(..)`, etc. * Built-in rotating logfile support. .. code-block:: python import logging import logzero from logzero import logger # This log message goes to the console logger.debug("hello") # Set a minimum log level logzero.loglevel(logging.INFO) # Set a logfile (all future log messages are also saved there) logzero.logfile("/tmp/logfile.log") # Set a rotating logfile (replaces the previous logfile handler) logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3) # Disable logging to a file logzero.logfile(None) # Set a custom formatter formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s'); logzero.formatter(formatter) # Log some variables logger.info("var1: %s, var2: %s", var1, var2) 1.1.2 (2017-07-04) ------------------ * Better reconfiguration of handlers, doesn't remove custom handlers anymore 1.1.0 (2017-07-03) ------------------ * Bugfix: Disabled color logging to logfile 1.1.0 (2017-07-02) ------------------ * Global default logger instance (`logzero.logger`) * Ability to reconfigure the default logger with (`logzero.setup_default_logger(..)`) * More tests * More documentation 1.0.0 (2017-06-27) ------------------ * Cleanup and documentation 0.2.0 (2017-06-12) ------------------ * Working logzero package with code and tests 0.1.0 (2017-06-12) ------------------ * First release on PyPI. logzero-1.5.0/LICENSE0000644000372000037200000000205713250015553015046 0ustar travistravis00000000000000 MIT License Copyright (c) 2017, Chris Hager Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. logzero-1.5.0/MANIFEST.in0000644000372000037200000000040613250015553015573 0ustar travistravis00000000000000include AUTHORS.rst include CONTRIBUTING.rst include HISTORY.rst include LICENSE include README.rst recursive-include tests * recursive-exclude * __pycache__ recursive-exclude * *.py[co] recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif logzero-1.5.0/README.rst0000644000372000037200000001301113250015553015520 0ustar travistravis00000000000000======= logzero ======= .. image:: https://img.shields.io/pypi/v/logzero.svg :target: https://pypi.python.org/pypi/logzero :alt: Latest version on PyPi .. image:: https://travis-ci.org/metachris/logzero.svg?branch=master :target: https://travis-ci.org/metachris/logzero :alt: Build status for master branch .. image:: https://readthedocs.org/projects/logzero/badge/?version=latest :target: https://logzero.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://pyup.io/repos/github/metachris/logzero/shield.svg :target: https://pyup.io/repos/github/metachris/logzero/ :alt: Updates .. image:: https://anaconda.org/conda-forge/logzero/badges/version.svg :target: https://anaconda.org/conda-forge/logzero :alt: Anaconda-Server Badge Robust and effective logging for Python 2 and 3. .. image:: https://raw.githubusercontent.com/metachris/logzero/master/docs/_static/logo-small.png :alt: Logo :width: 300px * Documentation: https://logzero.readthedocs.io * GitHub: https://github.com/metachris/logzero Features -------- * Easy logging to console and/or (rotating) file. * Provides a fully configured standard `Python logger object `_. * Pretty formatting, including level-specific colors in the console. * Windows color output supported by `colorama`_ * Robust against str/bytes encoding problems, works with all kinds of character encodings and special characters. * Multiple loggers can write to the same logfile (also across multiple Python files). * Global default logger with `logzero.logger `_ and custom loggers with `logzero.setup_logger(..) `_. * Compatible with Python 2 and 3. * All contained in a `single file`_. * Licensed under the MIT license. * Heavily inspired by the `Tornado web framework`_. .. image:: https://raw.githubusercontent.com/metachris/logzero/master/docs/_static/demo_output.png :alt: Demo output in color :width: 300px .. _single file: https://github.com/metachris/logzero/blob/master/logzero/__init__.py .. _Tornado web framework: https://github.com/tornadoweb/tornado .. _colorama: https://github.com/tartley/colorama Example Usage ------------- .. code-block:: python from logzero import logger logger.debug("hello") logger.info("info") logger.warn("warn") logger.error("error") # This is how you'd log an exception try: raise Exception("this is a demo exception") except Exception as e: logger.exception(e) Adding a rotating logfile is that easy: .. code-block:: python import logzero from logzero import logger # Setup rotating logfile with 3 rotations, each with a maximum filesize of 1MB: logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1e6, backupCount=3) # Log messages logger.info("This log message goes to the console and the logfile") Here are more examples which show how to use logfiles, custom formatters and setting a minimum loglevel: .. code-block:: python import logging import logzero from logzero import logger # This log message goes to the console logger.debug("hello") # Set a minimum log level logzero.loglevel(logging.INFO) # Set a logfile (all future log messages are also saved there) logzero.logfile("/tmp/logfile.log") # You can also set a different loglevel for the file handler logzero.logfile("/tmp/logfile.log", loglevel=logging.ERROR) # Set a rotating logfile (replaces the previous logfile handler) logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3) # Disable logging to a file logzero.logfile(None) # Set a custom formatter formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s'); logzero.formatter(formatter) # Log some variables logger.info("var1: %s, var2: %s", var1, var2) Take a look at the documentation for more information and examples: * Documentation: https://logzero.readthedocs.io. Installation ------------ Install `logzero` with `pip`_: .. code-block:: console $ pip install -U logzero If you don't have `pip`_ installed, this `Python installation guide`_ can guide you through the process. Alternatively, if you use the `Anaconda distribution `_: .. code-block:: console $ conda config --add channels conda-forge $ conda install logzero You can also install `logzero` from the public `Github repo`_: .. code-block:: console $ git clone https://github.com/metachris/logzero.git $ cd logzero $ python setup.py install On openSUSE you can install the current version from repos: `python2-logzero `_, `python3-logzero `_. In the newest openSUSE release you can install it with zypper: `sudo zypper in python2-logzero`. .. _pip: https://pip.pypa.io .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ .. _Github repo: https://github.com/metachris/logzero Changelog --------- See the changelog here: https://github.com/metachris/logzero/blob/master/HISTORY.rst Feedback -------- All kinds of feedback and contributions are welcome. * `Create an issue `_ * Create a pull request * `@metachris `_ // chris@linuxuser.at logzero-1.5.0/setup.cfg0000644000372000037200000000064213250015612015654 0ustar travistravis00000000000000[bumpversion] current_version = 1.5.0 commit = True tag = True [bumpversion:file:setup.py] search = version='{current_version}' replace = version='{new_version}' [bumpversion:file:logzero/__init__.py] search = __version__ = '{current_version}' replace = __version__ = '{new_version}' [bdist_wheel] universal = 1 [flake8] exclude = docs ignore = E501 [aliases] test = pytest [egg_info] tag_build = tag_date = 0 logzero-1.5.0/setup.py0000644000372000037200000000253213250015553015551 0ustar travistravis00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """The setup script.""" from setuptools import setup, find_packages with open('README.rst') as readme_file: readme = readme_file.read() with open('HISTORY.rst') as history_file: history = history_file.read() setup( name='logzero', version='1.5.0', description="Robust and effective logging for Python 2 and 3", long_description=readme + '\n\n' + history, author="Chris Hager", author_email='chris@linuxuser.at', url='https://github.com/metachris/logzero', packages=find_packages(include=['logzero']), include_package_data=True, license="MIT license", zip_safe=False, keywords='logzero', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', "Programming Language :: Python :: 2", 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', ], extras_require={ ':sys_platform=="win32"': ['colorama'] } ) logzero-1.5.0/PKG-INFO0000644000372000037200000002522513250015612015134 0ustar travistravis00000000000000Metadata-Version: 1.1 Name: logzero Version: 1.5.0 Summary: Robust and effective logging for Python 2 and 3 Home-page: https://github.com/metachris/logzero Author: Chris Hager Author-email: chris@linuxuser.at License: MIT license Description-Content-Type: UNKNOWN Description: ======= logzero ======= .. image:: https://img.shields.io/pypi/v/logzero.svg :target: https://pypi.python.org/pypi/logzero :alt: Latest version on PyPi .. image:: https://travis-ci.org/metachris/logzero.svg?branch=master :target: https://travis-ci.org/metachris/logzero :alt: Build status for master branch .. image:: https://readthedocs.org/projects/logzero/badge/?version=latest :target: https://logzero.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://pyup.io/repos/github/metachris/logzero/shield.svg :target: https://pyup.io/repos/github/metachris/logzero/ :alt: Updates .. image:: https://anaconda.org/conda-forge/logzero/badges/version.svg :target: https://anaconda.org/conda-forge/logzero :alt: Anaconda-Server Badge Robust and effective logging for Python 2 and 3. .. image:: https://raw.githubusercontent.com/metachris/logzero/master/docs/_static/logo-small.png :alt: Logo :width: 300px * Documentation: https://logzero.readthedocs.io * GitHub: https://github.com/metachris/logzero Features -------- * Easy logging to console and/or (rotating) file. * Provides a fully configured standard `Python logger object `_. * Pretty formatting, including level-specific colors in the console. * Windows color output supported by `colorama`_ * Robust against str/bytes encoding problems, works with all kinds of character encodings and special characters. * Multiple loggers can write to the same logfile (also across multiple Python files). * Global default logger with `logzero.logger `_ and custom loggers with `logzero.setup_logger(..) `_. * Compatible with Python 2 and 3. * All contained in a `single file`_. * Licensed under the MIT license. * Heavily inspired by the `Tornado web framework`_. .. image:: https://raw.githubusercontent.com/metachris/logzero/master/docs/_static/demo_output.png :alt: Demo output in color :width: 300px .. _single file: https://github.com/metachris/logzero/blob/master/logzero/__init__.py .. _Tornado web framework: https://github.com/tornadoweb/tornado .. _colorama: https://github.com/tartley/colorama Example Usage ------------- .. code-block:: python from logzero import logger logger.debug("hello") logger.info("info") logger.warn("warn") logger.error("error") # This is how you'd log an exception try: raise Exception("this is a demo exception") except Exception as e: logger.exception(e) Adding a rotating logfile is that easy: .. code-block:: python import logzero from logzero import logger # Setup rotating logfile with 3 rotations, each with a maximum filesize of 1MB: logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1e6, backupCount=3) # Log messages logger.info("This log message goes to the console and the logfile") Here are more examples which show how to use logfiles, custom formatters and setting a minimum loglevel: .. code-block:: python import logging import logzero from logzero import logger # This log message goes to the console logger.debug("hello") # Set a minimum log level logzero.loglevel(logging.INFO) # Set a logfile (all future log messages are also saved there) logzero.logfile("/tmp/logfile.log") # You can also set a different loglevel for the file handler logzero.logfile("/tmp/logfile.log", loglevel=logging.ERROR) # Set a rotating logfile (replaces the previous logfile handler) logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3) # Disable logging to a file logzero.logfile(None) # Set a custom formatter formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s'); logzero.formatter(formatter) # Log some variables logger.info("var1: %s, var2: %s", var1, var2) Take a look at the documentation for more information and examples: * Documentation: https://logzero.readthedocs.io. Installation ------------ Install `logzero` with `pip`_: .. code-block:: console $ pip install -U logzero If you don't have `pip`_ installed, this `Python installation guide`_ can guide you through the process. Alternatively, if you use the `Anaconda distribution `_: .. code-block:: console $ conda config --add channels conda-forge $ conda install logzero You can also install `logzero` from the public `Github repo`_: .. code-block:: console $ git clone https://github.com/metachris/logzero.git $ cd logzero $ python setup.py install On openSUSE you can install the current version from repos: `python2-logzero `_, `python3-logzero `_. In the newest openSUSE release you can install it with zypper: `sudo zypper in python2-logzero`. .. _pip: https://pip.pypa.io .. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ .. _Github repo: https://github.com/metachris/logzero Changelog --------- See the changelog here: https://github.com/metachris/logzero/blob/master/HISTORY.rst Feedback -------- All kinds of feedback and contributions are welcome. * `Create an issue `_ * Create a pull request * `@metachris `_ // chris@linuxuser.at ======= History ======= 1.5.0 (2018-03-07) ------------------ * ``logzero.syslog(..)`` (`PR 83 `_) 1.4.0 (2018-03-02) ------------------ * Allow Disabling stderr Output (`PR 83 `_) 1.3.0 (2017-07-19) ------------------ * Color output now works in Windows (supported by colorama) 1.2.1 (2017-07-09) ------------------ * Logfiles with custom loglevels (eg. stream handler with DEBUG and file handler with ERROR). 1.2.0 (2017-07-05) ------------------ * Way better API for configuring the default logger with `logzero.loglevel(..)`, `logzero.logfile(..)`, etc. * Built-in rotating logfile support. .. code-block:: python import logging import logzero from logzero import logger # This log message goes to the console logger.debug("hello") # Set a minimum log level logzero.loglevel(logging.INFO) # Set a logfile (all future log messages are also saved there) logzero.logfile("/tmp/logfile.log") # Set a rotating logfile (replaces the previous logfile handler) logzero.logfile("/tmp/rotating-logfile.log", maxBytes=1000000, backupCount=3) # Disable logging to a file logzero.logfile(None) # Set a custom formatter formatter = logging.Formatter('%(name)s - %(asctime)-15s - %(levelname)s: %(message)s'); logzero.formatter(formatter) # Log some variables logger.info("var1: %s, var2: %s", var1, var2) 1.1.2 (2017-07-04) ------------------ * Better reconfiguration of handlers, doesn't remove custom handlers anymore 1.1.0 (2017-07-03) ------------------ * Bugfix: Disabled color logging to logfile 1.1.0 (2017-07-02) ------------------ * Global default logger instance (`logzero.logger`) * Ability to reconfigure the default logger with (`logzero.setup_default_logger(..)`) * More tests * More documentation 1.0.0 (2017-06-27) ------------------ * Cleanup and documentation 0.2.0 (2017-06-12) ------------------ * Working logzero package with code and tests 0.1.0 (2017-06-12) ------------------ * First release on PyPI. Keywords: logzero Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6