Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

src upload

  • Loading branch information...
commit 6159d9a796ea73bf7d6a7d4224bfe601a47f740d 1 parent a7a5426
@ahmednawras ahmednawras authored
View
41 CHANGELOG.txt
@@ -0,0 +1,41 @@
+log4erl 0.8.3:
+==============
+* Added console_appender
+* Added more modifiers to the possible pattern of formats (milliseconds, short/long name of month)
+* Added an extra atom in the tuple argument for add_file_appender/2,3 for specifying format
+* Fixed a bug when rotation. (_02)
+
+log4erl 0.8.2:
+==============
+* Fixed issues with log4erl process not part of the supervisor
+* Added support for simple log formatters (similar to Layouts in Log4J)
+* Added change_format/2,3
+* Added change_log_level/1,2
+* Added get_appenders/0,1
+
+Known issues:
+- When file_appender crashes, the format is lost and log4erl will use the
+ default format
+
+log4erl 0.8.1:
+==============
+* Fixed unnecessary formatting of date/time for file_appender
+* Added add_file_appender/2, add_file_appender/3
+* Added add_dummy_appender/2, add_dummy_appender/3
+
+log4erl 0.8:
+============
+* Added the notion of appenders in order to allow different appenders
+for loggers and changed API to reflect this
+* Fixed restarting issues when appenders crash
+* Added dummy_appender for testing multiple appenders
+* Added get_appenders/0,1 function
+
+log4erl 0.7.1:
+==============
+* Changed default behaviour of new file_logger to append in order to preserve previous logs.
+* Changed file_logger_guard.erl to logger_guard.erl because this module will be useful once more
+ logger types are added (e.g. SNMP loggers, Syslog loggers...).
+* Added a function to change log level of loggers during run-time.
+* moved utility functions in file_logger.erl to log4erl_utils.
+* Added log_manager.erl in order to easily allow for more logger types
View
470 LICENSE.txt
@@ -0,0 +1,470 @@
+ MOZILLA PUBLIC LICENSE
+ Version 1.1
+
+ ---------------
+
+1. Definitions.
+
+ 1.0.1. "Commercial Use" means distribution or otherwise making the
+ Covered Code available to a third party.
+
+ 1.1. "Contributor" means each entity that creates or contributes to
+ the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Code, prior Modifications used by a Contributor, and the Modifications
+ made by that particular Contributor.
+
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case
+ including portions thereof.
+
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally
+ accepted in the software development community for the electronic
+ transfer of data.
+
+ 1.5. "Executable" means Covered Code in any form other than Source
+ Code.
+
+ 1.6. "Initial Developer" means the individual or entity identified
+ as the Initial Developer in the Source Code notice required by Exhibit
+ A.
+
+ 1.7. "Larger Work" means a work which combines Covered Code or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.8. "License" means this document.
+
+ 1.8.1. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means any addition to or deletion from the
+ substance or structure of either the Original Code or any previous
+ Modifications. When Covered Code is released as a series of files, a
+ Modification is:
+ A. Any addition to or deletion from the contents of a file
+ containing Original Code or previous Modifications.
+
+ B. Any new file that contains any part of the Original Code or
+ previous Modifications.
+
+ 1.10. "Original Code" means Source Code of computer software code
+ which is described in the Source Code notice required by Exhibit A as
+ Original Code, and which, at the time of its release under this
+ License is not already Covered Code governed by this License.
+
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.11. "Source Code" means the preferred form of the Covered Code for
+ making modifications to it, including all modules it contains, plus
+ any associated interface definition files, scripts used to control
+ compilation and installation of an Executable, or source code
+ differential comparisons against either the Original Code or another
+ well known, available Covered Code of the Contributor's choice. The
+ Source Code can be in a compressed or archival form, provided the
+ appropriate decompression or de-archiving software is widely available
+ for no charge.
+
+ 1.12. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of, this
+ License or a future version of this License issued under Section 6.1.
+ For legal entities, "You" includes any entity which controls, is
+ controlled by, or is under common control with You. For purposes of
+ this definition, "control" means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty percent
+ (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+
+2. Source Code License.
+
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Code (or portions thereof) with or without Modifications, and/or
+ as part of a Larger Work; and
+
+ (b) under Patents Claims infringed by the making, using or
+ selling of Original Code, to make, have made, use, practice,
+ sell, and offer for sale, and/or otherwise dispose of the
+ Original Code (or portions thereof).
+
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ Original Code under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: 1) for code that You delete from the Original Code; 2)
+ separate from the Original Code; or 3) for infringements caused
+ by: i) the modification of the Original Code or ii) the
+ combination of the Original Code with other software or devices.
+
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor
+ hereby grants You a world-wide, royalty-free, non-exclusive license
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor, to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof) either on an
+ unmodified basis, with other Modifications, as Covered Code
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either alone
+ and/or in combination with its Contributor Version (or portions
+ of such combination), to make, use, sell, offer for sale, have
+ made, and/or otherwise dispose of: 1) Modifications made by that
+ Contributor (or portions thereof); and 2) the combination of
+ Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first makes Commercial Use of
+ the Covered Code.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: 1) for any code that Contributor has deleted from the
+ Contributor Version; 2) separate from the Contributor Version;
+ 3) for infringements caused by: i) third party modifications of
+ Contributor Version or ii) the combination of Modifications made
+ by that Contributor with other software (except as part of the
+ Contributor Version) or other devices; or 4) under Patent Claims
+ infringed by Covered Code in the absence of Modifications made by
+ that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Application of License.
+ The Modifications which You create or to which You contribute are
+ governed by the terms of this License, including without limitation
+ Section 2.2. The Source Code version of Covered Code may be
+ distributed only under the terms of this License or a future version
+ of this License released under Section 6.1, and You must include a
+ copy of this License with every copy of the Source Code You
+ distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this
+ License or the recipients' rights hereunder. However, You may include
+ an additional document offering the additional rights described in
+ Section 3.5.
+
+ 3.2. Availability of Source Code.
+ Any Modification which You create or to which You contribute must be
+ made available in Source Code form under the terms of this License
+ either on the same media as an Executable version or via an accepted
+ Electronic Distribution Mechanism to anyone to whom you made an
+ Executable version available; and if made available via Electronic
+ Distribution Mechanism, must remain available for at least twelve (12)
+ months after the date it initially became available, or at least six
+ (6) months after a subsequent version of that particular Modification
+ has been made available to such recipients. You are responsible for
+ ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+
+ 3.3. Description of Modifications.
+ You must cause all Covered Code to which You contribute to contain a
+ file documenting the changes You made to create that Covered Code and
+ the date of any change. You must include a prominent statement that
+ the Modification is derived, directly or indirectly, from Original
+ Code provided by the Initial Developer and including the name of the
+ Initial Developer in (a) the Source Code, and (b) in any notice in an
+ Executable version or related documentation in which You describe the
+ origin or ownership of the Covered Code.
+
+ 3.4. Intellectual Property Matters
+ (a) Third Party Claims.
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+
+ (b) Contributor APIs.
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+
+ (c) Representations.
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+
+ 3.5. Required Notices.
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code. If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice. If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A. You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code. You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+
+ 3.6. Distribution of Executable Versions.
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+
+ 3.7. Larger Works.
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Application of this License.
+
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+ 6.1. New Versions.
+ Netscape Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+
+ 6.2. Effect of New Versions.
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by Netscape. No one
+ other than Netscape has the right to modify the terms applicable to
+ Covered Code created under this License.
+
+ 6.3. Derivative Works.
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ Netscape Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+ 8.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+
+ 8.2. If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant") alleging that:
+
+ (a) such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant. If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+
+ (b) any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+
+ 8.3. If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 8.4. In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+
+11. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the NPL or the alternative licenses, if any, specified
+ by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+ ``The contents of this file are subject to the Mozilla Public License
+ Version 1.1 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations
+ under the License.
+
+ The Original Code is ______________________________________.
+
+ The Initial Developer of the Original Code is ________________________.
+ Portions created by ______________________ are Copyright (C) ______
+ _______________________. All Rights Reserved.
+
+ Contributor(s): ______________________________________.
+
+ Alternatively, the contents of this file may be used under the terms
+ of the _____ license (the "[___] License"), in which case the
+ provisions of [______] License are applicable instead of those
+ above. If you wish to allow use of your version of this file only
+ under the terms of the [____] License and not to allow others to use
+ your version of this file under the MPL, indicate your decision by
+ deleting the provisions above and replace them with the notice and
+ other provisions required by the [___] License. If you do not delete
+ the provisions above, a recipient may use your version of this file
+ under either the MPL or the [___] License."
+
+ [NOTE: The text of this Exhibit A may differ slightly from the text of
+ the notices in the Source Code files of the Original Code. You should
+ use the text of this Exhibit A rather than the text found in the
+ Original Code Source Code for Your Modifications.]
+
View
17 Makefile
@@ -0,0 +1,17 @@
+SRC = src
+
+all: subdirs
+
+subdirs:
+ cd ${SRC}; make
+
+# remove all the code
+clean:
+ rm -rf ebin/*.beam erl_crash.dump
+ rm -f *~
+ rm -f src/*~
+ rm -f ebin/*~
+ rm -f include/*~
+# cd dir1; make clean
+#install:
+# cp -f ebin/* ../../www/ebin
View
18 TODO.txt
@@ -0,0 +1,18 @@
+TODO:
+=====
+
+* Add formatters functions that can be added to appenders to change
+default formatting patters [DONE]
+* Add support for pattern appender [DONE]
+* Update manual [DONE (latest for log4erl 0.8.2)]
+* Add performance benchmarks
+* Add support for file-based configuration to log4erl instead of only
+programmable-only configuration that is working now
+* Add support for SNMP appender
+* Add support for DB appender (MySQL, Postgres?, Mnesia,...etc)
+* Add support for SMTP appender
+* Add support for NT event appender
+* Add support for syslog appender
+* Add support for NDC/MDC
+* Add support for time-based log rotation (file_appender)
+
View
46 include/log4erl.hrl
@@ -0,0 +1,46 @@
+-define(ROTATION_CHECK, 10).
+
+-define(DEFAULT_CONF,"log4erl.conf").
+
+-define(DEFAULT_FORMAT, "[%L] %l%n").
+
+-define(DEFAULT_LEVEL, warn).
+
+-define(DEFAULT_LOGGER, default_logger).
+-define(DEFAULT_LOGGER_GUARD, default_logger_guard).
+
+-define(FILE_OPTIONS,[write, raw, binary, append]).
+-define(FILE_OPTIONS_ROTATE,[write, raw, binary]).
+
+%-define(DEBUG, true).
+
+-ifdef(DEBUG).
+-define(LOG(X), io:format("~p: " ++ X,[?MODULE])).
+-define(LOG2(X,D), io:format("~p: " ++ X,[?MODULE | D])).
+-else.
+-define(LOG(_X), ok).
+-define(LOG2(_X,_D), ok).
+-endif.
+
+
+%% type = time | size
+%% max = seconds (for time) | or kiloBytes (for size)
+-record(log_type,{type, max, timer}).
+
+%% file_name = the name of the file without counter
+%% fd = the descriptior for the file
+%% counter = current counter, used for appending to file_name in case of rotation
+%% log_type is a log_type record
+%% rotation = number of rotation before the logger wraps around the coutner (>1)
+%% suffix = suffix of file name (e.g. txt)
+%% The filename of a log is file_name ++ "_" ++ counter ++ "." ++ suffix
+%% e.g. log_1.txt
+%% tokens = format tokens generated from log_formatter:parse/1
+-record(file_appender, {dir, file_name, fd, counter, log_type, rotation, suffix, level, format}).
+
+-record(console_appender, {level, format}).
+
+-record(rotation_state, {state, timer}).
+
+%% log record
+-record(log, {level, msg, data, time, millis}).
View
1  priv/file_logger.conf
@@ -0,0 +1 @@
+{"logs", "flogger", {size, 10000}, 3, "txt", all, "%j %T [%L] %l%n"}.
View
1  priv/logger1.conf
@@ -0,0 +1 @@
+{"../logs", "logger1", {size, 1000000}, -3, "logs", all}.
View
1  priv/logger2.conf
@@ -0,0 +1 @@
+{"../logs","logger2", {size, 500000}, 2, "elog", all}.
View
46 src/Makefile
@@ -0,0 +1,46 @@
+# leave these lines alone
+.SUFFIXES: .erl .beam .yrl
+
+.erl.beam:
+ erlc -o $(EBIN_DIR) -W $<
+
+.yrl.erl:
+ erlc -o $(EBIN_DIR) -W $<
+
+SOURCE_DIR=src
+EBIN_DIR=../ebin
+INCLUDE_DIR=include
+#SRC=$(wildcard $(SOURCE_DIR)/*)
+ERL = erl -o $(EBIN_DIR) -I ${INCLUDE_DIR}
+SRC = src
+
+# Here's a list of the erlang modules you want compiling
+# If the modules don't fit onto one line add a \ character
+# to the end of the line and continue on the next line
+# Edit the lines below
+MODS = log4erl_sup log4erl file_appender console_appender log_manager logger_guard log4erl_utils dummy_appender log_formatter
+
+all: compile
+
+#compile: ${MODS:%=%.beam} #application
+#compile: ${SRC}/${MODS:%=%.beam}
+compile: ${MODS:%=%.beam}
+
+## special compilation requirements are added here
+#.beam:
+# ${ERL} -W0 *.erl
+
+application: compile
+# ${ERL} -pa ebin -o ${EBIN_DIR} -s application start Arg1 Arg2
+
+run:
+ ${ERL} -pa ebin -s test test
+# the subdirs target compiles any code in
+# sub-directories
+#subdirs:
+# cd dir1; make
+
+# remove all the code
+clean:
+ rm -rf ../ebin/*.beam erl_crash.dump
+# cd dir1; make clean
View
57 src/console_appender.erl
@@ -0,0 +1,57 @@
+-module(console_appender).
+
+-include("../include/log4erl.hrl").
+
+-behaviour(gen_event).
+%% gen_event callbacks
+-export([init/1, handle_event/2, handle_call/2,
+ handle_info/2, terminate/2, code_change/3]).
+
+init({Level}) ->
+ init({Level, ?DEFAULT_FORMAT});
+init({Level, Format} = _Args) ->
+ ?LOG2("Initializing console_appender with args = ~p~n",[_Args]),
+ {ok, Toks} = log_formatter:parse(Format),
+ ?LOG2("Tokens received is ~p",[Toks]),
+ State = #console_appender{level = Level, format = Toks},
+ ?LOG2("State is ~p",[State]),
+ {ok, State}.
+
+handle_event({change_level, Level}, State) ->
+ State2 = State#console_appender{level = Level},
+ ?LOG2("Changed level to ~p~n",[Level]),
+ {ok, State2};
+handle_event({log,LLog}, State) ->
+ ?LOG2("handl_event:log = ~p~n",[LLog]),
+ do_log(LLog, State),
+ {ok, State}.
+
+handle_call({change_format, Format}, State) ->
+ ?LOG2("Old State in console_appender is ~p~n",[State]),
+ {ok, Tokens} = log_formatter:parse(Format),
+ ?LOG2("Adding format of ~p~n",[Tokens]),
+ State1 = State#console_appender{format=Tokens},
+ {ok, ok, State1};
+handle_call(_Request, State) ->
+ Reply = ok,
+ {ok, Reply, State}.
+
+handle_info(_Info, State) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+do_log(#log{level = L} = Log,#console_appender{level=Level, format=Format}) ->
+ ToLog = log4erl_utils:to_log(L, Level),
+ case ToLog of
+ true ->
+ M = log_formatter:format(Log, Format),
+ ?LOG2("console_appender result message is ~s~n",[M]),
+ io:format(M);
+ false ->
+ ok
+ end.
View
32 src/dummy_appender.erl
@@ -0,0 +1,32 @@
+-module(dummy_appender).
+
+-include("../include/log4erl.hrl").
+
+-behaviour(gen_event).
+%% gen_event callbacks
+-export([init/1, handle_event/2, handle_call/2,
+ handle_info/2, terminate/2, code_change/3]).
+
+-record(state, {}).
+
+init(_Args) ->
+ io:format("Initializing dummy_appender with args = ~p~n",[_Args]),
+ {ok, #state{}}.
+
+handle_event(_Event, State) ->
+ io:format("dummy_appender received event ~p~n",[_Event]),
+ {ok, State}.
+
+handle_call(_Request, State) ->
+ Reply = ok,
+ {ok, Reply, State}.
+
+handle_info(_Info, State) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
View
147 src/file_appender.erl
@@ -0,0 +1,147 @@
+-module(file_appender).
+
+-author("Ahmed Al-Issaei").
+-license("MPL-1.1").
+
+-behaviour(gen_event).
+
+-include("../include/log4erl.hrl").
+-include_lib("kernel/include/file.hrl").
+
+%% gen_event callbacks
+-export([init/1, handle_event/2, handle_call/2,
+ handle_info/2, terminate/2, code_change/3]).
+
+%%======================================
+%% gen_event callback functions
+%%======================================
+init({Dir, Fname, {Type, Max}, Rot, Suf, Level})->
+ ?LOG("file_appender:init() - with default format~n"),
+ init({Dir, Fname, {Type, Max}, Rot, Suf, Level, ?DEFAULT_FORMAT});
+%% This one with custom format
+init({Dir, Fname, {Type, Max}, Rot, Suf, Level, Pattern} = _Conf) ->
+ ?LOG("file_appender:init() - 1~n"),
+ File = Dir ++ "/" ++ Fname ++ "." ++ Suf,
+ {ok, Fd} = file:open(File, ?FILE_OPTIONS),
+ Ltype = #log_type{type = Type, max = Max},
+ % Check Rot >= 0
+ Rot1 = case Rot < 0 of
+ true ->
+ 0;
+ false ->
+ Rot
+ end,
+ ?LOG2("To parse format with customer format ~p~n",[Pattern]),
+ {ok, Format} = log_formatter:parse(Pattern),
+ ?LOG2("Adding format of ~p~n",[Format]),
+ State = #file_appender{dir = Dir, file_name = Fname, fd = Fd, counter=0,
+ log_type = Ltype, rotation = Rot1, suffix=Suf,
+ level=Level, format=Format},
+ ?LOG2("file_appender:init() with conf ~p~n",[State]),
+ {ok, State};
+init(Conf) when is_list(Conf) ->
+ ?LOG2("file_appender:init() ~p~n",[Conf]),
+ case file:consult(Conf) of
+ {error, Reason} ->
+ error_logger:error_msg("file_appender: couldn't consult Conf file~n"),
+ {error, file:format_error(Reason)};
+ {ok, [Terms]} ->
+ init(Terms)
+ end;
+init(_N) ->
+ ?LOG2("file_appender:init() with parameter ~p~n",[_N]),
+ {ok, #file_appender{}}.
+
+handle_event({change_level, Level}, State) ->
+ State2 = State#file_appender{level = Level},
+ ?LOG2("Changed level to ~p~n",[Level]),
+ {ok, State2};
+handle_event({log,LLog}, State) ->
+ ?LOG2("handl_event:log = ~p~n",[LLog]),
+ do_log(LLog, State),
+ Res = check_rotation(State),
+ {ok, Res}.
+
+
+handle_call({change_format, Format}, State) ->
+ ?LOG2("Old State in file_appender is ~p~n",[State]),
+ {ok, Tokens} = log_formatter:parse(Format),
+ ?LOG2("Adding format of ~p~n",[Tokens]),
+ State1 = State#file_appender{format=Tokens},
+ {ok, ok, State1};
+handle_call(_Request, State) ->
+ Reply = ok,
+ {ok, Reply, State}.
+
+handle_info(_Info, State) ->
+ ?LOG2("~w received unknown message: ~p~n", [?MODULE, _Info]),
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%======================================
+%% internal callback functions
+%%======================================
+do_log(#log{level = L} = Log,#file_appender{fd = Fd, level=Level, format=Format} = _State) when is_atom(L) ->
+ ?LOG2("Formatting ~p~n",[Format]),
+ ToLog = log4erl_utils:to_log(L, Level),
+ case ToLog of
+ true ->
+ M = log_formatter:format(Log, Format),
+ file:write(Fd, M);
+ false ->
+ ok
+ end;
+do_log(_Other, _State) ->
+ ?LOG2("unknown level ~p~n",[_Other]),
+ ok.
+
+rotate(#file_appender{fd = Fd, dir=Dir, file_name=Fn, counter=Cntr, rotation=Rot, suffix=Suf, log_type=Ltype, level=Level, format=Format} = _S) ->
+ file:close(Fd),
+ ?LOG("Starting rotation~n"),
+ C = if
+ Rot == 0 ->
+ 0;
+ Cntr >= Rot ->
+ 1;
+ true ->
+ Cntr+1
+ end,
+ Src = Dir ++ "/" ++ Fn ++ "." ++ Suf,
+ Fname = case C of
+ 0 ->
+ Dir ++ "/" ++ Fn ++ "." ++ Suf;
+ _ ->
+ Dir ++ "/" ++ Fn ++ "_" ++ integer_to_list(C) ++ "." ++ Suf
+ end,
+ ?LOG2("Renaming file from ~p to ~p~n",[Src, Fname]),
+ file:copy(Src, Fname),
+ {ok ,Fd2} = file:open(Src, ?FILE_OPTIONS_ROTATE),
+ State2 = #file_appender{dir = Dir, file_name = Fn, fd = Fd2, counter=C, log_type = Ltype, rotation = Rot, suffix=Suf, level=Level, format=Format},
+ {ok, State2}.
+
+% Check if the file needs to be rotated
+% ignore in case of if log type is set to time instead of size
+check_rotation(State) ->
+ #file_appender{dir=Dir, file_name=Fname, log_type = #log_type{type=T, max=Max}, suffix=Suf} = State,
+ case T of
+ size ->
+ File = Dir ++ "/" ++ Fname ++ "." ++ Suf,
+ {ok, Finfo} = file:read_file_info(File),
+ Size = Finfo#file_info.size,
+ if
+ Size > Max ->
+ {ok, State2} = rotate(State),
+ State2;
+ true ->
+ State
+ end;
+ %% time-based rotation is not implemented yet
+ _ ->
+ State
+ end.
+
View
219 src/log4erl.erl
@@ -0,0 +1,219 @@
+-module(log4erl).
+
+-author("Ahmed Al-Issaei").
+-license("MPL-1.1").
+
+-behaviour(gen_server).
+-behaviour(application).
+
+-include("../include/log4erl.hrl").
+
+%% API
+-export([start_link/1]).
+
+-export([change_log_level/1, change_log_level/2]).
+-export([add_logger/1]).
+-export([add_appender/2, add_appender/3]).
+-export([add_file_appender/2, add_file_appender/3]).
+-export([add_console_appender/2, add_console_appender/3]).
+-export([add_dummy_appender/2, add_dummy_appender/3]).
+-export([get_appenders/0, get_appenders/1]).
+-export([change_format/2, change_format/3]).
+
+-export([log/2, log/3, log/4]).
+
+-export([warn/1, warn/2, warn/3]).
+-export([info/1, info/2, info/3]).
+-export([error/1, error/2, error/3]).
+-export([fatal/1, fatal/2, fatal/3]).
+-export([debug/1, debug/2, debug/3]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+start_link(Default_logger) ->
+ %log4erl_sup:add_logger(Default_logger),
+ ?LOG("Starting process log4erl"),
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [Default_logger], []).
+
+add_logger(Logger) ->
+ try_msg({add_logger, Logger}).
+
+%% Appender = {Appender, Name}
+add_appender(Appender, Conf) ->
+ try_msg({add_appender, Appender, Conf}).
+
+%% Appender = {Appender, Name}
+add_appender(Logger, Appender, Conf) ->
+ try_msg({add_appender, Logger, Appender, Conf}).
+
+add_console_appender(AName, Conf) ->
+ add_appender({console_appender, AName}, Conf).
+
+add_console_appender(Logger, AName, Conf) ->
+ add_appender(Logger, {console_appender, AName}, Conf).
+
+add_file_appender(AName, Conf) ->
+ add_appender({file_appender, AName}, Conf).
+
+add_file_appender(Logger, AName, Conf) ->
+ add_appender(Logger, {file_appender, AName}, Conf).
+
+add_dummy_appender(AName, Conf) ->
+ add_appender({dummy_appender, AName}, Conf).
+
+add_dummy_appender(Logger, AName, Conf) ->
+ add_appender(Logger, {dummy_appender, AName}, Conf).
+
+get_appenders() ->
+ try_msg(get_appenders).
+
+get_appenders(Logger) ->
+ try_msg({get_appenders, Logger}).
+
+change_format(Appender, Format) ->
+ try_msg({change_format, Appender, Format}).
+change_format(Logger, Appender, Format) ->
+ try_msg({change_format, Logger, Appender, Format}).
+
+%% For default logger
+change_log_level(Level) ->
+ try_msg({change_level, Level}).
+change_log_level(Logger, Level) ->
+ try_msg({change_level, Logger, Level}).
+
+try_msg(Msg) ->
+ try
+ gen_server:call(?MODULE, Msg)
+ catch
+ exit:{noproc, _M} ->
+ io:format("log4erl has not been initialized yet. To do so, please run~n"),
+ io:format("> application:start(log4erl).~n"),
+ {error, log4erl_not_started};
+ E:M ->
+ ?LOG2("Error message received by log4erl is ~p:~p~n",[E, M]),
+ {E, M}
+ end.
+
+log(Level, Log) ->
+ log(Level, Log, []).
+log(Level, Log, Data) ->
+ try_msg({log, Level, Log, Data}).
+log(Logger, Level, Log, Data) ->
+ try_msg({log, Logger, Level, Log, Data}).
+
+warn(Log) ->
+ log(warn, Log).
+%% If 1st parameter is atom, then it is Logger
+warn(Logger, Log) when is_atom(Logger) ->
+ log(Logger, warn, Log, []);
+warn(Log, Data) ->
+ log(warn, Log, Data).
+warn(Logger, Log, Data) ->
+ log(Logger, warn , Log, Data).
+
+info(Log) ->
+ log(info, Log).
+info(Logger, Log) when is_atom(Logger) ->
+ log(Logger, info, Log, []);
+info(Log, Data) ->
+ log(info, Log, Data).
+info(Logger, Log, Data) ->
+ log(Logger, info, Log, Data).
+
+error(Log) ->
+ log(error, Log).
+error(Logger, Log) when is_atom(Logger) ->
+ log(Logger, error, Log, []);
+error(Log, Data) ->
+ log(error, Log, Data).
+error(Logger, Log, Data) ->
+ log(Logger, error, Log, Data).
+
+fatal(Log) ->
+ log(fatal, Log).
+fatal(Logger, Log) when is_atom(Logger) ->
+ log(Logger, fatal, Log, []);
+fatal(Log, Data) ->
+ log(fatal, Log, Data).
+fatal(Logger, Log, Data) ->
+ log(Logger, fatal, Log, Data).
+
+debug(Log) ->
+ log(debug, Log).
+debug(Logger, Log) when is_atom(Logger) ->
+ log(Logger, debug, Log, []);
+debug(Log, Data) ->
+ log(debug, Log, Data).
+debug(Logger, Log, Data) ->
+ log(Logger, debug, Log, Data).
+
+%%======================================
+%% gen_server callback functions
+%%======================================
+init([Default_logger]) ->
+ ?LOG2("starting log4erl server with default_logger ~p~n",[Default_logger]),
+ {ok, {default_logger, Default_logger}}.
+
+%% No logger specified? use default logger
+handle_call({add_logger, Logger}, _From, State) ->
+ log_manager:add_logger(Logger),
+ {reply, ok, State};
+handle_call({add_appender, Appender, Conf}, _From, {default_logger, DL} = State) ->
+ log_manager:add_appender(DL, Appender, Conf),
+ {reply, ok, State};
+handle_call({add_appender, Logger, Appender, Conf}, _From, State) ->
+ log_manager:add_appender(Logger, Appender, Conf),
+ {reply, ok, State};
+handle_call(get_appenders, _From, {default_logger, DL} = State) ->
+ Reply = gen_event:which_handlers(DL),
+ {reply, Reply, State};
+handle_call({get_appenders, Logger}, _From, State) ->
+ Reply = gen_event:which_handlers(Logger),
+ {reply, Reply, State};
+handle_call({change_level, Level}, _From, {default_logger, DL} = State) ->
+ log_manager:change_level(DL, Level),
+ {reply, ok, State};
+handle_call({change_level, Logger, Level}, _From, State) ->
+ log_manager:change_level(Logger, Level),
+ {reply, ok, State};
+handle_call({change_format, Appender, Format}, _From, {default_logger,DL} = State) ->
+ log_manager:change_format(DL, Appender, Format),
+ {reply, ok, State};
+handle_call({change_format, Logger, Appender, Format}, _From, State) ->
+ log_manager:change_format(Logger, Appender, Format),
+ {reply, ok, State};
+handle_call({log, Level, Log, Data}, _From, {default_logger, Logger} = State) ->
+ log_manager:log(Logger, Level, Log, Data),
+ {reply, ok, State};
+handle_call({log, Logger, Level, Log, Data} , _From, State) ->
+ log_manager:log(Logger, Level, Log, Data),
+ {reply, ok, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%======================================
+%% application callback functions
+%%======================================
+start(_Type, [Arg]) ->
+ ?LOG("Starting log4erl app~n"),
+ log4erl_sup:start_link(Arg).
+
+stop(_State) ->
+ ok.
+
+
View
74 src/log4erl_sup.erl
@@ -0,0 +1,74 @@
+-module(log4erl_sup).
+
+-author("Ahmed Al-Issaei").
+-license("MPL-1.1").
+
+-behaviour(supervisor).
+
+-include("../include/log4erl.hrl").
+
+%% API
+-export([start_link/1]).
+-export([add_logger/1]).
+-export([add_guard/4]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link(Default_logger) ->
+ R = supervisor:start_link({local, ?MODULE}, ?MODULE, [Default_logger]),
+ %log4erl:start_link(Default_logger),
+ add_logger(Default_logger),
+ ?LOG2("Result in supervisor is ~p~n",[R]),
+ R.
+
+add_guard(Logger, Appender, Name, Conf) ->
+ C = {Name,
+ {logger_guard, start_link ,[Logger, Appender, Name, Conf]},
+ permanent,
+ 10000,
+ worker,
+ [logger_guard]},
+ ?LOG2("Adding ~p to ~p~n",[C, ?MODULE]),
+ supervisor:start_child(?MODULE, C).
+
+add_logger(Name) when is_atom(Name) ->
+ N = atom_to_list(Name),
+ add_logger(N);
+add_logger(Name) when is_list(Name) ->
+ C1 = {Name,
+ {log_manager, start_link ,[Name]},
+ permanent,
+ 10000,
+ worker,
+ [log_manager]},
+
+ ?LOG2("Adding ~p to ~p~n",[C1, ?MODULE]),
+ supervisor:start_child(?MODULE, C1).
+ %add_guard(N2).
+
+%%======================================
+%% supervisor callback functions
+%%======================================
+init([Default_logger]) ->
+ ?LOG("Starting supervisor~n"),
+ %% No children to be added yet.
+ %% The default has to be added from log4erl
+
+ % start log4erl gen_server
+ _Child = {log4erl,
+ {log4erl, start_link ,[Default_logger]},
+ permanent,
+ 10000,
+ worker,
+ [log4erl]},
+
+ {ok,
+ {
+ {one_for_one,3,10},
+ [_Child]
+ %[]
+ }
+ }.
+
+
View
122 src/log4erl_utils.erl
@@ -0,0 +1,122 @@
+-module(log4erl_utils).
+
+-export([gen_log_txt/1,return_2columns/1, get_current_time/1, to_log/2]).
+-export([get_id/0, get_month_name/1, get_month_long_name/1]).
+
+% a function to make the log level text look pretty
+gen_log_txt(L) when is_list(L) ->
+ case string:len(L) of
+ 1 ->
+ "[" ++ L ++ "] ";
+ 2 ->
+ "[" ++ L ++ "] ";
+ 3 ->
+ "[" ++ L ++ "] ";
+ 4 ->
+ "[" ++ L ++ "] ";
+ _ ->
+ "[" ++ L ++ "]"
+ end.
+
+% a function to format date/time properly (e.g. 09 instead of 9)
+return_2columns(X) ->
+ case length(X) of
+ 1 ->
+ "0" ++ X;
+ _ ->
+ X
+ end.
+
+% returns date/time as a properly formatted string (e.g. "01-01-2000 12:12:12")
+%get_current_time() ->
+get_current_time({{Y, M, D}, {H, Mi, S}}) ->
+ %{{Y, M, D}, {H, Mi, S}} = calendar:local_time(),
+ L = lists:map(fun(X) ->
+ X2=integer_to_list(X),
+ return_2columns(X2)
+ end,
+ [Y, M, D, H, Mi, S]
+ ),
+ [Y2, M2, D2, H2, Mi2, S2] = L,
+ Y2 ++ "-" ++ M2 ++ "-" ++ D2 ++ " " ++ H2 ++ ":" ++ Mi2 ++ ":" ++ S2.
+
+%% DEBUG <- INFO <- WARN <- ERROR <- FATAL
+%% user defined levels are always logged
+to_log(Cur, Level) ->
+ case Level of
+ debug ->
+ true;
+ info ->
+ ((Cur == info) or (Cur == warn) or (Cur == error) or (Cur == fatal));
+ warn ->
+ ((Cur == warn) or (Cur == error) or (Cur == fatal));
+ error ->
+ ((Cur == error) or (Cur == fatal));
+ fatal ->
+ (Cur == fatal);
+ none ->
+ false;
+ _ ->
+ true
+ end.
+
+get_id() ->
+ {_,_,N} = now(),
+ Id = "log4erl_" ++ integer_to_list(random:uniform(N)),
+ list_to_atom(Id).
+
+get_month_name(Month) ->
+ case Month of
+ 1 ->
+ "Jan";
+ 2 ->
+ "Feb";
+ 3 ->
+ "Mar";
+ 4 ->
+ "Apr";
+ 5 ->
+ "May";
+ 6 ->
+ "Jun";
+ 7 ->
+ "Jul";
+ 8 ->
+ "Aug";
+ 9 ->
+ "Sep";
+ 10 ->
+ "Oct";
+ 11 ->
+ "Nov";
+ 12 ->
+ "Dec"
+ end.
+
+get_month_long_name(Month) ->
+ case Month of
+ 1 ->
+ "January";
+ 2 ->
+ "February";
+ 3 ->
+ "March";
+ 4 ->
+ "April";
+ 5 ->
+ "May";
+ 6 ->
+ "June";
+ 7 ->
+ "July";
+ 8 ->
+ "August";
+ 9 ->
+ "September";
+ 10 ->
+ "October";
+ 11 ->
+ "November";
+ 12 ->
+ "December"
+ end.
View
216 src/log_formatter.erl
@@ -0,0 +1,216 @@
+-module(log_formatter).
+
+-compile(export_all).
+
+-include("../include/log4erl.hrl").
+
+%-record(log, {level, msg, data, time}).
+
+test() ->
+ Log = #log{level = warn,
+ msg = "logging message for testing purposes ~p",
+ data = [tt],
+ time = calendar:local_time()},
+ %Ts = "%j %T [%L] - %l %n",
+ Ts = "[%L] %l%n",
+ {ok, Tokens} = parse(Ts),
+ T = format(Log, Tokens),
+ io:format("~s",[T]).
+
+test2(Num) ->
+ Ts = "%j %T [%L] - %l",
+ {ok, Tokens} = parse(Ts),
+ Logs = lists:map(fun(X) ->
+ {X, make_log(warn, "testing a lot", [])}
+ end,
+ lists:seq(1, Num)),
+ lists:map(fun(X) ->
+ N = element(1,X),
+ X1 = element(2, X),
+ X2 = format(X1, Tokens),
+ io:format("~p: ~s~n",[N, X2])
+ end, Logs),
+ ok.
+
+make_log(Level, Msg, Data) ->
+ #log{level = Level,
+ msg = Msg,
+ data = Data,
+ time = calendar:local_time()}.
+
+
+%%%%%%%%%%%%%%%%%%%
+%% functions
+%%%%%%%%%%%%%%%%%%%
+format(Log, Tokens) ->
+ ?LOG2("log_formatter formatting log: ~p~n",[Log]),
+ F = fun(X) ->
+ M = get_token_value(X,Log),
+ M
+ end,
+ L = lists:map(F, Tokens),
+ L.
+
+get_token_value(date, Log) ->
+ D = Log#log.time,
+ {{Y, M, Dd},_} = D,
+ [C,B,A] = lists:map(
+ fun(X) ->
+ integer_to_list(X)
+ end,
+ [Y,M,Dd]),
+ Res = A ++ "-" ++ B ++ "-" ++ C,
+ Res;
+get_token_value(date2, Log) ->
+ D = Log#log.time,
+ {{Y, M, Dd},_} = D,
+ [C,B,A] = lists:map(
+ fun(X) ->
+ X2 = integer_to_list(X),
+ case string:len(X2) > 1 of
+ false ->
+ "0" ++ X2;
+ _ ->
+ X2
+ end
+ end,
+ [Y,M,Dd]),
+ Res = A ++ "-" ++ B ++ "-" ++ C,
+ Res;
+get_token_value(time, Log) ->
+ D = Log#log.time,
+ {_,{H, M, S}} = D,
+ [A,B,C] = lists:map(
+ fun(X) ->
+ integer_to_list(X)
+ end,
+ [H,M,S]),
+ Res = A ++ ":" ++ B ++ ":" ++ C,
+ Res;
+get_token_value(time2, Log) ->
+ D = Log#log.time,
+ Ms = Log#log.millis,
+ {_,{H, M, S}} = D,
+ [A,B,C,E] = lists:map(
+ fun(X) ->
+ X2 = integer_to_list(X),
+ case string:len(X2) > 1 of
+ false ->
+ "0" ++ X2;
+ _ ->
+ X2
+ end
+ end,
+ [H,M,S, Ms]),
+ Res = A ++ ":" ++ B ++ ":" ++ C ++ "," ++ E,
+ Res;
+get_token_value(year4, Log) ->
+ D = Log#log.time,
+ {{Y, _,_},_} = D,
+ integer_to_list(Y);
+get_token_value(year2, Log) ->
+ D = Log#log.time,
+ {{Y, _,_},_} = D,
+ L = integer_to_list(Y),
+ string:substr(L,3,2);
+get_token_value(month, Log) ->
+ {{_, M,_},_} = Log#log.time,
+ integer_to_list(M);
+get_token_value(month2, Log) ->
+ {{_,M,_},_} = Log#log.time,
+ log4erl_utils:get_month_name(M);
+get_token_value(month3, Log) ->
+ {{_, M,_},_} = Log#log.time,
+ log4erl_utils:get_month_long_name(M);
+get_token_value(day, Log) ->
+ D = Log#log.time,
+ {{_, _,Dd},_} = D,
+ integer_to_list(Dd);
+get_token_value(hour, Log) ->
+ D = Log#log.time,
+ {_,{H, _,_}} = D,
+ integer_to_list(H);
+get_token_value(minute, Log) ->
+ D = Log#log.time,
+ {_,{_, M,_}} = D,
+ integer_to_list(M);
+get_token_value(second, Log) ->
+ D = Log#log.time,
+ {_,{_, _,S}} = D,
+ integer_to_list(S);
+get_token_value(millis, Log) ->
+ Ms = Log#log.millis,
+ integer_to_list(Ms);
+get_token_value(log, Log) ->
+ Msg = Log#log.msg,
+ Data = Log#log.data,
+ io_lib:format(Msg, Data);
+get_token_value(level, Log) ->
+ atom_to_list(Log#log.level);
+get_token_value(new_line, _Log) ->
+ "\n";
+get_token_value(A, _Log) ->
+ A.
+
+%%%%%%%%%%%%%%%%%%%
+%% parse functions
+%%%%%%%%%%%%%%%%%%%
+parse(M) ->
+ ?LOG2("log_formatter parsing ~p~n",[M]),
+ try
+ Tokens = parse2(M,[]),
+ ?LOG2("Received tokens ~p~n",[Tokens]),
+ {ok, Tokens}
+ catch
+ E:R ->
+ {error, {E,R}}
+ end.
+
+parse2([], Acc) ->
+ lists:reverse(Acc);
+parse2([$\% | R], Acc) ->
+ [S|R2] = R,
+ T = parse_char(S),
+ parse2(R2,[T|Acc]);
+parse2([S | R], Acc) ->
+ parse2(R, [S|Acc]).
+
+parse_char($d) ->
+ date;
+parse_char($j) ->
+ date2;
+parse_char($t) ->
+ time;
+parse_char($T) ->
+ time2;
+parse_char($y) ->
+ year2;
+parse_char($Y) ->
+ year4;
+% 1
+parse_char($M) ->
+ month;
+% Jan
+parse_char($b) ->
+ month2;
+% January
+parse_char($B) ->
+ month3;
+parse_char($D) ->
+ day;
+parse_char($h) ->
+ hour;
+parse_char($m) ->
+ minute;
+parse_char($s) ->
+ second;
+parse_char($l) ->
+ log;
+parse_char($L) ->
+ level;
+parse_char($n) ->
+ new_line;
+parse_char($i) ->
+ millis;
+parse_char(C) ->
+ C.
View
54 src/log_manager.erl
@@ -0,0 +1,54 @@
+-module(log_manager).
+
+-author("Ahmed Al-Issaei").
+-license("MPL-1.1").
+
+-include("../include/log4erl.hrl").
+
+%% API
+-export([start_link/1]).
+-export([change_level/2]).
+-export([add_logger/1]).
+-export([add_appender/3]).
+-export([change_format/3]).
+-export([log/4]).
+
+start_link(Logger) when is_atom(Logger) ->
+ ?LOG2("log_manager adding Logger ~p~n",[Logger]),
+ gen_event:start_link({local, Logger});
+start_link(Logger) when is_list(Logger) ->
+ ?LOG2("log_manager adding Logger ~p~n",[Logger]),
+ gen_event:start_link({local, list_to_atom(Logger)}).
+
+add_logger(Logger) ->
+ log4erl_sup:add_logger(Logger).
+
+add_appender(Logger, {Appender, Name} , Conf) ->
+ ?LOG2("add_appender ~p with name ~p to ~p with Conf ~p ~n",[Appender, Name, Logger, Conf]),
+ log4erl_sup:add_guard(Logger, Appender, Name, Conf).
+
+change_level(Logger, Level) ->
+ gen_event:notify(Logger, {change_level, Level}).
+
+change_format(Logger, Appender, Format) ->
+ Apps = gen_event:which_handlers(Logger),
+ ?LOG2("log_manager:change_format/3 get apps ~p~n",[Apps]),
+ [Apps1] = lists:filter(fun({_,X}) -> X =:= Appender end, Apps),
+ ?LOG2("get apps: ~p~n",[Apps1]),
+ gen_event:call(Logger, Apps1, {change_format, Format}).
+
+%%--------------------------------------------------------------------
+%% Logger API functions
+%%--------------------------------------------------------------------
+log(Logger, Level, Log, Data) ->
+ T = calendar:local_time(),
+ {_, _, Ms} = erlang:now(),
+ ?LOG2("Logging:~n ~p ~p ~p ~p~n",[Logger, Level, Log, Data]),
+ LL = #log{level=Level, msg=Log, data=Data, time=T, millis = Ms},
+ try
+ gen_event:notify(Logger, {log, LL})
+ catch
+ _E:_R ->
+ ?LOG2("log_manager:log error ~p:~p~n",[_E,_R])
+ end.
+
View
56 src/logger_guard.erl
@@ -0,0 +1,56 @@
+-module(logger_guard).
+
+-author("Ahmed Al-Issaei").
+-license("MPL-1.1").
+
+-behaviour(gen_server).
+
+-include("../include/log4erl.hrl").
+
+%% API
+-export([start_link/4, add_sup_handler/3]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+start_link(Logger, Appender, Name, Conf) ->
+ %?LOG2("starting guard for logger ~p~n",[Logger]),
+ {ok, Pid} = gen_server:start_link(?MODULE, [Appender, Name], []),
+ add_sup_handler(Pid, Logger, Conf),
+ {ok, Pid}.
+
+add_sup_handler(G_pid, Logger, Conf) ->
+ ?LOG("add_sup()~n"),
+ gen_server:call(G_pid, {add_sup_handler, Logger, Conf}).
+
+%%=========================================
+%% gen_server callback functions
+%%=========================================
+init([Appender, Name]) ->
+ ?LOG2("Starting guard ~n",[]),
+ {ok, [{appender, Appender, Name}]}.
+
+handle_call({add_sup_handler, Logger, Conf}, _From, [{appender, Appender, Name}] = State) ->
+ ?LOG2("Adding handler ~p with name ~p for ~p From ~p~n",[Appender, Name, Logger, _From]),
+ gen_event:add_sup_handler(Logger, {Appender, Name}, Conf),
+ {reply, ok, State};
+handle_call(_Msg, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info({gen_event_EXIT, _Mod, R}, State) ->
+ ?LOG2("logger_guard received exit message. Terminating ~p~n",[now]),
+ {stop, {appender_died, R}, State};
+handle_info(_Info, [{appender, _Appender, _Name}] = State) ->
+ ?LOG2("logger_guard received msg ~p for appender ~p with name ~p~n ", [_Info, _Appender, _Name]),
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
Please sign in to comment.
Something went wrong with that request. Please try again.