Re: [Libguestfs] [PATCH 4/4] OCaml tools: output messages into JSON for machine readable

2019-03-27 Thread Tomáš Golembiovský
On Fri, 22 Mar 2019 16:33:43 +0100
Pino Toscano  wrote:

> When the machine readable mode is enabled, print all the messages
> (progress, info, warning, and errors) also as JSON in the machine
> readable stream: this way, users can easily parse the status of the
> OCaml tool, and report that back.
> 
> The formatting of the current date time into the RFC 3999 format is done
> in C, because of the lack of OCaml APIs for this.
> ---
>  common/mltools/Makefile.am |  2 +-
>  common/mltools/tools_utils-c.c | 51 ++
>  common/mltools/tools_utils.ml  | 16 +++
>  lib/guestfs.pod| 19 +
>  4 files changed, 87 insertions(+), 1 deletion(-)

ACK

-- 
Tomáš Golembiovský 

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs

Re: [Libguestfs] [PATCH 4/4] OCaml tools: output messages into JSON for machine readable

2019-03-25 Thread Richard W.M. Jones
On Fri, Mar 22, 2019 at 04:33:43PM +0100, Pino Toscano wrote:
> When the machine readable mode is enabled, print all the messages
> (progress, info, warning, and errors) also as JSON in the machine
> readable stream: this way, users can easily parse the status of the
> OCaml tool, and report that back.
> 
> The formatting of the current date time into the RFC 3999 format is done
> in C, because of the lack of OCaml APIs for this.
> ---
>  common/mltools/Makefile.am |  2 +-
>  common/mltools/tools_utils-c.c | 51 ++
>  common/mltools/tools_utils.ml  | 16 +++
>  lib/guestfs.pod| 19 +
>  4 files changed, 87 insertions(+), 1 deletion(-)
> 
> diff --git a/common/mltools/Makefile.am b/common/mltools/Makefile.am
> index 37d10e610..ee8c319fd 100644
> --- a/common/mltools/Makefile.am
> +++ b/common/mltools/Makefile.am
> @@ -45,12 +45,12 @@ SOURCES_MLI = \
>  
>  SOURCES_ML = \
>   getopt.ml \
> + JSON.ml \
>   tools_utils.ml \
>   URI.ml \
>   planner.ml \
>   registry.ml \
>   regedit.ml \
> - JSON.ml \
>   JSON_parser.ml \
>   curl.ml \
>   checksums.ml \
> diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c
> index 553aa6631..977f932d9 100644
> --- a/common/mltools/tools_utils-c.c
> +++ b/common/mltools/tools_utils-c.c
> @@ -23,6 +23,8 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  
>  #include 
>  #include 
> @@ -41,6 +43,7 @@ extern value guestfs_int_mllib_inspect_decrypt (value gv, 
> value gpv, value keysv
>  extern value guestfs_int_mllib_set_echo_keys (value unitv);
>  extern value guestfs_int_mllib_set_keys_from_stdin (value unitv);
>  extern value guestfs_int_mllib_open_out_channel_from_fd (value fdv);
> +extern value guestfs_int_mllib_rfc3999_date_time_string (value unitv);
>  
>  /* Interface with the guestfish inspection and decryption code. */
>  int echo_keys = 0;
> @@ -120,3 +123,51 @@ guestfs_int_mllib_open_out_channel_from_fd (value fdv)
>  
>CAMLreturn (caml_alloc_channel (chan));
>  }
> +
> +value
> +guestfs_int_mllib_rfc3999_date_time_string (value unitv)
> +{
> +  CAMLparam1 (unitv);
> +  char buf[64];
> +  struct timespec ts;
> +  struct tm tm;
> +  size_t ret;
> +  size_t total = 0;
> +
> +  if (clock_gettime (CLOCK_REALTIME, ) == -1)
> +unix_error (errno, (char *) "clock_gettime", Val_unit);
> +
> +  if (localtime_r (_sec, ) == NULL)
> +unix_error (errno, (char *) "localtime_r", caml_copy_int64 (ts.tv_sec));
> +
> +  /* Sadly strftime does not support nanoseconds, so what we do is:
> +   * - stringify everything before the nanoseconds
> +   * - print the nanoseconds
> +   * - stringify the rest (i.e. the timezone)
> +   * then place ':' between the hours, and the minutes of the
> +   * timezone offset.
> +   */
> +
> +  ret = strftime (buf, sizeof (buf), "%Y-%m-%dT%H:%M:%S.", );
> +  if (ret == 0)
> +unix_error (errno, (char *) "strftime", Val_unit);
> +  total += ret;
> +
> +  ret = snprintf (buf + total, sizeof (buf) - total, "%09ld", ts.tv_nsec);
> +  if (ret == 0)
> +unix_error (errno, (char *) "sprintf", caml_copy_int64 (ts.tv_nsec));
> +  total += ret;
> +
> +  ret = strftime (buf + total, sizeof (buf) - total, "%z", );
> +  if (ret == 0)
> +unix_error (errno, (char *) "strftime", Val_unit);
> +  total += ret;
> +
> +  /* Move the timezone minutes one character to the right, moving the
> +   * null character too.
> +   */
> +  memmove (buf + total - 1, buf + total - 2, 3);
> +  buf[total - 2] = ':';
> +
> +  CAMLreturn (caml_copy_string (buf));
> +}
> diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
> index 3c54cd4a0..1a1d11075 100644
> --- a/common/mltools/tools_utils.ml
> +++ b/common/mltools/tools_utils.ml
> @@ -33,6 +33,7 @@ external c_inspect_decrypt : Guestfs.t -> int64 -> (string 
> * key_store_key) list
>  external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" 
> "noalloc"
>  external c_set_keys_from_stdin : unit -> unit = 
> "guestfs_int_mllib_set_keys_from_stdin" "noalloc"
>  external c_out_channel_from_fd : int -> out_channel = 
> "guestfs_int_mllib_open_out_channel_from_fd"
> +external c_rfc3999_date_time_string : unit -> string = 
> "guestfs_int_mllib_rfc3999_date_time_string"
>  
>  type machine_readable_fn = {
>pr : 'a. ('a, unit, string, unit) format4 -> 'a;
> @@ -85,12 +86,24 @@ let ansi_magenta ?(chan = stdout) () =
>  let ansi_restore ?(chan = stdout) () =
>if colours () || istty chan then output_string chan "\x1b[0m"
>  
> +let log_as_json msgtype msg =
> +  match machine_readable () with
> +  | None -> ()
> +  | Some { pr } ->
> +let json = [
> +  "message", JSON.String msg;
> +  "timestamp", JSON.String (c_rfc3999_date_time_string ());
> +  "type", JSON.String msgtype;
> +] in
> +pr "%s\n" (JSON.string_of_doc ~fmt:JSON.Compact json)
> +
>  (* Timestamped progress messages, used for ordinary messages