Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
xiaofang li
Logging Log4j2
Commits
3df7f50e
Commit
3df7f50e
authored
7 years ago
by
Ralph Goers
Browse files
Options
Download
Email Patches
Plain Diff
LOG4J2-2008 - support multiple structured data elements
parent
4992db7b
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
log4j-api/src/main/java/org/apache/logging/log4j/message/MessageCollectionMessage.java
+26
-0
...pache/logging/log4j/message/MessageCollectionMessage.java
log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataCollectionMessage.java
+93
-0
...ogging/log4j/message/StructuredDataCollectionMessage.java
log4j-api/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java
+8
-0
...ain/java/org/apache/logging/log4j/util/ProcessIdUtil.java
log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
+28
-16
...a/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
log4j-core/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
+71
-0
...g/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
with
226 additions
and
16 deletions
+226
-16
log4j-api/src/main/java/org/apache/logging/log4j/message/MessageCollectionMessage.java
0 → 100644
+
26
-
0
View file @
3df7f50e
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package
org.apache.logging.log4j.message
;
/**
* A Message that is a collection of Messages.
* @param <T> The Message type.
*/
public
interface
MessageCollectionMessage
<
T
>
extends
Message
,
Iterable
<
T
>
{
}
This diff is collapsed.
Click to expand it.
log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataCollectionMessage.java
0 → 100644
+
93
-
0
View file @
3df7f50e
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package
org.apache.logging.log4j.message
;
import
java.util.ArrayList
;
import
java.util.Iterator
;
import
java.util.List
;
/**
* A collection of StructuredDataMessages.
*/
public
class
StructuredDataCollectionMessage
implements
MessageCollectionMessage
<
StructuredDataMessage
>
{
private
List
<
StructuredDataMessage
>
structuredDataMessageList
;
public
StructuredDataCollectionMessage
(
List
<
StructuredDataMessage
>
messages
)
{
this
.
structuredDataMessageList
=
messages
;
}
@Override
public
Iterator
<
StructuredDataMessage
>
iterator
()
{
return
structuredDataMessageList
.
iterator
();
}
@Override
public
String
getFormattedMessage
()
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
StructuredDataMessage
msg
:
structuredDataMessageList
)
{
sb
.
append
(
msg
.
getFormattedMessage
());
}
return
sb
.
toString
();
}
@Override
public
String
getFormat
()
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
StructuredDataMessage
msg
:
structuredDataMessageList
)
{
if
(
msg
.
getFormat
()
!=
null
)
{
if
(
sb
.
length
()
>
0
)
{
sb
.
append
(
", "
);
}
sb
.
append
(
msg
.
getFormat
());
}
}
return
sb
.
toString
();
}
@Override
public
Object
[]
getParameters
()
{
List
<
Object
[]>
objectList
=
new
ArrayList
<>();
int
count
=
0
;
for
(
StructuredDataMessage
msg
:
structuredDataMessageList
)
{
Object
[]
objects
=
msg
.
getParameters
();
if
(
objects
!=
null
)
{
objectList
.
add
(
objects
);
count
+=
objects
.
length
;
}
}
Object
[]
objects
=
new
Object
[
count
];
int
index
=
0
;
for
(
Object
[]
objs
:
objectList
)
{
for
(
Object
obj
:
objs
)
{
objects
[
index
++]
=
obj
;
}
}
return
objects
;
}
@Override
public
Throwable
getThrowable
()
{
for
(
StructuredDataMessage
msg
:
structuredDataMessageList
)
{
Throwable
t
=
msg
.
getThrowable
();
if
(
t
!=
null
)
{
return
t
;
}
}
return
null
;
}
}
This diff is collapsed.
Click to expand it.
log4j-api/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java
0 → 100644
+
8
-
0
View file @
3df7f50e
package
org.apache.logging.log4j.util
;
public
class
ProcessIdUtil
{
public
static
String
getProcessId
()
{
return
"-"
;
}
}
This diff is collapsed.
Click to expand it.
log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
+
28
-
16
View file @
3df7f50e
...
...
@@ -51,8 +51,11 @@ import org.apache.logging.log4j.core.pattern.ThrowablePatternConverter;
import
org.apache.logging.log4j.core.util.NetUtils
;
import
org.apache.logging.log4j.core.util.Patterns
;
import
org.apache.logging.log4j.message.Message
;
import
org.apache.logging.log4j.message.MessageCollectionMessage
;
import
org.apache.logging.log4j.message.StructuredDataCollectionMessage
;
import
org.apache.logging.log4j.message.StructuredDataId
;
import
org.apache.logging.log4j.message.StructuredDataMessage
;
import
org.apache.logging.log4j.util.ProcessIdUtil
;
import
org.apache.logging.log4j.util.StringBuilders
;
import
org.apache.logging.log4j.util.Strings
;
...
...
@@ -190,8 +193,7 @@ public final class Rfc5424Layout extends AbstractStringLayout {
final
String
name
=
config
==
null
?
null
:
config
.
getName
();
configName
=
Strings
.
isNotEmpty
(
name
)
?
name
:
null
;
this
.
fieldFormatters
=
createFieldFormatters
(
loggerFields
,
config
);
// TODO Java 9: ProcessHandle.current().getPid();
this
.
procId
=
"-"
;
this
.
procId
=
ProcessIdUtil
.
getProcessId
();
}
private
Map
<
String
,
FieldFormatter
>
createFieldFormatters
(
final
LoggerFields
[]
loggerFields
,
...
...
@@ -331,8 +333,8 @@ public final class Rfc5424Layout extends AbstractStringLayout {
private
void
appendMessage
(
final
StringBuilder
buffer
,
final
LogEvent
event
)
{
final
Message
message
=
event
.
getMessage
();
// This layout formats StructuredDataMessages instead of delegating to the Message itself.
final
String
text
=
(
message
instanceof
StructuredDataMessage
)
?
message
.
getFormat
()
:
m
essage
.
getFormattedMessage
();
final
String
text
=
(
message
instanceof
StructuredDataMessage
||
message
instanceof
MessageCollectionM
essage
)
?
message
.
getFormat
()
:
message
.
getFormattedMessage
();
if
(
text
!=
null
&&
text
.
length
()
>
0
)
{
buffer
.
append
(
' '
).
append
(
escapeNewlines
(
text
,
escapeNewLine
));
...
...
@@ -352,7 +354,8 @@ public final class Rfc5424Layout extends AbstractStringLayout {
private
void
appendStructuredElements
(
final
StringBuilder
buffer
,
final
LogEvent
event
)
{
final
Message
message
=
event
.
getMessage
();
final
boolean
isStructured
=
message
instanceof
StructuredDataMessage
;
final
boolean
isStructured
=
message
instanceof
StructuredDataMessage
||
message
instanceof
StructuredDataCollectionMessage
;
if
(!
isStructured
&&
(
fieldFormatters
!=
null
&&
fieldFormatters
.
isEmpty
())
&&
!
includeMdc
)
{
buffer
.
append
(
'-'
);
...
...
@@ -387,18 +390,12 @@ public final class Rfc5424Layout extends AbstractStringLayout {
}
if
(
isStructured
)
{
final
StructuredDataMessage
data
=
(
StructuredDataMessage
)
message
;
final
Map
<
String
,
String
>
map
=
data
.
getData
();
final
StructuredDataId
id
=
data
.
getId
();
final
String
sdId
=
getId
(
id
);
if
(
sdElements
.
containsKey
(
sdId
))
{
final
StructuredDataElement
union
=
sdElements
.
get
(
id
.
toString
());
union
.
union
(
map
);
sdElements
.
put
(
sdId
,
union
);
if
(
message
instanceof
MessageCollectionMessage
)
{
for
(
StructuredDataMessage
data
:
((
StructuredDataCollectionMessage
)
message
))
{
addStructuredData
(
sdElements
,
data
);
}
}
else
{
final
StructuredDataElement
formattedData
=
new
StructuredDataElement
(
map
,
eventPrefix
,
false
);
sdElements
.
put
(
sdId
,
formattedData
);
addStructuredData
(
sdElements
,
(
StructuredDataMessage
)
message
);
}
}
...
...
@@ -412,6 +409,21 @@ public final class Rfc5424Layout extends AbstractStringLayout {
}
}
private
void
addStructuredData
(
final
Map
<
String
,
StructuredDataElement
>
sdElements
,
final
StructuredDataMessage
data
)
{
final
Map
<
String
,
String
>
map
=
data
.
getData
();
final
StructuredDataId
id
=
data
.
getId
();
final
String
sdId
=
getId
(
id
);
if
(
sdElements
.
containsKey
(
sdId
))
{
final
StructuredDataElement
union
=
sdElements
.
get
(
id
.
toString
());
union
.
union
(
map
);
sdElements
.
put
(
sdId
,
union
);
}
else
{
final
StructuredDataElement
formattedData
=
new
StructuredDataElement
(
map
,
eventPrefix
,
false
);
sdElements
.
put
(
sdId
,
formattedData
);
}
}
private
String
escapeNewlines
(
final
String
text
,
final
String
replacement
)
{
if
(
null
==
replacement
)
{
return
text
;
...
...
This diff is collapsed.
Click to expand it.
log4j-core/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
+
71
-
0
View file @
3df7f50e
...
...
@@ -16,6 +16,7 @@
*/
package
org.apache.logging.log4j.core.layout
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Locale
;
...
...
@@ -31,6 +32,7 @@ import org.apache.logging.log4j.core.config.ConfigurationFactory;
import
org.apache.logging.log4j.core.net.Facility
;
import
org.apache.logging.log4j.core.util.KeyValuePair
;
import
org.apache.logging.log4j.junit.ThreadContextRule
;
import
org.apache.logging.log4j.message.StructuredDataCollectionMessage
;
import
org.apache.logging.log4j.message.StructuredDataMessage
;
import
org.apache.logging.log4j.status.StatusLogger
;
import
org.apache.logging.log4j.test.appender.ListAppender
;
...
...
@@ -58,6 +60,9 @@ public class Rfc5424LayoutTest {
private
static
final
String
lineEscaped4
=
"ATM - Audit [Transfer@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"]"
+
"[RequestContext@3692 escaped=\"Testing escaping #012 \\\" \\] \\\"\" ipAddress=\"192.168.0.120\" loginId=\"JohnDoe\"] Transfer Complete"
;
private
static
final
String
collectionLine
=
"[Transfer@18060 Amount=\"200.00\" FromAccount=\"123457\" "
+
"ToAccount=\"123456\"][Extra@18060 Item1=\"Hello\" Item2=\"World\"][RequestContext@3692 "
+
"ipAddress=\"192.168.0.120\" loginId=\"JohnDoe\"] Transfer Complete"
;
static
ConfigurationFactory
cf
=
new
BasicConfigurationFactory
();
...
...
@@ -148,6 +153,72 @@ public class Rfc5424LayoutTest {
list
=
appender
.
getMessages
();
assertTrue
(
"No messages expected, found "
+
list
.
size
(),
list
.
isEmpty
());
}
finally
{
ThreadContext
.
clearMap
();
root
.
removeAppender
(
appender
);
appender
.
stop
();
}
}
/**
* Test case for MDC conversion pattern.
*/
@Test
public
void
testCollection
()
throws
Exception
{
for
(
final
Appender
appender
:
root
.
getAppenders
().
values
())
{
root
.
removeAppender
(
appender
);
}
// set up appender
final
AbstractStringLayout
layout
=
Rfc5424Layout
.
createLayout
(
Facility
.
LOCAL0
,
"Event"
,
3692
,
true
,
"RequestContext"
,
null
,
null
,
true
,
null
,
"ATM"
,
null
,
"key1, key2, locale"
,
null
,
"loginId"
,
null
,
true
,
null
,
null
);
final
ListAppender
appender
=
new
ListAppender
(
"List"
,
null
,
layout
,
true
,
false
);
appender
.
start
();
// set appender on root and set level to debug
root
.
addAppender
(
appender
);
root
.
setLevel
(
Level
.
DEBUG
);
ThreadContext
.
put
(
"loginId"
,
"JohnDoe"
);
ThreadContext
.
put
(
"ipAddress"
,
"192.168.0.120"
);
ThreadContext
.
put
(
"locale"
,
Locale
.
US
.
getDisplayName
());
try
{
final
StructuredDataMessage
msg
=
new
StructuredDataMessage
(
"Transfer@18060"
,
"Transfer Complete"
,
"Audit"
);
msg
.
put
(
"ToAccount"
,
"123456"
);
msg
.
put
(
"FromAccount"
,
"123457"
);
msg
.
put
(
"Amount"
,
"200.00"
);
final
StructuredDataMessage
msg2
=
new
StructuredDataMessage
(
"Extra@18060"
,
null
,
"Audit"
);
msg2
.
put
(
"Item1"
,
"Hello"
);
msg2
.
put
(
"Item2"
,
"World"
);
List
<
StructuredDataMessage
>
messages
=
new
ArrayList
<>();
messages
.
add
(
msg
);
messages
.
add
(
msg2
);
final
StructuredDataCollectionMessage
collectionMessage
=
new
StructuredDataCollectionMessage
(
messages
);
root
.
info
(
MarkerManager
.
getMarker
(
"EVENT"
),
collectionMessage
);
List
<
String
>
list
=
appender
.
getMessages
();
assertTrue
(
"Expected line 1 to end with: "
+
collectionLine
+
" Actual "
+
list
.
get
(
0
),
list
.
get
(
0
).
endsWith
(
collectionLine
));
for
(
final
String
frame
:
list
)
{
int
length
=
-
1
;
final
int
frameLength
=
frame
.
length
();
final
int
firstSpacePosition
=
frame
.
indexOf
(
' '
);
final
String
messageLength
=
frame
.
substring
(
0
,
firstSpacePosition
);
try
{
length
=
Integer
.
parseInt
(
messageLength
);
// the ListAppender removes the ending newline, so we expect one less size
assertEquals
(
frameLength
,
messageLength
.
length
()
+
length
);
}
catch
(
final
NumberFormatException
e
)
{
assertTrue
(
"Not a valid RFC 5425 frame"
,
false
);
}
}
appender
.
clear
();
}
finally
{
ThreadContext
.
clearMap
();
root
.
removeAppender
(
appender
);
appender
.
stop
();
}
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment
Menu
Projects
Groups
Snippets
Help