Skip to content

Commit

Permalink
Support continuing log files with same dynamic path segment
Browse files Browse the repository at this point in the history
  • Loading branch information
pmwmedia committed Jan 9, 2024
1 parent f200377 commit 9987105
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 26 deletions.
9 changes: 6 additions & 3 deletions configuration/spotbugs-filters.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON" />
</Match>
<Match>
<!-- Dynamic Policy -->
<Class name="org.tinylog.policies.DynamicPolicy" />
<!-- Allow writing to static field org.tinylog.policies.DynamicPolicy.reset from instance method org.tinylog.policies.DynamicPolicy.reset -->
<!-- Dynamic Path Segment and Dynamic Policy -->
<Or>
<Class name="org.tinylog.path.DynamicSegment" />
<Class name="org.tinylog.policies.DynamicPolicy" />
</Or>
<!-- Allow the instances to write to their static fields -->
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" />
</Match>
<Match>
Expand Down
23 changes: 18 additions & 5 deletions tinylog-impl/src/main/java/org/tinylog/path/DynamicSegment.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@
*/
public class DynamicSegment implements Segment {

private static String text;
private static final Object mutex = new Object();

private static boolean created;
private static String text;

/**
* @param defaultValue Initial value for dynamic text
*/
DynamicSegment(final String defaultValue) {
setText(defaultValue);
synchronized (mutex) {
if (text == null) {
text = defaultValue;
}
}
}

/**
Expand Down Expand Up @@ -57,14 +63,21 @@ public static void setText(final String text) {
if (DynamicSegment.text != null && DynamicSegment.text.equals(text)) {
return;
}

DynamicSegment.text = text;
DynamicPolicy.setReset();

if (created) {
DynamicPolicy.setReset();
}
}
}

@Override
public String getStaticText() {
return getText();
synchronized (mutex) {
created = true;
return text;
}
}

@Override
Expand All @@ -76,7 +89,7 @@ public boolean validateToken(final String token) {

@Override
public String createToken(final String prefix, final Timestamp timestamp) {
return getText();
return getStaticText();
}

}
14 changes: 14 additions & 0 deletions tinylog-impl/src/test/java/org/tinylog/path/DynamicPathTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
import java.time.temporal.ChronoUnit;
import java.util.Date;

import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import org.tinylog.policies.DynamicPolicy;
import org.tinylog.runtime.RuntimeProvider;
import org.tinylog.runtime.Timestamp;

Expand All @@ -49,6 +52,17 @@ public final class DynamicPathTest {
@Rule
public final TemporaryFolder folder = new TemporaryFolder();


/**
* Resets the static dynamic segment and policy fields.
*/
@After
public void reset() {
Whitebox.setInternalState(DynamicSegment.class, boolean.class, false, DynamicSegment.class);
Whitebox.setInternalState(DynamicSegment.class, String.class, null, DynamicSegment.class);
Whitebox.setInternalState(DynamicPolicy.class, boolean.class, false, DynamicPolicy.class);
}

/**
* Verifies that a static path without any patterns can be resolved.
*
Expand Down
108 changes: 90 additions & 18 deletions tinylog-impl/src/test/java/org/tinylog/path/DynamicSegmentTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@

package org.tinylog.path;

import org.junit.After;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
import org.tinylog.policies.DynamicPolicy;

import static org.assertj.core.api.Assertions.assertThat;

Expand All @@ -23,49 +26,118 @@
public final class DynamicSegmentTest {

/**
* Verifies that the passed initial dynamic text as well as the dynamic text set via
* {@link DynamicSegment#setText(String)} will be returned as static text.
* Resets the static dynamic segment and policy fields.
*/
@After
public void reset() {
Whitebox.setInternalState(DynamicSegment.class, boolean.class, false, DynamicSegment.class);
Whitebox.setInternalState(DynamicSegment.class, String.class, null, DynamicSegment.class);
Whitebox.setInternalState(DynamicPolicy.class, boolean.class, false, DynamicPolicy.class);
}

/**
* Verifies that the passed default value will be used as dynamic text, if no other dynamic text is set yet.
*/
@Test
public void useDefaultValueIfTextAbsence() {
new DynamicSegment("foo");
assertThat(DynamicSegment.getText()).isEqualTo("foo");
}

/**
* Verifies that the passed default value will not be used as dynamic text, if another dynamic text is already set.
*/
@Test
public void useDefaultValueIfTextPresent() {
DynamicSegment.setText("bar");
new DynamicSegment("foo");
assertThat(DynamicSegment.getText()).isEqualTo("bar");
}

/**
* Verifies that the dynamic text can be set globally without triggering a rollover event.
*/
@Test
public void doesHaveStaticText() {
DynamicSegment segment = new DynamicSegment("test");
assertThat(segment.getStaticText()).isEqualTo("test");
public void setTextInitially() {
DynamicSegment.setText("foo");
assertThat(DynamicSegment.getText()).isEqualTo("foo");
assertThat(new DynamicPolicy(null).continueCurrentFile(new byte[0])).isTrue();
}

/**
* Verifies that the dynamic text can be overridden globally without triggering a rollover event.
*/
@Test
public void overrideExistingText() {
DynamicSegment.setText("foo");
DynamicSegment.setText("bar");
assertThat(DynamicSegment.getText()).isEqualTo("bar");
assertThat(new DynamicPolicy(null).continueCurrentFile(new byte[0])).isTrue();
}

/**
* Verifies setting a new dynamic text will trigger a rollover event, if it is different from the previous dynamic
* text and is already in use.
*/
@Test
public void triggerResetForDifferentText() {
DynamicSegment segment = new DynamicSegment("foo");
assertThat(segment.getStaticText()).isEqualTo("foo");
assertThat(new DynamicPolicy(null).continueCurrentFile(new byte[0])).isTrue();

DynamicSegment.setText("bar");
assertThat(segment.getStaticText()).isEqualTo("bar");
assertThat(new DynamicPolicy(null).continueCurrentFile(new byte[0])).isFalse();
}

/**
* Verifies that the passed initial dynamic text as well as the dynamic text set via
* {@link DynamicSegment#setText(String)} will be returned as generated token.
* Verifies setting the same dynamic text again will not trigger a rollover event, even if it is already in use.
*/
@Test
public void createToken() {
DynamicSegment segment = new DynamicSegment("test");
assertThat(segment.createToken(null, null)).isEqualTo("test");
public void preventResetForSameText() {
DynamicSegment segment = new DynamicSegment("foo");
assertThat(segment.getStaticText()).isEqualTo("foo");
assertThat(new DynamicPolicy(null).continueCurrentFile(new byte[0])).isTrue();

DynamicSegment.setText("foo");
assertThat(segment.getStaticText()).isEqualTo("foo");
assertThat(new DynamicPolicy(null).continueCurrentFile(new byte[0])).isTrue();
}

DynamicSegment.setText("bar");
assertThat(segment.getStaticText()).isEqualTo("bar");
/**
* Verifies that the current dynamic text will be returned as generated token.
*/
@Test
public void createToken() {
DynamicSegment segment = new DynamicSegment("foo");
assertThat(segment.createToken(null, null)).isEqualTo("foo");
}

/**
* Verifies that the dynamic text will be accepted as valid token.
* Verifies that a dynamic segment without a dynamic text will reject tokens.
*/
@Test
public void validateValidToken() {
DynamicSegment segment = new DynamicSegment("test");
assertThat(segment.validateToken("test")).isTrue();
public void validateNonExistingToken() {
DynamicSegment segment = new DynamicSegment(null);
assertThat(segment.validateToken("foo")).isFalse();
}

DynamicSegment.setText("foo");
assertThat(segment.validateToken("test")).isFalse();
/**
* Verifies that a dynamic segment with a dynamic text will accept the same tokens.
*/
@Test
public void validateValidToken() {
DynamicSegment segment = new DynamicSegment("foo");
assertThat(segment.validateToken("foo")).isTrue();
}

/**
* Verifies that a dynamic segment with a dynamic text will reject different tokens.
*/
@Test
public void validateInvalidToken() {
DynamicSegment segment = new DynamicSegment("foo");
assertThat(segment.validateToken("bar")).isFalse();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@

import java.io.IOException;

import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
import org.tinylog.configuration.ServiceLoader;
import org.tinylog.path.DynamicSegment;
import org.tinylog.rules.SystemStreamCollector;
import org.tinylog.util.FileSystem;

Expand All @@ -34,6 +37,16 @@ public final class DynamicPolicyTest {
@Rule
public final SystemStreamCollector systemStream = new SystemStreamCollector(true);

/**
* Resets the static dynamic segment and policy fields.
*/
@After
public void reset() {
Whitebox.setInternalState(DynamicSegment.class, boolean.class, false, DynamicSegment.class);
Whitebox.setInternalState(DynamicSegment.class, String.class, null, DynamicSegment.class);
Whitebox.setInternalState(DynamicPolicy.class, boolean.class, false, DynamicPolicy.class);
}

/**
* Verifies that an existing log file will always be continued.
*
Expand Down

0 comments on commit 9987105

Please sign in to comment.