Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4577 from rundeck/exp/thread-outputstream-core
Refactor: move threadbound log outstream to core
- Loading branch information
Showing
16 changed files
with
658 additions
and
351 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
core/src/main/java/com/dtolabs/rundeck/core/utils/LogBuffer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright 2019 Rundeck, Inc. (http://rundeck.com) | ||
* | ||
* Licensed 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 com.dtolabs.rundeck.core.utils; | ||
|
||
/** | ||
* Buffer for capturing data into another data type | ||
* | ||
* @param <D> data type | ||
*/ | ||
public interface LogBuffer<D> { | ||
/** | ||
* @return true if empty | ||
*/ | ||
boolean isEmpty(); | ||
|
||
/** | ||
* reset buffer | ||
*/ | ||
void reset(); | ||
|
||
/** | ||
* write a byte | ||
* | ||
* @param b data | ||
*/ | ||
void write(byte b); | ||
|
||
/** | ||
* Clear the buffer | ||
*/ | ||
void clear(); | ||
|
||
/** | ||
* @return result datatype | ||
*/ | ||
D get(); | ||
} |
42 changes: 42 additions & 0 deletions
42
core/src/main/java/com/dtolabs/rundeck/core/utils/LogBufferManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright 2019 Rundeck, Inc. (http://rundeck.com) | ||
* | ||
* Licensed 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 com.dtolabs.rundeck.core.utils; | ||
|
||
import java.nio.charset.Charset; | ||
import java.util.function.Consumer; | ||
|
||
/** | ||
* Manager for log buffers for a data type | ||
* | ||
* @param <D> datatype | ||
* @param <T> log buffer type | ||
*/ | ||
public interface LogBufferManager<D, T extends LogBuffer<D>> { | ||
/** | ||
* Create a new log buffer with the charset | ||
* | ||
* @param charset charset | ||
*/ | ||
T create(Charset charset); | ||
|
||
/** | ||
* Flush all buffers with the consumer | ||
* | ||
* @param writer consumer of log events | ||
*/ | ||
void flush(Consumer<D> writer); | ||
} |
62 changes: 62 additions & 0 deletions
62
core/src/main/java/com/dtolabs/rundeck/core/utils/StringLogBuffer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright 2019 Rundeck, Inc. (http://rundeck.com) | ||
* | ||
* Licensed 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 com.dtolabs.rundeck.core.utils; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.nio.charset.Charset; | ||
|
||
/** | ||
* Implements basic buffer of data into a String | ||
*/ | ||
public class StringLogBuffer | ||
implements LogBuffer<String> | ||
{ | ||
private ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
private final Charset charset; | ||
|
||
public StringLogBuffer(final Charset charset) { | ||
this.charset = charset; | ||
} | ||
|
||
@Override | ||
public boolean isEmpty() { | ||
return baos.size() == 0; | ||
} | ||
|
||
@Override | ||
public void reset() { | ||
baos = new ByteArrayOutputStream(); | ||
} | ||
|
||
@Override | ||
public void write(final byte b) { | ||
baos.write(b); | ||
} | ||
|
||
@Override | ||
public void clear() { | ||
reset(); | ||
} | ||
|
||
/** | ||
* @return contents as string | ||
*/ | ||
public String get() { | ||
return charset != null ? new String(baos.toByteArray(), charset) : new String(baos.toByteArray()); | ||
} | ||
|
||
} |
57 changes: 57 additions & 0 deletions
57
core/src/main/java/com/dtolabs/rundeck/core/utils/StringLogManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright 2019 Rundeck, Inc. (http://rundeck.com) | ||
* | ||
* Licensed 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 com.dtolabs.rundeck.core.utils; | ||
|
||
import java.nio.charset.Charset; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.function.Consumer; | ||
|
||
/** | ||
* Managers string log buffers | ||
*/ | ||
public class StringLogManager | ||
implements LogBufferManager<String, StringLogBuffer> | ||
|
||
{ | ||
private List<StringLogBuffer> buffers = new ArrayList<>(); | ||
private Charset charset; | ||
|
||
public StringLogManager(final Charset charset) { | ||
this.charset = charset; | ||
} | ||
|
||
@Override | ||
public StringLogBuffer create(final Charset charset) { | ||
StringLogBuffer buffer = new StringLogBuffer(charset != null ? charset : this.charset); | ||
buffers.add(buffer); | ||
return buffer; | ||
} | ||
|
||
@Override | ||
public void flush(final Consumer<String> writer) { | ||
for (StringLogBuffer buffer : buffers) { | ||
writer.accept(buffer.get()); | ||
buffer.clear(); | ||
} | ||
buffers.clear(); | ||
} | ||
|
||
public static StringLogManager factory(Charset charset) { | ||
return new StringLogManager(charset); | ||
} | ||
} |
171 changes: 171 additions & 0 deletions
171
core/src/main/java/com/dtolabs/rundeck/core/utils/ThreadBoundLogOutputStream.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
/* | ||
* Copyright 2016 SimplifyOps, Inc. (http://simplifyops.com) | ||
* | ||
* Licensed 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 com.dtolabs.rundeck.core.utils; | ||
|
||
import lombok.Data; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.nio.charset.Charset; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
|
||
/** | ||
* Thread local buffered log output | ||
* 解决rundeck中文log乱码的问题,此文件在rundeck源文件路径:./rundeckapp/src/groovy/com/dtolabs/rundeck/app/internal/logging/ThreadBoundLogOutputStream.groovy | ||
* yeml#ucweb.com | ||
*/ | ||
public class ThreadBoundLogOutputStream<D, T extends LogBuffer<D>> | ||
extends OutputStream | ||
{ | ||
private Consumer<D> logger; | ||
private ThreadLocal<Holder<T>> buffer = new ThreadLocal<>(); | ||
private InheritableThreadLocal<LogBufferManager<D,T>> manager = new InheritableThreadLocal<>(); | ||
private InheritableThreadLocal<Charset> charset = new InheritableThreadLocal<>(); | ||
private Function<Charset, LogBufferManager<D,T>> factory; | ||
|
||
@Data | ||
@RequiredArgsConstructor | ||
private static class Holder<X extends LogBuffer> { | ||
final X buffer; | ||
boolean crchar; | ||
|
||
public void clear() { | ||
crchar = false; | ||
buffer.clear(); | ||
} | ||
|
||
public void reset() { | ||
crchar = false; | ||
buffer.reset(); | ||
} | ||
} | ||
/** | ||
* Create a new thread local buffered stream | ||
* @param logger logger for events | ||
*/ | ||
public ThreadBoundLogOutputStream( | ||
Consumer<D> logger, | ||
Charset charset, | ||
Function<Charset, LogBufferManager<D,T>> factory | ||
) | ||
{ | ||
this.logger = logger; | ||
this.charset.set(charset); | ||
this.factory = factory; | ||
} | ||
/** | ||
* Set the charset to use | ||
* @param charset new charset | ||
* @return previous charset | ||
*/ | ||
public Charset setCharset(Charset charset) { | ||
Charset prev = this.charset.get(); | ||
this.charset.set(charset); | ||
return prev; | ||
} | ||
|
||
/** | ||
* Install a new inherited thread local buffer manager and return it | ||
* @return manager | ||
*/ | ||
public LogBufferManager<D,T> installManager() { | ||
LogBufferManager<D,T> manager = factory.apply(charset.get()); | ||
this.manager.set(manager); | ||
return manager; | ||
} | ||
|
||
/** | ||
* If no manager is set, install one, otherwise return the existing one | ||
* @return | ||
*/ | ||
private LogBufferManager<D,T> getOrCreateManager() { | ||
if (null == manager.get()) { | ||
installManager(); | ||
} | ||
return manager.get(); | ||
} | ||
|
||
/** | ||
* Write output | ||
* @param b | ||
*/ | ||
public void write(final int b) { | ||
Holder<T> log = getOrReset(); | ||
if (b == '\n') { | ||
flushEventBuffer(); | ||
} else if (b == '\r') { | ||
log.setCrchar(true); | ||
} else { | ||
if (log.isCrchar()) { | ||
flushEventBuffer(); | ||
resetEventBuffer(); | ||
} | ||
log.getBuffer().write((byte) b); | ||
} | ||
|
||
} | ||
|
||
/** | ||
* get the thread's event buffer, reset it if it is empty | ||
* @return | ||
*/ | ||
private Holder<T> getOrReset() { | ||
if (buffer.get() == null || buffer.get().getBuffer().isEmpty()) { | ||
resetEventBuffer(); | ||
} | ||
return buffer.get(); | ||
} | ||
|
||
/** | ||
* reset existing or create a new buffer with the current context | ||
*/ | ||
private void resetEventBuffer() { | ||
if (buffer.get() == null) { | ||
buffer.set(new Holder<>(getOrCreateManager().create(charset.get()))); | ||
} else { | ||
buffer.get().reset(); | ||
} | ||
} | ||
|
||
/** | ||
* emit a log event for the current contents of the buffer | ||
*/ | ||
private void flushEventBuffer() { | ||
Holder<T> holder = buffer.get(); | ||
logger.accept(holder.getBuffer().get()); | ||
holder.clear(); | ||
} | ||
|
||
/** | ||
* Flush all event buffers managed by the current manager | ||
*/ | ||
public void flushBuffers() { | ||
getOrCreateManager().flush(logger); | ||
} | ||
|
||
public void flush() { | ||
} | ||
|
||
@Override | ||
public void close() throws IOException { | ||
flushBuffers(); | ||
|
||
super.close(); | ||
} | ||
} |
Oops, something went wrong.