New logging framework

db4
Slava Pestov 2008-02-07 17:07:43 -06:00
parent 2126903739
commit 5310a2cabe
29 changed files with 523 additions and 170 deletions

2
extra/concurrency/distributed/distributed.factor Normal file → Executable file
View File

@ -14,7 +14,7 @@ C: <node> node
: node-server ( port -- )
internet-server
"concurrency"
"concurrency.distributed"
[ handle-node-client ] with-server ;
: send-to-node ( msg pid host port -- )

39
extra/http/server/responders/responders.factor Normal file → Executable file
View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license.
USING: arrays assocs hashtables html html.elements splitting
http io kernel math math.parser namespaces parser sequences
strings io.server vectors assocs.lib io.logging ;
strings io.server vectors assocs.lib logging ;
IN: http.server.responders
@ -22,7 +22,7 @@ SYMBOL: responders
<html> <body> <h1> write </h1> </body> </html> ;
: error-head ( error -- )
dup log-error response
response
H{ { "Content-Type" V{ "text/html" } } } print-header nl ;
: httpd-error ( error -- )
@ -30,6 +30,8 @@ SYMBOL: responders
dup error-head
"head" "method" get = [ drop ] [ error-body ] if ;
\ httpd-error ERROR add-error-logging
: bad-request ( -- )
[
! Make httpd-error print a body
@ -84,17 +86,21 @@ SYMBOL: max-post-request
: read-post-request ( header -- str hash )
content-length [ read dup query>hash ] [ f f ] if* ;
: log-headers ( hash -- )
LOG: log-headers DEBUG
: interesting-headers ( assoc -- string )
[
drop {
"user-agent"
"referer"
"x-forwarded-for"
"host"
} member?
] assoc-subset [
": " swap 3append log-message
] multi-assoc-each ;
[
drop {
"user-agent"
"referer"
"x-forwarded-for"
"host"
} member?
] assoc-subset [
": " swap 3append % "\n" %
] multi-assoc-each
] "" make ;
: prepare-url ( url -- url )
#! This is executed in the with-request namespace.
@ -105,7 +111,7 @@ SYMBOL: max-post-request
: prepare-header ( -- )
read-header
dup "header" set
dup log-headers
dup interesting-headers log-headers
read-post-request "response" set "raw-response" set ;
! Responders are called in a new namespace with these
@ -177,9 +183,6 @@ SYMBOL: max-post-request
"/" "responder-url" set
"default" responder call-responder ;
: log-responder ( path -- )
"Calling responder " swap append log-message ;
: trim-/ ( url -- url )
#! Trim a leading /, if there is one.
"/" ?head drop ;
@ -199,13 +202,15 @@ SYMBOL: max-post-request
#! /foo/bar... - default responder used
#! /responder/foo/bar - responder foo, argument bar
vhost [
dup log-responder trim-/ "responder/" ?head [
trim-/ "responder/" ?head [
serve-explicit-responder
] [
serve-default-responder
] if
] bind ;
\ serve-responder DEBUG add-input-logging
: no-such-responder ( -- )
"404 No such responder" httpd-error ;

6
extra/http/server/server.factor Normal file → Executable file
View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license.
USING: assocs kernel namespaces io strings splitting
threads http http.server.responders sequences prettyprint
io.server io.logging ;
io.server logging ;
IN: http.server
@ -36,7 +36,6 @@ IN: http.server
[ (handle-request) serve-responder ] with-scope ;
: parse-request ( request -- )
dup log-message
" " split1 dup [
" HTTP" split1 drop url>path secure-path dup [
swap handle-request
@ -47,8 +46,9 @@ IN: http.server
2drop bad-request
] if ;
\ parse-request NOTICE add-input-logging
: httpd ( port -- )
"Starting HTTP server on port " write dup . flush
internet-server "http.server" [
60000 stdio get set-timeout
readln [ parse-request ] when*

View File

@ -1,26 +0,0 @@
IN: io.logging
USING: help.markup help.syntax io ;
HELP: log-stream
{ $var-description "Holds an output stream for logging messages." }
{ $see-also log-error log-client with-logging } ;
HELP: log-message
{ $values { "str" "a string" } }
{ $description "Logs a message to the log stream. If " { $link log-stream } " is not set, logs to the " { $link stdio } " stream." }
{ $see-also log-error log-client } ;
HELP: log-error
{ $values { "str" "a string" } }
{ $description "Logs an error message." }
{ $see-also log-message log-client } ;
HELP: log-client
{ $values { "client" "a client socket stream" } }
{ $description "Logs an incoming client connection." }
{ $see-also log-message log-error } ;
HELP: with-logging
{ $values { "service" "a string or " { $link f } } { "quot" "a quotation" } }
{ $description "Calls the quotation in a new dynamic scope where the " { $link log-stream } " is set to a file stream appending to a log file (if " { $snippet "service" } " is not " { $link f } ") or the " { $link stdio } " stream at the time " { $link with-logging } " is called (if " { $snippet "service" } " is " { $link f } ")." } ;

View File

@ -1,47 +0,0 @@
! Copyright (C) 2003, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces kernel io calendar sequences io.files
io.sockets continuations prettyprint ;
IN: io.logging
SYMBOL: log-stream
: to-log-stream ( quot -- )
log-stream get swap with-stream* ; inline
: log-message ( str -- )
[
"[" write now timestamp>string write "] " write
print flush
] to-log-stream ;
: log-error ( str -- ) "Error: " swap append log-message ;
: log-client ( client -- )
"Accepted connection from "
swap client-stream-addr unparse append log-message ;
: log-file ( service -- path )
".log" append resource-path ;
: with-log-stream ( stream quot -- )
log-stream get [ nip call ] [
log-stream swap with-variable
] if ; inline
: with-log-file ( file quot -- )
>r <file-appender> r>
[ with-log-stream ] curry
with-disposal ; inline
: with-log-stdio ( quot -- )
stdio get swap with-log-stream ; inline
: with-logging ( service quot -- )
over [
>r log-file
"Writing log messages to " write dup print flush r>
with-log-file
] [
nip with-log-stdio
] if ; inline

View File

@ -1 +0,0 @@
Basic logging framework for server applications

View File

@ -1,32 +1,34 @@
! Copyright (C) 2003, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: io io.sockets io.files io.logging continuations kernel
USING: io io.sockets io.files logging continuations kernel
math math.parser namespaces parser sequences strings
prettyprint debugger quotations calendar qualified ;
QUALIFIED: concurrency
IN: io.server
: with-client ( quot client -- )
dup log-client
[ swap with-stream ] 2curry concurrency:spawn drop ; inline
LOG: accepted-connection NOTICE
: with-client ( client quot -- )
[
over client-stream-addr accepted-connection
with-stream*
] curry with-disposal ; inline
\ with-client NOTICE add-error-logging
: accept-loop ( server quot -- )
[ swap accept with-client ] 2keep accept-loop ; inline
[
>r accept r> [ with-client ] 2curry concurrency:spawn
] 2keep accept-loop ; inline
: server-loop ( server quot -- )
[ accept-loop ] curry with-disposal ; inline
: spawn-server ( addrspec quot -- )
"Waiting for connections on " pick unparse append
log-message
[
>r <server> r> server-loop
] [
"Cannot spawn server: " print
print-error
2drop
] recover ; inline
>r <server> r> server-loop ; inline
\ spawn-server NOTICE add-error-logging
: local-server ( port -- seq )
"localhost" swap t resolve-host ;
@ -39,19 +41,21 @@ IN: io.server
[ spawn-server ] curry concurrency:parallel-each
] curry with-logging ; inline
: log-datagram ( addrspec -- )
"Received datagram from " swap unparse append log-message ;
: received-datagram ( addrspec -- ) drop ;
\ received-datagram NOTICE add-input-logging
: datagram-loop ( quot datagram -- )
[
[ receive dup log-datagram >r swap call r> ] keep
[ receive dup received-datagram >r swap call r> ] keep
pick [ send ] [ 3drop ] keep
] 2keep datagram-loop ; inline
: spawn-datagrams ( quot addrspec -- )
"Waiting for datagrams on " over unparse append log-message
<datagram> [ datagram-loop ] with-disposal ; inline
\ spawn-datagrams NOTICE add-input-logging
: with-datagrams ( seq service quot -- )
[
[ swap spawn-datagrams ] curry concurrency:parallel-each

View File

@ -0,0 +1,69 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences namespaces words assocs logging sorting
prettyprint io io.styles strings logging.parser ;
IN: logging.analysis
SYMBOL: word-names
SYMBOL: errors
SYMBOL: word-histogram
SYMBOL: message-histogram
: analyze-entry ( entry -- )
dup second ERROR eq? [ dup errors get push ] when
1 over third word-histogram get at+
dup third word-names get member? [
1 over 1 tail message-histogram get at+
] when
drop ;
: analyze-entries ( entries word-names -- errors word-histogram message-histogram )
[
word-names set
V{ } clone errors set
H{ } clone word-histogram set
H{ } clone message-histogram set
[
analyze-entry
] each
errors get
word-histogram get
message-histogram get
] with-scope ;
: histogram. ( assoc quot -- )
standard-table-style [
>r >alist sort-values <reversed> r> [
[ >r swap r> with-cell pprint-cell ] with-row
] curry assoc-each
] tabular-output ;
: log-entry.
[
dup first [ write ] with-cell
dup second [ pprint ] with-cell
dup third [ write ] with-cell
fourth "\n" join [ write ] with-cell
] with-row ;
: errors. ( errors -- )
standard-table-style
[ [ log-entry. ] each ] tabular-output ;
: analysis. ( errors word-histogram message-histogram -- )
"==== INTERESTING MESSAGES:" print nl
"Total: " write dup values sum . nl
[
dup second write ": " write third "\n" join write
] histogram.
nl
"==== WORDS:" print nl
[ write ] histogram.
nl
"==== ERRORS:" print nl
errors. ;
: log-analysis ( lines word-names -- )
>r parse-log r> analyze-entries analysis. ;

View File

@ -1 +1 @@
Slava Pestov
Slava Pestov

View File

@ -0,0 +1 @@
Analyze logs and produce summaries

1
extra/logging/authors.txt Executable file
View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,49 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: logging.analysis logging.server logging smtp io.sockets
kernel io.files io.streams.string namespaces raptor.cron ;
IN: logging.insomniac
SYMBOL: insomniac-config
SYMBOL: insomniac-smtp-host
SYMBOL: insomniac-smtp-port
SYMBOL: insomniac-sender
SYMBOL: insomniac-recipients
: ?log-analysis ( service word-names -- string/f )
>r log-path 1 log# dup exists? [
file-lines r> [ log-analysis ] string-out
] [
r> 2drop f
] if ;
: with-insomniac-smtp ( quot -- )
[
insomniac-smtp-host get [ smtp-host set ] when*
insomniac-smtp-port get [ smtp-port set ] when*
call
] with-scope ; inline
: email-subject ( service -- string )
[ "[INSOMNIAC] " % % " on " % host-name % ] "" make ;
: (email-log-report) ( service word-names -- )
[
over >r
?log-analysis dup [
r> email-subject
insomniac-recipients get
insomniac-sender get
send-simple-message
] [ r> 2drop ] if
] with-insomniac-smtp ;
: email-log-report ( service word-names -- )
(email-log-report) ;
\ email-log-report NOTICE add-error-logging
: schedule-insomniac ( service word-names -- )
{ 25 } { 6 } f f f <when> -rot
[ email-log-report ] 2curry schedule ;

View File

@ -0,0 +1 @@
Task which rotates logs and e-mails summaries

122
extra/logging/logging.factor Executable file
View File

@ -0,0 +1,122 @@
! Copyright (C) 2003, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: logging.server sequences namespaces concurrency
words kernel arrays shuffle tools.annotations
prettyprint.config prettyprint debugger io.streams.string
splitting continuations effects arrays.lib parser strings
combinators.lib ;
IN: logging
SYMBOL: DEBUG
SYMBOL: NOTICE
SYMBOL: WARNING
SYMBOL: ERROR
SYMBOL: CRITICAL
: log-levels
{ DEBUG NOTICE NOTICE WARNING ERROR CRITICAL } ;
: send-to-log-server ( array string -- )
add* "log-server" get send ;
SYMBOL: log-service
: check-log-message
pick string?
pick word?
pick word? and and
[ "Bad parameters to log-message" throw ] unless ;
: log-message ( msg word level -- )
check-log-message
log-service get dup [
>r >r >r string-lines r> word-name r> word-name r>
4array "log-message" send-to-log-server
] [
4drop
] if ;
: rotate-logs ( -- )
{ } "rotate-logs" send-to-log-server ;
: close-log-files ( -- )
{ } "close-log-files" send-to-log-server ;
: with-logging ( service quot -- )
log-service swap with-variable ; inline
! Aspect-oriented programming idioms
<PRIVATE
: one-string?
{
[ dup array? ]
[ dup length 1 = ]
[ dup first string? ]
} && nip ;
: inputs>message ( obj -- inputs>message )
dup one-string? [ first ] [
H{
{ string-limit f }
{ line-limit 1 }
{ nesting-limit 3 }
{ margin 0 }
} clone [ unparse ] bind
] if ;
PRIVATE>
: (define-logging) ( word level quot -- )
>r >r dup r> r> 2curry annotate ;
: call-logging-quot ( quot word level -- quot' )
"called" -rot [ log-message ] 3curry swap compose ;
: add-logging ( word level -- )
[ call-logging-quot ] (define-logging) ;
: log-inputs ( n word level -- )
log-service get [
>r >r [ ndup ] keep narray inputs>message
r> r> log-message
] [
3drop
] if ; inline
: input# stack-effect effect-in length ;
: input-logging-quot ( quot word level -- quot' )
over input# -rot [ log-inputs ] 3curry swap compose ;
: add-input-logging ( word level -- )
[ input-logging-quot ] (define-logging) ;
: (log-error) ( object word level -- )
log-service get [
>r >r [ print-error ] string-out r> r> log-message
] [
2drop rethrow
] if ;
: log-error ( object word -- ) ERROR (log-error) ;
: log-critical ( object word -- ) CRITICAL (log-error) ;
: error-logging-quot ( quot word -- quot' )
dup stack-effect effect-in length
[ >r log-error r> ndrop ] 2curry
[ recover ] 2curry ;
: add-error-logging ( word level -- )
[ over >r input-logging-quot r> error-logging-quot ]
(define-logging) ;
: LOG:
#! Syntax: name level
CREATE
dup reset-generic
dup scan-word
[ >r >r 1array inputs>message r> r> log-message ] 2curry
define ; parsing

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,66 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: parser-combinators memoize kernel sequences
logging arrays words strings vectors io io.files
namespaces combinators combinators.lib logging.server ;
IN: logging.parser
: string-of satisfy <!*> [ >string ] <@ ;
: 'date'
[ CHAR: ] eq? not ] string-of
"[" "]" surrounded-by ;
: 'log-level'
log-levels [
[ word-name token ] keep [ nip ] curry <@
] map <or-parser> ;
: 'word-name'
[ " :" member? not ] string-of ;
SYMBOL: malformed
: 'malformed-line'
[ drop t ] string-of [ malformed swap 2array ] <@ ;
: 'log-message'
[ drop t ] string-of [ 1vector ] <@ ;
MEMO: 'log-line' ( -- parser )
'date' " " token <&
'log-level' " " token <& <&>
'word-name' ": " token <& <:&>
'log-message' <:&>
'malformed-line' <|> ;
: parse-log-line ( string -- entry )
'log-line' parse-1 ;
: malformed? ( line -- ? )
first malformed eq? ;
: multiline? ( line -- ? )
first first CHAR: - = ;
: malformed-line
"Warning: malformed log line:" print
second print ;
: add-multiline ( line -- )
building get empty? [
"Warning: log begins with multiline entry" print drop
] [
fourth first building get peek fourth push
] if ;
: parse-log ( lines -- entries )
[
[
parse-log-line {
{ [ dup malformed? ] [ malformed-line ] }
{ [ dup multiline? ] [ add-multiline ] }
{ [ t ] [ , ] }
} cond
] each
] { } make ;

View File

@ -0,0 +1 @@
Log parser

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,101 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces kernel io calendar sequences io.files
io.sockets continuations prettyprint assocs math.parser
words debugger math combinators concurrency arrays init
math.ranges strings ;
IN: logging.server
: log-root ( -- string )
\ log-root get "logs" resource-path or ;
: log-path ( service -- path )
log-root swap path+ ;
: log# ( path n -- path' )
number>string ".log" append path+ ;
SYMBOL: log-files
: open-log-stream ( service -- stream )
log-path
dup make-directories
1 log# <file-appender> ;
: log-stream ( service -- stream )
log-files get [ open-log-stream ] cache ;
: (write-message) ( msg word-name level multi? -- )
[
"[" write 20 CHAR: - <string> write "] " write
] [
"[" write now (timestamp>rfc3339) "] " write
] if
write bl write ": " write print ;
: write-message ( msg word-name level -- )
rot [ empty? not ] subset {
{ [ dup empty? ] [ 3drop ] }
{ [ dup length 1 = ] [ first -rot f (write-message) ] }
{ [ t ] [
[ first -rot f (write-message) ] 3keep
1 tail -rot [ t (write-message) ] 2curry each
] }
} cond ;
: (log-message) ( msg -- )
#! msg: { msg word-name level service }
first4 log-stream [ write-message flush ] with-stream* ;
: try-dispose ( stream -- )
[ dispose ] curry [ error. ] recover ;
: close-log-file ( service -- )
log-files get delete-at*
[ try-dispose ] [ drop ] if ;
: (close-log-files) ( -- )
log-files get
dup values [ try-dispose ] each
clear-assoc ;
: keep-logs 10 ;
: ?delete-file ( path -- )
dup exists? [ delete-file ] [ drop ] if ;
: delete-oldest keep-logs log# ?delete-file ;
: ?rename-file ( old new -- )
over exists? [ rename-file ] [ 2drop ] if ;
: advance-log ( path n -- )
[ 1- log# ] 2keep log# ?rename-file ;
: rotate-log ( service -- )
dup close-log-file
log-path
dup delete-oldest
keep-logs 1 [a,b] [ advance-log ] with each ;
: (rotate-logs) ( -- )
(close-log-files)
log-root directory [ drop rotate-log ] assoc-each ;
: log-server-loop
[
receive unclip {
{ "log-message" [ (log-message) ] }
{ "rotate-logs" [ drop (rotate-logs) ] }
{ "close-log-files" [ drop (close-log-files) ] }
} case
] [ error. (close-log-files) ] recover
log-server-loop ;
: log-server ( -- )
[ log-server-loop ] spawn "log-server" set-global ;
[
H{ } clone log-files set-global
log-server
] "logging" add-init-hook

View File

@ -0,0 +1 @@
Distributed concurrency log server

1
extra/logging/summary.txt Executable file
View File

@ -0,0 +1 @@
AOP Logging framework with support for log rotation and machine-readable logs

6
extra/raptor/cron/cron.factor Normal file → Executable file
View File

@ -1,6 +1,6 @@
USING: kernel namespaces threads sequences calendar
combinators.cleave combinators.lib ;
combinators.cleave combinators.lib debugger ;
IN: raptor.cron
@ -43,9 +43,9 @@ C: <when> when
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: recurring-job ( when quot -- )
[ swap when=now? [ call ] [ drop ] if 60000 sleep ] [ recurring-job ] 2bi ;
[ swap when=now? [ try ] [ drop ] if 60000 sleep ] [ recurring-job ] 2bi ;
: schedule ( when quot -- ) [ recurring-job ] curry curry in-thread ;
: schedule ( when quot -- ) [ recurring-job ] 2curry in-thread ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

2
extra/smtp/smtp-tests.factor Normal file → Executable file
View File

@ -1,4 +1,4 @@
USING: smtp tools.test io.streams.string io.logging threads
USING: smtp tools.test io.streams.string threads
smtp.server kernel sequences namespaces ;
IN: temporary

47
extra/smtp/smtp.factor Normal file → Executable file
View File

@ -1,6 +1,6 @@
! Copyright (C) 2007, 2008 Elie CHAFTARI, Dirk Vleugels, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces io kernel io.logging io.sockets sequences
USING: namespaces io kernel logging io.sockets sequences
combinators sequences.lib splitting assocs strings math.parser
random system calendar ;
@ -12,21 +12,18 @@ SYMBOL: smtp-port 25 smtp-port set-global
SYMBOL: read-timeout 60000 read-timeout set-global
SYMBOL: esmtp t esmtp set-global
: log-smtp-connection ( host port -- )
[
"Establishing SMTP connection to " % swap % ":" % #
] "" make log-message ;
: log-smtp-connection ( host port -- ) 2drop ;
\ log-smtp-connection NOTICE add-input-logging
: with-smtp-connection ( quot -- )
[
smtp-host get smtp-port get
2dup log-smtp-connection
<inet> <client> [
smtp-domain [ host-name or ] change
read-timeout get stdio get set-timeout
call
] with-stream
] with-log-stdio ; inline
smtp-host get smtp-port get
2dup log-smtp-connection
<inet> <client> [
smtp-domain [ host-name or ] change
read-timeout get stdio get set-timeout
call
] with-stream ; inline
: crlf "\r\n" write ;
@ -58,20 +55,20 @@ SYMBOL: esmtp t esmtp set-global
: quit ( -- )
"QUIT" write crlf ;
: log-response ( string -- ) "SMTP: " swap append log-message ;
LOG: smtp-response DEBUG
: check-response ( response -- )
{
{ [ dup "220" head? ] [ log-response ] }
{ [ dup "235" swap subseq? ] [ log-response ] }
{ [ dup "250" head? ] [ log-response ] }
{ [ dup "221" head? ] [ log-response ] }
{ [ dup "bye" head? ] [ log-response ] }
{ [ dup "220" head? ] [ smtp-response ] }
{ [ dup "235" swap subseq? ] [ smtp-response ] }
{ [ dup "250" head? ] [ smtp-response ] }
{ [ dup "221" head? ] [ smtp-response ] }
{ [ dup "bye" head? ] [ smtp-response ] }
{ [ dup "4" head? ] [ "server busy" throw ] }
{ [ dup "354" head? ] [ log-response ] }
{ [ dup "50" head? ] [ log-response "syntax error" throw ] }
{ [ dup "53" head? ] [ log-response "invalid authentication data" throw ] }
{ [ dup "55" head? ] [ log-response "fatal error" throw ] }
{ [ dup "354" head? ] [ smtp-response ] }
{ [ dup "50" head? ] [ smtp-response "syntax error" throw ] }
{ [ dup "53" head? ] [ smtp-response "invalid authentication data" throw ] }
{ [ dup "55" head? ] [ smtp-response "fatal error" throw ] }
{ [ t ] [ "unknown error" throw ] }
} cond ;
@ -80,7 +77,7 @@ SYMBOL: esmtp t esmtp set-global
: process-multiline ( multiline -- response )
>r readln r> 2dup " " append head? [
drop dup log-response
drop dup smtp-response
] [
swap check-response process-multiline
] if ;

View File

@ -7,23 +7,31 @@ IN: tools.annotations
: reset ( word -- )
dup "unannotated-def" word-prop [
[
dup "unannotated-def" word-prop define
dup dup "unannotated-def" word-prop define
] with-compilation-unit
f "unannotated-def" set-word-prop
] [ drop ] if ;
: annotate ( word quot -- )
over "unannotated-def" word-prop [
"Cannot annotate a word twice" throw
] when
[
over dup word-def "unannotated-def" set-word-prop
>r dup word-def r> call define
] with-compilation-unit ; inline
: word-inputs ( word -- seq )
stack-effect [
>r datastack r> effect-in length tail*
] [
datastack
] if* ;
: entering ( str -- )
"/-- Entering: " write dup .
stack-effect [
>r datastack r> effect-in length tail* stack.
] [
.s
] if* "\\--" print flush ;
word-inputs stack.
"\\--" print flush ;
: leaving ( str -- )
"/-- Leaving: " write dup .

View File

@ -127,6 +127,7 @@ MEMO: all-vocabs-seq ( -- seq )
{ [ "windows." ?head ] [ t ] }
{ [ "cocoa" ?head ] [ t ] }
{ [ ".test" ?tail ] [ t ] }
{ [ "raptor" ?head ] [ t ] }
{ [ dup "tools.deploy.app" = ] [ t ] }
{ [ t ] [ f ] }
} cond nip ;

View File

@ -3,7 +3,7 @@
USING: calendar html io io.files kernel math math.parser
http.server.responders http.server.templating namespaces parser
sequences strings assocs hashtables debugger http.mime sorting
html.elements ;
html.elements logging ;
IN: webapps.file
@ -58,6 +58,8 @@ SYMBOL: page
[ [ dup page set run-template-file ] with-scope ] try
drop ;
\ run-page DEBUG add-input-logging
: include-page ( filename -- )
"doc-root" get swap path+ run-page ;
@ -69,6 +71,8 @@ SYMBOL: page
dup mime-type dup "application/x-factor-server-page" =
[ drop serve-fhtml ] [ serve-static ] if ;
\ serve-file NOTICE add-input-logging
: file. ( name dirp -- )
[ "/" append ] when
dup <a =href a> write </a> ;
@ -104,15 +108,15 @@ SYMBOL: page
] if ;
: serve-object ( filename -- )
dup directory? [ serve-directory ] [ serve-file ] if ;
serving-path dup exists? [
dup directory? [ serve-directory ] [ serve-file ] if
] [
drop "404 not found" httpd-error
] if ;
: file-responder ( -- )
"doc-root" get [
"argument" get serving-path dup exists? [
serve-object
] [
drop "404 not found" httpd-error
] if
"argument" get serve-object
] [
"404 doc-root not set" httpd-error
] if ;

View File

@ -2,7 +2,7 @@ USING: sequences rss arrays concurrency kernel sorting
html.elements io assocs namespaces math threads vocabs html
furnace http.server.templating calendar math.parser splitting
continuations debugger system http.server.responders
xml.writer prettyprint io.logging ;
xml.writer prettyprint logging ;
IN: webapps.planet
: print-posting-summary ( posting -- )
@ -75,27 +75,19 @@ SYMBOL: cached-postings
SYMBOL: last-update
: fetch-feed ( triple -- feed )
second
"Fetching " over append log-message
dup download-feed feed-entries
"Done fetching " swap append log-message ;
: <posting> ( author entry -- entry' )
clone
[ ": " swap entry-title 3append ] keep
[ set-entry-title ] keep ;
: ?fetch-feed ( triple -- feed/f )
[
fetch-feed
] [
swap [ . error. ] to-log-stream f
] recover ;
: fetch-feed ( url -- feed )
download-feed feed-entries ;
\ fetch-feed DEBUG add-error-logging
: fetch-blogroll ( blogroll -- entries )
dup 0 <column>
swap [ ?fetch-feed ] parallel-map
swap [ fetch-feed ] parallel-map
[ [ <posting> ] with map ] 2map concat ;
: sort-entries ( entries -- entries' )