trusty (3) disk_log.3erl.gz

Provided by: erlang-manpages_16.b.3-dfsg-1ubuntu2.2_all bug

NAME

       disk_log - A disk based term logging facility

DESCRIPTION

       disk_log is a disk based term logger which makes it possible to efficiently log items on files. Two types
       of logs are supported, halt logs and wrap logs. A halt log appends items to a single file,  the  size  of
       which  may  or  may not be limited by the disk log module, whereas a wrap log utilizes a sequence of wrap
       log files of limited size. As a wrap log file has been filled up, further items are logged  onto  to  the
       next  file  in the sequence, starting all over with the first file when the last file has been filled up.
       For the sake of efficiency, items are always written to files as binaries.

       Two formats of the log files are supported, the internal format and the  external  format.  The  internal
       format  supports  automatic repair of log files that have not been properly closed, and makes it possible
       to efficiently read logged items in chunks using a set of functions defined in this module. In fact, this
       is  the  only way to read internally formatted logs. The external format leaves it up to the user to read
       the logged deep byte lists. The disk log module cannot repair externally formatted logs. An  item  logged
       to  an  internally  formatted  log  must  not occupy more than 4 GB of disk space (the size must fit in 4
       bytes).

       For each open disk log there is one process that handles requests made to the  disk  log;  the  disk  log
       process  is  created  when  open/1  is  called, provided there exists no process handling the disk log. A
       process that opens a disk log can either be an owner or an anonymous user of the disk log. Each owner  is
       linked  to  the  disk  log  process,  and the disk log is closed by the owner should the owner terminate.
       Owners can subscribe to notifications, messages of the form {disk_log, Node, Log,  Info}  that  are  sent
       from  the disk log process when certain events occur, see the commands below and in particular the open/1
       option notify. There can be several owners of a log, but a process cannot own a log more than  once.  One
       and  the  same  process  may,  however,  open the log as a user more than once. For a disk log process to
       properly close its file and terminate, it must be closed by its owners and once by some non-owner process
       for  each  time the log was used anonymously; the users are counted, and there must not be any users left
       when the disk log process terminates.

       Items can be logged synchronously by using the functions log/2, blog/2, log_terms/2 and blog_terms/2. For
       each  of these functions, the caller is put on hold until the items have been logged (but not necessarily
       written, use sync/1 to ensure that). By adding an a to each  of  the  mentioned  function  names  we  get
       functions  that  log items asynchronously. Asynchronous functions do not wait for the disk log process to
       actually write the items to the file, but return the control to the caller more or less immediately.

       When using the internal format for logs, the  functions  log/2,  log_terms/2,  alog/2,  and  alog_terms/2
       should be used. These functions log one or more Erlang terms. By prefixing each of the functions with a b
       (for "binary") we get the corresponding blog functions for the external format. These functions  log  one
       or  more  deep lists of bytes or, alternatively, binaries of deep lists of bytes. For example, to log the
       string  "hello"  in  ASCII  format,  we  can  use  disk_log:blog(Log,  "hello"),  or   disk_log:blog(Log,
       list_to_binary("hello")).  The two alternatives are equally efficient. The blog functions can be used for
       internally formatted logs as well, but in this case they must be called with  binaries  constructed  with
       calls  to  term_to_binary/1.  There  is no check to ensure this, it is entirely the responsibility of the
       caller. If these functions are called with binaries that do not correspond to Erlang terms, the chunk/2,3
       and  automatic  repair  functions  will fail. The corresponding terms (not the binaries) will be returned
       when chunk/2,3 is called.

       A collection of open disk logs with the same  name  running  on  different  nodes  is  said  to  be  a  a
       distributed  disk log if requests made to any one of the logs are automatically made to the other logs as
       well. The members of such a  collection  will  be  called  individual  distributed  disk  logs,  or  just
       distributed  disk  logs if there is no risk of confusion. There is no order between the members of such a
       collection. For instance, logged terms are not necessarily written onto the node where  the  request  was
       made  before written onto the other nodes. One could note here that there are a few functions that do not
       make requests to all members of distributed disk logs, namely info, chunk, bchunk, chunk_step and lclose.
       An  open  disk log that is not a distributed disk log is said to be a local disk log. A local disk log is
       accessible only from the node where the disk  log  process  runs,  whereas  a  distributed  disk  log  is
       accessible  from  all  nodes  in the Erlang system, with exception for those nodes where a local disk log
       with the same name as the distributed disk log exists. All processes on nodes that have access to a local
       or distributed disk log can log items or otherwise change, inspect or close the log.

       It is not guaranteed that all log files of a distributed disk log contain the same log items; there is no
       attempt made to synchronize the contents of the files. However, as long as at least one of  the  involved
       nodes  is  alive  at  each  time,  all  items will be logged. When logging items to a distributed log, or
       otherwise trying to change the log, the replies from individual logs are ignored. If all nodes are  down,
       the disk log functions reply with a nonode error.

   Note:
       In  some  applications  it  may  not  be  acceptable  that  replies  from individual logs are ignored. An
       alternative in such situations is to use several local disk logs instead of one distributed disk log, and
       implement the distribution without use of the disk log module.

       Errors are reported differently for asynchronous log attempts and other uses of the disk log module. When
       used synchronously the disk log module replies with an error message, but when called asynchronously, the
       disk  log  module  does  not  know  where  to  send  the  error  message.  Instead  owners subscribing to
       notifications will receive an error_status message.

       The disk log module itself does not report errors to the error_logger module; it is up to the  caller  to
       decide  whether  the  error  logger should be employed or not. The function format_error/1 can be used to
       produce readable messages from error replies. Information events are however sent to the error logger  in
       two situations, namely when a log is repaired, or when a file is missing while reading chunks.

       The  error message no_such_log means that the given disk log is not currently open. Nothing is said about
       whether the disk log files exist or not.

   Note:
       If an attempt to reopen or truncate  a  log  fails  (see  reopen  and  truncate)  the  disk  log  process
       immediately  terminates.  Before  the  process  terminates links to to owners and blocking processes (see
       block) are removed. The effect is that the links work in one direction only; any process using a disk log
       has  to  check  for  the error message no_such_log if some other process might truncate or reopen the log
       simultaneously.

