-
Notifications
You must be signed in to change notification settings - Fork 319
sdjournal: adds a follow with fields #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,10 +16,12 @@ | |
package sdjournal | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"log" | ||
"strings" | ||
"time" | ||
) | ||
|
||
|
@@ -188,6 +190,83 @@ process: | |
return | ||
} | ||
|
||
func (r *JournalReader) FollowWithFields(until <-chan time.Time, fields map[string]struct{}, writer io.Writer) (err error) { | ||
enc := json.NewEncoder(writer) | ||
journal: | ||
for { | ||
kvMap := make(map[string]string) | ||
select { | ||
case <-until: | ||
return ErrExpired | ||
default: | ||
var err error | ||
var c int | ||
|
||
// Advance the journal cursor | ||
c, err = r.journal.Next() | ||
|
||
// An unexpected error | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// We have a new journal entry go over the fields | ||
// get the data for what we care about and return | ||
r.journal.RestartData() | ||
if c > 0 { | ||
fields: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: maybe change to another name, because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea. |
||
for { | ||
s, err := r.journal.EnumerateData() | ||
if err != nil || len(s) == 0 { | ||
break fields | ||
} | ||
s = s[:len(s)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we need this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for reviewing. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @faiq Good idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually in retrospect, i think this method should be called I think the best way of doing so would be taking out the |
||
arr := strings.SplitN(s, "=", 2) | ||
if _, ok := fields[arr[0]]; ok { | ||
kvMap[arr[0]] = arr[1] | ||
} | ||
|
||
} | ||
if err := enc.Encode(kvMap); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
|
||
// we're at the tail, so wait for new events or time out. | ||
// holds journal events to process. tightly bounded for now unless there's a | ||
// reason to unblock the journal watch routine more quickly | ||
events := make(chan int, 1) | ||
pollDone := make(chan bool, 1) | ||
go func() { | ||
for { | ||
select { | ||
case <-pollDone: | ||
return | ||
default: | ||
events <- r.journal.Wait(time.Duration(1) * time.Second) | ||
} | ||
} | ||
}() | ||
|
||
select { | ||
case <-until: | ||
pollDone <- true | ||
return ErrExpired | ||
case e := <-events: | ||
pollDone <- true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @faiq I know this is copied from Follow(), but it doesn't feel right to me. |
||
switch e { | ||
case SD_JOURNAL_NOP, SD_JOURNAL_APPEND, SD_JOURNAL_INVALIDATE: | ||
// TODO: need to account for any of these? | ||
default: | ||
log.Printf("Received unknown event: %d\n", e) | ||
} | ||
continue journal | ||
} | ||
} | ||
return | ||
} | ||
|
||
// buildMessage returns a string representing the current journal entry in a simple format which | ||
// includes the entry timestamp and MESSAGE field. | ||
func (r *JournalReader) buildMessage() (string, error) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda copied from the Follow() function. But I feel it's better to just pass a time, then create a channel inside the function. (e.g.
untilCh := time.After(until)
)cc @jonboulle ?
No need for a change in this PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of passing in the channel, because it allows me more flexibility when I write my programs with this library. For example, I am working on a daemon that forwards journald logs to an external logging service over http. The only reason I would ever want it killed is if a signal interrupt were given, so to do this I send a
time.Now()
from my signal handler into this channel to stop the program gracefully.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@faiq OK, sounds fair.