1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 module thrift.base;
20 
21 /**
22  * Common base class for all Thrift exceptions.
23  */
24 class TException : Exception {
25   ///
26   this(string msg = "", string file = __FILE__, size_t line = __LINE__,
27     Throwable next = null)
28   {
29     super(msg, file, line, next);
30   }
31 }
32 
33 /**
34  * An operation failed because one or more sub-tasks failed.
35  */
36 class TCompoundOperationException : TException {
37   ///
38   this(string msg, Exception[] exceptions, string file = __FILE__,
39     size_t line = __LINE__, Throwable next = null)
40   {
41     super(msg, file, line, next);
42     this.exceptions = exceptions;
43   }
44 
45   /// The exceptions thrown by the children of the operation. If applicable,
46   /// the list is ordered in the same way the exceptions occurred.
47   Exception[] exceptions;
48 }
49 
50 /// The Thrift version string, used for informative purposes.
51 // Note: This is currently hardcoded, but will likely be filled in by the build
52 // system in future versions.
53 enum VERSION = "0.16.0";
54 
55 /**
56  * Functions used for logging inside Thrift.
57  *
58  * By default, the formatted messages are written to stdout/stderr, but this
59  * behavior can be overwritten by providing custom g_{Info, Error}LogSink
60  * handlers.
61  *
62  * Examples:
63  * ---
64  * logInfo("An informative message.");
65  * logError("Some error occurred: %s", e);
66  * ---
67  */
68 alias logFormatted!g_infoLogSink logInfo;
69 alias logFormatted!g_errorLogSink logError; /// Ditto
70 
71 /**
72  * Error and info log message sinks.
73  *
74  * These delegates are called with the log message passed as const(char)[]
75  * argument, and can be overwritten to hook the Thrift libraries up with a
76  * custom logging system. By default, they forward all output to stdout/stderr.
77  */
78 __gshared void delegate(const(char)[]) g_infoLogSink;
79 __gshared void delegate(const(char)[]) g_errorLogSink; /// Ditto
80 
81 shared static this() {
82   import std.stdio;
83 
84   g_infoLogSink = (const(char)[] text) {
85     stdout.writeln(text);
86   };
87 
88   g_errorLogSink = (const(char)[] text) {
89     stderr.writeln(text);
90   };
91 }
92 
93 // This should be private, if it could still be used through the aliases then.
94 template logFormatted(alias target) {
95   void logFormatted(string file = __FILE__, int line = __LINE__,
96     T...)(string fmt, T args) if (
97     __traits(compiles, { target(""); })
98   ) {
99     import std.format, std.stdio;
100     if (target !is null) {
101       scope(exit) g_formatBuffer.clear();
102 
103       // Phobos @@BUG@@: If the empty string put() is removed, Appender.data
104       // stays empty.
105       g_formatBuffer.put("");
106 
107       formattedWrite(g_formatBuffer, "%s:%s: ", file, line);
108 
109       static if (T.length == 0) {
110         g_formatBuffer.put(fmt);
111       } else {
112         formattedWrite(g_formatBuffer, fmt, args);
113       }
114       target(g_formatBuffer.data);
115     }
116   }
117 }
118 
119 private {
120   // Use a global, but thread-local buffer for constructing log messages.
121   import std.array : Appender;
122   Appender!(char[]) g_formatBuffer;
123 }