23 | * Note: To run for the first time you must be Administrator in Windows. 24 | * This application needs to write the registry when run for the first time 25 | *
26 | * 27 | * @author Claudio Trajtenberg 28 | * @author Daniel Doubrovkine 29 | * @author Ceri Storey 30 | */ 31 | public class NewDemo { 32 | 33 | private static Logger LOGGER = LogManager.getLogger(); 34 | 35 | private static final String MSG = "NewDemo: %s"; 36 | 37 | /** 38 | * @param args 39 | */ 40 | public static void main(String[] args) { 41 | NewDemo d = new NewDemo(); 42 | 43 | d.trace(); 44 | d.debug(); 45 | d.info(); 46 | d.warn(); 47 | d.error(); 48 | d.fatal(); 49 | d.warnWithException(); 50 | d.errorWithException(); 51 | d.fatalWithException(); 52 | } 53 | 54 | /** 55 | * 56 | */ 57 | public void trace() { 58 | LOGGER.trace(String.format(MSG, "Enter trace")); 59 | LOGGER.trace(String.format(MSG, "Exit trace")); 60 | } 61 | 62 | /** 63 | * 64 | */ 65 | public void debug() { 66 | LOGGER.debug(String.format(MSG, "Enter debug")); 67 | LOGGER.debug(String.format(MSG, "Exit debug")); 68 | } 69 | 70 | /** 71 | * 72 | */ 73 | public void info() { 74 | LOGGER.info(String.format(MSG, "Enter info")); 75 | LOGGER.info(String.format(MSG, "Exit info")); 76 | } 77 | 78 | /** 79 | * 80 | */ 81 | public void warn() { 82 | LOGGER.warn(String.format(MSG, "Enter warn")); 83 | LOGGER.warn(String.format(MSG, "Exit warn")); 84 | } 85 | 86 | /** 87 | * 88 | */ 89 | public void error() { 90 | LOGGER.error(String.format(MSG, "Enter error")); 91 | LOGGER.error(String.format(MSG, "Exit error")); 92 | } 93 | 94 | /** 95 | * 96 | */ 97 | public void fatal() { 98 | LOGGER.fatal(String.format(MSG, "Enter fatal")); 99 | LOGGER.fatal(String.format(MSG, "Exit fatal")); 100 | } 101 | 102 | /** 103 | * 104 | */ 105 | public void warnWithException() { 106 | try { 107 | throwException(); 108 | } catch (Exception e) { 109 | LOGGER.warn(String.format(MSG, "In warn with exception"), e); 110 | } 111 | } 112 | 113 | /** 114 | * @throws Exception 115 | */ 116 | private void throwException() throws Exception { 117 | throw new Exception("Pouporselly thrown for demo"); 118 | 119 | } 120 | 121 | /** 122 | * 123 | */ 124 | public void errorWithException() { 125 | try { 126 | throwException(); 127 | } catch (Throwable e) { 128 | LOGGER.error(String.format(MSG, "In error with exception"), e); 129 | } 130 | } 131 | 132 | /** 133 | * 134 | */ 135 | public void fatalWithException() { 136 | try { 137 | throwException(); 138 | } catch (Throwable e) { 139 | LOGGER.fatal(String.format(MSG, "In fatal with exception"), e); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Log4JNA 2 | ===================== 3 | 4 | Log4JNA is work of [many contributors](https://github.com/dblock/log4jna/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/dblock/log4jna/pulls), [propose features and discuss issues](https://github.com/dblock/log4jna/issues). 5 | 6 | #### Fork the Project 7 | 8 | Fork the [project on Github](https://github.com/dblock/log4jna) and check out your copy. 9 | 10 | ``` 11 | git clone https://github.com/contributor/log4jna.git 12 | cd log4jna 13 | git remote add upstream https://github.com/dblock/log4jna.git 14 | ``` 15 | 16 | #### Create a Topic Branch 17 | 18 | Make sure your fork is up-to-date and create a topic branch for your feature or bug fix. 19 | 20 | ``` 21 | git checkout master 22 | git pull upstream master 23 | git checkout -b my-feature-branch 24 | ``` 25 | 26 | #### Build and Test 27 | 28 | Ensure that you can build the project and run tests. 29 | 30 | ``` 31 | mvn test 32 | ``` 33 | 34 | ##### Notes on building 35 | 36 | See [Win32EventLogAppender README](log4jna-win32dll/README.md) for requirements on building the the message file. 37 | 38 | The build does not complain and skips the message file if it can't be build. 39 | 40 | #### Write Tests 41 | 42 | Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. 43 | 44 | We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix. 45 | 46 | #### Write Code 47 | 48 | Implement your feature or bug fix. 49 | 50 | Make sure that `mvn test` completes without errors. 51 | 52 | #### Write Documentation 53 | 54 | Document any external behavior in the [README](README.md). 55 | 56 | #### Update Changelog 57 | 58 | Add a line to [CHANGELOG](CHANGELOG.md) under *Next Release*. Make it look like every other line, including your name and link to your Github account. 59 | 60 | #### Commit Changes 61 | 62 | Make sure git knows your name and email address: 63 | 64 | ``` 65 | git config --global user.name "Your Name" 66 | git config --global user.email "contributor@example.com" 67 | ``` 68 | 69 | Writing good commit logs is important. A commit log should describe what changed and why. 70 | 71 | ``` 72 | git add ... 73 | git commit 74 | ``` 75 | 76 | #### Push 77 | 78 | ``` 79 | git push origin my-feature-branch 80 | ``` 81 | 82 | #### Make a Pull Request 83 | 84 | Go to https://github.com/contributor/log4jna and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days. 85 | 86 | #### Rebase 87 | 88 | If you've been working on a change for a while, rebase with upstream/master. 89 | 90 | ``` 91 | git fetch upstream 92 | git rebase upstream/master 93 | git push origin my-feature-branch -f 94 | ``` 95 | 96 | #### Update CHANGELOG Again 97 | 98 | Update the [CHANGELOG](CHANGELOG.md) with the pull request number. A typical entry looks as follows. 99 | 100 | ``` 101 | * [#123](https://github.com/dblock/log4jna/pull/123): Created some new feature - [@contributor](https://github.com/contributor). 102 | ``` 103 | 104 | Amend your previous commit and force push the changes. 105 | 106 | ``` 107 | git commit --amend 108 | git push origin my-feature-branch -f 109 | ``` 110 | 111 | #### Check on Your Pull Request 112 | 113 | Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above. 114 | 115 | #### Be Patient 116 | 117 | It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there! 118 | 119 | #### Thank You 120 | 121 | Please do know that we really appreciate and value your time and work. We love you, really. 122 | -------------------------------------------------------------------------------- /src/site/markdown/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Log4JNA 2 | ===================== 3 | 4 | Log4JNA is work of [many contributors](https://github.com/dblock/log4jna/graphs/contributors). You're encouraged to submit 5 | [pull requests](https://github.com/dblock/log4jna/pulls), [propose features and discuss issues](https://github.com/dblock/log4jna/issues). 6 | 7 | #### Fork the Project 8 | 9 | Fork the [project on Github](https://github.com/dblock/log4jna) and check out your copy. 10 | 11 | ``` 12 | git clone https://github.com/contributor/log4jna.git 13 | cd log4jna 14 | git remote add upstream https://github.com/dblock/log4jna.git 15 | ``` 16 | 17 | #### Create a Topic Branch 18 | 19 | Make sure your fork is up-to-date and create a topic branch for your feature or bug fix. 20 | 21 | ``` 22 | git checkout master 23 | git pull upstream master 24 | git checkout -b my-feature-branch 25 | ``` 26 | 27 | #### Build and Test 28 | 29 | Ensure that you can build the project and run tests. 30 | 31 | ``` 32 | mvn test 33 | ``` 34 | 35 | ##### Notes on building 36 | 37 | See [Win32EventLogAppender README](log4jna-win32dll/README.md) for requirements on building the the message file. 38 | 39 | The build does not complain and skips the message file if it can't be build. 40 | 41 | #### Write Tests 42 | 43 | Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. 44 | 45 | We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix. 46 | 47 | #### Write Code 48 | 49 | Implement your feature or bug fix. 50 | 51 | Make sure that `mvn test` completes without errors. 52 | 53 | #### Write Documentation 54 | 55 | Document any external behavior in the [README](README.md). 56 | 57 | #### Update Changelog 58 | 59 | Add a line to [CHANGELOG](CHANGELOG.md) under *Next Release*. Make it look like every other line, including your name and link to your Github account. 60 | 61 | #### Commit Changes 62 | 63 | Make sure git knows your name and email address: 64 | 65 | ``` 66 | git config --global user.name "Your Name" 67 | git config --global user.email "contributor@example.com" 68 | ``` 69 | 70 | Writing good commit logs is important. A commit log should describe what changed and why. 71 | 72 | ``` 73 | git add ... 74 | git commit 75 | ``` 76 | 77 | #### Push 78 | 79 | ``` 80 | git push origin my-feature-branch 81 | ``` 82 | 83 | #### Make a Pull Request 84 | 85 | Go to https://github.com/contributor/log4jna and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days. 86 | 87 | #### Rebase 88 | 89 | If you've been working on a change for a while, rebase with upstream/master. 90 | 91 | ``` 92 | git fetch upstream 93 | git rebase upstream/master 94 | git push origin my-feature-branch -f 95 | ``` 96 | 97 | #### Update CHANGELOG Again 98 | 99 | Update the [CHANGELOG](CHANGELOG.md) with the pull request number. A typical entry looks as follows. 100 | 101 | ``` 102 | * [#123](https://github.com/dblock/log4jna/pull/123): Created some new feature - [@contributor](https://github.com/contributor). 103 | ``` 104 | 105 | Amend your previous commit and force push the changes. 106 | 107 | ``` 108 | git commit --amend 109 | git push origin my-feature-branch -f 110 | ``` 111 | 112 | #### Check on Your Pull Request 113 | 114 | Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above. 115 | 116 | #### Be Patient 117 | 118 | It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there! 119 | 120 | #### Thank You 121 | 122 | Please do know that we really appreciate and value your time and work. We love you, really. 123 | -------------------------------------------------------------------------------- /src/site/markdown/ENVIRONMENT.md: -------------------------------------------------------------------------------- 1 | # Setting up your development environment 2 | 3 | The first time you run the test suite or any application using Log4JNA, Log4JNA attempts to write the necessary entries in 4 | WindowsTM Registry. If you don't have administrator privileges the run fails. 5 | 6 | ### Running the tests 7 | In order for the tests to pass you must run them as Administrator or set up the registry before your first run. 8 | 9 | Open a command window as administrator and execute `mvn test` 10 | 11 | If you are using an IDE launch it as Administrator import the Maven projects and run the tests. 12 | 13 | ### IDE Setup 14 | 15 | Please be careful and do not check IDE configuration files into GitHub, you can add the project to your IDE following the instructions bellow. 16 | 17 | Eclipse configuration files are already added to `.gitignore`, please add any configuration file created by your IDE to the ignore file. 18 | 19 | #### Eclipse 20 | See [this article](https://books.sonatype.com/m2eclipse-book/reference/creating-sect-importing-projects.html) to import the Maven projects. 21 | 22 | #### IteliJ IDEA 23 | See [this article](https://www.jetbrains.com/help/idea/2016.1/importing-project-from-maven-model.html) to import the Maven projects. 24 | 25 | #### NetBeans 26 | See [this article](http://wiki.netbeans.org/MavenBestPractices) to import the Maven projects. 27 | 28 | ### Set up the Registry manually 29 | #### For Log4JNA Api Tests 30 | 31 | The `Win32EventlogAppender.dll` file is provided in the source as a test asset in 32 | `55 | * Key: 56 | *
57 | *
58 | * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\Log4jnaTest
59 | *
61 | * With entries: 62 | *
63 | * 64 | *65 | * Name:73 | */ 74 | private static final String TEST_LOGGER_NAME = "Log4jnaTest"; 75 | 76 | /** 77 | * The dll file location from theTypesSupported66 | * Type:REG_DWORD67 | * Data:0x768 | * 69 | * Name:CategoryCount70 | * Type:REG_DWORD71 | * Data:0x672 | *
src/test/resources folder.
78 | */
79 | private static String _eventLogAppenderDLL = Paths.get("src/test/resources/Win32EventlogAppender.dll")
80 | .toAbsolutePath().toString();
81 |
82 | /**
83 | * Class under test
84 | */
85 | private Win32EventLogAppender _eventLogAppender = null;
86 |
87 | /**
88 | *
89 | */
90 | @Before
91 | public void setUp() {
92 | String source = null;
93 | String log = getClass().getName();
94 | Layout extends Serializable> layout = PatternLayout.newBuilder()
95 | .withPattern(PatternLayout.TTCC_CONVERSION_PATTERN).build();
96 |
97 | Filter filter = null;
98 | _eventLogAppender = Win32EventLogAppender.createAppender("appenderName", null, source, log, _eventLogAppenderDLL, _eventLogAppenderDLL, layout, filter);
99 | _eventLogAppender.setSource(TEST_LOGGER_NAME);
100 | _eventLogAppender.setApplication("Application");
101 | // _eventLogAppender.setCategoryMessageFile(_eventLogAppenderDLL);
102 | // _eventLogAppender.setEventMessageFile(_eventLogAppenderDLL);
103 | }
104 |
105 | /**
106 | * Test case for {@link Win32EventLogAppender#append(LogEvent)} with debug
107 | * level.
108 | */
109 | @Test
110 | public void testDebugEvent() {
111 | String message = "log4jna debug message @ " + Kernel32.INSTANCE.GetTickCount();
112 | _eventLogAppender.append(asLogEvent(message, Level.DEBUG));
113 | expectEvent(message, Level.DEBUG, EventLogType.Informational);
114 | }
115 |
116 | /**
117 | * Test case for {@link Win32EventLogAppender#append(LogEvent)} with info
118 | * level.
119 | */
120 | @Test
121 | public void testInfoEvent() {
122 | String message = "log4jna info message @ " + Kernel32.INSTANCE.GetTickCount();
123 | _eventLogAppender.append(asLogEvent(message, Level.INFO));
124 | expectEvent(message, Level.INFO, EventLogType.Informational);
125 | }
126 |
127 | /**
128 | * Test case for {@link Win32EventLogAppender#append(LogEvent)} with warn
129 | * level.
130 | */
131 | @Test
132 | public void testWarnEvent() {
133 | String message = "log4jna warn message @ " + Kernel32.INSTANCE.GetTickCount();
134 | _eventLogAppender.append(asLogEvent(message, Level.WARN));
135 | expectEvent(message, Level.WARN, EventLogType.Warning);
136 | }
137 |
138 | /**
139 | * Test case for {@link Win32EventLogAppender#append(LogEvent)} with fatal level.
140 | */
141 | @Test
142 | public void testFatalEvent() {
143 | String message = "log4jna fatal message @ " + Kernel32.INSTANCE.GetTickCount();
144 | _eventLogAppender.append(asLogEvent(message, Level.FATAL));
145 | expectEvent(message, Level.FATAL, EventLogType.Error);
146 | }
147 |
148 | public void donttestRegistryValues() {
149 | String eventSourceKeyPath = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\"
150 | + _eventLogAppender.getApplication() + "\\" + _eventLogAppender.getSource();
151 |
152 | String eventMessageFileInRegistry = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE,
153 | eventSourceKeyPath, "EventMessageFile");
154 |
155 | Path eventMessageFileGiven = Paths.get(_eventLogAppenderDLL);
156 | assertEquals(eventMessageFileInRegistry, eventMessageFileGiven.toString());
157 |
158 | String categoryMessageFileInRegistry = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE,
159 | eventSourceKeyPath, "CategoryMessageFile");
160 |
161 | Path categoryMessageFileGiven = Paths.get(_eventLogAppenderDLL);
162 | assertEquals(categoryMessageFileInRegistry, categoryMessageFileGiven.toString());
163 | }
164 |
165 | private LogEvent asLogEvent(String message, Level level) {
166 | return new Log4jLogEvent.Builder().setLoggerName(TEST_LOGGER_NAME).setMarker(null)
167 | .setLoggerFqcn(_eventLogAppender.getClass().getName()).setLevel(level)
168 | .setMessage(new SimpleMessage(message)).setTimeMillis(System.currentTimeMillis()).build();
169 | }
170 |
171 | /*
172 | * public void testException() { String message =
173 | * "log4jna exception message @ " + Kernel32.INSTANCE.GetTickCount();
174 | * _logger.debug(message, new Exception("testing exception"));
175 | * expectEvent(message, Level.DEBUG, EventLogType.Informational); }
176 | */
177 |
178 | private void expectEvent(String message, Level level, EventLogType eventLogType) {
179 | EventLogIterator iter = new EventLogIterator(null, TEST_LOGGER_NAME, WinNT.EVENTLOG_BACKWARDS_READ);
180 | try {
181 | assertTrue(iter.hasNext());
182 | EventLogRecord record = iter.next();
183 | assertEquals(TEST_LOGGER_NAME, record.getSource());
184 |
185 | assertEquals(eventLogType, record.getType());
186 | assertEquals(1, record.getRecord().NumStrings.intValue());
187 | assertNull(record.getData());
188 |
189 | // The full message includes a level and the full class name
190 | String fullMessage = level + " " + TEST_LOGGER_NAME + " - " + message;
191 |
192 | // The event message has the location tacked on the front
193 | StringBuilder eventMessage = new StringBuilder();
194 | for (int i = 0; i < record.getStrings().length; i++) {
195 | eventMessage.append(record.getStrings()[i].trim());
196 | }
197 |
198 | int levelMarker = eventMessage.indexOf(level.toString());
199 | assertTrue("missing level marker in '" + eventMessage + "'", levelMarker >= 0);
200 | String eventMessageWithoutLocation = eventMessage.substring(levelMarker);
201 |
202 | assertEquals(fullMessage, eventMessageWithoutLocation);
203 | } finally {
204 | iter.close();
205 | }
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
10 |
11 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
12 |
13 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
14 |
15 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
16 |
17 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
18 |
19 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
20 |
21 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
22 |
23 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
24 |
25 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
26 |
27 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
28 |
29 | 2. Grant of Copyright License.
30 |
31 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
32 |
33 | 3. Grant of Patent License.
34 |
35 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
36 |
37 | 4. Redistribution.
38 |
39 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
40 |
41 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
42 |
43 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
44 |
45 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
46 |
47 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
48 |
49 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
50 |
51 | 5. Submission of Contributions.
52 |
53 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
54 |
55 | 6. Trademarks.
56 |
57 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
58 |
59 | 7. Disclaimer of Warranty.
60 |
61 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
62 |
63 | 8. Limitation of Liability.
64 |
65 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
66 |
67 | 9. Accepting Warranty or Additional Liability.
68 |
69 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
--------------------------------------------------------------------------------
/log4jna-demo/src/test/java/org/dblock/log4jna/nt/demo/test/NewDemoTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache license, Version 2.0 (the "License");
3 | * you may not use this file except in compliance with
4 | * the License. You may obtain a copy of the License at
5 | *
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the license for the specific language governing permissions and
12 | * limitations under the license.
13 | */
14 | package org.dblock.log4jna.nt.demo.test;
15 |
16 | import static org.junit.Assert.*;
17 |
18 | import org.apache.logging.log4j.Level;
19 | import org.dblock.log4jna.nt.demo.NewDemo;
20 | import org.junit.Before;
21 | import org.junit.Test;
22 |
23 | import com.sun.jna.platform.win32.WinNT;
24 | import com.sun.jna.platform.win32.Advapi32Util.EventLogIterator;
25 | import com.sun.jna.platform.win32.Advapi32Util.EventLogRecord;
26 | import com.sun.jna.platform.win32.Advapi32Util.EventLogType;
27 |
28 | /**
29 | * Test cases for {@link NewDemo}
30 | *
31 | * @author Claudio Trajtenberg
32 | *
33 | */
34 | public class NewDemoTest {
35 |
36 | /*
37 | * Use this configuration if using the Application log4j2.xml file
38 | */
39 | // private static final String EVENT_SOURCE = "Log4jnaTest";
40 |
41 | /*
42 | * Use this configuration if using the Win32LogApplication log4j2.xml file
43 | */
44 | private static final String EVENT_SOURCE = "WinLogger";
45 |
46 | private static final String EXCEPTION = "java.lang.Exception: Pouporselly thrown for demo";
47 |
48 | private NewDemo classUnderTest;
49 |
50 | private long testStartedTime;
51 |
52 | private long testEndedTime;
53 |
54 | @Before
55 | public void setUp() throws Exception {
56 | this.classUnderTest = new NewDemo();
57 | }
58 |
59 | /**
60 | * Test case for {@link NewDemo#trace()}.
61 | */
62 | @Test
63 | public void testTrace() {
64 | this.testStartedTime = System.currentTimeMillis() / 1000;
65 | this.classUnderTest.trace();
66 | this.testEndedTime = System.currentTimeMillis() / 1000;
67 | expectEventNoException(Level.TRACE, EventLogType.Informational, 1);
68 | }
69 |
70 | /**
71 | * Test case for {@link NewDemo#debug()}.
72 | */
73 | @Test
74 | public void testDebug() {
75 | this.testStartedTime = System.currentTimeMillis() / 1000;
76 | this.classUnderTest.debug();
77 | this.testEndedTime = System.currentTimeMillis() / 1000;
78 | expectEventNoException(Level.DEBUG, EventLogType.Informational, 2);
79 | }
80 |
81 | /**
82 | * Test case for {@link NewDemo#info()}.
83 | */
84 | @Test
85 | public void testInfo() {
86 | this.testStartedTime = System.currentTimeMillis() / 1000;
87 | this.classUnderTest.info();
88 | this.testEndedTime = System.currentTimeMillis() / 1000;
89 | expectEventNoException(Level.INFO, EventLogType.Informational, 3);
90 | }
91 |
92 | /**
93 | * Test case for {@link NewDemo#warn()}.
94 | */
95 | @Test
96 | public void testWarn() {
97 | this.testStartedTime = System.currentTimeMillis() / 1000;
98 | this.classUnderTest.warn();
99 | this.testEndedTime = System.currentTimeMillis() / 1000;
100 | expectEventNoException(Level.WARN, EventLogType.Warning, 4);
101 | }
102 |
103 | /**
104 | * Test case for {@link NewDemo#error()}.
105 | */
106 | @Test
107 | public void testError() {
108 | this.testStartedTime = System.currentTimeMillis() / 1000;
109 | this.classUnderTest.error();
110 | this.testEndedTime = System.currentTimeMillis() / 1000;
111 | expectEventNoException(Level.ERROR, EventLogType.Error, 5);
112 | }
113 |
114 | /**
115 | * Test case for {@link NewDemo#fatal()}.
116 | */
117 | @Test
118 | public void testFatal() {
119 | this.testStartedTime = System.currentTimeMillis() / 1000;
120 | this.classUnderTest.fatal();
121 | this.testEndedTime = System.currentTimeMillis() / 1000;
122 | expectEventNoException(Level.FATAL, EventLogType.Error, 6);
123 | }
124 |
125 | /**
126 | * Test case for {@link NewDemo#warnWithException()}.
127 | */
128 | @Test
129 | public void testWarnWithException() {
130 | this.testStartedTime = System.currentTimeMillis() / 1000;
131 | this.classUnderTest.warnWithException();
132 | this.testEndedTime = System.currentTimeMillis() / 1000;
133 | expectEventException(Level.WARN, EventLogType.Warning, 4);
134 | }
135 |
136 | /**
137 | * Test case for {@link NewDemo#errorWithException()}.
138 | */
139 | @Test
140 | public void testErrorWithException() {
141 | this.testStartedTime = System.currentTimeMillis() / 1000;
142 | this.classUnderTest.errorWithException();
143 | this.testEndedTime = System.currentTimeMillis() / 1000;
144 | expectEventException(Level.ERROR, EventLogType.Error, 5);
145 | }
146 |
147 | /**
148 | * Test case for {@link NewDemo#fatalWithException()}.
149 | */
150 | @Test
151 | public void testFatalWithException() {
152 | this.testStartedTime = System.currentTimeMillis() / 1000;
153 | this.classUnderTest.fatalWithException();
154 | this.testEndedTime = System.currentTimeMillis() / 1000;
155 | expectEventException(Level.FATAL, EventLogType.Error, 6);
156 | }
157 |
158 | /**
159 | * @param level
160 | * @param eventLogType
161 | * @param eventLogCategory
162 | */
163 | private void expectEventNoException(Level level, EventLogType eventLogType, int eventLogCategory) {
164 | EventLogIterator iter = new EventLogIterator(null, EVENT_SOURCE, WinNT.EVENTLOG_BACKWARDS_READ);
165 | try {
166 | assertTrue("No event log records to process", iter.hasNext());
167 | int recordCount = 0;
168 | while (iter.hasNext() && recordCount < 2) {
169 | EventLogRecord record = iter.next();
170 |
171 | if (record.getRecord().TimeWritten.longValue() >= this.testStartedTime
172 | && record.getRecord().TimeWritten.longValue() <= this.testEndedTime) {
173 |
174 | recordCount++;
175 |
176 | assertEquals(EVENT_SOURCE, record.getSource());
177 |
178 | assertEquals(eventLogType, record.getType());
179 | assertEquals(eventLogCategory, record.getRecord().EventCategory.intValue());
180 | assertEquals(1, record.getRecord().NumStrings.intValue());
181 | assertNull(record.getData());
182 |
183 | // Build the message
184 | StringBuilder message = new StringBuilder();
185 | switch (recordCount) {
186 | case 1:
187 | message.append("NewDemo: Exit ");
188 | break;
189 |
190 | case 2:
191 | message.append("NewDemo: Enter ");
192 | break;
193 |
194 | default:
195 | break;
196 | }
197 | message.append(level.name().toLowerCase());
198 | String fullMessage = String.format("%-5s [main] %s", level, message);
199 |
200 | // The event message has the location tacked on the front
201 | StringBuilder eventMessage = new StringBuilder();
202 | for (int i = 0; i < record.getStrings().length; i++) {
203 | eventMessage.append(record.getStrings()[i].trim());
204 | }
205 |
206 | int levelMarker = eventMessage.indexOf(level.toString());
207 | assertTrue("missing level marker in '" + eventMessage + "'", levelMarker >= 0);
208 | String eventMessageWithoutLocation = eventMessage.substring(levelMarker);
209 |
210 | assertEquals(fullMessage, eventMessageWithoutLocation);
211 | }
212 | }
213 | assertTrue("No records to process", recordCount > 0);
214 | } finally {
215 | iter.close();
216 | }
217 | }
218 |
219 | /**
220 | * @param level
221 | * @param eventLogType
222 | * @param eventLogCategory
223 | */
224 | private void expectEventException(Level level, EventLogType eventLogType, int eventLogCategory) {
225 | EventLogIterator iter = new EventLogIterator(null, EVENT_SOURCE, WinNT.EVENTLOG_BACKWARDS_READ);
226 | try {
227 | assertTrue(iter.hasNext());
228 | EventLogRecord record = iter.next();
229 |
230 | if (record.getRecord().TimeWritten.longValue() >= this.testStartedTime
231 | && record.getRecord().TimeWritten.longValue() <= this.testEndedTime) {
232 |
233 | assertEquals(EVENT_SOURCE, record.getSource());
234 |
235 | assertEquals(eventLogType, record.getType());
236 | assertEquals(eventLogCategory, record.getRecord().EventCategory.intValue());
237 | assertEquals(1, record.getRecord().NumStrings.intValue());
238 | assertNull(record.getData());
239 |
240 | // Build the message
241 | String messageStart = String.format("%-5s [main] NewDemo: In %s with exception", level,
242 | level.name().toLowerCase());
243 |
244 | // The event message has the location tacked on the front
245 | StringBuilder eventMessage = new StringBuilder();
246 | for (int i = 0; i < record.getStrings().length; i++) {
247 | eventMessage.append(record.getStrings()[i].trim());
248 | }
249 |
250 | int levelMarker = eventMessage.indexOf(level.toString());
251 | assertTrue("missing level marker in '" + eventMessage + "'", levelMarker >= 0);
252 | String eventMessageWithoutLocation = eventMessage.substring(levelMarker);
253 |
254 | assertTrue(String.format("Mising %s", messageStart),
255 | eventMessageWithoutLocation.contains(messageStart));
256 | assertTrue(String.format("Mising %s", EXCEPTION), eventMessageWithoutLocation.contains(EXCEPTION));
257 | }
258 | } finally {
259 | iter.close();
260 | }
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/log4jna-demo/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2010 Daniel Doubrovkine (dblock[at]dblock[dot]org)
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/src/site/markdown/USAGE.md:
--------------------------------------------------------------------------------
1 | # Log4JNA Configuration
2 | Log4JNA uses some configuration parameters to set up values in WindowsTM Registry that are required in order to write to the Event Viewer, all other Log4j 2TM values are used as described in the [Log4j 2TM Configuration Guide](http://logging.apache.org/log4j/2.x/manual/configuration.html)
3 |
4 | **Note:** WindowsTM requires Administrator privileges in order to write into the Registry, therefore you have to run the application as Administrator at least once, or [setup the registry manually](#registry) before using Log4JNA or whenever the location of the message file `Win32EventlogAppender.dll` changes in the configuration file.
5 |
6 | - [The message file `Win32EventlogAppender.dll`](#msg)
7 | - [Log4JNA Configuration Parameters](#cp)
8 | - [Log4JNA Registry Entries](#re)
9 | - [Log4J 2 configuration](#lj)
10 | - [Registry set up](#registry)
11 | - [Dependencies](#dep)
12 |
13 | ## The message file `Win32EventlogAppender.dll`
14 | WindowsTM Event Viewer and log depends on message files to find message content, formats, categories and types.
15 |
16 | Log4JNA uses a message file named `Win32EventlogAppender.dll`, we only define the categories and types and a generic message format that
17 | acts as pass through for the message format defined by your Log4j messages.
18 |
19 | Log4JNA needs to be able to find the file in order tof
20 |
21 | ## Log4JNA Configuration Parameters
22 | --------
23 |
24 | | Name | Required | Default Value | Usage Description |
25 | | ----: | :--------: | :-------------: | ----- |
26 | | `name` | true | N/A | This required value **must always be `Win32EventLog`**.
Log4JNA depends on `log4j-core`, `log4j-api`, `jna-plaform` and `jna`.
236 |
237 | Place the dependencies in a location visible in the CLASSPATH.
238 |
239 | Verify that the dependencies are not already provided by an Application Sever at the server class loader level.
240 |
241 | Place the JNA dependencies at the Application Server class loader level and declare JNA dependencies as provided in your build.
242 |
243 | The same principle can be applied for Log4JNA and log4j dependencies in an Application Server if several applications log to the Event Viewer.
244 |
245 | On Application Servers consider placing the message file ``
246 |
247 | Here is an example of Tomcat dependencies distribution on the file system for a single application.
248 |
249 |
250 | ```
251 | Apche Tomcat
252 | |+ bin
253 | |+ conf
254 | |+ lib
255 | | |+ jna-core.jar
256 | | |+ jna.jar
257 | |+ logs
258 | |+ temp
259 | |+ webapps
260 | | |+ your-application
261 | | |+ WEBINF
262 | | |+ lib
263 | | |+ log4jna-api.jar
264 | | |+ lo4j-core.jar
265 | | |+ log4j-api.jar
266 | | |+ Win32EventlogAppender.dll
267 | |+ work
268 | ```
269 |
270 | Here is an example of Tomcat dependencies distribution on the file system for multiple applications.
271 |
272 | ```
273 | Apche Tomcat
274 | |+ bin
275 | |+ conf
276 | |+ lib
277 | | |+ jna-core.jar
278 | | |+ jna.jar
279 | | |+ log4jna-api.jar
280 | | |+ lo4j-core.jar
281 | | |+ log4j-api.jar
282 | | |+ Win32EventlogAppender.dll
283 | |+ logs
284 | |+ temp
285 | |+ webapps
286 | | |+ your-application 1
287 | | | |+ WEBINF
288 | | | |+ lib
289 | | | |+ other-dependencies.jar
290 | | |+ your-application 2
291 | | |+ WEBINF
292 | | |+ lib
293 | | |+ other-dependencies.jar
294 | |+ work
295 | ```
296 |
--------------------------------------------------------------------------------
/USAGE.md:
--------------------------------------------------------------------------------
1 | # Log4JNA Configuration
2 |
3 | Log4JNA uses some configuration parameters to set up values in WindowsTM Registry that are required in order to write to the Event Viewer, all other Log4j 2TM values are used as described in the [Log4j 2TM Configuration Guide](http://logging.apache.org/log4j/2.x/manual/configuration.html)
4 |
5 | **Note:** WindowsTM requires Administrator privileges in order to write into the Registry, therefore you have to run the application as Administrator at least once, or [setup the registry manually](#registry) before using Log4JNA or whenever the location of the message file `Win32EventlogAppender.dll` changes in the configuration file.
6 |
7 | - [The message file `Win32EventlogAppender.dll`](#msg)
8 | - [Log4JNA Configuration Parameters](#cp)
9 | - [Log4JNA Registry Entries](#re)
10 | - [Log4J 2 Configuration](#lj)
11 | - [Registry Set Up](#registry)
12 | - [Dependencies](#dep)
13 |
14 | ## The message file `Win32EventlogAppender.dll`
15 |
16 | WindowsTM Event Viewer and logging depends on message files to find message content, formats, categories and types.
17 |
18 | Log4JNA uses a message file named `Win32EventlogAppender.dll`, we only define the categories and a generic message format that acts as pass
19 | through for the message format defined by your Log4j messages.
20 |
21 | To format the messages properly Log4JNA and the native calls need to find the message file in the file system.
22 |
23 | Log4JNA locates the file using the `EventMessageFile` and `CategoryMessageFile` entries in the registry.
24 |
25 | If the entries in the registry do not exists, Log4JNA attempts to create them using the configuration values `eventMessageFile` and `categoryMessageFile`.
26 |
27 | ## Log4JNA Configuration Parameters
28 |
29 | | Name | Required | Default Value | Usage Description |
30 | | ----: | :--------: | :-------------: | ----- |
31 | | `name` | true | N/A | This required value **must always be `Win32EventLog`**.
Log4JNA depends on `log4j-core`, `log4j-api`, `jna-plaform` and `jna`.
243 |
244 | Place the dependencies in a location visible in the CLASSPATH.
245 |
246 | Verify that the dependencies are not already provided by an Application Sever at the server class loader level.
247 |
248 | Place the JNA dependencies at the Application Server class loader level and declare JNA dependencies as provided in your build.
249 |
250 | The same principle can be applied for Log4JNA and log4j dependencies in an Application Server if several applications log to the Event Viewer.
251 |
252 | On Application Servers consider placing the message file ``
253 |
254 | Here is an example of Tomcat dependencies distribution on the file system for a single application.
255 |
256 |
257 | ```
258 | Apache Tomcat
259 | |+ bin
260 | |+ conf
261 | |+ lib
262 | | |+ jna-core.jar
263 | | |+ jna.jar
264 | |+ logs
265 | |+ temp
266 | |+ webapps
267 | | |+ your-application
268 | | |+ WEBINF
269 | | |+ lib
270 | | |+ log4jna-api.jar
271 | | |+ lo4j-core.jar
272 | | |+ log4j-api.jar
273 | | |+ Win32EventlogAppender.dll
274 | |+ work
275 | ```
276 |
277 | Here is an example of Tomcat dependencies distribution on the file system for multiple applications.
278 |
279 | ```
280 | Apache Tomcat
281 | |+ bin
282 | |+ conf
283 | |+ lib
284 | | |+ jna-core.jar
285 | | |+ jna.jar
286 | | |+ log4jna-api.jar
287 | | |+ lo4j-core.jar
288 | | |+ log4j-api.jar
289 | | |+ Win32EventlogAppender.dll
290 | |+ logs
291 | |+ temp
292 | |+ webapps
293 | | |+ your-application 1
294 | | | |+ WEBINF
295 | | | |+ lib
296 | | | |+ other-dependencies.jar
297 | | |+ your-application 2
298 | | |+ WEBINF
299 | | |+ lib
300 | | |+ other-dependencies.jar
301 | |+ work
302 | ```
303 |
304 |
--------------------------------------------------------------------------------
/log4jna-api/src/main/java/org/dblock/log4jna/nt/Win32EventLogAppender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
3 | * use this file except in compliance with the License. You may obtain a copy
4 | * of the License at
5 | *
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the License for the specific language governing permissions and
12 | * limitations under the License.
13 | */
14 |
15 | package org.dblock.log4jna.nt;
16 |
17 | import java.io.Serializable;
18 | import java.nio.file.Files;
19 | import java.nio.file.Path;
20 | import java.nio.file.Paths;
21 |
22 | import org.apache.logging.log4j.Level;
23 | import org.apache.logging.log4j.core.Filter;
24 | import org.apache.logging.log4j.core.Layout;
25 | import org.apache.logging.log4j.core.LogEvent;
26 | import org.apache.logging.log4j.core.appender.AbstractAppender;
27 | import org.apache.logging.log4j.core.config.plugins.Plugin;
28 | import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
29 | import org.apache.logging.log4j.core.config.plugins.PluginElement;
30 | import org.apache.logging.log4j.core.config.plugins.PluginFactory;
31 | import org.apache.logging.log4j.spi.StandardLevel;
32 |
33 | import com.sun.jna.platform.win32.Advapi32;
34 | import com.sun.jna.platform.win32.Advapi32Util;
35 | import com.sun.jna.platform.win32.Kernel32;
36 | import com.sun.jna.platform.win32.Win32Exception;
37 | import com.sun.jna.platform.win32.WinNT;
38 | import com.sun.jna.platform.win32.WinNT.HANDLE;
39 | import com.sun.jna.platform.win32.WinReg;
40 |
41 | /**
42 | * Append to the NT event log system.
43 | *
44 | * 45 | * WARNING This appender can only be installed and used on a Windows 46 | * system. 47 | * 48 | *
49 | * Do not forget to place jna.jar and platform.jar in the CLASSPATH. 50 | *
51 | * 52 | * @author Chris Taylor 53 | * @author Jim Cakalic 54 | * @author Daniel Doubrovkine 55 | * @author Tony Niemira 56 | * @author Claudio Trajtenberg 57 | * @author yokra 58 | */ 59 | @Plugin(name = "Win32EventLog", category = "Core", elementType = "appender", printObject = true) 60 | public class Win32EventLogAppender extends AbstractAppender { 61 | 62 | private static final String EVENT_LOG_PATH = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\"; 63 | private static final String CATEGORY_MESSAGE_FILE = "CategoryMessageFile"; 64 | private static final String EVENT_MESSAGE_FILE = "EventMessageFile"; 65 | private static final int CATEGORY_COUNT = 6; 66 | private static final int TYPES_SUPPORTED = 7; 67 | private static final String DEFAULT_SOURCE = "Log4jna"; 68 | private static final String DEFAULT_APPLICATION = "Application"; 69 | /** 70 | * 71 | */ 72 | private String _source = null; 73 | private String _server = null; 74 | private String _application = DEFAULT_APPLICATION; 75 | private String _eventMessageFile = ""; 76 | private String _categoryMessageFile = ""; 77 | 78 | private HANDLE _handle = null; 79 | 80 | /** 81 | * @param name The appender name Win32EventLog 82 | * @param server The server for remote logging 83 | * @param source The Event View Source 84 | * @param application The Event View application (location) 85 | * @param eventMessageFile The message file location in the file system 86 | * @param categoryMessageFile The message file location in the file system 87 | * @param layout A Log4j Layout 88 | * @param filter A Log4j Filter 89 | * @return 90 | */ 91 | @PluginFactory 92 | public static Win32EventLogAppender createAppender(@PluginAttribute("name") String name, 93 | @PluginAttribute("server") String server, @PluginAttribute("source") String source, 94 | @PluginAttribute("application") String application, 95 | @PluginAttribute("eventMessageFile") String eventMessageFile, 96 | @PluginAttribute("categoryMessageFile") String categoryMessageFile, 97 | @PluginElement("Layout") Layout extends Serializable> layout, @PluginElement("Filters") Filter filter) { 98 | return new Win32EventLogAppender(name, server, source, application, eventMessageFile, categoryMessageFile, 99 | layout, filter); 100 | } 101 | 102 | /** 103 | * @param name The appender name Win32EventLog 104 | * @param server The server for remote logging 105 | * @param source The Event View Source 106 | * @param application The Event View application (location) 107 | * @param eventMessageFile The message file location in the file system 108 | * @param categoryMessageFile The message file location in the file system 109 | * @param layout A Log4j Layout 110 | * @param filter A Log4j Filter 111 | */ 112 | public Win32EventLogAppender(String name, String server, String source, String application, String eventMessageFile, 113 | String categoryMessageFile, Layout extends Serializable> layout, Filter filter) { 114 | super(name, filter, layout); 115 | if (source == null || source.length() == 0) { 116 | source = DEFAULT_SOURCE; 117 | } 118 | 119 | if (eventMessageFile != null) { 120 | Path p = Paths.get(eventMessageFile); 121 | if (Files.exists(p)) { 122 | setEventMessageFile(p.toAbsolutePath().toString()); 123 | } 124 | } 125 | 126 | if (categoryMessageFile != null) { 127 | Path p = Paths.get(categoryMessageFile); 128 | if (Files.exists(p)) { 129 | setCategoryMessageFile(p.toAbsolutePath().toString()); 130 | } 131 | } 132 | 133 | this._server = server; 134 | setSource(source); 135 | setApplication(application); 136 | } 137 | 138 | /** 139 | * The Source option which names the source of the event. The current 140 | * value of this constant is Source. 141 | */ 142 | public void setSource(String source) { 143 | 144 | if (source == null || source.length() == 0) { 145 | source = DEFAULT_SOURCE; 146 | } 147 | 148 | _source = source.trim(); 149 | } 150 | 151 | /** 152 | * @return 153 | */ 154 | public String getSource() { 155 | return _source; 156 | } 157 | 158 | /** 159 | * The Application option which names the subsection of the 160 | * 'Applications and Services Log'. The default value of this constant is 161 | * Application. 162 | * 163 | * @param application The Event View application (location) 164 | */ 165 | public void setApplication(String application) { 166 | 167 | if (application == null || application.length() == 0) { 168 | application = DEFAULT_APPLICATION; 169 | } 170 | 171 | _application = application.trim(); 172 | } 173 | 174 | /** 175 | * @return 176 | */ 177 | public String getApplication() { 178 | return _application; 179 | } 180 | 181 | /** 182 | * 183 | */ 184 | public void close() { 185 | if (_handle != null) { 186 | if (!Advapi32.INSTANCE.DeregisterEventSource(_handle)) { 187 | throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); 188 | } 189 | _handle = null; 190 | } 191 | } 192 | 193 | /** 194 | * The EventMessageFile option which sets file location of the Event 195 | * Messages 196 | * 197 | * @param eventMessageFile The message file location in the file system 198 | */ 199 | public void setEventMessageFile(String eventMessageFile) { 200 | _eventMessageFile = eventMessageFile.trim(); 201 | } 202 | 203 | /** 204 | * @return 205 | */ 206 | public String getEventMessageFile() { 207 | return _eventMessageFile; 208 | } 209 | 210 | /** 211 | * The CategoryMessageFile option which sets file location of the 212 | * Catagory Messages 213 | * 214 | * @param categoryMessageFile The message file location in the file system 215 | */ 216 | public void setCategoryMessageFile(String categoryMessageFile) { 217 | _categoryMessageFile = categoryMessageFile.trim(); 218 | } 219 | 220 | /** 221 | * @return 222 | */ 223 | public String getCategoryMessageFile() { 224 | return _categoryMessageFile; 225 | } 226 | 227 | /** 228 | * 229 | */ 230 | private void registerEventSource() { 231 | close(); 232 | 233 | try { 234 | _handle = registerEventSource(_server, _source, _application, _eventMessageFile, _categoryMessageFile); 235 | } catch (Exception e) { 236 | close(); 237 | throw new RuntimeException("Could not register event source.", e); 238 | } 239 | } 240 | 241 | /** 242 | * 243 | */ 244 | public void activateOptions() { 245 | registerEventSource(); 246 | } 247 | 248 | 249 | /** 250 | * {@inheritDoc} 251 | */ 252 | public void append(LogEvent event) { 253 | 254 | if (_handle == null) { 255 | registerEventSource(); 256 | } 257 | 258 | String s = new String(getLayout().toByteArray(event)); 259 | final int messageID = 0x1000; 260 | 261 | String[] buffer = { s }; 262 | 263 | if (Advapi32.INSTANCE.ReportEvent(_handle, getEventLogType(event.getLevel()), 264 | getEventLogCategory(event.getLevel()), messageID, null, buffer.length, 0, buffer, null) == false) { 265 | Exception e = new Win32Exception(Kernel32.INSTANCE.GetLastError()); 266 | getHandler().error("Failed to report event [" + s + "].", event, e); 267 | } 268 | } 269 | 270 | /** 271 | * {@inheritDoc} 272 | */ 273 | public void finalize() { 274 | close(); 275 | } 276 | 277 | /** 278 | * TheWin32EventLogAppender requires a layout. Hence, this
279 | * method always returns true.
280 | */
281 | public boolean requiresLayout() {
282 | return true;
283 | }
284 |
285 | /**
286 | * @param server The server for remote logging
287 | * @param source The Event View Source
288 | * @param application The Event View application (location)
289 | * @param eventMessageFile The message file location in the file system
290 | * @param categoryMessageFile The message file location in the file system
291 | * @return
292 | */
293 | private HANDLE registerEventSource(String server, String source, String application, String eventMessageFile,
294 | String categoryMessageFile) {
295 | String applicationKeyPath = EVENT_LOG_PATH + application;
296 | String eventSourceKeyPath = applicationKeyPath + "\\" + source;
297 | if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, applicationKeyPath)) {
298 | if (Advapi32Util.registryKeyExists(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath)) {
299 | setVariableKeys(eventMessageFile, categoryMessageFile, eventSourceKeyPath);
300 | } else {
301 | createAndSetAllKeys(eventMessageFile, categoryMessageFile, eventSourceKeyPath);
302 | }
303 | } else {
304 | createAndSetAllKeys(eventMessageFile, categoryMessageFile, eventSourceKeyPath);
305 | }
306 |
307 | HANDLE h = Advapi32.INSTANCE.RegisterEventSource(server, source);
308 | if (h == null) {
309 | throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
310 | }
311 |
312 | return h;
313 | }
314 |
315 | /**
316 | *
317 | * @param eventMessageFile The message file location in the file system
318 | * @param categoryMessageFile The message file location in the file system
319 | * @param eventSourceKeyPath The registry path
320 | */
321 | private void createAndSetAllKeys(String eventMessageFile, String categoryMessageFile, String eventSourceKeyPath) {
322 | if (Advapi32Util.registryCreateKey(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath)) {
323 | Advapi32Util.registrySetIntValue(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, "TypesSupported",
324 | TYPES_SUPPORTED);
325 | Advapi32Util.registrySetIntValue(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, "CategoryCount",
326 | CATEGORY_COUNT);
327 | setVariableKeys(eventMessageFile, categoryMessageFile, eventSourceKeyPath);
328 | }
329 | }
330 |
331 | /**
332 | * Set the file location only if it does not exist or has changed.
333 | *
334 | * @param eventMessageFile The message file location in the file system
335 | * @param categoryMessageFile The message file location in the file system
336 | * @param eventSourceKeyPath The registry path
337 | */
338 | private void setVariableKeys(String eventMessageFile, String categoryMessageFile, String eventSourceKeyPath) {
339 | if (!Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, EVENT_MESSAGE_FILE)
340 | || !Advapi32Util
341 | .registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, EVENT_MESSAGE_FILE)
342 | .equalsIgnoreCase(eventMessageFile)) {
343 | Advapi32Util.registrySetStringValue(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, EVENT_MESSAGE_FILE,
344 | eventMessageFile);
345 | }
346 | if (!Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, CATEGORY_MESSAGE_FILE)
347 | || !Advapi32Util
348 | .registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, CATEGORY_MESSAGE_FILE)
349 | .equalsIgnoreCase(categoryMessageFile)) {
350 | Advapi32Util.registrySetStringValue(WinReg.HKEY_LOCAL_MACHINE, eventSourceKeyPath, CATEGORY_MESSAGE_FILE,
351 | categoryMessageFile);
352 | }
353 | }
354 |
355 | /**
356 | * Convert log4j Priority to an EventLog type. The log4j package supports 8
357 | * defined priorities, but the NT EventLog only knows 3 event types of
358 | * interest to us: ERROR, WARNING, and INFO.
359 | *
360 | * @param level
361 | * Log4j priority.
362 | * @return EventLog type.
363 | */
364 | private static int getEventLogType(Level level) {
365 | StandardLevel standardLevel = StandardLevel.getStandardLevel(level.intLevel());
366 | switch (standardLevel) {
367 | case FATAL:
368 | case ERROR: {
369 | return WinNT.EVENTLOG_ERROR_TYPE;
370 | }
371 | case WARN: {
372 | return WinNT.EVENTLOG_WARNING_TYPE;
373 | }
374 | default: {
375 | return WinNT.EVENTLOG_INFORMATION_TYPE;
376 | }
377 | }
378 | }
379 |
380 | /**
381 | * Convert log4j Priority to an EventLog category. Each category is backed
382 | * by a message resource so that proper category names will be displayed in
383 | * the NT Event Viewer.
384 | *
385 | * @param level Log4J priority.
386 | * @return EventLog category.
387 | */
388 | private static int getEventLogCategory(Level level) {
389 | StandardLevel standardLevel = StandardLevel.getStandardLevel(level.intLevel());
390 | switch (standardLevel) {
391 | case FATAL: {
392 | return 6;
393 | }
394 | case ERROR: {
395 | return 5;
396 | }
397 | case WARN: {
398 | return 4;
399 | }
400 | case INFO: {
401 | return 3;
402 | }
403 | case DEBUG: {
404 | return 2;
405 | }
406 | default: {
407 | return 1;
408 | }
409 | }
410 | }
411 |
412 | }
413 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |