diff --git a/conmon-rs/common/proto/conmon.capnp b/conmon-rs/common/proto/conmon.capnp index a5b3ded083..506e0b1608 100644 --- a/conmon-rs/common/proto/conmon.capnp +++ b/conmon-rs/common/proto/conmon.capnp @@ -60,6 +60,8 @@ interface Conmon { containerRuntimeInterface @0; # The JSON logger, requires `path` to be set. json @1; + # The journald logger. + journald @2; } } diff --git a/conmon-rs/server/src/cri_logger.rs b/conmon-rs/server/src/container_log/cri.rs similarity index 100% rename from conmon-rs/server/src/cri_logger.rs rename to conmon-rs/server/src/container_log/cri.rs diff --git a/conmon-rs/server/src/container_log/journald.rs b/conmon-rs/server/src/container_log/journald.rs new file mode 100644 index 0000000000..870a46a5d1 --- /dev/null +++ b/conmon-rs/server/src/container_log/journald.rs @@ -0,0 +1,83 @@ +use crate::{container_io::Pipe, journal::Journal}; +use anyhow::{Context, Result}; +use std::io::Write; +use tokio::io::{AsyncBufRead, AsyncBufReadExt}; +use tracing::debug; + +#[derive(Debug)] +pub struct JournaldLogger; + +impl JournaldLogger { + pub fn new(_: Option) -> Result { + Ok(Self) + } + + pub async fn init(&mut self) -> Result<()> { + debug!("Initializing journald logger"); + Ok(()) + } + + pub async fn write(&mut self, _: Pipe, mut bytes: T) -> Result<()> + where + T: AsyncBufRead + Unpin, + { + let mut line_buf = String::new(); + while bytes.read_line(&mut line_buf).await? > 0 { + Journal + .write_all(line_buf.as_bytes()) + .context("write to journal")?; + line_buf.clear(); + } + + Ok(()) + } + + pub async fn reopen(&mut self) -> Result<()> { + debug!("Reopen journald log"); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Cursor; + + #[tokio::test] + async fn test_journald_logger_new() { + JournaldLogger::new(Some(1000)).unwrap(); + } + + #[tokio::test] + async fn test_journald_logger_init() { + let mut logger = JournaldLogger::new(Some(1000)).unwrap(); + assert!(logger.init().await.is_ok()); + } + + #[tokio::test] + async fn test_journald_logger_write() { + let mut logger = JournaldLogger::new(Some(1000)).unwrap(); + logger.init().await.unwrap(); + + let cursor = Cursor::new(b"Test log message\n".to_vec()); + assert!(logger.write(Pipe::StdOut, cursor).await.is_ok()); + + // Verifying the actual log message in Journald might require additional setup or permissions. + } + + #[tokio::test] + async fn test_journald_logger_reopen() { + let mut logger = JournaldLogger::new(Some(1000)).unwrap(); + logger.init().await.unwrap(); + + let cursor = Cursor::new(b"Test log message before reopen\n".to_vec()); + assert!(logger.write(Pipe::StdOut, cursor).await.is_ok()); + + assert!(logger.reopen().await.is_ok()); + + let cursor = Cursor::new(b"Test log message after reopen\n".to_vec()); + assert!(logger.write(Pipe::StdOut, cursor).await.is_ok()); + + // As with the write test, verifying the actual log messages in Journald might require additional setup or permissions. + } +} diff --git a/conmon-rs/server/src/json_logger.rs b/conmon-rs/server/src/container_log/json.rs similarity index 100% rename from conmon-rs/server/src/json_logger.rs rename to conmon-rs/server/src/container_log/json.rs diff --git a/conmon-rs/server/src/container_log.rs b/conmon-rs/server/src/container_log/mod.rs similarity index 80% rename from conmon-rs/server/src/container_log.rs rename to conmon-rs/server/src/container_log/mod.rs index 5fb8a8e349..3d73d3e31a 100644 --- a/conmon-rs/server/src/container_log.rs +++ b/conmon-rs/server/src/container_log/mod.rs @@ -1,4 +1,11 @@ -use crate::{container_io::Pipe, cri_logger::CriLogger, json_logger::JsonLogger}; +mod cri; +mod journald; +mod json; + +use crate::{ + container_io::Pipe, container_log::cri::CriLogger, container_log::journald::JournaldLogger, + container_log::json::JsonLogger, +}; use anyhow::Result; use capnp::struct_list::Reader; use conmon_common::conmon_capnp::conmon::log_driver::{Owned, Type}; @@ -16,6 +23,7 @@ pub struct ContainerLog { #[derive(Debug)] enum LogDriver { ContainerRuntimeInterface(CriLogger), + Journald(JournaldLogger), Json(JsonLogger), } @@ -25,6 +33,7 @@ impl ContainerLog { Arc::new(RwLock::new(Self::default())) } + /// Create a new SharedContainerLog from an owned reader. pub fn from(reader: Reader) -> Result { let drivers = reader .iter() @@ -48,6 +57,13 @@ impl ContainerLog { None }, )?)), + Type::Journald => Ok(LogDriver::Journald(JournaldLogger::new( + if x.get_max_size() > 0 { + Some(x.get_max_size() as usize) + } else { + None + }, + )?)), } }) .collect::>>()?; @@ -64,6 +80,7 @@ impl ContainerLog { cri_logger.init().boxed() } LogDriver::Json(ref mut json_logger) => json_logger.init().boxed(), + LogDriver::Journald(ref mut journald_logger) => journald_logger.init().boxed(), }) .collect::>(), ) @@ -83,6 +100,9 @@ impl ContainerLog { cri_logger.reopen().boxed() } LogDriver::Json(ref mut json_logger) => json_logger.reopen().boxed(), + LogDriver::Journald(ref mut journald_logger) => { + journald_logger.reopen().boxed() + } }) .collect::>(), ) @@ -110,6 +130,9 @@ impl ContainerLog { LogDriver::ContainerRuntimeInterface(cri_logger) => { cri_logger.write(pipe, bytes).await } + LogDriver::Journald(journald_logger) => { + journald_logger.write(pipe, bytes).await + } LogDriver::Json(json_logger) => json_logger.write(pipe, bytes).await, } } diff --git a/conmon-rs/server/src/lib.rs b/conmon-rs/server/src/lib.rs index 59870e0b7f..bfdaa2638d 100644 --- a/conmon-rs/server/src/lib.rs +++ b/conmon-rs/server/src/lib.rs @@ -15,11 +15,9 @@ mod child_reaper; mod config; mod container_io; mod container_log; -mod cri_logger; mod fd_socket; mod init; mod journal; -mod json_logger; mod listener; mod oom_watcher; mod pause; diff --git a/internal/proto/conmon.capnp.go b/internal/proto/conmon.capnp.go index 1e636b4229..77ed9824ee 100644 --- a/internal/proto/conmon.capnp.go +++ b/internal/proto/conmon.capnp.go @@ -523,7 +523,7 @@ func (c Conmon_startFdSocket) AllocResults() (Conmon_startFdSocket_Results, erro // Conmon_List is a list of Conmon. type Conmon_List = capnp.CapList[Conmon] -// NewConmon creates a new list of Conmon. +// NewConmon_List creates a new list of Conmon. func NewConmon_List(s *capnp.Segment, sz int32) (Conmon_List, error) { l, err := capnp.NewPointerList(s, sz) return capnp.CapList[Conmon](l), err @@ -1342,6 +1342,7 @@ const Conmon_LogDriver_Type_TypeID = 0xf026e3d750335bc1 const ( Conmon_LogDriver_Type_containerRuntimeInterface Conmon_LogDriver_Type = 0 Conmon_LogDriver_Type_json Conmon_LogDriver_Type = 1 + Conmon_LogDriver_Type_journald Conmon_LogDriver_Type = 2 ) // String returns the enum's constant name. @@ -1351,6 +1352,8 @@ func (c Conmon_LogDriver_Type) String() string { return "containerRuntimeInterface" case Conmon_LogDriver_Type_json: return "json" + case Conmon_LogDriver_Type_journald: + return "journald" default: return "" @@ -1365,6 +1368,8 @@ func Conmon_LogDriver_TypeFromString(c string) Conmon_LogDriver_Type { return Conmon_LogDriver_Type_containerRuntimeInterface case "json": return Conmon_LogDriver_Type_json + case "journald": + return Conmon_LogDriver_Type_journald default: return 0 @@ -4568,222 +4573,224 @@ func (p Conmon_startFdSocket_Results_Future) Response() Conmon_StartFdSocketResp return Conmon_StartFdSocketResponse_Future{Future: p.Future.Field(0, nil)} } -const schema_ffaaf7385bc4adad = "x\xda\xc4Y}p\x14\xe7y\x7f\x9e\xdd\x93V\xa7\x0f" + - "N\xdb=\x09\x10\xa8\xd2\x10HA\x0d\xe1C\xb8&\x0c" + - "\x19I\x80B!\xe0hu`ZH\\\x96\xbbE:" + - "\xb8\xdb=v\xf7\x00\x11\xa72I=v\x94\xd81*" + - "\x9e\xd8L\x99A\xb6\xa1\x80\xa1\xc6\x1fP\x83\xc1\x03\x18" + - "\xc6\x80M]h\xa1\xc6c\\0\xa6\xb6\x19\x7fQ\xbb" + - "S\xec\x81n\xe7y\xef\xf6C'\x19\x9fTw\xf2\x07" + - "\x83\xee\xd9\xdf>\xef\xc7\xf3\xf9{v\xe2\xe7\xc1\xc6\xc0" + - "\xa4\xb27\x86\x00'\xef*(\xb4\xcd\xcb\x1d\xc6\xb6\xcd" + - "\xb3\x7f\x05\xe2w\x10\xa0\x00\x05\x80\xfa\xf9\xc2\xbb\x08(" + - ")B\x03\xa0\xfd_O\x9d\xf8\xe1\xef7|\xda\xe5\x07" + - "\xac\xcf\x00\x1ee\x80\xb7\xa7\xd6-\xdf\xc2\xcf\xfb\x8d\x1f" + - "\xb0_x\x8b\x00\xa7\x19\xe0\xaf\x97\x866\xfem\xe5\x12" + - "\x06\xb0\xaf\xd7/\xbf\xf8\xf8\x07w\xfe#\x14\x08\x04\xfc" + - "Xx\x0b\xa5`\x11\xfdYP\xf4;\x04\xb4_\xfb\xe3" + - "u\x8bB\xdb\x1ex,\x07\xcd\xd4^\x0d\xbe\x8b\x12\x16" + - "\x0b\x00\xd2\xad \xa9\xbe\xff\xc3\xbb\xf6-\xfc\xd5\xa7[" + - "\xfckO*\xfeOZ\xbb\xb9\x98\x00\x8f/\xf9`e" + - "\xf3\x9c\xd0\x13\xbd\xb5\x05\x08\x17/\xde\x89\xd2\xfab\x01" + - "x\xbb\xf2\xab+O\x9d\x8fL\xdd\x01\xf2w\xb0\xcf\xa2" + - "?#\\\x9a-\xba\xaax\x0d\xa0=\xfa\x99W\xcet" + - "M\x9f\xb0\xd3\xbf\xe8\xe9\xe2\xb3\xb4\xe8e\xb6h\xd7\xdf" + - "\xab\x7fr\xe4\xc0\x8f\x09\xc0y\xda\x00\xeb\xb1\xa4\x0b\xa5" + - "\xe1%\xa4\xaa\xa2\xe4N@{\xcd\xd2\x13\xcf\xac\x93\xaf" + - "\xee\xeag{\xd5%\xdd(\xddQB\xdb\x93fM\xdc" + - "\x7f\xbe\xbenw\xee\xf68\xc2\x89\x84\x1b\xc7t\x8e)" + - "y\x06\xd0\x9e\xd2\xf3\xfc\xbe\x87?Y\xfb\x0f\x84\xe6r" + - "\x0fs\xaed\x05J\x1f\x96\x0c\x05\x90\xae3\xf4\xcf\xcf" + - "\\\xdb\xfe\xf0o\x9a\xf6\xe6\xea\xe6\x09\xfd\xeb\xd2\xa3(" + - "\xf5\x94\xd2\x9f\x9bKk\xc8:\xfc\xa5\xf7\x8a\x1fn\x9a" + - "\xb0\xaf?\xeb\x1c/;\x85\xd2\xe52\xda\xc9\xc52\xba" + - "\x07\xf7\xb98\x92\xb7w\xef>\xb6d\xea\x7f\xef\xb4\xe9" + - "\x1en\x95Ua}\xd9\x90EH\x8aC\x02'\x05E" + - "\x01\xc0\x1e\xf7\xd1\x83\xdb\x1ex:r\xa0?\xe5\xd7\xcb" + - "\x8fb\x06&\x15\x88\xa4\xfc\xd4\xbe\x1d\xd3\xbe\xba\xb2\xe6" + - "@\xee\xc6i\xfd\xfa\x1f\x88gQZH\xe8zY|" + - "\x80\x07\xb4\xcb\x97\xbc\xf1\xc3\x8f\xee\xf9\x8f\xe3~\xa3\x1d" + - "\xaf`^z\xa1\x82\xf4\xbd\xaf\xbc\xc45\x9fN\xbc\xea" + - "\x07\xdc\xaa(\xe6\x00\xa5\x8aJ\x06x\xef\x7fV\xb4\xa5" + - "&\xbc\xee\x07\xdcQ\xd9\xcd|\x8d\x01V\x96\x9c\x08\x07" + - "\x1b\xcc\x7f\xf2\x03\xd4\xca\xa3\x04H3\xc0\x8d\x8a\x97\x7f" + - "_5\xfd@/\xc0\xa3\x95l\x0f;\x18\xa0\xaa\xe9\xcc" + - "\x94\x906\xfb\x9fs.\x80\xd9\xe2t\xe5\x13(]\xad" + - "\xa4\x0b\xb8\\I\x96{\xf2\xf3\xedK\xf7n\x08\x9f\xef" + - "\xe3e\x1b\x86\xae@i\xebPB\xf6\x0c\xed\x04\xb4o" + - "\xde?\xfd\xbe\xea\xea\xf3\x17\xfa\xf5\x9fsC\xaf\xa1t" + - "\x9d\xa1?\x1e\xfa>\xa0\xbd\xe9O\xd7\xa4\xeeY6\xed" + - "\x9d\x1c4s\xca\x93\xc3\xdeB\xe9\xea0\xb6\x89a\xb4" + - "\xe3\x9b\xd3n\xbe\xbcez\xea\xdfsU\x17\xb0\x88\x1e" + - "\xde\x85R\xf5p\xfas\xf8\xf0E\xe4>\x0bS\xb3\xc5" + - "\xef\xb6\x0e\xb9\xe4\xbf\x81\x87\xaa\xfe\x88.yk\x15\xe9" + - "\x9b\xf8\xf3\xd9;\xee\x89KW\xfc\x80\x93U\x9b\x98\x99" + - "\x18\xe0\xcf\xa4W\xf6h\x1b\xae]\xede\xa6\xaak\x04" + - "\x10G\x10\xe0\xc8\x92\xfa\x96\x7f\xbb\xf2\xdd\xcf@\x1c\xcf" + - "y\xb1\x00X?iD7JsF\xd0\xde\x9bGP" + - "\xf0\x9d\xf9\xa4f\xd7kW\x7f\xfcy\xee\xde\x83\xa4s" + - "\xe1\x88M(%G\xb0D1\xe2N\x0e\xd0\xde\xb6\xea" + - "\xc9Gn\x8c\x12\xbf\xc8\x8d+v\xd4C\xd5\xef\xa2t" + - "\xa1\x9a]h\xf5\xabt\xd4\x177m\xfc\xdd\xb1\xc9\xb3" + - "\xbf\xf0o\xf4b\x0d\xcb\x12\xd7kh\xa3\x15\x7f\xb5\xfe" + - "R\xdd\x87Wz\x01\xc4\xdaS\x04\x18SK\x80\x83\xb8" + - "\xb3\xe4\xa7+>\xb8\xe1\x07\xcc\xa9eG\xfd\x19\x03\xdc" + - "\xe8y\xba\xfe\xbe\xd3\xcf\x7f\xd9O\xf6X_{\x0a\xa5" + - "\xcd\xb5\x94=\xba\xffen\xf2\x9d[/}\x95\xe3T" + - "\xcc\xf8\x1d\xb5O\xa0\xb4\xa1\x96\xee\xe4\xa1\xda50\xde" + - "\x8ek\x96jhJ\xa2pB\xca\xd0-}BT\xd7" + - "\x92\xba\xf6\xfd\xa8\x92\xd2R\xd3ff~\xa8k\xd5h" + - "\xa4C\x8b\xce\xd45K\x89k\xaa1\xbaE1\x04%" + - "i\xca\x01>\x00\x10@\x00\xb1l\x06\x80\\\xc4\xa3\x1c" + - "\xe6\xb0\xd3PW\xa5U\xd3\xc2r\xef\x0e\x01\xb1\x1c0" + - "\xaf\xe5\xa2\x86\xaaX\xea]JR5SJT5G" + - "\xb7\xaafZHX\xbd\x96\x9b\x0b \x97\xf2(\x0f\xe3" + - "\xd06T3\xa5k\xa6\x0a\x00X\xee\xd5\x93\xff\xcb\x92" + - "-\x8a\xa1\xf0\xf9\x1c\xd0\xadu\x03Xmf\xcej\xad" + - "\xa4\x8d7\xad\x16Dy\xa4\xbb\xe0\xdee\x00\xf2\x0b<" + - "\xca\x879\x14\x11\xc3H\xc2C\x8b\x01\xe4\x83<\xcao" + - "r(r\\\x189\x00\xf1\x1c!\xff\x95G\xf93\x0e" + - "E\x9e\x0f#\x0f ~L\xc2\x8fx\x8c\x14!\x87b" + - " \x10\xc6\x00\xa5R\x9c\x0b\x10\x09 \x8f\x91r\x92\x17" + - "\x14\x84\xb1\x00@*\xc3\xc9\x00\x91\"\x92\x87I^X" + - "\x18\xc6B\x00Id\xf8r\x92\x7f\x0f9\xb4\x93\xaa\xa5" + - "\xc4\x14K\x01\xe1'\x89\x18\x96\x01\x87e\x80\xb6\x96=" + - "\x0a\xf0\xaa\x89C\x00[x\xc4\x90\x97\xaf\x00Ih\xa7" + - "\xe3\xb1\xf9J*\x15\x07Aksa\xa5\xc0\xb1\x87m" + - "\xb7{\xb8L1\xd5\x16\xc5j'\x03\x93\xac\x14\xb0&" + - "\xa5\xc7\xe6\xc4\x9c_\xde\xbe\x00\x9c\x97\xcb\xbd@\xc8n" + - "`p\xb61S\xba\xa0\x99*\x19\xc7\xe7\x0d\x8b\xb3\xfe" + - "7\x96\xeb\xff\xf8\xe5^\x8f1\x80\xd5\x0dUO\xa9\xda" + - "<\xbd\xcd\x0b\xb5V\xb5\xc6L\xe7\xed\xfcn\xfb\x93\xe3" + - "\x8e\x05\xb7Y\xb4\xd5Y\x94\xce\x1a\xd23g\xcd\xebM" + - "\xf7\x9a\xfco\xcaE\xeeF\xc7\xd5\x01\xc8\xa3y\x94'" + - "r\xe8x\xf0x\x92\x8d\xe5Q\x9e\xc2a\xc8\xeaH\xa9" + - "9\x9e\x12\x02\x0c\xa5\x14\xab\xdd5m>\xf7\xa6X\x96" + - "\x12m\xef\x95\x9f\x94$\xe6\x11\xben9\x1b\xc0}\xcd" + - "l3\xf4tj\xbe\xa2)m\xaa\x01\xc0\x8e\xcc\xe2P" + - "\x9cAj\xc4\xe0\\\x80N\xb3\xc3\xb4\xd4d\xcc\x8e2" + - "\xf0r\x13\x00\xf2R\xde\xc4N\xd2\x9a1*\xe6m\x89" + - "\xbbU\xc3\x8c\xeb\x1a\xcb$&\xb2LR\xea\x9e\xbd\x99" + - "\xce\xde\xc8\xa3<\xcf3\xc3\x1cJ\x0f\x7f\xce\xa3\xbc\x80" + - "\x12\x09f\x12\x89L\x8e\xd5\xc2\xa3\x9c\xe0\xb0s\xb5j" + - ",\xd3M\x15\x118D\xf8\xba\xd0\x1fP\xe0\x05ns" + - "\x82yz\xdb,#\x14_\xad\x1ar\x00\xfdU\x1d\xeb" + - "B\x0b:R\xaa\xff*v\xf19_\x93w\xb9\xcbv\xa2\x1f" + - "\x1a2\xee\xe7\x0ax\xc7\x08\x99\xb2\xe6&\xc8V\x07\xc8" + - "\xa2.\xbeZ\x054l'\xafA\x0d\xcbl\xb6\xf3N" + - "\x81\xf3\x92\xa3\xac9\xb7\x1ft\xbc\x1el\xe7\x11\xe7{" + - "\x96Me\xb6\x93\xda\xa0&\xb3\xb6\xfb\xbb!\xa3\xd7v" + - "\x0a\x11\xb6y\x0a\xfd2G\x91\x13q\xe8\x84\\\x88\xe9" + - "\xcb\x15\x9b5\x19\xb5NI\xe7{\xf5[\xa6\x05N\xf9" + - "B\x0f\xc3\xf5\xaa\xfb\xcc}m\x0f\xe6\xdbB\xd6\xd51" + - "\xeb\xeb\xce\x16r\xc4\xce\x16\x16\xa8k-\xfa\x87\xf3\x95" + - "T\xb3f\x19\x1d\x00r-_\x00\xe0\x92Lt\x88\x90" + - "x}\x06p\xe2U\x01=F\x81\x0e\x8f\x14/\xfc\x12" + - "8\xf1\x8c\x80\x9c;\xc6A\x874\x88\xc7\xbb\x81\x13\x8f" + - "\x08\xc8\xbb\xf3\x0at8\xb0\xb8\x97\xde\xdb-`\xc0\xa5" + - "S\xe8LR\xc4\x9eM\xc0\x89\x9b\x05,p\x191:" + - "\xacM\xdcp\x008\xf1!\x01\x0b\xdd\xa1\x0f:\xe3!" + - "q}\x17p\xe2/\x04\x14\\\x1e\x8c\x0e\xc3\x11W\x19" + - "\xc0\x89q\x81j\x08\xf9a#\xda\xd1\xac3a\xd6-" + - "\xa0\x11m\x87W\xa0\xe3,h4\xa2\xed\xd4r?\xd2" + - "p\xbd \x0b\xe5U\x82\x9a\xbd,>S\xd7\x1a2\xaf" + - "\xb8\xeb\xdd\xa5\xa0cP =f\xd6>P\xc3\x0c\xd4" + - "\x88\xfe\xfa:\x80\xd4\xe6%\xf9~\xba\xb2\xb1\xdc\xb7\xde" + - "\x8f\xe6DZ\xa6\xc07:KK\xcfb\x15@d\x17" + - "u\xe9/\xa2\xc7\x16\xa4\xbd\xb8\x18 \xf2\x02\xc9\x0f#" + - "\x87\x98\xe1\x0b\xd2!\xd6\xd4\x1f$\xf1\x09\xf4\x0a\x8dt" + - "\x9c\x91\x80\xc3$\x7f\x1d\xbdZ#\x9d\xc4V\x80\xc8\x09" + - "\x92\xbf\xc7H\x03\x9f!\x0d\x97q\x05@\xe4\x12\xc9o" + - "2\xd2\x10\xc8\x90\x86/\xd9\xb27\x18\x99\xe08\x14\x85" + - "\x820qYI\xe4H^\xce\x11\x99 yQa\x18" + - "\x8b\x00\xa4qL>\x96\xe4\xb3H\x1e\x14\xc2\x18\x04\x90" + - "\x9a\xb8e\x00\x91F\x92\xff\x94\xe4\xc5Ea,\x06\x90" + - "\xfe\x92\xc9\xff\x82\xe41\x92\x97\x04\xc3X\x02 )\x1c" + - "\x9dk)\xc9\xef%yiq\x18K\x01\xa4\x0en\x06" + - "@\xc4\"\xf9#$/\xc30\x96\x11\x03\xe6\x0c\x80\xc8" + - "oI\xfe\x18\xc9\x87\x94\x84q\x08\x80\xf4(\x93o$" + - "\xf9\x1e\x92\x87J\xc3\x18\x02\x90v3=\xdbI~\x8c" + - "\xebUv\xedei-\x96P[\x14\xe0}\x05\xcdR" + - "\x8dd\\S\x12\xe4\x04\xd9.\xaa\xc6\xb4bq\xcd\xed" + - "\xa9\xd4\xb5q\x8b\x11\x1b\xec\xc3yt=\xd9LO!" + - "\xa4X\xed}\x9e&\x9c\xbc\xcd\x1b>\xca\xe1\x9b~0" + - "T4\xa1*Z:5\x13\xf8d\xac\x0f\xe1J\xe8\xcb" + - "\x94D\x93\x01|_\xbe\x15\xd5\x93IE\x8b5\x81`" + - "\xf4}8\xf8&\xa2S\xd5V\xdf\xad\xf87\x9c\x1b\x11" + - "\xd1\xde%\x08C^\xdd\xce\xb4k\xb6\x12\x8b\xc5\xad\xb8" + - "\xaeA\x8d\x92\xf8Q\xccU\x15\xccl\xae3\xa1*+" + - "\xfb\x8a\x07\xc5!ZU3\x9d\xe0\xf3%^n{\x90" + - "C$\x84\xdb\xach\xfa;\xc7\x1c\xf2b\x02|3{" + - "q\x9b\x8d\x01\xb0\x97lJ\xce\x9f\"\xb9\xdd\xd6\x00&" + - "\x1c\xa6?]:\x07\xfa\xe6\xa5\xdcvg\xc0\xa3\x9b\xc1" + - "\x9a\xcd\xed\x04\x07\xc7\x97W\xa5\x05\xd5\xcce[U\x1e" + - ";\x11\xfb\xa7[\\_\xba\xe5O&\xff\xcfL\x8b\xf5" + - "3!*\x8a\x8c\xa5\xb0\xad\xdc1\x8aQ\xd7\xf1\xf4\x1f" + - "'\x8e\xa1\xffx\xb1\xba\x0e\x00\x03b\xc5(\x00!\x9e" + - "\x8a\x0a\x9aj\x09\xa9x,\x946UCH[f^" + - "\xf6\xe9\xa7Y\xf4\xcd\x0a\xca\xddkS\xe82\x96f." + - "\xc3\xb9\xb58\xd1\xa1\x18\x8fr\xca\xc7\x91\x92$l\xe7" + - "Q\xb6\xa8t\xd5f8\xd2*z;\xc5\xa3|/\x97" + - "\xc9\xaa3\xf5\x183q\x008\x0c\x006\x98VLO" + - "[\xcee\xd2O\xd50\xdc\xbb\xb5\xe2I5\xf6\x93\xb4" + - "\xe5\xcb\xd4\x83\xab\xce\xe4[|\x9fa\xd1\x0a\x9f\xffE" + - "\xb3`\x08\x19-\xf1\x18\x16\x01\x87Ey:\x9e\xd30" + - "g{cZd\x98\xbb\xc8\xe3\xe4v\x1by\x94\xb7\xf8" + - "\xdcn\xf3b\x00\xf9\xefx\x94\xb7\xfb\xdcn\xab\x01 " + - "?\xc5\xa3\xbc\x87C\xccN\x0bww\x03\xc8{x\x94" + - "\x0fR\xdd\xe73\x1cs?9\xed\x8b<\xca\xc7\xa8\xe8" + - "\x07X\xd1\x17\x8f\xd0M\x1f\xe6Q~\xbb\xb7\xd3\x9a," + - "\xd6s* \xeb\xf0T\xd3\x84\x9a\xb8\xae\xf9\xc6u\xa6" + - "\xa5\xa7\x9a\x96[*\x1a\x11\xaa\x87\xcd:.\xff6\xe7" + - "\x0c\x83H\xba,mX\x98g\xdap\x89\xdd \x12\xef" + - "\xc0\x12\x94Ko\x07\x90\x12\xfb\x99\"\xb6(!#\xaf" + - "\x81\xbd\xcbl\x07p2\x87D\x1a\xdf_\xd0\x91B\xd5" + - "7\x10;\xcb\xb2JE\x1d\x80\xeb\xf7\x9c\xd1\x9a\xd6(" + - "\xde\xe6\x90\xe6\xe5D\xabB+L]\x1b\xd8\x98\xcb\x17" + - "gc\xdd68\xc8\xfaTw\x88\xedt\xc1\"R\xdb" + - "VJ\xe2a\xe8%\x12\xa9\x02G9\xb3\xed\x91\xac\x0d" + - "\xe62m\xf0p\x9c\x06\x10\x09\x93\xbc\x16\xbdp\x90\xaa" + - "\x99\xfa\x91$\x1f\x8b^DHc\x18\xbe\xd6\x99\x91\x8b" + - "\x85\x05\x996x\x1cR\x9b:\x96\xe4SH.\x14f" + - "\xda\xe0I\xacm\x9eH\xf2\xe9$/\x122m\xf0\x0f" + - "\x98\xfe\xa9$\x9fE\xf2`Q\xb6\x0df\xedz#\xc9" + - "\xe7!\x87v\xca\xd0\xa3\xaai\xce\x01t\xd3\x87C\xb4" + - "\x9c\x00\x13,\xa5\xcd\xf9\xbb\x81\xba\xb9\xb8\xe5kU\xe3" + - "\x89\xd8,\xc5\x02T]\x88\xa5\x18m\xaa\x071\xd2\xa6" + - "EW\x0d\x82O\xa7\x1dU\x8c6\xfdn\xd5\x80\x90\xd9" + - "G\xbc\xc0P}\xfazE\xab\x13\xc1\x83,\x16^\x89" + - "\xadu}\xf7\x0c\xe5\xba\xd73_A\x9cTwnq" + - "\xf6#\xc8%_\xad\xb8HN\xfe&\x8f\xf2\x17d\xdf" + - "\xc6L\xae\xbbN\xd1\xf6\x19\x8f\xf2M\xdf<\xedK\xca" + - "u7x\x8c\x04\xfc\x0c\x07\xe9\xea[]\x0fq\x08\xce" + - "p\xe6Q\xccC&\xa2\x8f\xe0\x8cG\"\x0e\xdf#\xf9" + - "T\xec\x9d\x1e\xc9\xe3\xf5\xb4\x15\x01^\x8d:\xe3\xc5\xce" + - "l\x9f\x9d\xdba\xf7\xc3\x1b\xfe\xc0]\xf7`\x1a\xb1\xbc" + - "\x1bLwh7\xe8\x063\x93\xbcsZ\xe6\xaf\xcf\xa9" + - "\xee m\x00\x0b\xf6\xfd\x06\xda\xaa\x9a\xa1\xfc?\xcc\xb8" + - "\x83\xc5\x01\xac\x993Y\xf6\xcdS\xf3J\x96\xce\xd0\x89" + - "\xcd\x9c\x04\xcb\xe8\xc8\xf983\xca\xfb8\xe36\x0c\xe3" + - "'{_g\x84\x95j\x87;W^\xad$\xd2n|" + - "\xffo\x00\x00\x00\xff\xff\xfe\x11AT" +const schema_ffaaf7385bc4adad = "x\xda\xc4Y\x7fp\x14\xf7u\x7fo\xf7N\xab\xd3\x0f" + + "N\xdb=\x09$P\xa5\x12HA\x0d\xe1\x87p\x8d\x19" + + "2\x92\x00\x85B\xc0\xd6\xea\xb0i!qY\xee\x16\xe9" + + "\xc4i\xf7\xd8\xdd\x03D\xec\xca$\xf5\xd8Q\x82cT" + + "\x98\xc4L\x99A\x8e\xa1@\xa0\xc6I\xa0\x86\xe0\x0c\x10" + + "\x98\x001M\xa1\x85\x06OH\xc1\x98\xda0\xc66\xb5" + + ";\xc5\x1e\xe8v\xde\xf7n\x7f\xe8$\xe3\x93\xeaN\xff" + + "\xd0\xe8\xee\xedg\xdf\xfb~\xbf\xef}\xdf{\x9fwS" + + "\xee\x84\x1a\x03SK\x7f3\x028yo\xb0\xc06\xaf" + + "v\x19;\xb7\xcd\xfb6\x88_@\x80 \x0a\x00\xf5\x8b" + + "\x847\x11PR\x84\x06@\xfb?_:\xf5\x95\x1fl" + + "z\xbf\xc7\x0f\xd8\x90\x01la\x80\xdf\xcd\xa8[\xb9\x9d" + + "_\xf8]?\xe0\x90\xf0\x06\x01\xce2\xc0_-\x0fo" + + "\xfe\x9b\x8ae\x0c`\xdf\xae_y\xf9\x85w\x1e\xfc\x07" + + "\x08\x0a\x04\xbc%\xbc\x81R\xa8\x90>\x06\x0b\xbf\x8f\x80" + + "\xf6\xaf\xffp\xfd\x92\xf0\xceg~\x98\x83fj\xaf\x87" + + "\xdeD\x09\x8b\x04\x00\xe9^\x88T?}\xe3\xe1\x83\x8f" + + "~\xfb\xfd\xed~\xdbS\x8b\xfe\x83l7\x17\x11\xe0\x85" + + "e\xef\xacj\x9e\x1f~\xb1\xbf\xb6\x00\xe1\x12E{P" + + "\xdaP$\x00oW|r\xed\xa5\x8b\xd1\x19\xbbA\xfe" + + "\x02\x0e0\xfa\x0d\xc2\xa5\x99\xd1\xd5Ek\x01\xedq/" + + "\xff\xf2\\\xcf\xac\xc9{\xfcF\xcf\x16\x9d'\xa3W\x99" + + "\xd1\x9e\xbfS\xff\xf8\xd8\xe1\xaf\x11\x80\xf3\xb4\x01\xd6c" + + "q\x0fJ\x95\xc5\xa4\xaa\xbc\xf8A@{\xed\xf2S/" + + "\xaf\x97\xaf\xef\x1ddy\xd5\xc5\xbd(=PL\xcb\x93" + + "\xe6N9t\xb1\xben_\xee\xf28\xc2\x89\x84\x9b\xc8" + + "t\x8e/~\x19\xd0\x9e\xde\xf7\xd3\x83\xcf\xbd\xb7\xee\xef" + + "\x09\xcd\xe5n\xe6Bq\x07J7\x8aG\x02H\xb7\x19" + + "\xfa\x9b\xe7n\xeez\xee\xbbM\x07ru\xf3\x84\xfeN" + + "\xc9q\x94\xfaJ\xe8\xe3\xb6\x92\x1a\xf2\x0e\x7f\xe5\xad\xa2" + + "\xe7\x9a&\x1f\x1c\xcc;'K\xcf\xa0t\xb5\x94Vr" + + "\xb9\x94\xce\xc1}.\x8e\xe1\xed}\xfbN,\x9b\xf1_" + + "{l:\x87{\xa5UX_:b\x09\x92\xe2\xb0\xc0" + + "I!Q\x00\xb0'\xbe\xfb\xec\xceg~\x1c=<\x98" + + "\xf2\xdbe\xc71\x03\x93\x82\")?sp\xf7\xccO" + + "\xae\xad=\x9c\xbbp\xb2_\xff\x90x\x1e\xa5G\x09]" + + "/\x8b\xcf\xf0\x80v\xd9\xb2\xdf|\xe5\xdd\xc7\xff\xfd\xa4" + + "\xdfi'\xcbY\x94^*'}o+?\xe7\x9a\xcf" + + "&\x7f\xe5\x07\xdc+/\xe2\x00\xa5\xf2\x0a\x06x\xeb\xbf" + + ";\xdaR\x93_\xf7\x03\x1e\xa8\xe8e\xb1\xc6\x00\xab\x8a" + + "OEB\x0d\xe6?\xfa\x01j\xc5q\x02\xa4\x19\xe0N" + + "\xf9/~P5\xebp?\xc0\x96\x0a\xb6\x86\xdd\x0cP" + + "\xd5tnzX\x9b\xf7O9\x07\xc0|q\xb6\xe2E" + + "\x94\xaeW\xd0\x01\\\xad \xcf\xfd\xe8\xc3]\xcb\x0fl" + + "\x8a\\\x1c\x10e\x9bFv\xa0\xb4c$!\xfbFv" + + "\x03\xdaw\x9f\x9e\xf5Tu\xf5\xc5K\x83\xc6\xcf\x85\x91" + + "7Q\xba\xcd\xd0\xb7F\xbe\x0dho\xfd\x93\xb5\xa9\xc7" + + "W\xcc\xfc}\x0e\x9a\x05\xe5\xe9Qo\xa0t}\x14[" + + "\xc4(Z\xf1\xdd\x99w\x7f\xb1}V\xea\xdfrU\x07" + + "\xd9\x8d\xae\xecA\xa9\xba\x92>VV.\xa1\xf0y4" + + "5O\xfcb\xeb\x88+\xfe\x13\xd8X\xf5\x07t\xc8;" + + "\xaaH\xdf\x94o\xce\xdb\xfdxB\xba\xe6\x07\x9c\xae\xda" + + "\xca\xdc\xc4\x00\x7f*\xfdr\xbf\xb6\xe9\xe6\xf5~n\xaa" + + "\xbaI\x00q4\x01\x8e-\xabo\xf9\xd7k_\xfc\x00" + + "\xc4I\x9cw\x17\x00\xeb\xa7\x8e\xeeEi\xfehZ{" + + "\xf3\xe8G\x00\xeds\xef\xd5\xec\xfd\xf5\xf5\xaf}\x98\xbb" + + "\xf6\x10\xcb\x0e\xa3\xb7\xa2\xb4\x81\xd0\xf5O\x8e~\x90\x03" + + "\xb4w\xae\xfe\xd1\xf3w\xc6\x8a\x1f\xe5\xde+\xb6\xd5s" + + "\xd5o\xa2t\xab\x9a>\xde\xa8\xfe\x15m\xf5\xd5\xad\x9b" + + "\xbf\x7fb\xda\xbc\x8f\xfc\x0b\xbd]\xc3\xb2D\xb0\x96\x16" + + "Z\xfe\x97\x1b\xae\xd4\xdd\xb8\xd6\x0f0\xbe\xf6\x0c\x01\x1e" + + "b\x80#\xb8\xa7\xf8\xeb\x1d\xef\xdc\xf1\x03\xbeQ\xcb\xb6" + + "\xba\x9a\x01\xee\xf4\xfd\xb8\xfe\xa9\xb3?\xfdx\x90\xec\xb1" + + "\xa5\xf6\x0cJ\xaf\xd4R\xf6\xe8\xfd\xe7\x05\x9d\xbf\xbf\xf7" + + "\xf3Or\x82\x8a9\x7fc\xed\x8b(\xed\xa8e\xa1R" + + "\xbb\x16&\xd9\x09\xcdR\x0dMI\x16LN\x19\xba\xa5" + + "O\x8e\xe9Z\xa7\xae}9\xa6\xa4\xb4\xd4\xcc9\x99/" + + "\xea:5\x16\xed\xd2bst\xcdR\x12\x9aj\x8ck" + + "Q\x0cA\xe94\xe5\x00\x1f\x00\x08 \x80X:\x1b@" + + ".\xe4Q\x8ep\xd8m\xa8\xab\xd3\xaaia\x99w\x86" + + "\x80X\x06\x98\x97\xb9\x98\xa1*\x96\xfa\xb0\xd2\xa9\x9a)" + + "%\xa6\x9a\xe3ZU3-$\xad~\xe6\x16\x00\xc8%" + + "<\xca\xa38\xb4\x0d\xd5L\xe9\x9a\xa9\x02\x00\x96y\xf5" + + "\xe4\x7fc\xb2E1\x14>\x9f\x0d\xba\xb5n\x08\xd6\xe6" + + "\xe4Xk%m\xbci\xb5 \xcac\\\x83\x07V\x00" + + "\xc8?\xe3Q>\xca\xa1\x88\x18A\x12\xbe\xb6\x14@>" + + "\xc2\xa3\xfc[\x0eE\x8e\x8b \x07 ^ \xe4\xbf\xf0" + + "(\x7f\xc0\xa1\xc8\xf3\x11\xe4\x01\xc4[$|\x97\xc7h" + + "!r(\x06\x02\x11\x0cP*\xc5\x05\x00\xd1\x00\xf2\x18" + + "-#y0\x18\xc1 \x80T\x8a\xd3\x00\xa2\x85$\x8f" + + "\x90\xbc\xa0 \x82\x05\x00\x92\xc8\xf0e$\xff\x12rh" + + "w\xaa\x96\x12W,\x05\x84G\x92q,\x05\x0eK\x01" + + "m-\xbb\x15\xe0U\x13G\x00\xb6\xf0\x88a/_\x01" + + "\x92\xd0N'\xe2\x8b\x94T*\x01\x82\xd6\xe6\xc2J\x80" + + "c\x0f\xdb\xee\xf7p\x85b\xaa-\x8a\xd5N\x0e&Y" + + "\x09`MJ\x8f\xcf\x8f;\xdf\xbcu\x018/\x97y" + + "\x17!\xbb\x80\xe1\xf9\xc6L\xe9\x82f\xaa\xe4\x1c_4" + + ",\xcd\xc6\xdf\x04n\xf0\xed\x97y=\xc6\x10\xac\x1b\xaa" + + "\x9eR\xb5\x85z\x9bw\xd5Z\xd5\x1a3\x9dw\xf0\xbb" + + "\xedON8\x06\xefc\xb4\xd51J{\x0d\xeb\x99\xbd" + + "\xe6\xf5\xa6{L\xfe7\xe5Bw\xa1\x13\xeb\x00\xe4q" + + "<\xcaS8t\"x\x12\xc9&\xf0(O\xe70l" + + "u\xa5\xd4\x9cH\x09\x03\x86S\x8a\xd5\xee\xba6\x9fs" + + "S,K\x89\xb5\xf7\xcbOJ'\xe6q}\xddr6" + + "\x84\xf3\x9a\xd3f\xe8\xe9\xd4\"ES\xdaT\x03\x80m" + + "\x99\xddCq6\xa9\x11C\x0b\x00\xba\xcd.\xd3R;" + + "\xe3v\x8c\x81W\x9a\x00\x90\x97\xf2&\xb6\x93\xd6\x8cS" + + "1oO<\xa6\x1afB\xd7X&1\x91e\x92\x12" + + "w\xef\xcd\xb4\xf7F\x1e\xe5\x85\x9e\x1b\xe6Sz\xf83" + + "\x1e\xe5\xc5\x94H0\x93Hd\x0a\xac\x16\x1e\xe5$\x87" + + "\xddkTc\x85n\xaa\x88\xc0!\xc2\xa7]\xfd!]" + + "\xbc\xc0}v\xb0Po\x9bk\x84\x13kTC\x0e\xa0" + + "\xbf\xaac]xqWJ\xf5\xef\xa7n\x90\xfd\x90l" + + ".\x8fr\x8bo?\x8bf{\x9btb\xcdU\x8a\xb6\xc3" + + "\xf0:^q\xc7q\xafE\x11w\x9f\xf1:g\xf1\x95" + + "\xf3^r\x10\x0f\x19>\xe6vh\xbd\xafo?\xd4\xe3" + + "\xa3\x9c\xaf\xf5z\xf4J<\xb6\xc7\xd7\xaf\x9d\xfc\x89\x8f" + + "\x15\x9f>\xee\xeb\xe5\xcf\xb6\xfa\x18\xf0\xd93^\xd9\x10" + + "/\xf4\xfa\x08\xd2\xa5=>*v\xf9'\xbe&\xefj" + + "\x8f\xed\xdc~h\xc8\x84\x9f+\xe0\x1d'd\xca\x9a\x9b" + + " [\x1d \xbbu\x895*\xa0a;y\x0djX" + + "f\xb3\x9dw\x82\xceK\x8e\xb2\xe6\xdc~\xd0\x89z\xb0" + + "\x9dG\x9c\xefY6\x95\xd9Nj\x83\x9a\x8cm\xf7{" + + "CF\xaf\xed\x14\"l\xf3\x14\xfae\x8e\"\xe7\xc6\xa1" + + "s\xe5\xc2L_\xae\xd8\xac\xc9\xa8uJ:\xdf\xaf\xdf" + + "2-p\xca\x17z\x18\xae_\xddg\xe1k{0\xdf" + + "\x12\xb2\xa1\x8e\xd9Xw\x96\x90#v\x96\xb0X]g" + + "\xd1\x1f.RR\xcd\x9aet\x01\xc8\xb5|\x10\xc0%" + + "\x99\xe8\x10!\xf1\xf6l\xe0\xc4\xeb\x02z\x8c\x02\x1d\x1e" + + ")^\xfa\x16p\xe29\x019w\x8c\x83\x0ei\x10O" + + "\xf6\x02'\x1e\x13\x90w\xe7\x15\xe8p`\xf1\x00\xbd\xb7" + + "O\xc0\x80K\xa7\xd0\x99\xa4\x88}[\x81\x13\xb7\x09\x18" + + "t\x191:\xacM\xdct\x188q\xa3\x80\x05\xee\xd0" + + "\x07\x9d\xf1\x90\xb8\xa1\x078\xf1I\x01\x05\x97\x07\xa3\xc3" + + "p\xc4\xd5\x06pbB\xa0\x1aBq\xd8\x88v,\x1b" + + "L\x98\x0d\x0bhD\xdb\xe1\x15\xe8\x04\x0b\x1a\x8dh;" + + "\xb5\xdc\x8f4\xdc(\xc8By\x95\xa0f?\x8f\xcf\xd1" + + "\xb5\x86\xcc+\xae\xbd\x87\x15t\x1c\x0a\xa4\xc7\xcc\xfa\x07" + + "j\x98\x83\x1a\xd1__\x87\x90\xda\xbc$?HW6" + + "\x81\xfb\xdc\xfb\xd1\x9c\x9b\x96)\xf0\x8d\x8ei\xe9\x15\xac" + + "\x02\x88\xee\xa5.\xfdU\xf4\xd8\x82t\x00\x97\x02D\x7f" + + "F\xf2\xa3\xc8!f\xf8\x82\xf4\x1ak\xea\x8f\x90\xf8\x14" + + "z\x85F:\xc9H\xc0Q\x92\xbf\x8e^\xad\x91Nc" + + "+@\xf4\x14\xc9\xdfb\xa4\x81\xcf\x90\x86\xab\xd8\x01\x10" + + "\xbdB\xf2\xbb\x8c4\x042\xa4\xe1cf\xf6\x0e#\x13" + + "\x1c\x87\xa2\x10\x8c\x10\x97\x95D\x8e\xe4e\x1c\x91\x09\x92" + + "\x17\x16D\xb0\x10@\x9a\xc8\xe4\x13H>\x97\xe4!!" + + "\x82!\x00\xa9\x89[\x01\x10m$\xf9\xd7I^T\x18" + + "\xc1\"\x00\xe9/\x98\xfc\xcfI\x1e'yq(\x82\xc5" + + "\x00\x92\xc2\xd1\xbe\x96\x93\xfc\x09\x92\x97\x14E\xb0\x04@" + + "\xea\xe2f\x03D-\x92?O\xf2R\x8c`)\x80\xb4" + + "\x913\x00\xa2\xdf#\xf9\x0fI>\xa28\x82#\x00\xa4" + + "-L\xbe\x99\xe4\xfbI\x1e.\x89`\x18@\xda\xc7\xf4" + + "\xec\"\xf9\x09\xae_\xd9\xb5W\xa4\xb5xRmQ\x80" + + "\xf7\x154K5:\x13\x9a\x92\xa4 \xc8vQ5\xa6" + + "\x15OhnO\xa5\xaeKX\x8c\xd8\xe0\x00\xce\xa3\xeb" + + "\x9d\xcd\xf4\x14\xc2\x8a\xd5>\xe0i\xd2\xc9\xdb\xbc\xe1\xa3" + + "\x1c\xbe\xe9\x07C\xc5\x92\xaa\xa2\xa5Ss\x80\xef\x8c\x0f" + + " \\I}\x85\x92l2\x80\x1f\xc8\xb7bzg\xa7" + + "\xa2\xc5\x9b@0\x06>\x1c~\x13\xd1\xadjk\x1eS" + + "\xfc\x0b\xce\xbd\x11\xb1\xfe%\x08\xc3^\xdd\xce\xb4k\xb6" + + "\x12\x8f'\xac\x84\xaeA\x8d\x92\xfcj\xdcU\x15\xca," + + "\xae;\xa9*\xab\x06\x8a\x87\xc5!ZU3\x9d\xe4\xf3" + + "%^n{\x90C$\x84\xfbX4\xfd\x9dc\x0ey" + + "1\x01>\x9b\xbd\xb8\xcd\xc6\x10\xd8K6%\xe7O\x91" + + "\xdcnk\x08\x13\x0e\xd3\x9f.\x9d\x0d}\xb6)\xb7\xdd" + + "\x19\xf2\xe8f\xb8ns;\xc1\xe1\xf1\xe5\xd5iA5" + + "s\xd9V\x95\xc7N\xc4\xc1\xe9\x167\x90n\xf9\x93\xc9" + + "\xff1\xd3b\xfdL\x98\x8a\"c)l)\x0f\x8ce" + + "\xd4u\x12\xfd\xe3\xc4\xf1\xf4\x8f\x17\xab\xeb\x000 \x96" + + "\x8f\x05\x10\x12\xa9\x98\xa0\xa9\x96\x90J\xc4\xc3iS5" + + "\x84\xb4e\xe6\xe5\x9fA\x9aE\xdf\xac\xa0\xcc=6\x85" + + "\x0ecy\xe60\x9cSK\x10\x1d\x8a\xf3(\xa7|\x1c" + + "\xa9\x93\x84\xed<\xca\x16\x95\xae\xda\x0cGZMo\xa7" + + "x\x94\x9f\xe02Yu\x8e\x1eg.\x0e\x00\x87\x01\xc0" + + "\x06\xd3\x8a\xebi\xcb9L\xfa\xaa\x1a\x86{\xb6V\xa2" + + "S\x8d?\x92\xb6|\x99zx\xd5\x99b\x8b\x1f0," + + "\xea\xf0\xc5_,\x0b\x86\xb0\xd1\x92\x88c!pX\x98" + + "g\xe09\x0ds\xb67&#\xa3\\#/P\xd8m" + + "\xe6Q\xde\xee\x0b\xbbmK\x01\xe4\xbf\xe5Q\xde\xe5\x0b" + + "\xbb\x1d\x06\x80\xfc\x12\x8f\xf2~\x0e1;-\xdc\xd7\x0b" + + " \xef\xe7Q>Bu\x9f\xcfp\xccC\x14\xb4\xaf\xf2" + + "(\x9f\xa0\xa2\x1f`E_\x97\xe4\xa1\xc2lg" + + "\xcc:\xf8F\x92/D\x0e\xed\x94\xa1\xc7T\xd3\x9c\x0f" + + "\xe8f\x14\x87{9wN\xb0\x946\xe7s\x035x" + + "\x09\xcb\xd7\xbd&\x92\xf1\xb9\x8a\x05\xa8\xba\x10K1\xda" + + "T\x0fb\xa4M\x8b\x8e\x1a\x04\x9fN;\xa6\x18m\xfa" + + "c\xaa\x01as\x80x\xb1\xa1\xfa\xf4\xf5\xbb\xc0\xce\xa5" + + "\x1ef\xfd\xf0\xaan\xad\x1b\xce\xe7(\xfd\xbd\x9e\xf9a" + + "\xc4\xc9~\x17\x96f\x7f\x17\xb9\xe2+\x1f\x97)\xee\x7f" + + "\xcb\xa3\xfc\x11\xf9\xb71\x93\xfen\xd3\x05\xfc\x80G\xf9" + + "\xaeo\xc4\xf61\xa5\xbf;\x03\xfbgL\x8a~=mE\x81" + + "Wc\xce\xc4\xb1;\xdbz\xe76\xdd\x83P\x89\xff\xe7" + + "F|8\xbdY\xde=\xa7;\xc7\x1bv\xcf\x99\xc9\xe7" + + "9]\xf4\xa7\xa7Yw\xb66\x04\x83\x03\x7f\x16mU" + + "\xcdp\xfe\xbf\xd5\xb8\xb3\xc6!\xd8\xcc\x196\xfbF\xac" + + "y%Kg\x0e\xc5\xc6P\x82et\xe5\xfc^3\xd6" + + "\xfb\xbd\xc6\xed!&M\xf3~\xb0\x11V\xa9]\xee\xa8" + + "y\x8d\x92L\xbb\xf7\xfb\x7f\x02\x00\x00\xff\xffz\xdfF" + + "\xb7" func RegisterSchema(reg *schemas.Registry) { reg.Register(&schemas.Schema{ diff --git a/pkg/client/client.go b/pkg/client/client.go index ba20358326..3beb8be714 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -687,6 +687,7 @@ const ( // type. LogDriverTypeContainerRuntimeInterface LogDriverType = iota LogDriverTypeJSONLogger LogDriverType = iota + LogDriverTypeJournald LogDriverType = iota ) // CreateContainerResponse is the response of the CreateContainer method. @@ -910,6 +911,9 @@ func (c *ConmonClient) initLogDrivers(req *proto.Conmon_CreateContainerRequest, if logDriver.Type == LogDriverTypeJSONLogger { n.SetType(proto.Conmon_LogDriver_Type_json) } + if logDriver.Type == LogDriverTypeJournald { + n.SetType(proto.Conmon_LogDriver_Type_journald) + } if err := n.SetPath(logDriver.Path); err != nil { return fmt.Errorf("set log driver path: %w", err) } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 32fd1af94c..69560c6204 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -722,3 +722,46 @@ var _ = Describe("JSONLogger", func() { } }) }) + +var _ = Describe("JournaldLogger", func() { + var tr *testRunner + var sut *client.ConmonClient + + AfterEach(func() { + if sut != nil { + Expect(sut.Shutdown()).To(Succeed()) + } + }) + + Describe("Logging", func() { + for _, terminal := range []bool{true, false} { + It(testName("should log to journald", terminal), func() { + tr = newTestRunner() + tr.createRuntimeConfigWithProcessArgs( + terminal, + []string{"/busybox", "sh", "-c", "echo hello world && echo foo bar"}, + nil, + ) + + sut = tr.configGivenEnv() + _, err := sut.CreateContainer(context.Background(), &client.CreateContainerConfig{ + ID: tr.ctrID, + BundlePath: tr.tmpDir, + Terminal: terminal, + LogDrivers: []client.ContainerLogDriver{{Type: client.LogDriverTypeJournald}}, + }) + Expect(err).NotTo(HaveOccurred()) + tr.startContainer(sut) + + // Verify the journal logs + cmd := exec.Command("journalctl", "-n2", "_COMM=conmonrs") + stdout := strings.Builder{} + cmd.Stdout = &stdout + Expect(cmd.Run()).NotTo(HaveOccurred()) + res := stdout.String() + Expect(res).To(ContainSubstring("hello world")) + Expect(res).To(ContainSubstring("foo bar")) + }) + } + }) +})