-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
feat(sources): Add http source using Warp #1650
Conversation
This is based off the logplex source. Code that may be reused by other http source plugins has been separated out into a util/http.rs. Supports text, json and ndjson body. Signed-off-by: Giles Edkins <gedkins@bluecatnetworks.com>
Hey! I got a notification for this, I hope you don't mind if I nitpick a few random things. |
src/sources/http.rs
Outdated
fn json_parse_array_of_object(value: JsonValue) -> Result<Vec<Event>, ErrorMessage> { | ||
match value { | ||
JsonValue::Array(v) => { | ||
let mut out_vec = vec![]; |
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.
JsonValue::Array(v) => Ok(v
.into_iter()
.map(json_parse_object)
.collect::<Result<Vec<Event>, _>>()?),
There's a FromIterator<Result<A, E>>
that makes this collect()
call work. Kinda like traverse
from Haskell. I didn't run any tests but I think this says the same thing.
Thanks! @lukesteensen is the best person to review this since he built the |
Signed-off-by: Giles Edkins <gedkins@bluecatnetworks.com>
src/sources/http.rs
Outdated
} | ||
|
||
fn json_error() -> ErrorMessage { | ||
ErrorMessage::new(StatusCode::BAD_REQUEST, "Bad JSON".to_string()) |
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.
Maybe this should support some error context? Eg "Expected Array or Object, got Number"
src/sources/http.rs
Outdated
} | ||
|
||
fn json_parse(json_str: String) -> Result<JsonValue, ErrorMessage> { | ||
serde_json::from_str(&json_str).map_err(|_| json_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.
I don't know if this function's purpose warrants it's existence. If all it does is throw away error context from from_str
maybe we can just remove it entirely?
src/sources/util/http.rs
Outdated
) | ||
.and_then(|events| { | ||
out.send_all(futures::stream::iter_ok(events)).map_err( | ||
move |_: mpsc::SendError<Event>| { |
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.
Is there any context we can get from this error? It'd be sad to throw it away.
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.
We sort of can get more context.
We can log the event it was trying to send when it failed (which is a good idea), but the only reason it would fail is if the receiver is dropped, and the error doesn't give any more insight than that.
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.
OK, fair!
Once you're feeling this is ready to go code-wise we should also add documentation! You can see what that would look like here: https://github.com/timberio/vector/pull/1264/files#diff-d97eef340a70cc48bfd4c26e66a12780 |
Signed-off-by: Bill Bateman <bbateman@bluecatnetworks.com>
Signed-off-by: Bill Bateman <bbateman@bluecatnetworks.com>
Signed-off-by: Bill Bateman <bbateman@bluecatnetworks.com>
Signed-off-by: Giles Edkins <gedkins@bluecatnetworks.com>
Just checking in if you are waiting on anything from us. Is the documentation that we added enough? |
@bill-bateman Somehow this notification got lost, I'm sorry about the delay. :( |
@Hoverbear no worries! |
@LucioFranco I'm asking you to give a second set of eyes to this since I feel like it has some big picture ideas involved I might be yet familiar with. |
src/sources/util/http.rs
Outdated
|
||
fn string_to_static_str(s: String) -> &'static str { | ||
//necessary because warp 0.1.18 needs a &'static str for the path | ||
Box::leak(s.into_boxed_str()) |
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 don't think this is safe, and it definitely looks like a memory leak. https://doc.rust-lang.org/std/boxed/struct.Box.html#method.leak
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.
Yeah it's kinda gross. Couldn't see a way around this if we wanted the path to come from the config, since the version of warp needs &'static str.
If there's a way around this that I don't know then I'd love to know it.
Or if it's more important to not have the leak, we could just pass in a &'static str and have it be hard-coded.
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'd prefer to see it hard coded until we upgrade warp to 0.2.x, since this problem only exists for us in 0.1.x. :)
If we're listening on a socket, I suggest just listen to everything on that socket. The path could be part of the event maybe? @binarylogic 's spec in #328 didn't mention anything about being able to set paths.
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.
OK! - I think I'll just make it hard-coded for now, since it doesn't seem to be needed.
You're right, there is to be a way to get the full-path after the fact (see here) but they say
should probably not be used for request matching/routing.
so not sure about that, better I think to have the hard-coded path and worry about this when someone wants a configurable path (by which point we'll hopefully be on warp 0.2.x!)
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.
Yeah, for now I think removing path support is fine 👍
@gedkins Can you ammend that commit with a DCO sign? |
Co-Authored-By: Ana Hobden <operator@hoverbear.org> Signed-off-by: Giles Edkins <gedkins@bluecatnetworks.com>
Signed-off-by: Giles Edkins <gedkins@bluecatnetworks.com>
876e9f3
to
9384507
Compare
Signed-off-by: Bill Bateman <bbateman@bluecatnetworks.com>
src/sources/util/http.rs
Outdated
let trigger = trigger.clone(); | ||
info!("Handling http request: {:?}", headers); | ||
|
||
futures::future::result( |
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.
btw if you bring in the IntoFuture
trait then you can do Result::into_future
.
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.
oh nice didn't know about that
src/sources/util/http.rs
Outdated
pub trait HttpSource: Clone + Send + Sync + 'static { | ||
fn build_event( | ||
&self, | ||
body: impl Buf, |
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.
Is there a reason we don't just make this FullBody
?
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.
FullBody doesn't seem to exist in 0.2.x versions of warp so I just didn't use it.
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.
Right it should exist since we are using 0.1, right?
src/sources/util/http.rs
Outdated
} | ||
let svc = filter | ||
.and(warp::path::end()) | ||
.boxed() |
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.
why does this need to be boxed here?
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.
doesn't need to be
src/sources/util/http.rs
Outdated
|
||
fn string_to_static_str(s: String) -> &'static str { | ||
//necessary because warp 0.1.18 needs a &'static str for the path | ||
Box::leak(s.into_boxed_str()) |
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.
Yeah, for now I think removing path support is fine 👍
src/sources/util/http.rs
Outdated
Err(r) | ||
} | ||
}; | ||
futures::future::result(err) |
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.
should be able to use into_future here too
src/sources/http.rs
Outdated
.filter(|s| !s.is_empty()) | ||
} | ||
|
||
fn decode_body(body: impl Buf, enc: Encoding) -> Result<Vec<Event>, ErrorMessage> { |
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.
So I think it may be a bit better here to do something like:
let body = buf.collect::<BytesMut>();
then for the encodings that need them in lines format we can take advantage of https://github.com/timberio/vector/blob/master/lib/codec/src/lib.rs#L18
then for the json
encoding we can do something like:
serde_json::from_slice(&body[..])
This would avoid some additional copying
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.
ok sounds good
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.
new commit is mostly for this. lots of changes to the body_to_lines function, which is now not the prettiest... let me know what you think of it, if there are better ways to do what I'm doing.
one issue I had is that the codec won't give the last line if it doesn't end in a newline, so I have a special case for that.
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.
Our codec that we wrote should handle that, you may want to call decode_eof though instead which should handle the last line.
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.
oh perfect! Thanks :)
Signed-off-by: Bill Bateman <bbateman@bluecatnetworks.com>
Signed-off-by: Bill Bateman <bbateman@bluecatnetworks.com>
Signed-off-by: Ana Hobden <operator@hoverbear.org>
Signed-off-by: Ana Hobden <operator@hoverbear.org>
@gedkins Thanks so much for this contribution. You rock! |
Silly question, looking at the code (and the underlying packages) this looks fully capable of listening on IPv6 addresses (note that I am not a rust dev). However during usage we get errors when trying to listen on both Is it possible to bind to the IPv6 global address? |
I responded to this over here: #2508 (comment) . It should be possible to bind to |
This addresses #328.
This is based off the logplex source. Code that may be reused by other http source plugins has been separated out into a util/http.rs.
Supports text, json and ndjson body.
Signed-off-by: Giles Edkins gedkins@bluecatnetworks.com