DATA TYPES

       log() = term()

       dlog_size() = infinity
                   | integer() >= 1
                   | {MaxNoBytes :: integer() >= 1,
                      MaxNoFiles :: integer() >= 1}

       dlog_format() = external | internal

       dlog_head_opt() = none | term() | binary() | [dlog_byte()]

       dlog_byte() = [dlog_byte()] | byte()

       dlog_mode() = read_only | read_write

       dlog_type() = halt | wrap

       continuation()

              Chunk continuation returned by chunk/2,3, bchunk/2,3, or chunk_step/3.

       bytes() = binary() | [byte()]

       invalid_header() = term()

       file_error() = term()

EXPORTS

       accessible_logs() -> {[LocalLog], [DistributedLog]}

              Types:

                 LocalLog = DistributedLog = log()

              The accessible_logs/0 function returns the names of the disk logs accessible on the current  node.
              The first list contains local disk logs, and the second list contains distributed disk logs.

       alog(Log, Term) -> notify_ret()

       balog(Log, Bytes) -> notify_ret()

              Types:

                 Log = log()
                 Term = term()
                 Bytes = bytes()
                 notify_ret() = ok | {error, no_such_log}

              The  alog/2 and balog/2 functions asynchronously append an item to a disk log. The function alog/2
              is used for internally formatted logs, and the function balog/2  for  externally  formatted  logs.
              balog/2 can be used for internally formatted logs as well provided the binary was constructed with
              a call to term_to_binary/1.

              The owners that subscribe to notifications will receive  the  message  read_only,  blocked_log  or
              format_external  in  case  the item cannot be written on the log, and possibly one of the messages
              wrap, full and error_status if an item was written on the log. The message error_status is sent if
              there is something wrong with the header function or a file error occurred.

       alog_terms(Log, TermList) -> notify_ret()

       balog_terms(Log, ByteList) -> notify_ret()

              Types:

                 Log = log()
                 TermList = [term()]
                 ByteList = [bytes()]
                 notify_ret() = ok | {error, no_such_log}

              The  alog_terms/2 and balog_terms/2 functions asynchronously append a list of items to a disk log.
              The function alog_terms/2 is used for internally formatted logs, and  the  function  balog_terms/2
              for  externally  formatted  logs.  balog_terms/2 can be used for internally formatted logs as well
              provided the binaries were constructed with calls to term_to_binary/1.

              The owners that subscribe to notifications will receive  the  message  read_only,  blocked_log  or
              format_external  in  case  the items cannot be written on the log, and possibly one or more of the
              messages wrap, full and error_status if items were written on the log. The message error_status is
              sent if there is something wrong with the header function or a file error occurred.

       block(Log) -> ok | {error, block_error_rsn()}

       block(Log, QueueLogRecords) -> ok | {error, block_error_rsn()}

              Types:

                 Log = log()
                 QueueLogRecords = boolean()
                 block_error_rsn() = no_such_log | nonode | {blocked_log, log()}

              With a call to block/1,2 a process can block a log. If the blocking process is not an owner of the
              log, a temporary link is created between the disk log process and the blocking process.  The  link
              is  used  to  ensure  that the disk log is unblocked should the blocking process terminate without
              first closing or unblocking the log.

              Any process can probe a blocked log with info/1 or close it with close/1. The blocking process can
              also  use  the functions chunk/2,3, bchunk/2,3, chunk_step/3, and unblock/1 without being affected
              by the block. Any other attempt than those hitherto mentioned to update  or  read  a  blocked  log
              suspends  the calling process until the log is unblocked or returns an error message {blocked_log,
              Log}, depending on whether the value of QueueLogRecords is true or false.  The  default  value  of
              QueueLogRecords is true, which is used by block/1.

       change_header(Log, Header) -> ok | {error, Reason}

              Types:

                 Log = log()
                 Header = {head, dlog_head_opt()}
                        | {head_func, MFA :: {atom(), atom(), list()}}
                 Reason = no_such_log
                        | nonode
                        | {read_only_mode, Log}
                        | {blocked_log, Log}
                        | {badarg, head}

              The change_header/2 function changes the value of the head or head_func option of a disk log.

       change_notify(Log, Owner, Notify) -> ok | {error, Reason}

              Types:

                 Log = log()
                 Owner = pid()
                 Notify = boolean()
                 Reason = no_such_log
                        | nonode
                        | {blocked_log, Log}
                        | {badarg, notify}
                        | {not_owner, Owner}

              The change_notify/3 function changes the value of the notify option for an owner of a disk log.

       change_size(Log, Size) -> ok | {error, Reason}

              Types:

                 Log = log()
                 Size = dlog_size()
                 Reason = no_such_log
                        | nonode
                        | {read_only_mode, Log}
                        | {blocked_log, Log}
                        | {new_size_too_small, CurrentSize :: integer() >= 1}
                        | {badarg, size}
                        | {file_error, file:filename(), file_error()}

              The  change_size/2  function changes the size of an open log. For a halt log it is always possible
              to increase the size, but it is not possible to decrease the  size  to  something  less  than  the
              current size of the file.

              For a wrap log it is always possible to increase both the size and number of files, as long as the
              number of files does not exceed 65000. If the maximum number of files  is  decreased,  the  change
              will not be valid until the current file is full and the log wraps to the next file. The redundant
              files will be removed next time the log wraps around, i.e. starts to log to file number 1.

              As an example, assume that the old maximum number of files is 10 and that the new  maximum  number
              of files is 6. If the current file number is not greater than the new maximum number of files, the
              files 7 to 10 will be removed when file number 6 is full and the  log  starts  to  write  to  file
              number 1 again. Otherwise the files greater than the current file will be removed when the current
              file is full (e.g. if the current file is 8, the files 9 and 10); the files  between  new  maximum
              number  of files and the current file (i.e. files 7 and 8) will be removed next time file number 6
              is full.

              If the size of the files is decreased the change will immediately affect the current log. It  will
              not of course change the size of log files already full until next time they are used.

              If  the log size is decreased for instance to save space, the function inc_wrap_file/1 can be used
              to force the log to wrap.

       chunk(Log, Continuation) -> chunk_ret()

       chunk(Log, Continuation, N) -> chunk_ret()

       bchunk(Log, Continuation) -> bchunk_ret()

       bchunk(Log, Continuation, N) -> bchunk_ret()

              Types:

                 Log = log()
                 Continuation = start | continuation()
                 N = integer() >= 1 | infinity
                 chunk_ret() = {Continuation2 :: continuation(),
                                Terms :: [term()]}
                             | {Continuation2 :: continuation(),
                                Terms :: [term()],
                                Badbytes :: integer() >= 0}
                             | eof
                             | {error, Reason :: chunk_error_rsn()}
                 bchunk_ret() = {Continuation2 :: continuation(),
                                 Binaries :: [binary()]}
                              | {Continuation2 :: continuation(),
                                 Binaries :: [binary()],
                                 Badbytes :: integer() >= 0}
                              | eof
                              | {error, Reason :: chunk_error_rsn()}
                 chunk_error_rsn() = no_such_log
                                   | {format_external, log()}
                                   | {blocked_log, log()}
                                   | {badarg, continuation}
                                   | {not_internal_wrap, log()}
                                   | {corrupt_log_file,
                                      FileName :: file:filename()}
                                   | {file_error, file:filename(), file_error()}

              The chunk/2,3 and bchunk/2,3 functions make it possible to efficiently read the terms  which  have
              been  appended to an internally formatted log. It minimizes disk I/O by reading 64 kilobyte chunks
              from the file. The bchunk/2,3 functions return the binaries read from the file; they do  not  call
              binary_to_term. Otherwise the work just like chunk/2,3.

              The  first  time  chunk  (or  bchunk)  is called, an initial continuation, the atom start, must be
              provided. If there is a disk log process running on the current node, terms  are  read  from  that
              log, otherwise an individual distributed log on some other node is chosen, if such a log exists.

              When  chunk/3 is called, N controls the maximum number of terms that are read from the log in each
              chunk. Default is infinity, which means that all the terms contained in the 64 kilobyte chunk  are
              read.  If  less than N terms are returned, this does not necessarily mean that the end of the file
              has been reached.

              The chunk function returns a tuple {Continuation2, Terms}, where Terms is a list of terms found in
              the log. Continuation2 is yet another continuation which must be passed on to any subsequent calls
              to chunk. With a series of calls to chunk it is possible to extract all terms from a log.

              The chunk function returns a tuple {Continuation2, Terms, Badbytes} if the log is opened in  read-
              only  mode  and  the read chunk is corrupt. Badbytes is the number of bytes in the file which were
              found not to be Erlang terms in the chunk. Note also that the log is not repaired. When trying  to
              read  chunks  from  a  log  opened  in  read-write mode, the tuple {corrupt_log_file, FileName} is
              returned if the read chunk is corrupt.

              chunk returns eof when the end of the log is reached, or  {error,  Reason}  if  an  error  occurs.
              Should a wrap log file be missing, a message is output on the error log.

              When  chunk/2,3  is  used with wrap logs, the returned continuation may or may not be valid in the
              next call to chunk. This is because  the  log  may  wrap  and  delete  the  file  into  which  the
              continuation points. To make sure this does not happen, the log can be blocked during the search.

       chunk_info(Continuation) -> InfoList | {error, Reason}

              Types:

                 Continuation = continuation()
                 InfoList = [{node, Node :: node()}, ...]
                 Reason = {no_continuation, Continuation}

              The chunk_info/1 function returns the following pair describing the chunk continuation returned by
              chunk/2,3, bchunk/2,3, or chunk_step/3:

                * {node, Node}. Terms are read from the disk log running on Node.

       chunk_step(Log, Continuation, Step) ->
                     {ok, any()} | {error, Reason}

              Types:

                 Log = log()
                 Continuation = start | continuation()
                 Step = integer()
                 Reason = no_such_log
                        | end_of_log
                        | {format_external, Log}
                        | {blocked_log, Log}
                        | {badarg, continuation}
                        | {file_error, file:filename(), file_error()}

              The function chunk_step can be used in conjunction with chunk/2,3 and bchunk/2,3 to search through
              an  internally  formatted  wrap log. It takes as argument a continuation as returned by chunk/2,3,
              bchunk/2,3, or chunk_step/3, and steps forward (or backward) Step  files  in  the  wrap  log.  The
              continuation returned points to the first log item in the new current file.

              If  the  atom  start is given as continuation, a disk log to read terms from is chosen. A local or
              distributed disk log on the current node is preferred to an individual  distributed  log  on  some
              other node.

              If  the  wrap  log  is  not  full because all files have not been used yet, {error, end_of_log} is
              returned if trying to step outside the log.

       close(Log) -> ok | {error, close_error_rsn()}

              Types:

                 Log = log()
                 close_error_rsn() = no_such_log
                                   | nonode
                                   | {file_error, file:filename(), file_error()}

              The function close/1 closes a local or distributed disk log properly. An internally formatted  log
              must  be closed before the Erlang system is stopped, otherwise the log is regarded as unclosed and
              the automatic repair procedure will be activated next time the log is opened.

              The disk log process in not terminated as long as there are owners or users of the log. It  should
              be  stressed  that  each and every owner must close the log, possibly by terminating, and that any
              other process - not only the processes that have opened the log anonymously -  can  decrement  the
              users  counter  by  closing the log. Attempts to close a log by a process that is not an owner are
              simply ignored if there are no users.

              If the log is blocked by the closing process, the log is also unblocked.

       format_error(Error) -> io_lib:chars()

              Types:

                 Error = term()

              Given the error returned by any function in this  module,  the  function  format_error  returns  a
              descriptive  string  of  the error in English. For file errors, the function format_error/1 in the
              file module is called.

       inc_wrap_file(Log) -> ok | {error, inc_wrap_error_rsn()}

              Types:

                 Log = log()
                 inc_wrap_error_rsn() = no_such_log
                                      | nonode
                                      | {read_only_mode, log()}
                                      | {blocked_log, log()}
                                      | {halt_log, log()}
                                      | {invalid_header, invalid_header()}
                                      | {file_error,
                                         file:filename(),
                                         file_error()}
                 invalid_header() = term()

              The inc_wrap_file/1 function forces the internally formatted disk log to start logging to the next
              log  file. It can be used, for instance, in conjunction with change_size/2 to reduce the amount of
              disk space allocated by the disk log.

              The owners that subscribe to notifications will normally receive a wrap message, but in case of an
              error with a reason tag of invalid_header or file_error an error_status message will be sent.

       info(Log) -> InfoList | {error, no_such_log}

              Types:

                 Log = log()
                 InfoList = [dlog_info()]
                 dlog_info() = {name, Log :: log()}
                             | {file, File :: file:filename()}
                             | {type, Type :: dlog_type()}
                             | {format, Format :: dlog_format()}
                             | {size, Size :: dlog_size()}
                             | {mode, Mode :: dlog_mode()}
                             | {owners, [{pid(), Notify :: boolean()}]}
                             | {users, Users :: integer() >= 0}
                             | {status,
                                Status :: ok
                                        | {blocked,
                                           QueueLogRecords :: boolean()}}
                             | {node, Node :: node()}
                             | {distributed, Dist :: local | [node()]}
                             | {head,
                                Head :: none
                                      | {head, term()}
                                      | (MFA :: {atom(), atom(), list()})}
                             | {no_written_items,
                                NoWrittenItems :: integer() >= 0}
                             | {full, Full :: boolean}
                             | {no_current_bytes, integer() >= 0}
                             | {no_current_items, integer() >= 0}
                             | {no_items, integer() >= 0}
                             | {current_file, integer() >= 1}
                             | {no_overflows,
                                {SinceLogWasOpened :: integer() >= 0,
                                 SinceLastInfo :: integer() >= 0}}

              The  info/1  function  returns a list of {Tag, Value} pairs describing the log. If there is a disk
              log process running on the current node, that log is used as source of information,  otherwise  an
              individual distributed log on some other node is chosen, if such a log exists.

              The following pairs are returned for all logs:

                * {name, Log}, where Log is the name of the log as given by the open/1 option name.

                * {file, File}. For halt logs File is the filename, and for wrap logs File is the base name.

                * {type, Type}, where Type is the type of the log as given by the open/1 option type.

                * {format, Format}, where Format is the format of the log as given by the open/1 option format.

                * {size,  Size},  where  Size  is the size of the log as given by the open/1 option size, or the
                  size set by change_size/2. The value set by change_size/2 is reflected immediately.

                * {mode, Mode}, where Mode is the mode of the log as given by the open/1 option mode.

                * {owners, [{pid(), Notify}]} where Notify is the value set by the open/1 option notify  or  the
                  function change_notify/3 for the owners of the log.

                * {users,  Users} where Users is the number of anonymous users of the log, see the open/1 option
                  linkto.

                * {status, Status}, where Status is ok or {blocked, QueueLogRecords} as  set  by  the  functions
                  block/1,2 and unblock/1.

                * {node,  Node}.  The  information returned by the current invocation of the info/1 function has
                  been gathered from the disk log process running on Node.

                * {distributed, Dist}. If the log is local on the current node, then Dist has the  value  local,
                  otherwise all nodes where the log is distributed are returned as a list.

              The following pairs are returned for all logs opened in read_write mode:

                * {head,  Head}.  Depending  of the value of the open/1 options head and head_func or set by the
                  function change_header/2, the value of Head is none (default),  {head,  H}  (head  option)  or
                  {M,F,A} (head_func option).

                * {no_written_items, NoWrittenItems}, where NoWrittenItems is the number of items written to the
                  log since the disk log process was created.

              The following pair is returned for halt logs opened in read_write mode:

                * {full, Full}, where Full is true or false depending on whether the halt log is full or not.

              The following pairs are returned for wrap logs opened in read_write mode:

                * {no_current_bytes, integer() >= 0} is the number of bytes written  to  the  current  wrap  log
                  file.

                * {no_current_items,  integer()  >=  0}  is  the number of items written to the current wrap log
                  file, header inclusive.

                * {no_items, integer() >= 0} is the total number of items in all wrap log files.

                * {current_file, integer()} is  the  ordinal  for  the  current  wrap  log  file  in  the  range
                  1..MaxNoFiles, where MaxNoFiles is given by the open/1 option size or set by change_size/2.

                * {no_overflows, {SinceLogWasOpened, SinceLastInfo}}, where SinceLogWasOpened (SinceLastInfo) is
                  the number of times a wrap log file has been filled up and a new one opened or inc_wrap_file/1
                  has  been  called  since the disk log was last opened (info/1 was last called). The first time
                  info/2 is called after a log was (re)opened or truncated, the two values are equal.

              Note that the chunk/2,3, bchunk/2,3, and chunk_step/3 functions do not affect any  value  returned
              by info/1.

       lclose(Log) -> ok | {error, lclose_error_rsn()}

       lclose(Log, Node) -> ok | {error, lclose_error_rsn()}

              Types:

                 Log = log()
                 Node = node()
                 lclose_error_rsn() = no_such_log
                                    | {file_error,
                                       file:filename(),
                                       file_error()}

              The function lclose/1 closes a local log or an individual distributed log on the current node. The
              function lclose/2 closes an individual distributed log on the specified node if the  node  is  not
              the current one. lclose(Log) is equivalent to lclose(Log, node()). See also close/1.

              If there is no log with the given name on the specified node, no_such_log is returned.

       log(Log, Term) -> ok | {error, Reason :: log_error_rsn()}

       blog(Log, Bytes) -> ok | {error, Reason :: log_error_rsn()}

              Types:

                 Log = log()
                 Term = term()
                 Bytes = bytes()
                 log_error_rsn() = no_such_log
                                 | nonode
                                 | {read_only_mode, log()}
                                 | {format_external, log()}
                                 | {blocked_log, log()}
                                 | {full, log()}
                                 | {invalid_header, invalid_header()}
                                 | {file_error, file:filename(), file_error()}

              The  log/2  and  blog/2  functions  synchronously  append  a term to a disk log. They return ok or
              {error, Reason} when the term has been written to disk. If the log is distributed,  ok  is  always
              returned,  unless  all nodes are down. Terms are written by means of the ordinary write() function
              of the operating system. Hence, there is no guarantee that the term has actually been  written  to
              the  disk,  it  might  linger in the operating system kernel for a while. To make sure the item is
              actually written to disk, the sync/1 function must be called.

              The log/2 function is used for internally formatted logs,  and  blog/2  for  externally  formatted
              logs. blog/2 can be used for internally formatted logs as well provided the binary was constructed
              with a call to term_to_binary/1.

              The owners that subscribe to notifications will be notified  of  an  error  with  an  error_status
              message if the error reason tag is invalid_header or file_error.

       log_terms(Log, TermList) ->
                    ok | {error, Resaon :: log_error_rsn()}

       blog_terms(Log, BytesList) ->
                     ok | {error, Reason :: log_error_rsn()}

              Types:

                 Log = log()
                 TermList = [term()]
                 BytesList = [bytes()]
                 log_error_rsn() = no_such_log
                                 | nonode
                                 | {read_only_mode, log()}
                                 | {format_external, log()}
                                 | {blocked_log, log()}
                                 | {full, log()}
                                 | {invalid_header, invalid_header()}
                                 | {file_error, file:filename(), file_error()}

              The  log_terms/2  and  blog_terms/2 functions synchronously append a list of items to the log. The
              benefit of using these functions rather than the log/2 and blog/2 functions is that of efficiency:
              the  given  list  is  split  into  as  large sublists as possible (limited by the size of wrap log
              files), and each sublist is logged as one single item, which reduces the overhead.

              The log_terms/2 function is used for internally formatted logs, and  blog_terms/2  for  externally
              formatted  logs.  blog_terms/2  can  be  used  for  internally formatted logs as well provided the
              binaries were constructed with calls to term_to_binary/1.

              The owners that subscribe to notifications will be notified  of  an  error  with  an  error_status
              message if the error reason tag is invalid_header or file_error.

       open(ArgL) -> open_ret() | dist_open_ret()

              Types:

                 ArgL = dlog_options()
                 dlog_options() = [dlog_option()]
                 dlog_option() = {name, Log :: log()}
                               | {file, FileName :: file:filename()}
                               | {linkto, LinkTo :: none | pid()}
                               | {repair, Repair :: true | false | truncate}
                               | {type, Type :: dlog_type}
                               | {format, Format :: dlog_format()}
                               | {size, Size :: dlog_size()}
                               | {distributed, Nodes :: [node()]}
                               | {notify, boolean()}
                               | {head, Head :: dlog_head_opt()}
                               | {head_func, MFA :: {atom(), atom(), list()}}
                               | {mode, Mode :: dlog_mode()}
                 open_ret() = ret() | {error, open_error_rsn()}
                 ret() = {ok, Log :: log()}
                       | {repaired,
                          Log :: log(),
                          {recovered, Rec :: integer() >= 0},
                          {badbytes, Bad :: integer() >= 0}}
                 dist_open_ret() =
                     {[{node(), ret()}], [{node(), {error, dist_error_rsn()}}]}
                 dist_error_rsn() = nodedown | open_error_rsn()
                 open_error_rsn() = no_such_log
                                  | {badarg, term()}
                                  | {size_mismatch,
                                     CurrentSize :: dlog_size(),
                                     NewSize :: dlog_size()}
                                  | {arg_mismatch,
                                     OptionName :: dlog_optattr(),
                                     CurrentValue :: term(),
                                     Value :: term()}
                                  | {name_already_open, Log :: log()}
                                  | {open_read_write, Log :: log()}
                                  | {open_read_only, Log :: log()}
                                  | {need_repair, Log :: log()}
                                  | {not_a_log_file,
                                     FileName :: file:filename()}
                                  | {invalid_index_file,
                                     FileName :: file:filename()}
                                  | {invalid_header, invalid_header()}
                                  | {file_error, file:filename(), file_error()}
                                  | {node_already_open, Log :: log()}
                 dlog_optattr() = name
                                | file
                                | linkto
                                | repair
                                | type
                                | format
                                | size
                                | distributed
                                | notify
                                | head
                                | head_func
                                | mode
                 dlog_size() = infinity
                             | integer() >= 1
                             | {MaxNoBytes :: integer() >= 1,
                                MaxNoFiles :: integer() >= 1}

              The ArgL parameter is a list of options which have the following meanings:

                * {name,  Log}  specifies  the  name  of  the log. This is the name which must be passed on as a
                  parameter in all subsequent logging operations. A name must always be supplied.

                * {file, FileName} specifies the name of the file which will be used for logged terms.  If  this
                  value  is  omitted  and  the name of the log is either an atom or a string, the file name will
                  default to lists:concat([Log, ".LOG"]) for halt logs. For wrap logs, this  will  be  the  base
                  name  of  the  files.  Each  file  in  a  wrap log will be called <base_name>.N, where N is an
                  integer. Each wrap log will also have two files called <base_name>.idx and <base_name>.siz.

                * {linkto, LinkTo}. If LinkTo is a pid, that pid becomes an owner of the log. If LinkTo is  none
                  the log records that it is used anonymously by some process by incrementing the users counter.
                  By default, the process which calls open/1 owns the log.

                * {repair, Repair}. If Repair is true, the current log file will be repaired, if needed. As  the
                  restoration  is  initiated,  a  message  is  output  on  the  error log. If false is given, no
                  automatic repair will be attempted. Instead, the tuple {error, {need_repair, Log}} is returned
                  if  an  attempt is made to open a corrupt log file. If truncate is given, the log file will be
                  truncated, creating an empty log. Default is true, which has no effect on logs opened in read-
                  only mode.

                * {type, Type} is the type of the log. Default is halt.

                * {format, Format} specifies the format of the disk log. Default is internal.

                * {size,  Size} specifies the size of the log. When a halt log has reached its maximum size, all
                  attempts to log more items are rejected. The default size is infinity, which for halt  implies
                  that  there  is  no  maximum  size.  For  wrap  logs,  the Size parameter may be either a pair
                  {MaxNoBytes, MaxNoFiles} or infinity. In the latter case, if the files of an already  existing
                  wrap  log  with  the  same  name  can  be  found, the size is read from the existing wrap log,
                  otherwise an error is returned. Wrap logs write at most MaxNoBytes bytes on each file and  use
                  MaxNoFiles  files  before  starting  all  over  with  the  first  wrap log file. Regardless of
                  MaxNoBytes, at least the header (if there is one) and one item is written  on  each  wrap  log
                  file  before wrapping to the next file. When opening an existing wrap log, it is not necessary
                  to supply a value for the option Size, but any supplied value must equal the current  size  of
                  the log, otherwise the tuple {error, {size_mismatch, CurrentSize, NewSize}} is returned.

                * {distributed,  Nodes}.  This  option can be used for adding members to a distributed disk log.
                  The default value is [], which means that the log is local on the current node.

                *

                  {notify, bool()}. If true, the owners of the log are notified when certain events occur in the
                  log. Default is false. The owners are sent one of the following messages when an event occurs:

                  * {disk_log,  Node, Log, {wrap, NoLostItems}} is sent when a wrap log has filled up one of its
                    files and a new file is opened. NoLostItems is the number of previously  logged  items  that
                    have been lost when truncating existing files.

                  * {disk_log,  Node,  Log,  {truncated,  NoLostItems}} is sent when a log has been truncated or
                    reopened. For halt logs NoLostItems is the number of items written on the log since the disk
                    log  process  was  created. For wrap logs NoLostItems is the number of items on all wrap log
                    files.

                  * {disk_log, Node, Log, {read_only, Items}} is sent when an asynchronous log attempt  is  made
                    to a log file opened in read-only mode. Items is the items from the log attempt.

                  * {disk_log, Node, Log, {blocked_log, Items}} is sent when an asynchronous log attempt is made
                    to a blocked log that does not queue log attempts. Items is the items from the log attempt.

                  * {disk_log, Node, Log, {format_external, Items}} is sent when alog/2 or alog_terms/2 is  used
                    for internally formatted logs. Items is the items from the log attempt.

                  * {disk_log,  Node,  Log, full} is sent when an attempt to log items to a wrap log would write
                    more bytes than the limit set by the size option.

                  * {disk_log, Node, Log, {error_status, Status}} is sent when the  error  status  changes.  The
                    error  status  is defined by the outcome of the last attempt to log items to a the log or to
                    truncate the log or the last use of sync/1, inc_wrap_file/1 or change_size/2. Status is  one
                    of ok and {error, Error}, the former being the initial value.

                * {head, Head} specifies a header to be written first on the log file. If the log is a wrap log,
                  the item Head is written first in each new file. Head should  be  a  term  if  the  format  is
                  internal,  and a deep list of bytes (or a binary) otherwise. Default is none, which means that
                  no header is written first on the file.

                * {head_func, {M,F,A}} specifies a function to be called each time a new log file is opened. The
                  call M:F(A) is assumed to return {ok, Head}. The item Head is written first in each file. Head
                  should be a term if the format is internal, and a deep list of bytes (or a binary) otherwise.

                * {mode, Mode} specifies if the log is to be opened in read-only or read-write mode. It defaults
                  to read_write.

              The  open/1  function  returns  {ok, Log} if the log file was successfully opened. If the file was
              successfully repaired, the tuple {repaired, Log, {recovered, Rec}, {badbytes, Bad}}  is  returned,
              where  Rec is the number of whole Erlang terms found in the file and Bad is the number of bytes in
              the file which were non-Erlang terms. If the distributed parameter was  given,  open/1  returns  a
              list  of  successful  replies  and a list of erroneous replies. Each reply is tagged with the node
              name.

              When a disk log is opened in read-write mode, any existing log file is checked for.  If  there  is
              none  a  new empty log is created, otherwise the existing file is opened at the position after the
              last logged item, and the logging of items will commence from there. If the format is internal and
              the   existing   file  is  not  recognized  as  an  internally  formatted  log,  a  tuple  {error,
              {not_a_log_file, FileName}} is returned.

              The open/1 function cannot be used for changing the values of options of an already open log; when
              there  are  prior  owners  or users of a log, all option values except name, linkto and notify are
              just checked against the values that have  been  supplied  before  as  option  values  to  open/1,
              change_header/2,  change_notify/3  or  change_size/2. As a consequence, none of the options except
              name is mandatory.  If  some  given  value  differs  from  the  current  value,  a  tuple  {error,
              {arg_mismatch,  OptionName, CurrentValue, Value}} is returned. Caution: an owner's attempt to open
              a log as owner once again is acknowledged with the return value {ok, Log}, but the  state  of  the
              disk log is not affected in any way.

              If a log with a given name is local on some node, and one tries to open the log distributed on the
              same node, then the tuple {error,  {node_already_open,  Log}}  is  returned.  The  same  tuple  is
              returned if the log is distributed on some node, and one tries to open the log locally on the same
              node. Opening individual distributed disk logs for the first time adds those logs to  a  (possibly
              empty)  distributed  disk  log.  The option values supplied are used on all nodes mentioned by the
              distributed option. Individual distributed logs know nothing about each other's option values,  so
              each  node  can  be given unique option values by creating a distributed log with several calls to
              open/1.

              It is possible to open a log file more than once by giving different values to the option name  or
              by  using  the  same  file when distributing a log on different nodes. It is up to the user of the
              disk_log module to ensure that no more than one disk log process has write access to any file,  or
              the the file may be corrupted.

              If  an  attempt  to open a log file for the first time fails, the disk log process terminates with
              the EXIT message {{failed,Reason},[{disk_log,open,1}]}. The function returns {error,  Reason}  for
              all other errors.

       pid2name(Pid) -> {ok, Log} | undefined

              Types:

                 Pid = pid()
                 Log = log()

              The  pid2name/1  function  returns  the name of the log given the pid of a disk log process on the
              current node, or undefined if the given pid is not a disk log process.

              This function is meant to be used for debugging only.

       reopen(Log, File) -> ok | {error, reopen_error_rsn()}

       reopen(Log, File, Head) -> ok | {error, reopen_error_rsn()}

       breopen(Log, File, BHead) -> ok | {error, reopen_error_rsn()}

              Types:

                 Log = log()
                 File = file:filename()
                 Head = term()
                 BHead = bytes()
                 reopen_error_rsn() = no_such_log
                                    | nonode
                                    | {read_only_mode, log()}
                                    | {blocked_log, log()}
                                    | {same_file_name, log()}
                                    | {invalid_index_file, file:filename()}
                                    | {invalid_header, invalid_header()}
                                    | {file_error,
                                       file:filename(),
                                       file_error()}

              The reopen functions first rename the log file to File and then re-create a new log file. In  case
              of  a wrap log, File is used as the base name of the renamed files. By default the header given to
              open/1 is written first in the newly opened log file, but if the Head or  the  BHead  argument  is
              given, this item is used instead. The header argument is used once only; next time a wrap log file
              is opened, the header given to open/1 is used.

              The reopen/2,3 functions are used for internally formatted  logs,  and  breopen/3  for  externally
              formatted logs.

              The owners that subscribe to notifications will receive a truncate message.

              Upon  failure  to  reopen  the  log,  the  disk  log  process  terminates  with  the  EXIT message
              {{failed,Error},[{disk_log,Fun,Arity}]}, and other processes that have requests queued receive the
              message {disk_log, Node, {error, disk_log_stopped}}.

       sync(Log) -> ok | {error, sync_error_rsn()}

              Types:

                 Log = log()
                 sync_error_rsn() = no_such_log
                                  | nonode
                                  | {read_only_mode, log()}
                                  | {blocked_log, log()}
                                  | {file_error, file:filename(), file_error()}

              The sync/1 function ensures that the contents of the log are actually written to the disk. This is
              usually a rather expensive operation.

       truncate(Log) -> ok | {error, trunc_error_rsn()}

       truncate(Log, Head) -> ok | {error, trunc_error_rsn()}

       btruncate(Log, BHead) -> ok | {error, trunc_error_rsn()}

              Types:

                 Log = log()
                 Head = term()
                 BHead = bytes()
                 trunc_error_rsn() = no_such_log
                                   | nonode
                                   | {read_only_mode, log()}
                                   | {blocked_log, log()}
                                   | {invalid_header, invalid_header()}
                                   | {file_error, file:filename(), file_error()}

              The truncate functions remove all items from a disk log. If the Head  or  the  BHead  argument  is
              given, this item is written first in the newly truncated log, otherwise the header given to open/1
              is used. The header argument is only used once; next time a wrap log file is  opened,  the  header
              given to open/1 is used.

              The  truncate/1,2 functions are used for internally formatted logs, and btruncate/2 for externally
              formatted logs.

              The owners that subscribe to notifications will receive a truncate message.

              If the attempt to truncate the log fails, the disk log process terminates with  the  EXIT  message
              {{failed,Reason},[{disk_log,Fun,Arity}]},  and  other  processes that have requests queued receive
              the message {disk_log, Node, {error, disk_log_stopped}}.

       unblock(Log) -> ok | {error, unblock_error_rsn()}

              Types:

                 Log = log()
                 unblock_error_rsn() = no_such_log
                                     | nonode
                                     | {not_blocked, log()}
                                     | {not_blocked_by_pid, log()}

              The unblock/1 function unblocks a log. A log can only be unblocked by the blocking process.

SEE ALSO

       file(3erl), pg2(3erl), wrap_log_reader(3erl)