disk_log(3erl) Erlang Module Definition disk_log(3erl)
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 can-
not 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 prop-
erly 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 anony-
mously; 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 exter-
nal 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 alterna-
tives 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 call-
er. 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 simultane-
ously.
EXPORTS
accessible_logs() -> {[LocalLog], [DistributedLog]}
Types LocalLog = DistributedLog = term()
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)
balog(Log, Bytes) -> ok | {error, Reason}
Types Log = term()
Term = term()
Bytes = binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
Reason = 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 can-
not 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 mes-
sage error_status is sent if there is something wrong with the header function or a file error occurred.
alog_terms(Log, TermList)
balog_terms(Log, BytesList) -> ok | {error, Reason}
Types Log = term()
TermList = [term()]
BytesList = [Bytes]
Bytes = binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
Reason = 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 inter-
nally 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)
block(Log, QueueLogRecords) -> ok | {error, Reason}
Types Log = term()
QueueLogRecords = bool()
Reason = 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 = term()
Header = {head, Head} | {head_func, {M,F,A}}
Head = none | term() | binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
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 = term()
Owner = pid()
Notify = bool()
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 = term()
Size = integer() > 0 | infinity | {MaxNoBytes, MaxNoFiles}
MaxNoBytes = integer() > 0
MaxNoFiles = integer() > 0
Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {new_size_too_small, CurrentSize} | {badarg,
size} | {file_error, FileName, FileError}
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(Log, Continuation, N) -> {Continuation2, Terms} | {Continuation2, Terms, Badbytes} | eof | {error, Reason}
bchunk(Log, Continuation)
bchunk(Log, Continuation, N) -> {Continuation2, Binaries} | {Continuation2, Binaries, Badbytes} | eof | {error, Reason}
Types Log = term()
Continuation = start | cont()
N = integer() > 0 | infinity
Continuation2 = cont()
Terms = [term()]
Badbytes = integer()
Reason = no_such_log | {format_external, Log} | {blocked_log, Log} | {badarg, continuation} | {not_internal_wrap, Log} |
{corrupt_log_file, FileName} | {file_error, FileName, FileError}
Binaries = [binary()]
The chunk/2,3 and bchunk/2,3 functions make it possible to efficiently read the terms which have been appended to an internally for-
matted 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 = cont()
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, Continuation2} | {error, Reason}
Types Log = term()
Continuation = start | cont()
Step = integer()
Continuation2 = cont()
Reason = no_such_log | end_of_log | {format_external, Log} | {blocked_log, Log} | {badarg, continuation} | {file_error, File-
Name, FileError}
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, Reason}
Types Reason = no_such_log | nonode | {file_error, FileName, FileError}
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 sim-
ply ignored if there are no users.
If the log is blocked by the closing process, the log is also unblocked.
format_error(Error) -> Chars
Types Chars = [char() | Chars]
Given the error returned by any function in this module, the function format_error returns a descriptive string of the error in Eng-
lish. For file errors, the function format_error/1 in the file module is called.
inc_wrap_file(Log) -> ok | {error, Reason}
Types Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {halt_log, Log} | {invalid_header, Invalid-
Header} | {file_error, FileName, FileError}
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}
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)
lclose(Log, Node) -> ok | {error, Reason}
Types Node = node()
Reason = no_such_log | {file_error, FileName, FileError}
The function lclose/1 closes a local log or an individual distributed log on the current node. The function lclose/2 closes an indi-
vidual 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)
blog(Log, Bytes) -> ok | {error, Reason}
Types Log = term()
Term = term()
Bytes = binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
Reason = no_such_log | nonode | {read_only_mode, Log} | {format_external, Log} | {blocked_log, Log} | {full, Log} |
{invalid_header, InvalidHeader} | {file_error, FileName, FileError}
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 inter-
nally 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)
blog_terms(Log, BytesList) -> ok | {error, Reason}
Types Log = term()
TermList = [term()]
BytesList = [Bytes]
Bytes = binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
Reason = no_such_log | nonode | {read_only_mode, Log} | {format_external, Log} | {blocked_log, Log} | {full, Log} |
{invalid_header, InvalidHeader} | {file_error, FileName, FileError}
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 (lim-
ited 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) -> OpenRet | DistOpenRet
Types ArgL = [Opt]
Opt = {name, term()} | {file, FileName}, {linkto, LinkTo} | {repair, Repair} | {type, Type} | {format, Format} | {size, Size}
| {distributed, [Node]} | {notify, bool()} | {head, Head} | {head_func, {M,F,A}} | {mode, Mode}
FileName = string() | atom()
LinkTo = pid() | none
Repair = true | false | truncate
Type = halt | wrap
Format = internal | external
Size = integer() > 0 | infinity | {MaxNoBytes, MaxNoFiles}
MaxNoBytes = integer() > 0
MaxNoFiles = 0 < integer() < 65000
Rec = integer()
Bad = integer()
Head = none | term() | binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
Mode = read_write | read_only
OpenRet = Ret | {error, Reason}
DistOpenRet = {[{Node, Ret}], [{BadNode, {error, DistReason}}]}
Node = BadNode = atom()
Ret = {ok, Log} | {repaired, Log, {recovered, Rec}, {badbytes, Bad}}
DistReason = nodedown | Reason
Reason = no_such_log | {badarg, Arg} | {size_mismatch, CurrentSize, NewSize} | {arg_mismatch, OptionName, CurrentValue,
Value} | {name_already_open, Log} | {open_read_write, Log} | {open_read_only, Log} | {need_repair, Log} | {not_a_log_file,
FileName} | {invalid_index_file, FileName} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError} |
{node_already_open, Log}
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 mes-
sage 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 out-
come 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, Name}} 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) dis-
tributed 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 dis-
tributing 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,Rea-
son},[{disk_log,open,1}]} . The function returns {error, Reason} for all other errors.
pid2name(Pid) -> {ok, Log} | undefined
Types Log = term()
Pid = pid()
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)
reopen(Log, File, Head)
breopen(Log, File, BHead) -> ok | {error, Reason}
Types Log = term()
File = string()
Head = term()
BHead = binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {same_file_name, Log} | {invalid_index_file,
FileName} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError}
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, Reason}
Types Log = term()
Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {file_error, FileName, FileError}
The sync/1 function ensures that the contents of the log are actually written to the disk. This is usually a rather expensive opera-
tion.
truncate(Log)
truncate(Log, Head)
btruncate(Log, BHead) -> ok | {error, Reason}
Types Log = term()
Head = term()
BHead = binary() | [Byte]
Byte = [Byte] | 0 =< integer() =< 255
Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {invalid_header, InvalidHeader} | {file_error,
FileName, FileError}
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,Rea-
son},[{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, Reason}
Types Log = term()
Reason = 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)
Ericsson AB kernel 2.14.3 disk_log(3erl)