diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/jaegertracing/thrift/contrib | |
parent | Initial commit. (diff) | |
download | ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
107 files changed, 9696 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/contrib/Rebus/App.config b/src/jaegertracing/thrift/contrib/Rebus/App.config new file mode 100644 index 000000000..4208af6b2 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/App.config @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<configuration> + + <configSections> + <section name="rebus" type="Rebus.Configuration.RebusConfigurationSection, Rebus"/> + </configSections> + + <rebus inputQueue="MyResponses" errorQueue="MyErrors" workers="1"> + <endpoints> + <add messages="RebusSample.MathRequestCall, RebusSample" endpoint="MathRequests"/> + <add messages="RebusSample.MathResponseCall, RebusSample" endpoint="MathResponses"/> + </endpoints> + </rebus> + + <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration> diff --git a/src/jaegertracing/thrift/contrib/Rebus/Program.cs b/src/jaegertracing/thrift/contrib/Rebus/Program.cs new file mode 100644 index 000000000..563c62ad5 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/Program.cs @@ -0,0 +1,81 @@ +/** + * 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. + */ + +using Rebus.Configuration; +using Rebus.RabbitMQ; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RebusSample.Client; +using RebusSample.Server; + +namespace RebusSample +{ + class Program + { + static BuiltinContainerAdapter StartRequestServer(string server) + { + // client Rebus configuration + var adapter = new BuiltinContainerAdapter(); + Configure.With(adapter) + .Transport(t => t.UseRabbitMq("amqp://" + server, "MathRequests", "MathRequestErrors")) + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + + // register all relevant message handlers + adapter.Register(typeof(MathRequestCallHandler)); + return adapter; + } + + + static BuiltinContainerAdapter StartResponseServer(string server) + { + // client Rebus configuration + var adapter = new BuiltinContainerAdapter(); + Configure.With(adapter) + .Transport(t => t.UseRabbitMq("amqp://" + server, "MathResponses", "MathResponseErrors")) + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + + // register all relevant message handlers + adapter.Register(typeof(MathResponseCallHandler)); + return adapter; + } + + static void Main(string[] args) + { + string server = "localhost"; + + // start all servers + var req = StartRequestServer(server); + var rsp = StartResponseServer(server); + + // send the first message + var random = new Random(); + var client = new MathRequestClient(server); + client.DoTheMath(random.Next(), random.Next()); + + // now what? + Console.Write("Hit <ENTER> to stop ... "); + Console.ReadLine(); + } + } +} diff --git a/src/jaegertracing/thrift/contrib/Rebus/Properties/AssemblyInfo.cs b/src/jaegertracing/thrift/contrib/Rebus/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..e476eab76 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +/** + * 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. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("RebusSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RebusSample")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("0af10984-40d3-453d-b1e5-421529e8c7e2")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/jaegertracing/thrift/contrib/Rebus/README.md b/src/jaegertracing/thrift/contrib/Rebus/README.md new file mode 100644 index 000000000..bbb9c496e --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/README.md @@ -0,0 +1,21 @@ +Sample code for the combination of Thrift with Rebus. + +Rebus is a .NET service bus, similar to NServiceBus, but more lightweight. +It ihas been mainly written by Mogens Heller Grabe and is currently hosted +on GitHub (https://github.com/rebus-org/Rebus) + +As with all ServiceBus or MQ scenarios, due to the highly asynchronous +operations it is recommended to do all calls as "oneway void" calls. + +The configuration can be done via App.Config, via code or even mixed from +both locations. Refer to the Rebus documentation for further details. For +this example, since we are effectively implementing two queue listeners in +only one single process, we do configuration of incoming and error queues +in the code. + +If you want to communicate with non-NET languages, you may need a customized +serializer as well, in order to override Rebus' default wire format. Please +refer to the Rebus docs on how to do that (it's not that hard, really). + +Additional requirements: +- RabbitMQ .NET client (see nuget) diff --git a/src/jaegertracing/thrift/contrib/Rebus/RebusSample.csproj b/src/jaegertracing/thrift/contrib/Rebus/RebusSample.csproj new file mode 100644 index 000000000..4058a6da2 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/RebusSample.csproj @@ -0,0 +1,102 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{264E2126-EDE0-4B47-89C1-B397B25BB13D}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>RebusSample</RootNamespace> + <AssemblyName>RebusSample</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="RabbitMQ.Client"> + <HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\rabbitmq-dotnet-client-3.2.1-dotnet-3.0\bin\RabbitMQ.Client.dll</HintPath> + </Reference> + <Reference Include="Rebus"> + <HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.dll</HintPath> + </Reference> + <Reference Include="Rebus.RabbitMQ"> + <HintPath>..\..\..\..\..\Toolbox\ServiceBus\3rdparty\Rebus-master\deploy\NET40\Rebus.RabbitMQ.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="gen-csharp\BasicMathClient.cs" /> + <Compile Include="gen-csharp\BasicMathServer.cs" /> + <Compile Include="ServiceImpl\Both.cs" /> + <Compile Include="ServiceImpl\Client.cs" /> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ServiceImpl\Server.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + </ItemGroup> + <ItemGroup /> + <ItemGroup> + <ProjectReference Include="..\..\lib\csharp\src\Thrift.csproj"> + <Project>{499eb63c-d74c-47e8-ae48-a2fc94538e9d}</Project> + <Name>Thrift</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <PropertyGroup> + <PreBuildEvent>cd $(ProjectDir) +if not exist gen-csharp\*.cs thrift -gen csharp sample.thrift +</PreBuildEvent> + </PropertyGroup> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/src/jaegertracing/thrift/contrib/Rebus/RebusSample.sln b/src/jaegertracing/thrift/contrib/Rebus/RebusSample.sln new file mode 100644 index 000000000..284ef36a7 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/RebusSample.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RebusSample", "RebusSample.csproj", "{264E2126-EDE0-4B47-89C1-B397B25BB13D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {264E2126-EDE0-4B47-89C1-B397B25BB13D}.Release|Any CPU.Build.0 = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Both.cs b/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Both.cs new file mode 100644 index 000000000..fba67ec15 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Both.cs @@ -0,0 +1,35 @@ +/** + * 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. + */ + +using System; + + +namespace RebusSample +{ + // generic data container for serialized Thrift calls + public class GenericThriftServiceCall + { + public byte[] rawBytes; + } + + // specific containers (one per Thrift service) to leverage Rebus' handler routing + public class MathRequestCall : GenericThriftServiceCall { } + public class MathResponseCall : GenericThriftServiceCall { } + +}
\ No newline at end of file diff --git a/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Client.cs b/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Client.cs new file mode 100644 index 000000000..2408041a9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Client.cs @@ -0,0 +1,157 @@ +/** + * 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. + */ + +using Rebus; +using Rebus.Configuration; +using Rebus.Messages; +using Rebus.RabbitMQ; +using System; +using System.Collections.Generic; +using System.IO; +using Thrift.Protocol; +using Thrift.Transport; + +/* + * The client emits calls to BasicMathServers + * + * The client implements the BasicMathClient service. + * If the server has processed our request, we get the results back through this service + */ + +namespace RebusSample.Client +{ + + // handler to be registered with Rebus + class MathResponseCallHandler : IHandleMessages<MathResponseCall> + { + public void Handle(MathResponseCall message) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(message.rawBytes); + var trns = new TStreamTransport(stm, null); + var prot = new TBinaryProtocol(trns); + + // create a processor and let him handle the call + var hndl = new MathResponsesHandler(); + var proc = new BasicMathClient.Processor(hndl); + proc.Process(prot, null); // oneway only + } + } + + + // serves incoming responses with calculation results + internal class MathResponsesHandler : BasicMathClient.Iface + { + public void FourResults(int added, int multiplied, int subtracted, int divided) + { + Console.WriteLine("added = {0}", added); + Console.WriteLine("multiplied= {0}", multiplied); + Console.WriteLine("subtracted = {0}", subtracted); + Console.WriteLine("divided = {0}", divided); + + PingAndDoAnotherCalculation(); + } + + + public void ThreeResults(int added, int multiplied, int subtracted) + { + Console.WriteLine("added = {0}", added); + Console.WriteLine("multiplied= {0}", multiplied); + Console.WriteLine("subtracted = {0}", subtracted); + Console.WriteLine("DIV/0 error during division"); + + PingAndDoAnotherCalculation(); + } + + + public void Pong(long value) + { + var latency = DateTime.Now.Ticks - value; + Console.WriteLine("Ping took {0} ms", new DateTime(latency).Millisecond); + } + + + private void PingAndDoAnotherCalculation() + { + var random = new Random(); + var client = new MathRequestClient("localhost"); + client.Ping(DateTime.Now.Ticks); + client.DoTheMath(random.Next(), random.Next()); + } + } + + + // provides the client-side interface for calculation requests + internal class MathRequestClient : BasicMathServer.Iface + { + private BuiltinContainerAdapter MQAdapter; + + + public MathRequestClient(string server) + { + MQAdapter = new BuiltinContainerAdapter(); + Configure.With(MQAdapter) + .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + } + + + public void SerializeThriftCall(Action<BasicMathServer.Iface> action) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(); + var trns = new TStreamTransport(null, stm); + var prot = new TBinaryProtocol(trns); + + // serialize the call into a bunch of bytes + var client = new BasicMathServer.Client(prot); + if( action != null) + action(client); + else + throw new ArgumentException("action must not be null"); + + // make sure everything is written to the MemoryStream + trns.Flush(); + + // send the message + var msg = new MathRequestCall() { rawBytes = stm.ToArray() }; + MQAdapter.Bus.Send(msg); + } + + + public void Ping(long value) + { + SerializeThriftCall(client => + { + client.Ping(value); + }); + } + + + public void DoTheMath( int arg1, int arg2) + { + SerializeThriftCall(client => + { + client.DoTheMath(arg1, arg2); + }); + } + } +} + diff --git a/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Server.cs b/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Server.cs new file mode 100644 index 000000000..149d513c6 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/ServiceImpl/Server.cs @@ -0,0 +1,143 @@ +/** + * 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. + */ + +using Rebus; +using Rebus.Configuration; +using Rebus.Messages; +using Rebus.RabbitMQ; +using System; +using System.Collections.Generic; +using System.IO; +using Thrift.Protocol; +using Thrift.Transport; + +/* + * The server implements the BasicMathServer service . + * All results are sent back to the client via the BasicMathClient service + */ + + +namespace RebusSample.Server +{ + // handler to be registered with Rebus + class MathRequestCallHandler : IHandleMessages<MathRequestCall> + { + public void Handle(MathRequestCall message) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(message.rawBytes); + var trns = new TStreamTransport(stm, null); + var prot = new TBinaryProtocol(trns); + + // create a processor and let him handle the call + var hndl = new MathRequestsHandler(); + var proc = new BasicMathServer.Processor(hndl); + proc.Process(prot, null); // oneway only + } + } + + + // serves incoming calculation requests + internal class MathRequestsHandler : BasicMathServer.Iface + { + public void Ping(long value) + { + var client = new MathResponseClient("localhost"); + client.Pong(value); + } + + + public void DoTheMath(int arg1, int arg2) + { + var client = new MathResponseClient("localhost"); + if( arg2 != 0) + client.FourResults( arg1+arg2, arg1*arg2, arg1-arg2, arg1/arg2); + else + client.ThreeResults( arg1+arg2, arg1*arg2, arg1-arg2); + } + } + + + // provides the client-side interface for calculation responses + internal class MathResponseClient : BasicMathClient.Iface + { + private BuiltinContainerAdapter MQAdapter; + + + public MathResponseClient(string server) + { + MQAdapter = new BuiltinContainerAdapter(); + Configure.With(MQAdapter) + .Transport(t => t.UseRabbitMqInOneWayMode("amqp://" + server)) // we need send only + .MessageOwnership(o => o.FromRebusConfigurationSection()) + .CreateBus().Start(); + } + + + public void SerializeThriftCall(Action<BasicMathClient.Iface> action) + { + // Thrift protocol/transport stack + var stm = new MemoryStream(); + var trns = new TStreamTransport(null, stm); + var prot = new TBinaryProtocol(trns); + + // serialize the call into a bunch of bytes + var client = new BasicMathClient.Client(prot); + if (action != null) + action(client); + else + throw new ArgumentException("action must not be null"); + + // make sure everything is written to the MemoryStream + trns.Flush(); + + // send the message + var msg = new MathResponseCall() { rawBytes = stm.ToArray() }; + MQAdapter.Bus.Send(msg); + } + + + public void Pong(long value) + { + SerializeThriftCall(client => + { + client.Pong(value); + }); + } + + + public void ThreeResults(int added, int multiplied, int suctracted) + { + SerializeThriftCall(client => + { + client.ThreeResults(added, multiplied, suctracted); + }); + } + + + public void FourResults(int added, int multiplied, int suctracted, int divided) + { + SerializeThriftCall(client => + { + client.FourResults(added, multiplied, suctracted, divided); + }); + } + } +} + diff --git a/src/jaegertracing/thrift/contrib/Rebus/sample.thrift b/src/jaegertracing/thrift/contrib/Rebus/sample.thrift new file mode 100644 index 000000000..785e2d38f --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Rebus/sample.thrift @@ -0,0 +1,30 @@ +/** + * 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. + */ + + +service BasicMathServer { + oneway void DoTheMath( 1: i32 arg1, 2: i32 arg2) + oneway void Ping(1: i64 value) +} + +service BasicMathClient { + oneway void ThreeResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted); + oneway void FourResults( 1 : i32 added, 2 : i32 multiplied, 3 : i32 subtracted, 4 : i32 divided); + oneway void Pong(1: i64 value) +} diff --git a/src/jaegertracing/thrift/contrib/Stomp/README.md b/src/jaegertracing/thrift/contrib/Stomp/README.md new file mode 100644 index 000000000..2e5f21cbf --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Stomp/README.md @@ -0,0 +1,18 @@ +Sample code for STOMP-based Thrift clients and/or servers. + +Although the sample Thrift STOMP Transport is written in +Delphi/Pascal, it can easily serve as a starting point for +similar implementations in other languages. + +STOMP is a protocol widely supported by many messaging systems, +such as Apache ActiveMQ, RabbitMQ and many others. In particular, +it can be used to communicate with Service-Bus products like Rebus +or NServiceBus, when running against a STOMP-capable MQ system. + +A prerequisite for this sample is the Delphi STOMP Adapter written +by Daniele Teti (http://www.danieleteti.it/stomp-client), currently +hosted at Google Code (http://code.google.com/p/delphistompclient). + +At the time of writing, the STOMP adapter does not fully support +binary data. Please check whether this has been fixed, otherwise +you have to use the JSON protocol (or to fix it on your own). diff --git a/src/jaegertracing/thrift/contrib/Stomp/Thrift.Transport.STOMP.pas b/src/jaegertracing/thrift/contrib/Stomp/Thrift.Transport.STOMP.pas new file mode 100644 index 000000000..7dfb3763c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Stomp/Thrift.Transport.STOMP.pas @@ -0,0 +1,200 @@ +(* + * 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. + *) + +unit Thrift.Transport.STOMP; + +interface + +uses + Classes,Windows, SysUtils, + Thrift, + Thrift.Transport, + Thrift.Protocol, + Thrift.Stream, + StompClient, + StompTypes; + +type + TStompTransportImpl = class( TStreamTransportImpl) + strict private + FData : TStringStream; + FServer : string; + FOutQueue : string; + FStompCli : IStompClient; + protected + function GetIsOpen: Boolean; override; + function Peek: Boolean; override; + public + constructor Create( const aServerAndPort, aOutQueue : string); + destructor Destroy; override; + + procedure Open(); override; + procedure Close(); override; + procedure Flush; override; + end; + + + TStompServerTransportImpl = class( TServerTransportImpl) + strict private + FServer : string; + FInQueue : string; + FClient : IStompClient; + protected + procedure Listen; override; + procedure Close; override; + function Accept( const fnAccepting: TProc): ITransport; override; + public + constructor Create( const aServerAndPort, aInQueue : string); + destructor Destroy; override; + end; + + +const + QUEUE_PREFIX = '/queue/'; + TOPIC_PREFIX = '/topic/'; + EXCHANGE_PREFIX = '/exchange/'; + + +implementation + + + +constructor TStompTransportImpl.Create( const aServerAndPort, aOutQueue : string); +var adapter : IThriftStream; +begin + FData := TStringStream.Create; + FServer := aServerAndPort; + FOutQueue := aOutQueue; + + adapter := TThriftStreamAdapterDelphi.Create( FData, FALSE); + inherited Create( nil, adapter); // output only +end; + + +destructor TStompTransportImpl.Destroy; +begin + inherited Destroy; + FreeAndNil( FData); + FStompCli := nil; +end; + + +function TStompTransportImpl.GetIsOpen: Boolean; +begin + result := (FStompCli <> nil); +end; + + +function TStompTransportImpl.Peek: Boolean; +begin + result := FALSE; // output only +end; + + +procedure TStompTransportImpl.Open; +begin + if FStompCli <> nil + then raise TTransportException.Create( TTransportException.TExceptionType.AlreadyOpen, 'already open') + else FStompCli := StompUtils.NewStomp( FServer); +end; + + +procedure TStompTransportImpl.Close; +begin + FStompCli := nil; + FData.Clear; +end; + + +procedure TStompTransportImpl.Flush; +begin + if FStompCli = nil + then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, 'not open'); + + FStompCli.Send( FOutQueue, FData.DataString); + FData.Clear; +end; + + +//--- TStompServerTransportImpl -------------------------------------------- + + +constructor TStompServerTransportImpl.Create( const aServerAndPort, aInQueue : string); +begin + inherited Create; + FServer := aServerAndPort; + FInQueue := aInQueue; +end; + + +destructor TStompServerTransportImpl.Destroy; +begin + try + Close; + finally + inherited Destroy; + end; +end; + + +procedure TStompServerTransportImpl.Listen; +begin + FClient := StompUtils.NewStomp(FServer); + FClient.Subscribe( FInQueue); +end; + + +procedure TStompServerTransportImpl.Close; +begin + if FClient <> nil then begin + FClient.Unsubscribe( FInQueue); + FClient := nil; + end; +end; + + +function TStompServerTransportImpl.Accept( const fnAccepting: TProc): ITransport; +var frame : IStompFrame; + adapter : IThriftStream; + stream : TStringStream; +begin + if FClient = nil + then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen, + 'Not connected.'); + + if Assigned(fnAccepting) + then fnAccepting(); + + try + frame := FClient.Receive(MAXINT); + if frame = nil then Exit(nil); + + stream := TStringStream.Create( frame.GetBody); + adapter := TThriftStreamAdapterDelphi.Create( stream, TRUE); + result := TStreamTransportImpl.Create( adapter, nil); + + except + on E: Exception + do raise TTransportException.Create( E.ToString ); + end; +end; + + +end. + diff --git a/src/jaegertracing/thrift/contrib/Vagrantfile b/src/jaegertracing/thrift/contrib/Vagrantfile new file mode 100644 index 000000000..b34056333 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/Vagrantfile @@ -0,0 +1,133 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# +# 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. +# + +$build_and_test = <<SCRIPT +echo "Provisioning system to compile and test Apache Thrift." + +# Create swap space +sudo fallocate -l 2G /swapfile +sudo chmod 600 /swapfile +sudo mkswap /swapfile +sudo swapon /swapfile +sudo swapon -s + +# Update the system +sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq -y +sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq -y + +# Install Dependencies +# --- +# General dependencies +sudo apt-get install -qq automake libtool flex bison pkg-config g++ libssl-dev make git debhelper + +# C++ dependencies +sudo apt-get install -qq libboost-dev libboost-test-dev libboost-program-options-dev libboost-filesystem-dev libboost-system-dev libevent-dev + +# Java dependencies +sudo apt-get install -qq ant openjdk-8-jdk maven + +# Python dependencies +sudo apt-get install -qq python-all python-all-dev python-all-dbg python-setuptools python-support python-six python3-six + +# Ruby dependencies +sudo apt-get install -qq ruby ruby-dev +sudo gem install bundler rake + +# Perl dependencies +sudo apt-get install -qq libbit-vector-perl libclass-accessor-class-perl + +# Php dependencies +sudo apt-get install -qq php5 php5-dev php5-cli php-pear re2c + +# GlibC dependencies +sudo apt-get install -qq libglib2.0-dev + +# Erlang dependencies +sudo apt-get install -qq erlang-base erlang-eunit erlang-dev erlang-tools + +# GO dependencies +echo "golang-go golang-go/dashboard boolean false" | debconf-set-selections +sudo apt-get -y install -qq golang golang-go + +# Haskell dependencies +sudo apt-get install -qq ghc cabal-install libghc-binary-dev libghc-network-dev libghc-http-dev libghc-hashable-dev libghc-unordered-containers-dev libghc-vector-dev +sudo cabal update + +# Lua dependencies +sudo apt-get install -qq lua5.2 lua5.2-dev + +# Node.js dependencies +sudo apt-get install -qq nodejs nodejs-dev nodejs-legacy npm + +# CSharp +sudo apt-get install -qq mono-gmcs mono-devel mono-xbuild mono-complete libmono-system-web2.0-cil +sudo apt-get install -qq mingw32 mingw32-binutils mingw32-runtime nsis + +# D dependencies +sudo wget http://master.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list +sudo apt-get update && sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring && sudo apt-get update +sudo apt-get install -qq xdg-utils dmd-bin + +# Customize the system +# --- +# Default java to latest 1.8 version +update-java-alternatives -s java-1.8.0-openjdk-amd64 + +# PHPUnit package broken in ubuntu. see https://bugs.launchpad.net/ubuntu/+source/phpunit/+bug/701544 +sudo apt-get upgrade pear +sudo pear channel-discover pear.phpunit.de +sudo pear channel-discover pear.symfony.com +sudo pear channel-discover components.ez.no +sudo pear update-channels +sudo pear upgrade-all +sudo pear install --alldeps phpunit/PHPUnit + +date > /etc/vagrant.provisioned + +# Start the source build +# --- +echo "Starting Apache Thrift build..." +cd /thrift +sh bootstrap.sh +sh configure +make +make check +echo "Finished building Apache Thrift." + +SCRIPT + +Vagrant.configure("2") do |config| + # Ubuntu 14.04 LTS (Trusty Tahr) + config.vm.box = "trusty64" + config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box" + + config.vm.synced_folder "../", "/thrift" + + config.vm.provider :virtualbox do |vbox| + vbox.customize ["modifyvm", :id, "--memory", "1024"] + vbox.customize ["modifyvm", :id, "--cpus", "2"] + vbox.customize ["modifyvm", :id, "--rtcuseutc", "on"] + end + + # Run the build script to configure the system + config.vm.provision :shell, :inline => $build_and_test +end diff --git a/src/jaegertracing/thrift/contrib/async-test/Makefile b/src/jaegertracing/thrift/contrib/async-test/Makefile new file mode 100644 index 000000000..33e7f8ad1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/async-test/Makefile @@ -0,0 +1,33 @@ +THRIFT = thrift +CXXFLAGS = `pkg-config --cflags thrift thrift-nb` -levent +LDLIBS = `pkg-config --libs thrift thrift-nb` -levent +CXXFLAGS += -g -O0 + +GENNAMES = Aggr aggr_types +GENHEADERS = $(addsuffix .h, $(GENNAMES)) +GENSRCS = $(addsuffix .cpp, $(GENNAMES)) +GENOBJS = $(addsuffix .o, $(GENNAMES)) + +PYLIBS = aggr/__init__.py + +PROGS = test-server + +all: $(PYLIBS) $(PROGS) + +test-server: test-server.o $(GENOBJS) + +test-server.o: $(GENSRCS) + +aggr/__init__.py: aggr.thrift + $(RM) $(dir $@) + $(THRIFT) --gen py:newstyle $< + mv gen-py/$(dir $@) . + +$(GENSRCS): aggr.thrift + $(THRIFT) --gen cpp:cob_style $< + mv $(addprefix gen-cpp/, $(GENSRCS) $(GENHEADERS)) . + +clean: + $(RM) -r *.o $(PROGS) $(GENSRCS) $(GENHEADERS) gen-* aggr + +.PHONY: clean diff --git a/src/jaegertracing/thrift/contrib/async-test/aggr.thrift b/src/jaegertracing/thrift/contrib/async-test/aggr.thrift new file mode 100644 index 000000000..c016a65d8 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/async-test/aggr.thrift @@ -0,0 +1,8 @@ +exception Error { + 1: string desc; +} + +service Aggr { + void addValue(1: i32 value); + list<i32> getValues() throws (1: Error err); +} diff --git a/src/jaegertracing/thrift/contrib/async-test/test-leaf.py b/src/jaegertracing/thrift/contrib/async-test/test-leaf.py new file mode 100755 index 000000000..4ea4a9b8c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/async-test/test-leaf.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +import sys +import time +from thrift.transport import TTransport +from thrift.transport import TSocket +from thrift.protocol import TBinaryProtocol +from thrift.server import THttpServer +from aggr import Aggr + + +class AggrHandler(Aggr.Iface): + def __init__(self): + self.values = [] + + def addValue(self, value): + self.values.append(value) + + def getValues(self, ): + time.sleep(1) + return self.values + +processor = Aggr.Processor(AggrHandler()) +pfactory = TBinaryProtocol.TBinaryProtocolFactory() +THttpServer.THttpServer(processor, ('', int(sys.argv[1])), pfactory).serve() diff --git a/src/jaegertracing/thrift/contrib/async-test/test-server.cpp b/src/jaegertracing/thrift/contrib/async-test/test-server.cpp new file mode 100644 index 000000000..b304e1bc9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/async-test/test-server.cpp @@ -0,0 +1,97 @@ +#include <tr1/functional> +#include <thrift/protocol/TBinaryProtocol.h> +#include <thrift/async/TAsyncProtocolProcessor.h> +#include <thrift/async/TEvhttpServer.h> +#include <thrift/async/TEvhttpClientChannel.h> +#include "Aggr.h" + +using std::tr1::bind; +using std::tr1::placeholders::_1; + +using apache::thrift::TException; +using apache::thrift::protocol::TBinaryProtocolFactory; +using apache::thrift::protocol::TProtocolFactory; +using apache::thrift::async::TEvhttpServer; +using apache::thrift::async::TAsyncProcessor; +using apache::thrift::async::TAsyncBufferProcessor; +using apache::thrift::async::TAsyncProtocolProcessor; +using apache::thrift::async::TAsyncChannel; +using apache::thrift::async::TEvhttpClientChannel; + +class AggrAsyncHandler : public AggrCobSvIf { + protected: + struct RequestContext { + std::tr1::function<void(std::vector<int32_t> const& _return)> cob; + std::vector<int32_t> ret; + int pending_calls; + }; + + public: + AggrAsyncHandler() + : eb_(NULL) + , pfact_(new TBinaryProtocolFactory()) + { + leaf_ports_.push_back(8081); + leaf_ports_.push_back(8082); + } + + void addValue(std::tr1::function<void()> cob, const int32_t value) { + // Silently drop writes to the aggrgator. + return cob(); + } + + void getValues(std::tr1::function<void( + std::vector<int32_t> const& _return)> cob, + std::tr1::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob) { + RequestContext* ctx = new RequestContext(); + ctx->cob = cob; + ctx->pending_calls = leaf_ports_.size(); + for (std::vector<int>::iterator it = leaf_ports_.begin(); + it != leaf_ports_.end(); ++it) { + boost::shared_ptr<TAsyncChannel> channel( + new TEvhttpClientChannel( + "localhost", "/", "127.0.0.1", *it, eb_)); + AggrCobClient* client = new AggrCobClient(channel, pfact_.get()); + client->getValues(std::tr1::bind(&AggrAsyncHandler::clientReturn, this, ctx, _1)); + } + } + + void setEventBase(struct event_base* eb) { + eb_ = eb; + } + + void clientReturn(RequestContext* ctx, AggrCobClient* client) { + ctx->pending_calls -= 1; + + try { + std::vector<int32_t> subret; + client->recv_getValues(subret); + ctx->ret.insert(ctx->ret.end(), subret.begin(), subret.end()); + } catch (TException& exn) { + // TODO: Log error + } + + delete client; + + if (ctx->pending_calls == 0) { + ctx->cob(ctx->ret); + delete ctx; + } + } + + protected: + struct event_base* eb_; + std::vector<int> leaf_ports_; + boost::shared_ptr<TProtocolFactory> pfact_; +}; + + +int main() { + boost::shared_ptr<AggrAsyncHandler> handler(new AggrAsyncHandler()); + boost::shared_ptr<TAsyncProcessor> proc(new AggrAsyncProcessor(handler)); + boost::shared_ptr<TProtocolFactory> pfact(new TBinaryProtocolFactory()); + boost::shared_ptr<TAsyncBufferProcessor> bufproc(new TAsyncProtocolProcessor(proc, pfact)); + boost::shared_ptr<TEvhttpServer> server(new TEvhttpServer(bufproc, 8080)); + handler->setEventBase(server->getEventBase()); + server->serve(); +} diff --git a/src/jaegertracing/thrift/contrib/fb303/LICENSE b/src/jaegertracing/thrift/contrib/fb303/LICENSE new file mode 100644 index 000000000..4eacb6431 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/LICENSE @@ -0,0 +1,16 @@ +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. diff --git a/src/jaegertracing/thrift/contrib/fb303/Makefile.am b/src/jaegertracing/thrift/contrib/fb303/Makefile.am new file mode 100644 index 000000000..e773e522c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/Makefile.am @@ -0,0 +1,46 @@ +# +# 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. +# + +@GLOBAL_HEADER_MK@ + +@PRODUCT_MK@ + +SUBDIRS = . + +if WITH_CPP +SUBDIRS += cpp +endif + +if WITH_JAVA +SUBDIRS += java +endif + +if WITH_PHP +SUBDIRS += php +endif + +if WITH_PYTHON +SUBDIRS += py +endif + +BUILT_SOURCES = + +clean-local: clean-common + +@GLOBAL_FOOTER_MK@ diff --git a/src/jaegertracing/thrift/contrib/fb303/README.md b/src/jaegertracing/thrift/contrib/fb303/README.md new file mode 100644 index 000000000..8ade560c9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/README.md @@ -0,0 +1,37 @@ +Project FB303: The Facebook Bassline +------------------------------------ + +* Curious about the 303? * +http://en.wikipedia.org/wiki/Roland_TB-303 + +* Why the name? * +The TB303 makes bass lines. +.Bass is what lies underneath any strong tune. +..fb303 is the shared root of all thrift services. +...fb303 => FacebookBase303. + +* How do I use this? * +Take a look at the examples to see how your backend project can +and should inherit from this service. + +* What does it provide? * +A standard interface to monitoring, dynamic options and configuration, +uptime reports, activity, etc. + +* I want more. * +Think carefully first about whether the functionality you are going to add +belongs here or in your application. If it can be abstracted and is generally +useful, then it probably belongs somewhere in the fb303 tree. Keep in mind, +not every product has to use ALL the functionality of fb303, but every product +CANNOT use functionality that is NOT in fb303. + +* Is this open source? * +Yes. fb303 is distributed under the Thrift Software License. See the +LICENSE file for more details. + +* Installation * +fb303 is configured/built/installed similar to Thrift. See the README +in the Thrift root directory for more information. + +* Who wrote this README? * +mcslee@facebook.com diff --git a/src/jaegertracing/thrift/contrib/fb303/TClientInfo.cpp b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.cpp new file mode 100644 index 000000000..1fc661251 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.cpp @@ -0,0 +1,178 @@ +/* + * 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. + */ + +#include <thrift/server/TClientInfo.h> + +namespace apache { namespace thrift { namespace server { + +using namespace apache::thrift; +using namespace apache::thrift::transport; + +TClientInfoConnection::TClientInfoConnection() { + call_[kNameLen - 1] = '\0'; // insure NUL terminator is there + eraseAddr(); + eraseCall(); +} + +void TClientInfoConnection::recordAddr(const sockaddr* addr) { + eraseAddr(); + initTime(); + ncalls_ = 0; + if (addr != NULL) { + if (addr->sa_family == AF_INET) { + memcpy((void*)&addr_.ipv4, (const void *)addr, sizeof(sockaddr_in)); + } + else if (addr->sa_family == AF_INET6) { + memcpy((void*)&addr_.ipv6, (const void *)addr, sizeof(sockaddr_in6)); + } + } +} + +void TClientInfoConnection::eraseAddr() { + addr_.ipv4.sin_family = AF_UNSPEC; +} + +const char* TClientInfoConnection::getAddr(char* buf, int len) const { + switch (addr_.ipv4.sin_family) { + case AF_INET: + return inet_ntop(AF_INET, &addr_.ipv4.sin_addr, buf, len); + case AF_INET6: + return inet_ntop(AF_INET6, &addr_.ipv6.sin6_addr, buf, len); + default: + return NULL; + } +} + +void TClientInfoConnection::recordCall(const char* name) { + strncpy(call_, name, kNameLen - 1); // NUL terminator set in constructor + ncalls_++; +} + +void TClientInfoConnection::eraseCall() { + call_[0] = '\0'; +} + +const char* TClientInfoConnection::getCall() const { + if (call_[0] == '\0') { + return NULL; + } + return call_; +} + +void TClientInfoConnection::getTime(timespec* time) const { + *time = time_; +} + +uint64_t TClientInfoConnection::getNCalls() const { + return ncalls_; +} + +void TClientInfoConnection::initTime() { + clock_gettime(CLOCK_REALTIME, &time_); +} + + +TClientInfoConnection* TClientInfo::getConnection(int fd, bool grow) { + if (fd < 0 || (!grow && fd >= info_.size())) { + return NULL; + } + return &info_[fd]; +} + +size_t TClientInfo::size() const { + return info_.size(); +} + +void* TClientInfoServerHandler::createContext(boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output) { + (void)input; + (void)output; + return (void*) new Connect(&clientInfo_); +} + +void TClientInfoServerHandler::deleteContext(void* connectionContext, + boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output) { + Connect* call = static_cast<Connect*>(connectionContext); + if (call->callInfo_) { + call->callInfo_->eraseCall(); + } + delete call; +} + +void TClientInfoServerHandler::processContext(void* connectionContext, + shared_ptr<TTransport> transport) { + Connect* call = static_cast<Connect*>(connectionContext); + if (call->callInfo_ == NULL) { + if (typeid(*(transport.get())) == typeid(TSocket)) { + TSocket* tsocket = static_cast<TSocket*>(transport.get()); + int fd = tsocket->getSocketFD(); + if (fd < 0) { + return; + } + call->callInfo_ = call->clientInfo_->getConnection(fd, true); + assert(call->callInfo_ != NULL); + socklen_t len; + call->callInfo_->recordAddr(tsocket->getCachedAddress(&len)); + } + } +} + +void TClientInfoServerHandler::getStatsStrings(vector<string>& result) { + result.clear(); + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + for (int i = 0; i < clientInfo_.size(); ++i) { + TClientInfoConnection* info = clientInfo_.getConnection(i, false); + const char* callStr = info->getCall(); + if (callStr == NULL) { + continue; + } + + char addrBuf[INET6_ADDRSTRLEN]; + const char* addrStr = info->getAddr(addrBuf, sizeof addrBuf); + if (addrStr == NULL) { + // cerr << "no addr!" << endl; + continue; + } + + timespec start; + info->getTime(&start); + double secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001; + + char buf[256]; + snprintf(buf, sizeof buf, "%d %s %s %.3f %llu", i, addrStr, callStr, secs, + (uint64_t)info->getNCalls()); + + result.push_back(buf); + } +} + +void* TClientInfoCallHandler::getContext(const char* fn_name, void* serverContext) { + if (serverContext) { + TClientInfoConnection* callInfo = static_cast<TClientInfoServerHandler::Connect*>(serverContext)->callInfo_; + if (callInfo != NULL) { + callInfo->recordCall(fn_name); + } + } + return NULL; +} + +} } } // namespace apache::thrift::server diff --git a/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h new file mode 100644 index 000000000..6668c1921 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h @@ -0,0 +1,320 @@ +/* + * 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. + */ + +#ifndef _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ +#define _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ 1 + +// for inet_ntop -- +#include <arpa/inet.h> +#include <thrift/server/TServer.h> +#include <thrift/transport/TSocket.h> +#include <thrift/concurrency/Mutex.h> + +namespace apache { namespace thrift { namespace server { + +using namespace apache::thrift; +using namespace apache::thrift::transport; +using namespace apache::thrift::concurrency; +using boost::shared_ptr; +using std::string; +using std::vector; + +/** + * StableVector -- a minimal vector class where growth is automatic and + * vector elements never move as the vector grows. Allocates new space + * as needed, but does not copy old values. + * + * A level vector stores a list of storage vectors containing the actual + * elements. Levels are added as needed, doubling in size each time. + * Locking is only done when a level is added. Access is amortized + * constant time. + */ +template <typename T> +class StableVector { + /// The initial allocation as an exponent of 2 + static const uint32_t kInitialSizePowOf2 = 10; + /// The initial allocation size + static const uint32_t kInitialVectorSize = 1 << kInitialSizePowOf2; + /// This bound is guaranteed not to be exceeded on 64-bit archs + static const int kMaxLevels = 64; + + /// Values are kept in one or more of these + typedef vector<T> Vect; + /// One or more value vectors are kept in one of these + typedef vector<Vect*> LevelVector; + + Mutex mutex_; + /// current size + size_t size_; + _Atomic_word vectLvl_; + LevelVector vects_; + + public: + /** + * Constructor -- initialize the level vector and allocate the + * initial storage vector + */ + StableVector() + : size_(0) + , vectLvl_(0) { + vects_.reserve(kMaxLevels); + Vect* storageVector(new Vect(1 << kInitialSizePowOf2)); + vects_.push_back(storageVector); + } + + private: + /** + * make sure the requested number of storage levels have been allocated. + */ + void expand(uint32_t level) { + // we need the guard to insure that we only allocate once. + Guard g(mutex_); + while (level > vectLvl_) { + Vect* levelVect(new Vect(1 << (vectLvl_ + kInitialSizePowOf2))); + vects_.push_back(levelVect); + // we need to make sure this is done after levelVect is inserted + // (what we want is effectively a memory barrier here). + __gnu_cxx::__atomic_add(&vectLvl_, 1); + } + } + + /** + * Given an index, determine which level and element of that level is + * required. Grows if needed. + */ + void which(uint32_t n, uint32_t* vno, uint32_t* idx) { + if (n >= size_) { + size_ = n + 1; + } + if (n < kInitialVectorSize) { + *idx = n; + *vno = 0; + } else { + uint32_t upper = n >> kInitialSizePowOf2; + *vno = CHAR_BIT*sizeof(upper) - __builtin_clz(upper); + *idx = n - (1 << (*vno + kInitialSizePowOf2 - 1)); + if (*vno > vectLvl_) { + expand(*vno); + } + } + } + + public: + /** + * Given an index, return a reference to that element, perhaps after + * allocating additional space. + * + * @param n a positive integer + */ + T& operator[](uint32_t n) { + uint32_t vno; + uint32_t idx; + which(n, &vno, &idx); + return (*vects_[vno])[idx]; + } + + /** + * Return the present size of the vector. + */ + size_t size() const { return size_; } +}; + + +/** + * This class embodies the representation of a single connection during + * processing. We'll keep one of these per file descriptor in TClientInfo. + */ +class TClientInfoConnection { + public: + const static int kNameLen = 32; + + private: + typedef union IPAddrUnion { + sockaddr_in ipv4; + sockaddr_in6 ipv6; + }; + + char call_[kNameLen]; ///< The name of the thrift call + IPAddrUnion addr_; ///< The client's IP address + timespec time_; ///< Time processing started + uint64_t ncalls_; ///< # of calls processed + + public: + /** + * Constructor; insure that no client address or thrift call name is + * represented. + */ + TClientInfoConnection(); + + /** + * A connection has been made; record its address. Since this is the + * first we'll know of a connection we start the timer here as well. + */ + void recordAddr(const sockaddr* addr); + + /** + * Mark the address as empty/unknown. + */ + void eraseAddr(); + + /** + * Return a string representing the present address, or NULL if none. + * Copies the string into the buffer provided. + */ + const char* getAddr(char* buf, int len) const; + + /** + * A call has been made on this connection; record its name. Since this is + * called for every thrift call processed, we also do our call count here. + */ + void recordCall(const char* name); + + /** + * Invoked when processing has ended to clear the call name. + */ + void eraseCall(); + + /** + * Return as string the thrift call either currently being processed or + * most recently processed if the connection is still open for additional + * calls. Returns NULL if a call hasn't been made yet or processing + * has ended. + */ + const char* getCall() const; + + /** + * Get the timespec for the start of this connection (specifically, when + * recordAddr() was first called). + */ + void getTime(timespec* time) const; + + /** + * Return the number of calls made on this connection. + */ + uint64_t getNCalls() const; + + private: + void initTime(); +}; + + +/** + * Store for info about a server's clients -- specifically, the client's IP + * address and the call it is executing. This information is indexed by + * socket file descriptor and in the present implementation is updated + * asynchronously, so it may only approximate reality. + */ +class TClientInfo { + private: + StableVector<TClientInfoConnection> info_; + + public: + /** + * Return the info object for a given file descriptor. If "grow" is true + * extend the info vector if required (such as for a file descriptor not seen + * before). If "grow" is false and the info vector isn't large enough, + * or if "fd" is negative, return NULL. + */ + TClientInfoConnection* getConnection(int fd, bool grow); + + size_t size() const; +}; + +/** + * This derivation of TServerEventHandler encapsulates the main status vector + * and provides context to the server's processing loop via overrides. + * Together with TClientInfoCallHandler (derived from TProcessorEventHandler) + * it integrates client info collection into the server. + */ +class TClientInfoServerHandler : public TServerEventHandler { + private: + TClientInfo clientInfo_; + + public: + /** + * One of these is constructed for each open connection/descriptor and links + * to both the status vector (clientInfo_) and that descriptor's entry + * within it. + */ + struct Connect { + TClientInfo* clientInfo_; + TClientInfoConnection* callInfo_; + + explicit Connect(TClientInfo* clientInfo) + : clientInfo_(clientInfo) + , callInfo_(NULL) { + } + }; + + /** + * Generate processor context; we don't know what descriptor we belong to + * yet -- we'll get hooked up in contextProcess(). + */ + void* createContext(boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output); + + /** + * Mark our slot as unused and delete the context created in createContext(). + */ + void deleteContext(void* processorContext, + boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output); + + /** + * Called in the processing loop just before the server invokes the + * processor itself, on the first call we establish which descriptor + * we correspond to and set it to that socket's peer IP address. This + * also has the side effect of initializing call counting and connection + * timing. We won't know which call we're handling until the handler + * first gets called in TClientInfoCallHandler::getContext(). + */ + void processContext(void* processorContext, + shared_ptr<TTransport> transport); + + /** + * Get status report for server in the form of a vector of strings. + * Each active client appears as one string in the format: + * + * FD IPADDR CALLNAME DURATION NCALLS + * + * where "FD" is the file descriptor for the client's socket, "IPADDR" + * is the IP address (as reported by accept()), "CALLNAME" is the + * current or most recent Thrift function name, "DURATION" is the + * duration of the connection, while NCALLS is the number of Thrift + * calls made since the connection was made. A single space separates + * fields. + */ + void getStatsStrings(vector<string>& result); +}; + +/** + * This class derives from TProcessorEventHandler to gain access to the + * function name for the current Thrift call. We need two versions of + * this -- TClientInfoCallStatsHandler is the other -- since in the latter + * case we pass through to TFunctionStatHandler to perform Thrift call + * stats. + */ +class TClientInfoCallHandler : public TProcessorEventHandler { + public: + virtual void* getContext(const char* fn_name, void* serverContext); +}; + +} } } // namespace apache::thrift::server + +#endif // !_FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ diff --git a/src/jaegertracing/thrift/contrib/fb303/acinclude.m4 b/src/jaegertracing/thrift/contrib/fb303/acinclude.m4 new file mode 100644 index 000000000..faafba6b3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/acinclude.m4 @@ -0,0 +1,258 @@ +dnl Copyright (C) 2009 Facebook +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +AC_DEFUN([FB_INITIALIZE], +[ +AM_INIT_AUTOMAKE([ foreign 1.9.5 no-define ]) +if test "x$1" = "xlocalinstall"; then +wdir=`pwd` +# To use $wdir undef quote. +# +########## +AC_PREFIX_DEFAULT([`pwd`/install]) +echo +fi +AC_PROG_CC +AC_PROG_CXX +AC_PROG_RANLIB(RANLIB, ranlib) +AC_PATH_PROGS(BASH, bash) +AC_PATH_PROGS(PERL, perl) +AC_PATH_PROGS(PYTHON, python) +AC_PATH_PROGS(AR, ar) +AC_PATH_PROGS(ANT, ant) +PRODUCT_MK="" +]) + +AC_DEFUN([FB_WITH_EXTERNAL_PATH], +[ +cdir=`pwd` +AC_MSG_CHECKING([Checking EXTERNAL_PATH set to]) +AC_ARG_WITH([externalpath], + [ --with-externalpath=DIR User specified path to external facebook components.], + [ + if test "x${EXTERNAL_PATH}" != "x"; then + echo "" + echo "ERROR: You have already set EXTERNAL_PATH in your environment" + echo "Cannot override it using --with-externalpath. Unset EXTERNAL_PATH to use this option" + exit 1 + fi + EXTERNAL_PATH=$withval + ], + [ + if test "x${EXTERNAL_PATH}" = "x"; then + EXTERNAL_PATH=$1 + fi + ] +) +if test "x${EXTERNAL_PATH}" = "x"; then + export EXTERNAL_PATH="$cdir/external" + GLOBAL_HEADER_MK="include ${EXTERNAL_PATH}/global_header.mk" + GLOBAL_FOOTER_MK="include ${EXTERNAL_PATH}/global_footer.mk" +else + export EXTERNAL_PATH + GLOBAL_HEADER_MK="include ${EXTERNAL_PATH}/global_header.mk" + GLOBAL_FOOTER_MK="include ${EXTERNAL_PATH}/global_footer.mk" +fi +AC_MSG_RESULT($EXTERNAL_PATH) +if test ! -d ${EXTERNAL_PATH}; then + echo "" + echo "ERROR: EXTERNAL_PATH set to an nonexistent directory ${EXTERNAL_PATH}" + exit 1 +fi +AC_SUBST(EXTERNAL_PATH) +AC_SUBST(GLOBAL_HEADER_MK) +AC_SUBST(GLOBAL_FOOTER_MK) +]) + +# Set option to enable shared mode. Set DEBUG and OPT for use in Makefile.am. +AC_DEFUN([FB_ENABLE_DEFAULT_OPT_BUILD], +[ +AC_MSG_CHECKING([whether to enable optimized build]) +AC_ARG_ENABLE([opt], + [ --disable-opt Set up debug mode.], + [ + ENABLED_OPT=$enableval + ], + [ + ENABLED_OPT="yes" + ] +) +if test "$ENABLED_OPT" = "yes" +then + CFLAGS="-Wall -O3" + CXXFLAGS="-Wall -O3" +else + CFLAGS="-Wall -g" + CXXFLAGS="-Wall -g" +fi +AC_MSG_RESULT($ENABLED_OPT) +AM_CONDITIONAL([OPT], [test "$ENABLED_OPT" = yes]) +AM_CONDITIONAL([DEBUG], [test "$ENABLED_OPT" = no]) +]) + +# Set option to enable debug mode. Set DEBUG and OPT for use in Makefile.am. +AC_DEFUN([FB_ENABLE_DEFAULT_DEBUG_BUILD], +[ +AC_MSG_CHECKING([whether to enable debug build]) +AC_ARG_ENABLE([debug], + [ --disable-debug Set up opt mode.], + [ + ENABLED_DEBUG=$enableval + ], + [ + ENABLED_DEBUG="yes" + ] +) +if test "$ENABLED_DEBUG" = "yes" +then + CFLAGS="-Wall -g" + CXXFLAGS="-Wall -g" +else + CFLAGS="-Wall -O3" + CXXFLAGS="-Wall -O3" +fi +AC_MSG_RESULT($ENABLED_DEBUG) +AM_CONDITIONAL([DEBUG], [test "$ENABLED_DEBUG" = yes]) +AM_CONDITIONAL([OPT], [test "$ENABLED_DEBUG" = no]) +]) + +# Set option to enable static libs. +AC_DEFUN([FB_ENABLE_DEFAULT_STATIC], +[ +SHARED="" +STATIC="" +AC_MSG_CHECKING([whether to enable static mode]) +AC_ARG_ENABLE([static], + [ --disable-static Set up shared mode.], + [ + ENABLED_STATIC=$enableval + ], + [ + ENABLED_STATIC="yes" + ] +) +if test "$ENABLED_STATIC" = "yes" +then + LTYPE=".a" +else + LTYPE=".so" + SHARED_CXXFLAGS="-fPIC" + SHARED_CFLAGS="-fPIC" + SHARED_LDFLAGS="-shared -fPIC" + AC_SUBST(SHARED_CXXFLAGS) + AC_SUBST(SHARED_CFLAGS) + AC_SUBST(SHARED_LDFLAGS) +fi +AC_MSG_RESULT($ENABLED_STATIC) +AC_SUBST(LTYPE) +AM_CONDITIONAL([STATIC], [test "$ENABLED_STATIC" = yes]) +AM_CONDITIONAL([SHARED], [test "$ENABLED_STATIC" = no]) +]) + +# Set option to enable shared libs. +AC_DEFUN([FB_ENABLE_DEFAULT_SHARED], +[ +SHARED="" +STATIC="" +AC_MSG_CHECKING([whether to enable shared mode]) +AC_ARG_ENABLE([shared], + [ --disable-shared Set up static mode.], + [ + ENABLED_SHARED=$enableval + ], + [ + ENABLED_SHARED="yes" + ] +) +if test "$ENABLED_SHARED" = "yes" +then + LTYPE=".so" + SHARED_CXXFLAGS="-fPIC" + SHARED_CFLAGS="-fPIC" + SHARED_LDFLAGS="-shared -fPIC" + AC_SUBST(SHARED_CXXFLAGS) + AC_SUBST(SHARED_CFLAGS) + AC_SUBST(SHARED_LDFLAGS) +else + LTYPE=".a" +fi +AC_MSG_RESULT($ENABLED_SHARED) +AC_SUBST(LTYPE) +AM_CONDITIONAL([SHARED], [test "$ENABLED_SHARED" = yes]) +AM_CONDITIONAL([STATIC], [test "$ENABLED_SHARED" = no]) +]) + +# Generates define flags and conditionals as specified by user. +# This gets enabled *only* if user selects --enable-<FEATURE> otion. +AC_DEFUN([FB_ENABLE_FEATURE], +[ +ENABLE="" +flag="$1" +value="$3" +AC_MSG_CHECKING([whether to enable $1]) +AC_ARG_ENABLE([$2], + [ --enable-$2 Enable $2.], + [ + ENABLE=$enableval + ], + [ + ENABLE="no" + ] +) +AM_CONDITIONAL([$1], [test "$ENABLE" = yes]) +if test "$ENABLE" = "yes" +then + if test "x${value}" = "x" + then + AC_DEFINE([$1]) + else + AC_DEFINE_UNQUOTED([$1], [$value]) + fi +fi +AC_MSG_RESULT($ENABLE) +]) + + +# can also use eval $2=$withval;AC_SUBST($2) +AC_DEFUN([FB_WITH_PATH], +[ +USRFLAG="" +USRFLAG=$1 +AC_MSG_CHECKING([Checking $1 set to]) +AC_ARG_WITH([$2], + [ --with-$2=DIR User specified path.], + [ + LOC=$withval + eval $USRFLAG=$withval + ], + [ + LOC=$3 + eval $USRFLAG=$3 + ] +) +AC_SUBST([$1]) +AC_MSG_RESULT($LOC) +]) + +AC_DEFUN([FB_SET_FLAG_VALUE], +[ +SETFLAG="" +AC_MSG_CHECKING([Checking $1 set to]) +SETFLAG=$1 +eval $SETFLAG=\"$2\" +AC_SUBST([$SETFLAG]) +AC_MSG_RESULT($2) +]) + +# NOTES +# if using if else bourne stmt you must have more than a macro in it. +# EX1 is not correct. EX2 is correct +# EX1: if test "$XX" = "yes"; then +# AC_SUBST(xx) +# fi +# EX2: if test "$XX" = "yes"; then +# xx="foo" +# AC_SUBST(xx) +# fi diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_boost_base.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_boost_base.m4 new file mode 100644 index 000000000..e56bb7380 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_boost_base.m4 @@ -0,0 +1,198 @@ +##### http://autoconf-archive.cryp.to/ax_boost_base.html +# +# SYNOPSIS +# +# AX_BOOST_BASE([MINIMUM-VERSION]) +# +# DESCRIPTION +# +# Test for the Boost C++ libraries of a particular version (or newer) +# +# If no path to the installed boost library is given the macro +# searchs under /usr, /usr/local, /opt and /opt/local and evaluates +# the $BOOST_ROOT environment variable. Further documentation is +# available at <http://randspringer.de/boost/index.html>. +# +# This macro calls: +# +# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) +# +# And sets: +# +# HAVE_BOOST +# +# LAST MODIFICATION +# +# 2007-07-28 +# +# COPYLEFT +# +# Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de> +# +# Copying and distribution of this file, with or without +# modification, are permitted in any medium without royalty provided +# the copyright notice and this notice are preserved. + +AC_DEFUN([AX_BOOST_BASE], +[ +AC_ARG_WITH([boost], + AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ac_boost_path="" + else + want_boost="yes" + ac_boost_path="$withval" + fi + ], + [want_boost="yes"]) + +if test "x$want_boost" = "xyes"; then + boost_lib_version_req=ifelse([$1], ,1.20.0,$1) + boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` + boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` + boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$boost_lib_version_req_sub_minor" = "x" ; then + boost_lib_version_req_sub_minor="0" + fi + WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` + AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) + succeeded=no + + dnl first we check the system location for boost libraries + dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl or if you install boost with RPM + if test "$ac_boost_path" != ""; then + BOOST_LDFLAGS="-L$ac_boost_path/lib" + BOOST_CPPFLAGS="-I$ac_boost_path/include" + else + for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then + BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib" + BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" + break; + fi + done + fi + + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include <boost/version.hpp> + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + + + + dnl if we found no boost with system layout we search for boost libraries + dnl built and installed without the --layout=system option or for a staged(not installed) version + if test "x$succeeded" != "xyes"; then + _version=0 + if test "$ac_boost_path" != ""; then + BOOST_LDFLAGS="-L$ac_boost_path/lib" + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" + done + fi + else + for ac_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + best_path=$ac_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + BOOST_LDFLAGS="-L$best_path/lib" + + if test "x$BOOST_ROOT" != "x"; then + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "$V_CHECK" = "1" ; then + AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include <boost/version.hpp> + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + fi + + if test "$succeeded" != "yes" ; then + if test "$_version" = "0" ; then + AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]]) + else + AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) + fi + else + AC_SUBST(BOOST_CPPFLAGS) + AC_SUBST(BOOST_LDFLAGS) + AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" +fi + +]) diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 000000000..a4c9189c9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,134 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++11 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX11 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> +# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> +# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ + template <typename T> + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check<check<bool>> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check<int> check_type; + check_type c; + check_type&& cr = static_cast<check_type&&>(c); + + auto d = a; +]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], + [$2], [optional], [ax_cxx_compile_cxx11_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=c++11; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + AC_MSG_NOTICE([No compiler with C++11 support was found]) + else + HAVE_CXX11=1 + AC_DEFINE(HAVE_CXX11,1, + [define if the compiler supports basic C++11 syntax]) + fi + + AC_SUBST(HAVE_CXX11) + fi +]) + diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_javac_and_java.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_javac_and_java.m4 new file mode 100644 index 000000000..581b45066 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_javac_and_java.m4 @@ -0,0 +1,121 @@ +dnl @synopsis AX_JAVAC_AND_JAVA +dnl @synopsis AX_CHECK_JAVA_CLASS(CLASSNAME) +dnl +dnl Test for the presence of a JDK, and (optionally) specific classes. +dnl +dnl If "JAVA" is defined in the environment, that will be the only +dnl java command tested. Otherwise, a hard-coded list will be used. +dnl Similarly for "JAVAC". +dnl +dnl AX_JAVAC_AND_JAVA does not currently support testing for a particular +dnl Java version, testing for only one of "java" and "javac", or +dnl compiling or running user-provided Java code. +dnl +dnl After AX_JAVAC_AND_JAVA runs, the shell variables "success" and +dnl "ax_javac_and_java" are set to "yes" or "no", and "JAVAC" and +dnl "JAVA" are set to the appropriate commands. +dnl +dnl AX_CHECK_JAVA_CLASS must be run after AX_JAVAC_AND_JAVA. +dnl It tests for the presence of a class based on a fully-qualified name. +dnl It sets the shell variable "success" to "yes" or "no". +dnl +dnl @category Java +dnl @version 2009-02-09 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + + +AC_DEFUN([AX_JAVAC_AND_JAVA], + [ + + dnl Hard-coded default commands to test. + JAVAC_PROGS="javac,jikes,gcj -C" + JAVA_PROGS="java,kaffe" + + dnl Allow the user to specify an alternative. + if test -n "$JAVAC" ; then + JAVAC_PROGS="$JAVAC" + fi + if test -n "$JAVA" ; then + JAVA_PROGS="$JAVA" + fi + + AC_MSG_CHECKING(for javac and java) + + echo "public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java + success=no + oIFS="$IFS" + + IFS="," + for JAVAC in $JAVAC_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD + if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then + + IFS="," + for JAVA in $JAVA_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVA configtest_ax_javac_and_java\"" >&AS_MESSAGE_LOG_FD + if $JAVA configtest_ax_javac_and_java >&AS_MESSAGE_LOG_FD 2>&1 ; then + success=yes + break 2 + fi + + done + + fi + + done + + rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class + + if test "$success" != "yes" ; then + AC_MSG_RESULT(no) + JAVAC="" + JAVA="" + else + AC_MSG_RESULT(yes) + fi + + ax_javac_and_java="$success" + + ]) + + +AC_DEFUN([AX_CHECK_JAVA_CLASS], + [ + AC_MSG_CHECKING(for Java class [$1]) + + echo "import $1; public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java + + echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD + if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then + AC_MSG_RESULT(yes) + success=yes + else + AC_MSG_RESULT(no) + success=no + fi + + rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class + ]) + + +AC_DEFUN([AX_CHECK_ANT_VERSION], + [ + AC_MSG_CHECKING(for ant version > $2) + ANT_VALID=`expr $($1 -version 2>/dev/null | sed -n 's/.*version \(@<:@0-9\.@:>@*\).*/\1/p') \>= $2` + if test "x$ANT_VALID" = "x1" ; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + ANT="" + fi + ]) + diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_thrift_internal.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_thrift_internal.m4 new file mode 100644 index 000000000..8c0e3cbc1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_thrift_internal.m4 @@ -0,0 +1,28 @@ +dnl @synopsis AX_THRIFT_GEN(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) +dnl @synopsis AX_THRIFT_LIB(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) +dnl +dnl Allow a particular language generator to be disabled. +dnl Allow a particular language library to be disabled. +dnl +dnl These macros have poor error handling and are poorly documented. +dnl They are intended only for internal use by the Thrift compiler. +dnl +dnl @version 2008-02-20 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +AC_DEFUN([AX_THRIFT_LIB], + [ + AC_ARG_WITH($1, + AC_HELP_STRING([--with-$1], [build the $2 library @<:@default=$3@:>@]), + [with_$1="$withval"], + [with_$1=$3] + ) + have_$1=no + dnl What we do here is going to vary from library to library, + dnl so we can't really generalize (yet!). + ]) diff --git a/src/jaegertracing/thrift/contrib/fb303/bootstrap.sh b/src/jaegertracing/thrift/contrib/fb303/bootstrap.sh new file mode 100755 index 000000000..3cbeddb34 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/bootstrap.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# +# 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. +# + +# To be safe include -I flag +aclocal -I ./aclocal +automake -a +autoconf +./configure --config-cache $* diff --git a/src/jaegertracing/thrift/contrib/fb303/configure.ac b/src/jaegertracing/thrift/contrib/fb303/configure.ac new file mode 100644 index 000000000..73b35ba07 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/configure.ac @@ -0,0 +1,164 @@ +# Autoconf input file +# $Id$ + +# AC - autoconf +# FB - facebook + +# +# 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. +# + +######################################################################### +# DO NOT TOUCH EXCEPT TO CHANGE REV# IN AC_INIT + +AC_PREREQ(2.52) +AC_INIT([libfb303],[20080209]) +#AC_CONFIG_AUX_DIR([/usr/share/automake-1.9]) +# To install locally +FB_INITIALIZE([localinstall]) +AC_PREFIX_DEFAULT([/usr/local]) + +############################################################################ +# User Configurable. Change With CAUTION! +# User can include custom makefile rules. Uncomment and update only <name> in PRODUCT_MK. +# Include where appropriate in any Makefile.am as @PRODUCT_MK@ + +#PRODUCT_MK="include ${EXTERNAL_PATH}/shared/build/<name>.mk" + +# Default path to external Facebook components and shared build toools I.e fb303 etc. +# To point to other locations set environment variable EXTERNAL_PATH. +# To change the current default you must change bootstrap.sh. +FB_WITH_EXTERNAL_PATH([`pwd`]) + +AC_ARG_VAR([PY_PREFIX], [Prefix for installing Python modules. + (Normal --prefix is ignored for Python because + Python has different conventions.) + Default = "/usr"]) +AS_IF([test "x$PY_PREFIX" = x], [PY_PREFIX="/usr"]) + +########################################################################## +# User Configurable + +# Pre-defined macro to set opt build mode. Run with --disable-shared option to turn off optimization. +FB_ENABLE_DEFAULT_OPT_BUILD + +# Predefined macro to set static library mode. Run with --disable-static option to turn off static lib mode. +FB_ENABLE_DEFAULT_STATIC + +# Personalized feature generator. Creates defines/conditionals and --enable --disable command line options. +# FB_ENABLE_FEATURE([FEATURE], [feature]) OR FB_ENABLE_FEATURE([FEATURE], [feature], [\"<value>\"]) + +# Example: Macro supplies -DFACEBOOK at compile time and "if FACEBOOK endif" capabilities. + +# Personalized path generator Sets default paths. Provides --with-xx=DIR options. +# FB_WITH_PATH([<var>_home], [<var>path], [<default location>] + +# Example: sets $(thrift_home) variable with default path set to /usr/local. +FB_WITH_PATH([thrift_home], [thriftpath], [/usr/local]) + +AX_CXX_COMPILE_STDCXX_11([noext]) +AX_THRIFT_LIB(cpp, [C++], yes) +have_cpp=no +if test "$with_cpp" = "yes"; then + # Require boost 1.40.0 or later + AX_BOOST_BASE([1.40.0]) + if test "x$succeeded" = "xyes"; then + have_cpp="yes" + fi +fi +AM_CONDITIONAL([WITH_CPP], [test "$have_cpp" = "yes"]) + +AX_THRIFT_LIB(java, [Java], yes) +if test "$with_java" = "yes"; then + AX_JAVAC_AND_JAVA + AC_PATH_PROG([ANT], [ant]) + AX_CHECK_ANT_VERSION($ANT, 1.7) + AC_SUBST(CLASSPATH) + AC_SUBST(ANT_FLAGS) + if test "x$JAVAC" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then + have_java="yes" + fi +fi +AM_CONDITIONAL(WITH_JAVA, [test "$have_java" = "yes"]) + +AX_THRIFT_LIB(php, [PHP], yes) +if test "$with_php" = "yes"; then + AC_PATH_PROG([PHP], [php]) + if test "x$PHP" != "x" && test "x$PHP" != "x:" ; then + have_php="yes" + fi +fi +AM_CONDITIONAL(WITH_PHP, [test "$have_php" = "yes"]) + +AX_THRIFT_LIB(python, [Python], yes) +if test "$with_python" = "yes"; then + AM_PATH_PYTHON(2.4,, :) + if test "x$PYTHON" != "x" && test "x$PYTHON" != "x:" ; then + have_python="yes" + fi +fi +AM_CONDITIONAL(WITH_PYTHON, [test "$have_python" = "yes"]) + +# Generates Makefile from Makefile.am. Modify when new subdirs are added. +# Change Makefile.am also to add subdirectly. +AC_CONFIG_FILES(Makefile cpp/Makefile py/Makefile) + +# Check for headers +AC_CHECK_HEADERS([inttypes.h]) +AC_CHECK_HEADERS([netinet/in.h]) + +############################################################################ +# DO NOT TOUCH. + +AC_SUBST(PRODUCT_MK) +AC_OUTPUT + +############################################################################# +######### FINISH ############################################################ + +echo "EXTERNAL_PATH $EXTERNAL_PATH" +echo +echo "Building C++ Library ......... : $have_cpp" +echo "Building Java Library ........ : $have_java" +echo "Building Python Library ...... : $have_python" +echo "Building PHP Library ......... : $have_php" + + +# +# NOTES FOR USER +# Short cut to create conditional flags. +#enable_facebook="yes" +#AM_CONDITIONAL([FACEBOOK], [test "$enable_facebook" = yes]) +#enable_hdfs="yes" +#AM_CONDITIONAL([HDFS], [test "$enable_hdfs" = yes]) + +# Enable options with --enable and --disable configurable. +#AC_MSG_CHECKING([whether to enable FACEBOOK]) +#FACEBOOK="" +#AC_ARG_ENABLE([facebook], +# [ --enable-facebook Enable facebook.], +# [ +# ENABLE_FACEBOOK=$enableval +# ], +# [ +# ENABLE_FACEBOOK="no" +# ] +#) +#AM_CONDITIONAL([FACEBOOK], [test "$ENABLE_FACEBOOK" = yes]) +#AC_MSG_RESULT($ENABLE_FACEBOOK) + diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.cpp b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.cpp new file mode 100644 index 000000000..3c569759c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.cpp @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#include "FacebookBase.h" + +using namespace facebook::fb303; +using apache::thrift::concurrency::Guard; + +FacebookBase::FacebookBase(std::string name) : + name_(name) { + aliveSince_ = (int64_t) time(NULL); +} + +inline void FacebookBase::getName(std::string& _return) { + _return = name_; +} + +void FacebookBase::setOption(const std::string& key, const std::string& value) { + Guard g(optionsLock_); + options_[key] = value; +} + +void FacebookBase::getOption(std::string& _return, const std::string& key) { + Guard g(optionsLock_); + _return = options_[key]; +} + +void FacebookBase::getOptions(std::map<std::string, std::string> & _return) { + Guard g(optionsLock_); + _return = options_; +} + +int64_t FacebookBase::incrementCounter(const std::string& key, int64_t amount) { + counters_.acquireRead(); + + // if we didn't find the key, we need to write lock the whole map to create it + ReadWriteCounterMap::iterator it = counters_.find(key); + if (it == counters_.end()) { + counters_.release(); + counters_.acquireWrite(); + + // we need to check again to make sure someone didn't create this key + // already while we released the lock + it = counters_.find(key); + if(it == counters_.end()){ + counters_[key].value = amount; + counters_.release(); + return amount; + } + } + + it->second.acquireWrite(); + int64_t count = it->second.value + amount; + it->second.value = count; + it->second.release(); + counters_.release(); + return count; +} + +int64_t FacebookBase::setCounter(const std::string& key, int64_t value) { + counters_.acquireRead(); + + // if we didn't find the key, we need to write lock the whole map to create it + ReadWriteCounterMap::iterator it = counters_.find(key); + if (it == counters_.end()) { + counters_.release(); + counters_.acquireWrite(); + counters_[key].value = value; + counters_.release(); + return value; + } + + it->second.acquireWrite(); + it->second.value = value; + it->second.release(); + counters_.release(); + return value; +} + +void FacebookBase::getCounters(std::map<std::string, int64_t>& _return) { + // we need to lock the whole thing and actually build the map since we don't + // want our read/write structure to go over the wire + counters_.acquireRead(); + for(ReadWriteCounterMap::iterator it = counters_.begin(); + it != counters_.end(); ++it) + { + _return[it->first] = it->second.value; + } + counters_.release(); +} + +int64_t FacebookBase::getCounter(const std::string& key) { + int64_t rv = 0; + counters_.acquireRead(); + ReadWriteCounterMap::iterator it = counters_.find(key); + if (it != counters_.end()) { + it->second.acquireRead(); + rv = it->second.value; + it->second.release(); + } + counters_.release(); + return rv; +} + +inline int64_t FacebookBase::aliveSince() { + return aliveSince_; +} + diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.h b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.h new file mode 100644 index 000000000..daa524644 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#ifndef _FACEBOOK_TB303_FACEBOOKBASE_H_ +#define _FACEBOOK_TB303_FACEBOOKBASE_H_ 1 + +#include "FacebookService.h" + +#include <boost/shared_ptr.hpp> +#include <thrift/server/TServer.h> +#include <thrift/concurrency/Mutex.h> + +#include <time.h> +#include <string> +#include <map> + +namespace facebook { namespace fb303 { + +using apache::thrift::concurrency::Mutex; +using apache::thrift::concurrency::ReadWriteMutex; +using apache::thrift::server::TServer; + +struct ReadWriteInt : ReadWriteMutex {int64_t value;}; +struct ReadWriteCounterMap : ReadWriteMutex, + std::map<std::string, ReadWriteInt> {}; + +/** + * Base Facebook service implementation in C++. + * + */ +class FacebookBase : virtual public FacebookServiceIf { + protected: + FacebookBase(std::string name); + virtual ~FacebookBase() {} + + public: + void getName(std::string& _return); + virtual void getVersion(std::string& _return) { _return = ""; } + + virtual fb_status getStatus() = 0; + virtual void getStatusDetails(std::string& _return) { _return = ""; } + + void setOption(const std::string& key, const std::string& value); + void getOption(std::string& _return, const std::string& key); + void getOptions(std::map<std::string, std::string> & _return); + + int64_t aliveSince(); + + virtual void reinitialize() {} + + virtual void shutdown() { + if (server_.get() != NULL) { + server_->stop(); + } + } + + int64_t incrementCounter(const std::string& key, int64_t amount = 1); + int64_t setCounter(const std::string& key, int64_t value); + + void getCounters(std::map<std::string, int64_t>& _return); + int64_t getCounter(const std::string& key); + + /** + * Set server handle for shutdown method + */ + void setServer(boost::shared_ptr<TServer> server) { + server_ = server; + } + + void getCpuProfile(std::string& _return, int32_t durSecs) { _return = ""; } + + private: + + std::string name_; + int64_t aliveSince_; + + std::map<std::string, std::string> options_; + Mutex optionsLock_; + + ReadWriteCounterMap counters_; + + boost::shared_ptr<TServer> server_; + +}; + +}} // facebook::tb303 + +#endif // _FACEBOOK_TB303_FACEBOOKBASE_H_ diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/Makefile.am b/src/jaegertracing/thrift/contrib/fb303/cpp/Makefile.am new file mode 100644 index 000000000..748d3298d --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/Makefile.am @@ -0,0 +1,84 @@ +# +# 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. +# + +@GLOBAL_HEADER_MK@ + +@PRODUCT_MK@ + + +# User specified path variables set in configure.ac. +# thrift_home +# +THRIFT = $(thrift_home)/bin/thrift + +# User defined conditionals and conditonal statements set up in configure.ac. +if DEBUG + DEBUG_CPPFLAGS = -DDEBUG_TIMING +endif + +# Set common flags recognized by automake. +# DO NOT USE CPPFLAGS, CXXFLAGS, CFLAGS, LDFLAGS here! Set in configure.ac and|or override on command line. +# USE flags AM_CXXFLAGS, AM_CFLAGS, AM_CPPFLAGS, AM_LDFLAGS, LDADD in this section. + +AM_CPPFLAGS = -I.. +AM_CPPFLAGS += -Igen-cpp +AM_CPPFLAGS += -I$(thrift_home)/include/thrift +AM_CPPFLAGS += $(BOOST_CPPFLAGS) +AM_CPPFLAGS += $(FB_CPPFLAGS) $(DEBUG_CPPFLAGS) + +# GENERATE BUILD RULES +# Set Program/library specific flags recognized by automake. +# Use <progname|libname>_<FLAG> to set prog / lib specific flag s +# foo_CXXFLAGS foo_CPPFLAGS foo_LDFLAGS foo_LDADD + +fb303_lib = gen-cpp/FacebookService.cpp gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp FacebookBase.cpp ServiceTracker.cpp + +# Static -- multiple libraries can be defined +if STATIC +lib_LIBRARIES = libfb303.a +libfb303_a_SOURCES = $(fb303_lib) +INTERNAL_LIBS = libfb303.a +endif + +# Shared -- multiple libraries can be defined +if SHARED +shareddir = $(prefix)/lib +shared_PROGRAMS = libfb303.so +libfb303_so_SOURCES = $(fb303_lib) +libfb303_so_CXXFLAGS = $(SHARED_CXXFLAGS) +libfb303_so_LDFLAGS = $(SHARED_LDFLAGS) +INTERNAL_LIBS = libfb303.so +endif + +# Set up Thrift specific activity here. +# We assume that a <name>+types.cpp will always be built from <name>.thrift. +$(eval $(call thrift_template,.,../if/fb303.thrift,-I $(thrift_home)/share --gen cpp:pure_enums )) + +include_fb303dir = $(includedir)/thrift/fb303 +include_fb303_HEADERS = FacebookBase.h ServiceTracker.h gen-cpp/FacebookService.h gen-cpp/fb303_constants.h gen-cpp/fb303_types.h + +include_fb303ifdir = $(prefix)/share/fb303/if +include_fb303if_HEADERS = ../if/fb303.thrift + +BUILT_SOURCES = thriftstyle + +# Add to pre-existing target clean +clean-local: clean-common + +@GLOBAL_FOOTER_MK@ diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.cpp b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.cpp new file mode 100644 index 000000000..7a61b21a9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.cpp @@ -0,0 +1,481 @@ +/* + * 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. + */ + +#include <sys/time.h> + +#include "FacebookBase.h" +#include "ServiceTracker.h" +#include <thrift/concurrency/ThreadManager.h> + +using namespace std; +using namespace facebook::fb303; +using namespace apache::thrift::concurrency; + + +uint64_t ServiceTracker::CHECKPOINT_MINIMUM_INTERVAL_SECONDS = 60; +int ServiceTracker::LOG_LEVEL = 5; + + +ServiceTracker::ServiceTracker(facebook::fb303::FacebookBase *handler, + void (*logMethod)(int, const string &), + bool featureCheckpoint, + bool featureStatusCheck, + bool featureThreadCheck, + Stopwatch::Unit stopwatchUnit) + : handler_(handler), logMethod_(logMethod), + featureCheckpoint_(featureCheckpoint), + featureStatusCheck_(featureStatusCheck), + featureThreadCheck_(featureThreadCheck), + stopwatchUnit_(stopwatchUnit), + checkpointServices_(0) +{ + if (featureCheckpoint_) { + time_t now = time(NULL); + checkpointTime_ = now; + } else { + checkpointTime_ = 0; + } +} + +/** + * Registers the beginning of a "service method": basically, any of + * the implementations of Thrift remote procedure calls that a + * FacebookBase handler is handling. Controls concurrent + * services and reports statistics (via log and via fb303 counters). + * Throws an exception if the server is not ready to handle service + * methods yet. + * + * note: The relationship between startService() and finishService() + * is currently defined so that a call to finishService() should only + * be matched to this call to startService() if this method returns + * without exception. It wouldn't be a problem to implement things + * the other way, so that *every* start needed a finish, but this + * convention was chosen to match the way an object's constructor and + * destructor work together, i.e. to work well with ServiceMethod + * objects. + * + * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod + * object instantiated at the start + * of the service method. + */ +void +ServiceTracker::startService(const ServiceMethod &serviceMethod) +{ + // note: serviceMethod.timer_ automatically starts at construction. + + // log service start + logMethod_(5, serviceMethod.signature_); + + // check handler ready + if (featureStatusCheck_ && !serviceMethod.featureLogOnly_) { + // note: Throwing exceptions before counting statistics. See note + // in method header. + // note: A STOPPING server is not accepting new connections, but it + // is still handling any already-connected threads -- so from the + // service method's point of view, a status of STOPPING is a green + // light. + facebook::fb303::fb_status status = handler_->getStatus(); + if (status != facebook::fb303::ALIVE + && status != facebook::fb303::STOPPING) { + if (status == facebook::fb303::STARTING) { + throw ServiceException("Server starting up; please try again later"); + } else { + throw ServiceException("Server not alive; please try again later"); + } + } + } + + // check server threads + if (featureThreadCheck_ && !serviceMethod.featureLogOnly_) { + // note: Might want to put these messages in reportCheckpoint() if + // log is getting spammed. + if (threadManager_ != NULL) { + size_t idle_count = threadManager_->idleWorkerCount(); + if (idle_count == 0) { + stringstream message; + message << "service " << serviceMethod.signature_ + << ": all threads (" << threadManager_->workerCount() + << ") in use"; + logMethod_(3, message.str()); + } + } + } +} + +/** + * Logs a significant step in the middle of a "service method"; see + * startService. + * + * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod + * object instantiated at the start + * of the service method. + * @return int64_t Elapsed units (see stopwatchUnit_) since ServiceMethod + * instantiation. + */ +int64_t +ServiceTracker::stepService(const ServiceMethod &serviceMethod, + const string &stepName) +{ + stringstream message; + string elapsed_label; + int64_t elapsed = serviceMethod.timer_.elapsedUnits(stopwatchUnit_, + &elapsed_label); + message << serviceMethod.signature_ + << ' ' << stepName + << " [" << elapsed_label << ']'; + logMethod_(5, message.str()); + return elapsed; +} + +/** + * Registers the end of a "service method"; see startService(). + * + * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod + * object instantiated at the start + * of the service method. + */ +void +ServiceTracker::finishService(const ServiceMethod &serviceMethod) +{ + // log end of service + stringstream message; + string duration_label; + int64_t duration = serviceMethod.timer_.elapsedUnits(stopwatchUnit_, + &duration_label); + message << serviceMethod.signature_ + << " finish [" << duration_label << ']'; + logMethod_(5, message.str()); + + // count, record, and maybe report service statistics + if (!serviceMethod.featureLogOnly_) { + + if (!featureCheckpoint_) { + + // lifetime counters + // (note: No need to lock statisticsMutex_ if not doing checkpoint; + // FacebookService::incrementCounter() is already thread-safe.) + handler_->incrementCounter("lifetime_services"); + + } else { + + statisticsMutex_.lock(); + // note: No exceptions expected from this code block. Wrap in a try + // just to be safe. + try { + + // lifetime counters + // note: Good to synchronize this with the increment of + // checkpoint services, even though incrementCounter() is + // already thread-safe, for the sake of checkpoint reporting + // consistency (i.e. since the last checkpoint, + // lifetime_services has incremented by checkpointServices_). + handler_->incrementCounter("lifetime_services"); + + // checkpoint counters + checkpointServices_++; + checkpointDuration_ += duration; + + // per-service timing + // note kjv: According to my tests it is very slightly faster to + // call insert() once (and detect not-found) than calling find() + // and then maybe insert (if not-found). However, the difference + // is tiny for small maps like this one, and the code for the + // faster solution is slightly less readable. Also, I wonder if + // the instantiation of the (often unused) pair to insert makes + // the first algorithm slower after all. + map<string, pair<uint64_t, uint64_t> >::iterator iter; + iter = checkpointServiceDuration_.find(serviceMethod.name_); + if (iter != checkpointServiceDuration_.end()) { + iter->second.first++; + iter->second.second += duration; + } else { + checkpointServiceDuration_.insert(make_pair(serviceMethod.name_, + make_pair(1, duration))); + } + + // maybe report checkpoint + // note: ...if it's been long enough since the last report. + time_t now = time(NULL); + uint64_t check_interval = now - checkpointTime_; + if (check_interval >= CHECKPOINT_MINIMUM_INTERVAL_SECONDS) { + reportCheckpoint(); + } + + } catch (...) { + statisticsMutex_.unlock(); + throw; + } + statisticsMutex_.unlock(); + + } + } +} + +/** + * Logs some statistics gathered since the last call to this method. + * + * note: Thread race conditions on this method could cause + * misreporting and/or undefined behavior; the caller must protect + * uses of the object variables (and calls to this method) with a + * mutex. + * + */ +void +ServiceTracker::reportCheckpoint() +{ + time_t now = time(NULL); + + uint64_t check_count = checkpointServices_; + uint64_t check_interval = now - checkpointTime_; + uint64_t check_duration = checkpointDuration_; + + // export counters for timing of service methods (by service name) + handler_->setCounter("checkpoint_time", check_interval); + map<string, pair<uint64_t, uint64_t> >::iterator iter; + uint64_t count; + for (iter = checkpointServiceDuration_.begin(); + iter != checkpointServiceDuration_.end(); + ++iter) { + count = iter->second.first; + handler_->setCounter(string("checkpoint_count_") + iter->first, count); + if (count == 0) { + handler_->setCounter(string("checkpoint_speed_") + iter->first, + 0); + } else { + handler_->setCounter(string("checkpoint_speed_") + iter->first, + iter->second.second / count); + } + } + + // reset checkpoint variables + // note: Clearing the map while other threads are using it might + // cause undefined behavior. + checkpointServiceDuration_.clear(); + checkpointTime_ = now; + checkpointServices_ = 0; + checkpointDuration_ = 0; + + // get lifetime variables + uint64_t life_count = handler_->getCounter("lifetime_services"); + uint64_t life_interval = now - handler_->aliveSince(); + + // log checkpoint + stringstream message; + message << "checkpoint_time:" << check_interval + << " checkpoint_services:" << check_count + << " checkpoint_speed_sum:" << check_duration + << " lifetime_time:" << life_interval + << " lifetime_services:" << life_count; + if (featureThreadCheck_ && threadManager_ != NULL) { + size_t worker_count = threadManager_->workerCount(); + size_t idle_count = threadManager_->idleWorkerCount(); + message << " total_workers:" << worker_count + << " active_workers:" << (worker_count - idle_count); + } + logMethod_(4, message.str()); +} + +/** + * Remembers the thread manager used in the server, for monitoring thread + * activity. + * + * @param shared_ptr<ThreadManager> threadManager The server's thread manager. + */ +void +ServiceTracker::setThreadManager(boost::shared_ptr<ThreadManager> + threadManager) +{ + threadManager_ = threadManager; +} + +/** + * Logs messages to stdout; the passed message will be logged if the + * passed level is less than or equal to LOG_LEVEL. + * + * This is the default logging method used by the ServiceTracker. An + * alternate logging method (that accepts the same parameters) may be + * specified to the constructor. + * + * @param int level A level associated with the message: higher levels + * are used to indicate higher levels of detail. + * @param string message The message to log. + */ +void +ServiceTracker::defaultLogMethod(int level, const string &message) +{ + if (level <= LOG_LEVEL) { + string level_string; + time_t now = time(NULL); + char now_pretty[26]; + ctime_r(&now, now_pretty); + now_pretty[24] = '\0'; + switch (level) { + case 1: + level_string = "CRITICAL"; + break; + case 2: + level_string = "ERROR"; + break; + case 3: + level_string = "WARNING"; + break; + case 5: + level_string = "DEBUG"; + break; + case 4: + default: + level_string = "INFO"; + break; + } + cout << '[' << level_string << "] [" << now_pretty << "] " + << message << endl; + } +} + + +/** + * Creates a Stopwatch, which can report the time elapsed since its + * creation. + * + */ +Stopwatch::Stopwatch() +{ + gettimeofday(&startTime_, NULL); +} + +void +Stopwatch::reset() +{ + gettimeofday(&startTime_, NULL); +} + +uint64_t +Stopwatch::elapsedUnits(Stopwatch::Unit unit, string *label) const +{ + timeval now_time; + gettimeofday(&now_time, NULL); + time_t duration_secs = now_time.tv_sec - startTime_.tv_sec; + + uint64_t duration_units; + switch (unit) { + case UNIT_SECONDS: + duration_units = duration_secs + + (now_time.tv_usec - startTime_.tv_usec + 500000) / 1000000; + if (NULL != label) { + stringstream ss_label; + ss_label << duration_units << " secs"; + label->assign(ss_label.str()); + } + break; + case UNIT_MICROSECONDS: + duration_units = duration_secs * 1000000 + + now_time.tv_usec - startTime_.tv_usec; + if (NULL != label) { + stringstream ss_label; + ss_label << duration_units << " us"; + label->assign(ss_label.str()); + } + break; + case UNIT_MILLISECONDS: + default: + duration_units = duration_secs * 1000 + + (now_time.tv_usec - startTime_.tv_usec + 500) / 1000; + if (NULL != label) { + stringstream ss_label; + ss_label << duration_units << " ms"; + label->assign(ss_label.str()); + } + break; + } + return duration_units; +} + +/** + * Creates a ServiceMethod, used for tracking a single service method + * invocation (via the ServiceTracker). The passed name of the + * ServiceMethod is used to group statistics (e.g. counts and durations) + * for similar invocations; the passed signature is used to uniquely + * identify the particular invocation in the log. + * + * note: A version of this constructor is provided that automatically + * forms a signature the name and a passed numeric id. Silly, sure, + * but commonly used, since it often saves the caller a line or two of + * code. + * + * @param ServiceTracker *tracker The service tracker that will track this + * ServiceMethod. + * @param const string &name The service method name (usually independent + * of service method parameters). + * @param const string &signature A signature uniquely identifying the method + * invocation (usually name plus parameters). + */ +ServiceMethod::ServiceMethod(ServiceTracker *tracker, + const string &name, + const string &signature, + bool featureLogOnly) + : tracker_(tracker), name_(name), signature_(signature), + featureLogOnly_(featureLogOnly) +{ + // note: timer_ automatically starts at construction. + + // invoke tracker to start service + // note: Might throw. If it throws, then this object's destructor + // won't be called, which is according to plan: finishService() is + // only supposed to be matched to startService() if startService() + // returns without error. + tracker_->startService(*this); +} + +ServiceMethod::ServiceMethod(ServiceTracker *tracker, + const string &name, + uint64_t id, + bool featureLogOnly) + : tracker_(tracker), name_(name), featureLogOnly_(featureLogOnly) +{ + // note: timer_ automatically starts at construction. + stringstream ss_signature; + ss_signature << name << " (" << id << ')'; + signature_ = ss_signature.str(); + + // invoke tracker to start service + // note: Might throw. If it throws, then this object's destructor + // won't be called, which is according to plan: finishService() is + // only supposed to be matched to startService() if startService() + // returns without error. + tracker_->startService(*this); +} + +ServiceMethod::~ServiceMethod() +{ + // invoke tracker to finish service + // note: Not expecting an exception from this code, but + // finishService() might conceivably throw an out-of-memory + // exception. + try { + tracker_->finishService(*this); + } catch (...) { + // don't throw + } +} + +uint64_t +ServiceMethod::step(const std::string &stepName) +{ + return tracker_->stepService(*this, stepName); +} diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.h b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.h new file mode 100644 index 000000000..9a3edd8f1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.h @@ -0,0 +1,215 @@ +/* + * 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. + */ + +/** + * ServiceTracker is a utility class for logging and timing service + * calls to a fb303 Thrift server. Currently, ServiceTracker offers + * the following features: + * + * . Logging of service method start, end (and duration), and + * optional steps in between. + * + * . Automatic check of server status via fb303::getStatus() + * with a ServiceException thrown if server not alive + * (at method start). + * + * . A periodic logged checkpoint reporting lifetime time, lifetime + * service count, and per-method statistics since the last checkpoint + * time (at method finish). + * + * . Export of fb303 counters for lifetime and checkpoint statistics + * (at method finish). + * + * . For TThreadPoolServers, a logged warning when all server threads + * are busy (at method start). (Must call setThreadManager() after + * ServiceTracker instantiation for this feature to be enabled.) + * + * Individual features may be enabled or disabled by arguments to the + * constructor. The constructor also accepts a pointer to a logging + * method -- if no pointer is passed, the tracker will log to stdout. + * + * ServiceTracker defines private methods for service start, finish, + * and step, which are designed to be accessed by instantiating a + * friend ServiceMethod object, as in the following example: + * + * #include <ServiceTracker.h> + * class MyServiceHandler : virtual public MyServiceIf, + * public facebook::fb303::FacebookBase + * { + * public: + * MyServiceHandler::MyServiceHandler() : mServiceTracker(this) {} + * void MyServiceHandler::myServiceMethod(int userId) { + * // note: Instantiating a ServiceMethod object starts a timer + * // and tells the ServiceTracker to log the start. Might throw + * // a ServiceException. + * ServiceMethod serviceMethod(&mServiceTracker, + * "myServiceMethod", + * userId); + * ... + * // note: Calling the step method tells the ServiceTracker to + * // log the step, with a time elapsed since start. + * serviceMethod.step("post parsing, begin processing"); + * ... + * // note: When the ServiceMethod object goes out of scope, the + * // ServiceTracker will log the total elapsed time of the method. + * } + * ... + * private: + * ServiceTracker mServiceTracker; + * } + * + * The step() method call is optional; the startService() and + * finishService() methods are handled by the object's constructor and + * destructor. + * + * The ServiceTracker is (intended to be) thread-safe. + * + * Future: + * + * . Come up with something better for logging than passing a + * function pointer to the constructor. + * + * . Add methods for tracking errors from service methods, e.g. + * ServiceTracker::reportService(). + */ + +#ifndef SERVICETRACKER_H +#define SERVICETRACKER_H + + +#include <iostream> +#include <string> +#include <sstream> +#include <exception> +#include <map> +#include <boost/shared_ptr.hpp> + +#include <thrift/concurrency/Mutex.h> + + +namespace apache { namespace thrift { namespace concurrency { + class ThreadManager; +}}} + + +namespace facebook { namespace fb303 { + + +class FacebookBase; +class ServiceMethod; + + +class Stopwatch +{ +public: + enum Unit { UNIT_SECONDS, UNIT_MILLISECONDS, UNIT_MICROSECONDS }; + Stopwatch(); + uint64_t elapsedUnits(Unit unit, std::string *label = NULL) const; + void reset(); +private: + timeval startTime_; +}; + + +class ServiceTracker +{ + friend class ServiceMethod; + +public: + + static uint64_t CHECKPOINT_MINIMUM_INTERVAL_SECONDS; + static int LOG_LEVEL; + + ServiceTracker(facebook::fb303::FacebookBase *handler, + void (*logMethod)(int, const std::string &) + = &ServiceTracker::defaultLogMethod, + bool featureCheckpoint = true, + bool featureStatusCheck = true, + bool featureThreadCheck = true, + Stopwatch::Unit stopwatchUnit + = Stopwatch::UNIT_MILLISECONDS); + + void setThreadManager(boost::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager); + +private: + + facebook::fb303::FacebookBase *handler_; + void (*logMethod_)(int, const std::string &); + boost::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager_; + + bool featureCheckpoint_; + bool featureStatusCheck_; + bool featureThreadCheck_; + Stopwatch::Unit stopwatchUnit_; + + apache::thrift::concurrency::Mutex statisticsMutex_; + time_t checkpointTime_; + uint64_t checkpointServices_; + uint64_t checkpointDuration_; + std::map<std::string, std::pair<uint64_t, uint64_t> > checkpointServiceDuration_; + + void startService(const ServiceMethod &serviceMethod); + int64_t stepService(const ServiceMethod &serviceMethod, + const std::string &stepName); + void finishService(const ServiceMethod &serviceMethod); + void reportCheckpoint(); + static void defaultLogMethod(int level, const std::string &message); +}; + + +class ServiceMethod +{ + friend class ServiceTracker; +public: + ServiceMethod(ServiceTracker *tracker, + const std::string &name, + const std::string &signature, + bool featureLogOnly = false); + ServiceMethod(ServiceTracker *tracker, + const std::string &name, + uint64_t id, + bool featureLogOnly = false); + ~ServiceMethod(); + uint64_t step(const std::string &stepName); +private: + ServiceTracker *tracker_; + std::string name_; + std::string signature_; + bool featureLogOnly_; + Stopwatch timer_; +}; + + +class ServiceException : public std::exception +{ +public: + explicit ServiceException(const std::string &message, int code = 0) + : message_(message), code_(code) {} + ~ServiceException() throw() {} + virtual const char *what() const throw() { return message_.c_str(); } + int code() const throw() { return code_; } +private: + std::string message_; + int code_; +}; + + +}} // facebook::fb303 + +#endif diff --git a/src/jaegertracing/thrift/contrib/fb303/global_footer.mk b/src/jaegertracing/thrift/contrib/fb303/global_footer.mk new file mode 100644 index 000000000..96f82ebd2 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/global_footer.mk @@ -0,0 +1,21 @@ +# +# 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. +# + +thriftstyle : $(XBUILT_SOURCES) + diff --git a/src/jaegertracing/thrift/contrib/fb303/global_header.mk b/src/jaegertracing/thrift/contrib/fb303/global_header.mk new file mode 100644 index 000000000..77c9455ee --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/global_header.mk @@ -0,0 +1,38 @@ +# +# 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. +# + +#define thrift_template +# $(1) : $(2) +# $$(THRIFT) $(3) $(4) $(5) $(6) $(7) $(8) $$< +#endef + +define thrift_template +XTARGET := $(shell perl -e '@val = split("\/","$(2)"); $$last = pop(@val);split("\\.",$$last);print "$(1)/"."gen-cpp/"."@_[0]"."_types.cpp\n"' ) + +ifneq ($$(XBUILT_SOURCES),) + XBUILT_SOURCES := $$(XBUILT_SOURCES) $$(XTARGET) +else + XBUILT_SOURCES := $$(XTARGET) +endif +$$(XTARGET) : $(2) + $$(THRIFT) -o $1 $3 $$< +endef + +clean-common: + rm -rf gen-* diff --git a/src/jaegertracing/thrift/contrib/fb303/if/fb303.thrift b/src/jaegertracing/thrift/contrib/fb303/if/fb303.thrift new file mode 100644 index 000000000..89bd6eb7b --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/if/fb303.thrift @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + * fb303.thrift + */ + +namespace java com.facebook.fb303 +namespace cpp facebook.fb303 +namespace perl Facebook.FB303 +namespace netcore Facebook.FB303.Test + +/** + * Common status reporting mechanism across all services + */ +enum fb_status { + DEAD = 0, + STARTING = 1, + ALIVE = 2, + STOPPING = 3, + STOPPED = 4, + WARNING = 5, +} + +/** + * Standard base service + */ +service FacebookService { + + /** + * Returns a descriptive name of the service + */ + string getName(), + + /** + * Returns the version of the service + */ + string getVersion(), + + /** + * Gets the status of this service + */ + fb_status getStatus(), + + /** + * User friendly description of status, such as why the service is in + * the dead or warning state, or what is being started or stopped. + */ + string getStatusDetails(), + + /** + * Gets the counters for this service + */ + map<string, i64> getCounters(), + + /** + * Gets the value of a single counter + */ + i64 getCounter(1: string key), + + /** + * Sets an option + */ + void setOption(1: string key, 2: string value), + + /** + * Gets an option + */ + string getOption(1: string key), + + /** + * Gets all options + */ + map<string, string> getOptions(), + + /** + * Returns a CPU profile over the given time interval (client and server + * must agree on the profile format). + */ + string getCpuProfile(1: i32 profileDurationInSec), + + /** + * Returns the unix time that the server has been running since + */ + i64 aliveSince(), + + /** + * Tell the server to reload its configuration, reopen log files, etc + */ + oneway void reinitialize(), + + /** + * Suggest a shutdown to the server + */ + oneway void shutdown(), + +} diff --git a/src/jaegertracing/thrift/contrib/fb303/java/build.properties b/src/jaegertracing/thrift/contrib/fb303/java/build.properties new file mode 100644 index 000000000..84636683c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/java/build.properties @@ -0,0 +1,5 @@ +# Maven Ant tasks Jar details +mvn.ant.task.version=2.1.3 +mvn.repo=http://repo1.maven.org/maven2 +mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version} +mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar diff --git a/src/jaegertracing/thrift/contrib/fb303/java/build.xml b/src/jaegertracing/thrift/contrib/fb303/java/build.xml new file mode 100755 index 000000000..7a1b8f105 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/java/build.xml @@ -0,0 +1,199 @@ +<?xml version="1.0"?> +<!-- + 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. + --> +<project name="libfb303" default="dist" basedir="." + xmlns:artifact="antlib:org.apache.maven.artifact.ant"> + + <!-- project wide settings. All directories relative to basedir --> + <property name="thrift.root" location="${basedir}/../../../"/> + <property name="fb303.artifactid" value="libfb303"/> + <property name="interface.dir" value="${basedir}/../if"/> + <property name="thrift.java.dir" location="${thrift.root}/lib/java"/> + <property name="build.tools.dir" location="${thrift.java.dir}/build/tools/"/> + <property name="thrift_compiler" value="${thrift.root}/compiler/cpp/thrift"/> + <property file="${basedir}/build.properties"/> + + <!-- inherit from the java build file for version and other properties --> + <property file="${thrift.java.dir}/gradle.properties" /> + + <property environment="env"/> + + <condition property="version" value="${thrift.version}"> + <isset property="release"/> + </condition> + <property name="version" value="${thrift.version}-SNAPSHOT"/> + + <property name="fb303.final.name" value="${fb303.artifactid}-${version}"/> + + <property name="src" value="${basedir}/src"/> + <property name="gen" value="${basedir}/gen-java"/> + <property name="build.dir" value="${basedir}/build"/> + <property name="build.lib.dir" value="${build.dir}/lib"/> + <property name="build.classes.dir" value="${build.dir}/classes"/> + + <property name="fb303.jar.file" location="${build.dir}/${fb303.final.name}.jar"/> + <property name="fb303.pom.xml" location="${build.dir}/${fb303.final.name}.pom"/> + + <target name="init" depends="setup.init,mvn.init" unless="init.finished"> + <property name="init.finished" value="true"/> + </target> + + <target name="setup.init"> + <tstamp/> + <mkdir dir="${build.dir}"/> + <mkdir dir="${build.classes.dir}"/> + <mkdir dir="${build.lib.dir}"/> + </target> + + <!-- generate fb303 thrift code --> + <target name="generate"> + <echo message="generating thrift fb303 files"/> + <exec executable="${thrift_compiler}" failonerror="true"> + <arg line="--gen java -o ${basedir} ${interface.dir}/fb303.thrift"/> + </exec> + </target> + + <!-- compile the base and thrift generated code and jar them --> + <target name="dist" depends="init,generate"> + <echo message="Building ${fb303.final.name}.jar"/> + <javac destdir="${build.classes.dir}" debug="on"> + <classpath> + <fileset dir="${thrift.java.dir}/build/libs"> + <include name="libthrift*.jar" /> + <exclude name="libthrift*javadoc.jar" /> + <exclude name="libthrift*sources.jar" /> + </fileset> + <fileset dir="${thrift.java.dir}/build/deps"> + <include name="*.jar"/> + </fileset> + </classpath> + <src path="${src}"/> + <src path="${gen}"/> + <include name="**/*.java"/> + </javac> + <jar jarfile="${build.dir}/${fb303.final.name}.jar" basedir="${build.classes.dir}"> + </jar> + </target> + + <!-- copy the build jar to the distribution library directory --> + <target name="install" depends="dist"> + <copy todir="${install.path}"> + <fileset dir="${build.lib.dir}" includes="*.jar"/> + <fileset dir="${build.lib.dir}" includes="${fb303.final.name}.jar"/> + </copy> + </target> + + <target name="clean"> + <delete dir="${build.dir}"/> + <delete dir="${gen}"/> + </target> + + <target name="mvn.ant.tasks.download" depends="setup.init,mvn.ant.tasks.check" unless="mvn.ant.tasks.found"> + <get src="${mvn.ant.task.url}/${mvn.ant.task.jar}" dest="${build.tools.dir}/${mvn.ant.task.jar}" usetimestamp="true"/> + </target> + + <target name="mvn.ant.tasks.check"> + <condition property="mvn.ant.tasks.found"> + <typefound uri="antlib:org.apache.maven.artifact.ant" name="artifact"/> + </condition> + </target> + + <target name="mvn.init" depends="mvn.ant.tasks.download" unless="mvn.finished"> + <echo message="${mvn.ant.task.jar}"/> + <!-- Download mvn ant tasks, download dependencies, and setup pom file --> + <typedef uri="antlib:org.apache.maven.artifact.ant" classpath="${build.tools.dir}/${mvn.ant.task.jar}"/> + + <!-- remote repositories used to download dependencies from --> + <artifact:remoteRepository id="central" url="${mvn.repo}"/> + <artifact:remoteRepository id="apache" url="${apache.repo}"/> + + <!-- Pom file information --> + <artifact:pom id="pom" + groupId="${thrift.groupid}" + artifactId="${fb303.artifactid}" + version="${version}" + url="http://thrift.apache.org" + name="Apache Thrift" + description="Thrift is a software framework for scalable cross-language services development." + packaging="jar" + > + <remoteRepository refid="central"/> + <remoteRepository refid="apache"/> + <license name="The Apache Software License, Version 2.0" url="${license}"/> + <scm connection="scm:git:https://github.com/apache/thrift.git" + developerConnection="scm:git:https://github.com/apache/thrift.git" + url="https://github.com/apache/thrift" + /> + <!-- Thrift Developers --> + <developer id="mcslee" name="Mark Slee"/> + <developer id="dreiss" name="David Reiss"/> + <developer id="aditya" name="Aditya Agarwal"/> + <developer id="marck" name="Marc Kwiatkowski"/> + <developer id="jwang" name="James Wang"/> + <developer id="cpiro" name="Chris Piro"/> + <developer id="bmaurer" name="Ben Maurer"/> + <developer id="kclark" name="Kevin Clark"/> + <developer id="jake" name="Jake Luciani"/> + <developer id="bryanduxbury" name="Bryan Duxbury"/> + <developer id="esteve" name="Esteve Fernandez"/> + <developer id="todd" name="Todd Lipcon"/> + <developer id="geechorama" name="Andrew McGeachie"/> + <developer id="molinaro" name="Anthony Molinaro"/> + <developer id="roger" name="Roger Meier"/> + <developer id="jfarrell" name="Jake Farrell"/> + <developer id="jensg" name="Jens Geyer"/> + <developer id="carl" name="Carl Yeksigian"/> + + <!-- Thrift dependencies list --> + <dependency groupId="org.apache.thrift" artifactId="libthrift" version="${version}"/> + </artifact:pom> + + <!-- Generate the pom file --> + <artifact:writepom pomRefId="pom" file="${fb303.pom.xml}"/> + + <property name="mvn.finished" value="true"/> + </target> + + <macrodef name="signAndDeploy"> + <!-- Sign and deploy jars to apache repo --> + <attribute name="file"/> + <attribute name="classifier" default=""/> + <attribute name="packaging" default="jar"/> + <attribute name="pom" default=""/> + <sequential> + <artifact:mvn fork="true"> + <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file"/> + <arg value="-DrepositoryId=${maven-repository-id}"/> + <arg value="-Durl=${maven-repository-url}"/> + <arg value="-DpomFile=@{pom}"/> + <arg value="-Dfile=@{file}"/> + <arg value="-Dclassifier=@{classifier}"/> + <arg value="-Dpackaging=@{packaging}"/> + <arg value="-Pgpg"/> + </artifact:mvn> + </sequential> + </macrodef> + + <target name="publish" depends="clean,dist"> + <!-- Compile, packages and then send release to apache maven repo --> + <!-- run with: ant -Drelease=true publish--> + <signAndDeploy file="${fb303.pom.xml}" packaging="pom" classifier="" pom="${fb303.pom.xml}"/> + <signAndDeploy file="${fb303.jar.file}" packaging="jar" classifier="" pom="${fb303.pom.xml}"/> + </target> +</project> diff --git a/src/jaegertracing/thrift/contrib/fb303/java/src/FacebookBase.java b/src/jaegertracing/thrift/contrib/fb303/java/src/FacebookBase.java new file mode 100644 index 000000000..f8f26a318 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/java/src/FacebookBase.java @@ -0,0 +1,114 @@ +/* + * 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 com.facebook.fb303; + +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class FacebookBase implements FacebookService.Iface { + + private String name_; + + private long alive_; + + private final ConcurrentHashMap<String,Long> counters_ = + new ConcurrentHashMap<String, Long>(); + + private final ConcurrentHashMap<String,String> options_ = + new ConcurrentHashMap<String, String>(); + + protected FacebookBase(String name) { + name_ = name; + alive_ = System.currentTimeMillis() / 1000; + } + + public String getName() { + return name_; + } + + public abstract fb_status getStatus(); + + public String getStatusDetails() { + return ""; + } + + public void deleteCounter(String key) { + counters_.remove(key); + } + + public void resetCounter(String key) { + counters_.put(key, 0L); + } + + public long incrementCounter(String key) { + long val = getCounter(key) + 1; + counters_.put(key, val); + return val; + } + + public long incrementCounter(String key, long increment) { + long val = getCounter(key) + increment; + counters_.put(key, val); + return val; + } + + public long setCounter(String key, long value) { + counters_.put(key, value); + return value; + } + + public AbstractMap<String,Long> getCounters() { + return counters_; + } + + public long getCounter(String key) { + Long val = counters_.get(key); + if (val == null) { + return 0; + } + return val.longValue(); + } + + public void setOption(String key, String value) { + options_.put(key, value); + } + + public String getOption(String key) { + return options_.get(key); + } + + public AbstractMap<String,String> getOptions() { + return options_; + } + + public long aliveSince() { + return alive_; + } + + public String getCpuProfile() { + return ""; + } + + public void reinitialize() {} + + public void shutdown() {} + +} diff --git a/src/jaegertracing/thrift/contrib/fb303/php/FacebookBase.php b/src/jaegertracing/thrift/contrib/fb303/php/FacebookBase.php new file mode 100644 index 000000000..2ac318fb3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/php/FacebookBase.php @@ -0,0 +1,89 @@ +<?php +/* + * 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. + */ + +/** + * Abstract Class providing null implementation for FacebookService + * methods. + */ +class FacebookBase implements FacebookServiceIf { + protected $name_ = ''; + + public function __construct($name) { + $this->name_ = $name; + } + + public function getName() { + return $this->name_; + } + + public function getVersion() { + return ''; + } + + public function getStatus() { + return null; + } + + public function getStatusDetails() { + return ''; + } + + public function getCounters() { + return array(); + } + + public function getCounter($key) { + return null; + } + + public function setOption($key, $value) { + return; + } + + public function getOption($key) { + return ''; + } + + public function getOptions() { + return array(); + } + + public function aliveSince() { + return 0; + } + + public function getCpuProfile($duration) { + return ''; + } + + public function getLimitedReflection() { + return array(); + } + + public function reinitialize() { + return; + } + + public function shutdown() { + return; + } + +} + diff --git a/src/jaegertracing/thrift/contrib/fb303/py/Makefile.am b/src/jaegertracing/thrift/contrib/fb303/py/Makefile.am new file mode 100644 index 000000000..060495e58 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/Makefile.am @@ -0,0 +1,44 @@ +# +# 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. +# + +DESTDIR ?= / +EXTRA_DIST = setup.py src + +all: + +all-local: + $(thrift_home)/bin/thrift --gen py $(top_srcdir)/if/fb303.thrift + mv gen-py/fb303/* fb303 + $(PYTHON) setup.py build + +# We're ignoring prefix here because site-packages seems to be +# the equivalent of /usr/local/lib in Python land. +# Old version (can't put inline because it's not portable). +#$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS) +install-exec-hook: + $(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS) + + + +clean: clean-local + +clean-local: + $(RM) -r build + +check-local: all diff --git a/src/jaegertracing/thrift/contrib/fb303/py/fb303/FacebookBase.py b/src/jaegertracing/thrift/contrib/fb303/py/fb303/FacebookBase.py new file mode 100644 index 000000000..07db10cd3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/fb303/FacebookBase.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +# +# 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. +# + +import time +import FacebookService +import thrift.reflection.limited +from ttypes import fb_status + + +class FacebookBase(FacebookService.Iface): + + def __init__(self, name): + self.name = name + self.alive = int(time.time()) + self.counters = {} + + def getName(self, ): + return self.name + + def getVersion(self, ): + return '' + + def getStatus(self, ): + return fb_status.ALIVE + + def getCounters(self): + return self.counters + + def resetCounter(self, key): + self.counters[key] = 0 + + def getCounter(self, key): + if self.counters.has_key(key): + return self.counters[key] + return 0 + + def incrementCounter(self, key): + self.counters[key] = self.getCounter(key) + 1 + + def setOption(self, key, value): + pass + + def getOption(self, key): + return "" + + def getOptions(self): + return {} + + def getOptions(self): + return {} + + def aliveSince(self): + return self.alive + + def getCpuProfile(self, duration): + return "" + + def getLimitedReflection(self): + return thrift.reflection.limited.Service() + + def reinitialize(self): + pass + + def shutdown(self): + pass diff --git a/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/__init__.py b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/__init__.py new file mode 100644 index 000000000..f8e3a94b9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/__init__.py @@ -0,0 +1,20 @@ +# +# 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. +# + +__all__ = ['fb303_simple_mgmt'] diff --git a/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py new file mode 100644 index 000000000..5c8f409c1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +# +# 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. +# + +from __future__ import print_function +import sys +import os +from optparse import OptionParser + +from thrift.Thrift import * + +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + +from fb303 import * +from fb303.ttypes import * + + +def service_ctrl( + command, + port, + trans_factory=None, + prot_factory=None): + """ + service_ctrl is a generic function to execute standard fb303 functions + + @param command: one of stop, start, reload, status, counters, name, alive + @param port: service's port + @param trans_factory: TTransportFactory to use for obtaining a TTransport. Default is + TBufferedTransportFactory + @param prot_factory: TProtocolFactory to use for obtaining a TProtocol. Default is + TBinaryProtocolFactory + """ + + if command in ["status"]: + try: + status = fb303_wrapper('status', port, trans_factory, prot_factory) + status_details = fb303_wrapper('get_status_details', port, trans_factory, prot_factory) + + msg = fb_status_string(status) + if (len(status_details)): + msg += " - %s" % status_details + print(msg) + return 2 if status == fb_status.ALIVE else 3 + except: + print("Failed to get status") + return 3 + + # scalar commands + if command in ["version", "alive", "name"]: + try: + result = fb303_wrapper(command, port, trans_factory, prot_factory) + print(result) + return 0 + except: + print("failed to get ", command) + return 3 + + # counters + if command in ["counters"]: + try: + counters = fb303_wrapper('counters', port, trans_factory, prot_factory) + for counter in counters: + print("%s: %d" % (counter.encode('utf-8'), counters[counter])) + return 0 + except: + print("failed to get counters") + return 3 + + # Only root should be able to run the following commands + if os.getuid() == 0: + # async commands + if command in ["stop", "reload"]: + try: + fb303_wrapper(command, port, trans_factory, prot_factory) + return 0 + except: + print("failed to tell the service to ", command) + return 3 + else: + if command in ["stop", "reload"]: + print("root privileges are required to stop or reload the service.") + return 4 + + print("The following commands are available:") + for command in ["counters", "name", "version", "alive", "status"]: + print("\t%s" % command) + print("The following commands are available for users with root privileges:") + for command in ["stop", "reload"]: + print("\t%s" % command) + + return 0 + + +def fb303_wrapper(command, port, trans_factory=None, prot_factory=None): + sock = TSocket.TSocket('localhost', port) + + # use input transport factory if provided + if (trans_factory is None): + trans = TTransport.TBufferedTransport(sock) + else: + trans = trans_factory.getTransport(sock) + + # use input protocol factory if provided + if (prot_factory is None): + prot = TBinaryProtocol.TBinaryProtocol(trans) + else: + prot = prot_factory.getProtocol(trans) + + # initialize client and open transport + fb303_client = FacebookService.Client(prot, prot) + trans.open() + + if (command == 'reload'): + fb303_client.reinitialize() + + elif (command == 'stop'): + fb303_client.shutdown() + + elif (command == 'status'): + return fb303_client.getStatus() + + elif (command == 'version'): + return fb303_client.getVersion() + + elif (command == 'get_status_details'): + return fb303_client.getStatusDetails() + + elif (command == 'counters'): + return fb303_client.getCounters() + + elif (command == 'name'): + return fb303_client.getName() + + elif (command == 'alive'): + return fb303_client.aliveSince() + + trans.close() + + +def fb_status_string(status_enum): + if (status_enum == fb_status.DEAD): + return "DEAD" + if (status_enum == fb_status.STARTING): + return "STARTING" + if (status_enum == fb_status.ALIVE): + return "ALIVE" + if (status_enum == fb_status.STOPPING): + return "STOPPING" + if (status_enum == fb_status.STOPPED): + return "STOPPED" + if (status_enum == fb_status.WARNING): + return "WARNING" + + +def main(): + + # parse command line options + parser = OptionParser() + commands = ["stop", "counters", "status", "reload", "version", "name", "alive"] + + parser.add_option("-c", "--command", dest="command", help="execute this API", + choices=commands, default="status") + parser.add_option("-p", "--port", dest="port", help="the service's port", + default=9082) + + (options, args) = parser.parse_args() + status = service_ctrl(options.command, options.port) + sys.exit(status) + + +if __name__ == '__main__': + main() diff --git a/src/jaegertracing/thrift/contrib/fb303/py/setup.py b/src/jaegertracing/thrift/contrib/fb303/py/setup.py new file mode 100644 index 000000000..d27c2962f --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/setup.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# +# 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. +# + +import sys +try: + from setuptools import setup, Extension +except: + from distutils.core import setup, Extension, Command + +setup(name='thrift_fb303', + version='1.0.0', + description='Python bindings for the Apache Thrift FB303', + author=['Apache Thrift Developers'], + author_email=['dev@thrift.apache.org'], + url='http://thrift.apache.org', + license='Apache License 2.0', + packages=[ + 'fb303', + 'fb303_scripts', + ], + classifiers=[ + 'Development Status :: 7 - Inactive', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Topic :: Software Development :: Libraries', + 'Topic :: System :: Networking' + ], + ) diff --git a/src/jaegertracing/thrift/contrib/mingw-cross-compile.sh b/src/jaegertracing/thrift/contrib/mingw-cross-compile.sh new file mode 100755 index 000000000..7ed5d4773 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/mingw-cross-compile.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -e + +./configure \ + --disable-libs \ + --build=i686-pc-linux-gnu \ + --host=i586-mingw32msvc \ + CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ + +make + +# Check two locations to be compatible with libtool 1.5.26 or 2.2.6b. +if test -f compiler/cpp/.libs/thrift.exe ; then + i586-mingw32msvc-strip compiler/cpp/.libs/thrift.exe -o ./thrift.exe +else + i586-mingw32msvc-strip compiler/cpp/thrift.exe -o ./thrift.exe +fi +echo "Finished compiling with resulting exe" +ls -l ./thrift.exe diff --git a/src/jaegertracing/thrift/contrib/parse_profiling.py b/src/jaegertracing/thrift/contrib/parse_profiling.py new file mode 100755 index 000000000..0be5f29ed --- /dev/null +++ b/src/jaegertracing/thrift/contrib/parse_profiling.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python +# +# 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. +# +""" +This script can be used to make the output from +apache::thrift::profile_print_info() more human-readable. + +It translates each executable file name and address into the corresponding +source file name, line number, and function name. By default, it also +demangles C++ symbol names. +""" + +import optparse +import os +import re +import subprocess +import sys + + +class AddressInfo(object): + """ + A class to store information about a particular address in an object file. + """ + def __init__(self, obj_file, address): + self.objectFile = obj_file + self.address = address + self.sourceFile = None + self.sourceLine = None + self.function = None + + +g_addrs_by_filename = {} + + +def get_address(filename, address): + """ + Retrieve an AddressInfo object for the specified object file and address. + + Keeps a global list of AddressInfo objects. Two calls to get_address() + with the same filename and address will always return the same AddressInfo + object. + """ + global g_addrs_by_filename + try: + by_address = g_addrs_by_filename[filename] + except KeyError: + by_address = {} + g_addrs_by_filename[filename] = by_address + + try: + addr_info = by_address[address] + except KeyError: + addr_info = AddressInfo(filename, address) + by_address[address] = addr_info + return addr_info + + +def translate_file_addresses(filename, addresses, options): + """ + Use addr2line to look up information for the specified addresses. + All of the addresses must belong to the same object file. + """ + # Do nothing if we can't find the file + if not os.path.isfile(filename): + return + + args = ['addr2line'] + if options.printFunctions: + args.append('-f') + args.extend(['-e', filename]) + + proc = subprocess.Popen(args, stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + for address in addresses: + assert address.objectFile == filename + proc.stdin.write(address.address + '\n') + + if options.printFunctions: + function = proc.stdout.readline() + function = function.strip() + if not function: + raise Exception('unexpected EOF from addr2line') + address.function = function + + file_and_line = proc.stdout.readline() + file_and_line = file_and_line.strip() + if not file_and_line: + raise Exception('unexpected EOF from addr2line') + idx = file_and_line.rfind(':') + if idx < 0: + msg = 'expected file and line number from addr2line; got %r' % \ + (file_and_line,) + msg += '\nfile=%r, address=%r' % (filename, address.address) + raise Exception(msg) + + address.sourceFile = file_and_line[:idx] + address.sourceLine = file_and_line[idx + 1:] + + (remaining_out, cmd_err) = proc.communicate() + retcode = proc.wait() + if retcode != 0: + raise subprocess.CalledProcessError(retcode, args) + + +def lookup_addresses(options): + """ + Look up source file information for all of the addresses currently stored + in the global list of AddressInfo objects. + """ + global g_addrs_by_filename + for (file, addresses) in g_addrs_by_filename.items(): + translate_file_addresses(file, addresses.values(), options) + + +class Entry(object): + """ + An entry in the thrift profile output. + Contains a header line, and a backtrace. + """ + def __init__(self, header): + self.header = header + self.bt = [] + + def addFrame(self, filename, address): + # If libc was able to determine the symbols names, the filename + # argument will be of the form <filename>(<function>+<offset>) + # So, strip off anything after the last '(' + idx = filename.rfind('(') + if idx >= 0: + filename = filename[:idx] + + addr = get_address(filename, address) + self.bt.append(addr) + + def write(self, f, options): + f.write(self.header) + f.write('\n') + n = 0 + for address in self.bt: + f.write(' #%-2d %s:%s\n' % (n, address.sourceFile, + address.sourceLine)) + n += 1 + if options.printFunctions: + if address.function: + f.write(' %s\n' % (address.function,)) + else: + f.write(' ??\n') + + +def process_file(in_file, out_file, options): + """ + Read thrift profile output from the specified input file, and print + prettier information on the output file. + """ + # + # A naive approach would be to read the input line by line, + # and each time we come to a filename and address, pass it to addr2line + # and print the resulting information. Unfortunately, addr2line can be + # quite slow, especially with large executables. + # + # This approach is much faster. We read in all of the input, storing + # the addresses in each file that need to be resolved. We then call + # addr2line just once for each file. This is much faster than calling + # addr2line once per address. + # + + virt_call_regex = re.compile(r'^\s*T_VIRTUAL_CALL: (\d+) calls on (.*):$') + gen_prot_regex = re.compile( + r'^\s*T_GENERIC_PROTOCOL: (\d+) calls to (.*) with a (.*):$') + bt_regex = re.compile(r'^\s*#(\d+)\s*(.*) \[(0x[0-9A-Za-z]+)\]$') + + # Parse all of the input, and store it as Entry objects + entries = [] + current_entry = None + while True: + line = in_file.readline() + if not line: + break + + if line == '\n' or line.startswith('Thrift virtual call info:'): + continue + + virt_call_match = virt_call_regex.match(line) + if virt_call_match: + num_calls = int(virt_call_match.group(1)) + type_name = virt_call_match.group(2) + if options.cxxfilt: + # Type names reported by typeid() are internal names. + # By default, c++filt doesn't demangle internal type names. + # (Some versions of c++filt have a "-t" option to enable this. + # Other versions don't have this argument, but demangle type + # names passed as an argument, but not on stdin.) + # + # If the output is being filtered through c++filt, prepend + # "_Z" to the type name to make it look like an external name. + type_name = '_Z' + type_name + header = 'T_VIRTUAL_CALL: %d calls on "%s"' % \ + (num_calls, type_name) + if current_entry is not None: + entries.append(current_entry) + current_entry = Entry(header) + continue + + gen_prot_match = gen_prot_regex.match(line) + if gen_prot_match: + num_calls = int(gen_prot_match.group(1)) + type_name1 = gen_prot_match.group(2) + type_name2 = gen_prot_match.group(3) + if options.cxxfilt: + type_name1 = '_Z' + type_name1 + type_name2 = '_Z' + type_name2 + header = 'T_GENERIC_PROTOCOL: %d calls to "%s" with a "%s"' % \ + (num_calls, type_name1, type_name2) + if current_entry is not None: + entries.append(current_entry) + current_entry = Entry(header) + continue + + bt_match = bt_regex.match(line) + if bt_match: + if current_entry is None: + raise Exception('found backtrace frame before entry header') + frame_num = int(bt_match.group(1)) + filename = bt_match.group(2) + address = bt_match.group(3) + current_entry.addFrame(filename, address) + continue + + raise Exception('unexpected line in input: %r' % (line,)) + + # Add the last entry we were processing to the list + if current_entry is not None: + entries.append(current_entry) + current_entry = None + + # Look up all of the addresses + lookup_addresses(options) + + # Print out the entries, now that the information has been translated + for entry in entries: + entry.write(out_file, options) + out_file.write('\n') + + +def start_cppfilt(): + (read_pipe, write_pipe) = os.pipe() + + # Fork. Run c++filt in the parent process, + # and then continue normal processing in the child. + pid = os.fork() + if pid == 0: + # child + os.dup2(write_pipe, sys.stdout.fileno()) + os.close(read_pipe) + os.close(write_pipe) + return + else: + # parent + os.dup2(read_pipe, sys.stdin.fileno()) + os.close(read_pipe) + os.close(write_pipe) + + cmd = ['c++filt'] + os.execvp(cmd[0], cmd) + + +def main(argv): + parser = optparse.OptionParser(usage='%prog [options] [<file>]') + parser.add_option('--no-functions', help='Don\'t print function names', + dest='printFunctions', action='store_false', + default=True) + parser.add_option('--no-demangle', + help='Don\'t demangle C++ symbol names', + dest='cxxfilt', action='store_false', + default=True) + + (options, args) = parser.parse_args(argv[1:]) + num_args = len(args) + if num_args == 0: + in_file = sys.stdin + elif num_args == 1: + in_file = open(argv[1], 'r') + else: + parser.print_usage(sys.stderr) + print >> sys.stderr, 'trailing arguments: %s' % (' '.join(args[1:],)) + return 1 + + if options.cxxfilt: + start_cppfilt() + + process_file(in_file, sys.stdout, options) + + +if __name__ == '__main__': + rc = main(sys.argv) + sys.exit(rc) diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/pom.xml b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/pom.xml new file mode 100644 index 000000000..4179b1d91 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/pom.xml @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. + --> +<project + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.thrift</groupId> + <artifactId>thrift-maven-plugin</artifactId> + <packaging>maven-plugin</packaging> + <name>thrift-maven-plugin</name> + <version>1.0.0</version> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.14.1</version> + <configuration> + <systemPropertyVariables> + <thriftExecutable>${thrift.compiler}</thriftExecutable> + </systemPropertyVariables> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <version>1.8</version> + <executions> + <execution> + <id>generate-jar-for-test</id> + <phase>generate-test-resources</phase> + <configuration> + <target> + <jar destfile="${project.build.directory}/SharedIdl.jar" basedir="${basedir}/src/test/resources" includes="**/*.thrift" /> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>3.1.0</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-project</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>14.0.1</version> + </dependency> + <dependency> + <groupId>org.codehaus.plexus</groupId> + <artifactId>plexus-utils</artifactId> + <version>3.0.14</version> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> + </dependencies> + <properties> + <thrift.root>${basedir}/../..</thrift.root> + <thrift.compiler>${thrift.root}/compiler/cpp/thrift</thrift.compiler> + <thrift.test.home>${thrift.root}/test</thrift.test.home> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> +</project> diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java new file mode 100644 index 000000000..869be95e4 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/AbstractThriftMojo.java @@ -0,0 +1,380 @@ +/* + * 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.thrift.maven; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectHelper; +import org.codehaus.plexus.util.cli.CommandLineException; +import org.codehaus.plexus.util.io.RawInputStreamFacade; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Sets.newHashSet; +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static java.util.Collections.list; +import static org.codehaus.plexus.util.FileUtils.cleanDirectory; +import static org.codehaus.plexus.util.FileUtils.copyStreamToFile; +import static org.codehaus.plexus.util.FileUtils.getFiles; + +/** + * Abstract Mojo implementation. + * <p/> + * This class is extended by {@link org.apache.thrift.maven.ThriftCompileMojo} and + * {@link org.apache.thrift.maven.ThriftTestCompileMojo} in order to override the specific configuration for + * compiling the main or test classes respectively. + */ +abstract class AbstractThriftMojo extends AbstractMojo { + + private static final String THRIFT_FILE_SUFFIX = ".thrift"; + + private static final String DEFAULT_INCLUDES = "**/*" + THRIFT_FILE_SUFFIX; + + /** + * The current Maven project. + * + * @parameter default-value="${project}" + * @readonly + * @required + */ + protected MavenProject project; + + /** + * A helper used to add resources to the project. + * + * @component + * @required + */ + protected MavenProjectHelper projectHelper; + + /** + * This is the path to the {@code thrift} executable. By default it will search the {@code $PATH}. + * + * @parameter default-value="thrift" + * @required + */ + private String thriftExecutable; + + /** + * This string is passed to the {@code --gen} option of the {@code thrift} parameter. By default + * it will generate Java output. The main reason for this option is to be able to add options + * to the Java generator - if you generate something else, you're on your own. + * + * @parameter default-value="java" + */ + private String generator; + + /** + * @parameter + */ + private File[] additionalThriftPathElements = new File[]{}; + + /** + * Since {@code thrift} cannot access jars, thrift files in dependencies are extracted to this location + * and deleted on exit. This directory is always cleaned during execution. + * + * @parameter default-value="${project.build.directory}/thrift-dependencies" + * @required + */ + private File temporaryThriftFileDirectory; + + /** + * This is the path to the local maven {@code repository}. + * + * @parameter default-value="${localRepository}" + * @required + */ + protected ArtifactRepository localRepository; + + /** + * Set this to {@code false} to disable hashing of dependent jar paths. + * <p/> + * This plugin expands jars on the classpath looking for embedded .thrift files. + * Normally these paths are hashed (MD5) to avoid issues with long file names on windows. + * However if this property is set to {@code false} longer paths will be used. + * + * @parameter default-value="true" + * @required + */ + protected boolean hashDependentPaths; + + /** + * @parameter + */ + private Set<String> includes = ImmutableSet.of(DEFAULT_INCLUDES); + + /** + * @parameter + */ + private Set<String> excludes = ImmutableSet.of(); + + /** + * @parameter + */ + private long staleMillis = 0; + + /** + * @parameter + */ + private boolean checkStaleness = false; + + /** + * Executes the mojo. + */ + public void execute() throws MojoExecutionException, MojoFailureException { + checkParameters(); + final File thriftSourceRoot = getThriftSourceRoot(); + if (thriftSourceRoot.exists()) { + try { + ImmutableSet<File> thriftFiles = findThriftFilesInDirectory(thriftSourceRoot); + final File outputDirectory = getOutputDirectory(); + ImmutableSet<File> outputFiles = findGeneratedFilesInDirectory(getOutputDirectory()); + + if (thriftFiles.isEmpty()) { + getLog().info("No thrift files to compile."); + } else if (checkStaleness && ((lastModified(thriftFiles) + staleMillis) < lastModified(outputFiles))) { + getLog().info("Skipping compilation because target directory newer than sources."); + attachFiles(); + } else { + ImmutableSet<File> derivedThriftPathElements = + makeThriftPathFromJars(temporaryThriftFileDirectory, getDependencyArtifactFiles()); + outputDirectory.mkdirs(); + + // Quick fix to fix issues with two mvn installs in a row (ie no clean) + // cleanDirectory(outputDirectory); + + Thrift thrift = new Thrift.Builder(thriftExecutable, outputDirectory) + .setGenerator(generator) + .addThriftPathElement(thriftSourceRoot) + .addThriftPathElements(derivedThriftPathElements) + .addThriftPathElements(asList(additionalThriftPathElements)) + .addThriftFiles(thriftFiles) + .build(); + final int exitStatus = thrift.compile(); + if (exitStatus != 0) { + getLog().error("thrift failed output: " + thrift.getOutput()); + getLog().error("thrift failed error: " + thrift.getError()); + throw new MojoFailureException( + "thrift did not exit cleanly. Review output for more information."); + } + attachFiles(); + } + } catch (IOException e) { + throw new MojoExecutionException("An IO error occurred", e); + } catch (IllegalArgumentException e) { + throw new MojoFailureException("thrift failed to execute because: " + e.getMessage(), e); + } catch (CommandLineException e) { + throw new MojoExecutionException("An error occurred while invoking thrift.", e); + } + } else { + getLog().info(format("%s does not exist. Review the configuration or consider disabling the plugin.", + thriftSourceRoot)); + } + } + + ImmutableSet<File> findGeneratedFilesInDirectory(File directory) throws IOException { + if (directory == null || !directory.isDirectory()) + return ImmutableSet.of(); + + List<File> javaFilesInDirectory = getFiles(directory, "**/*.java", null); + return ImmutableSet.copyOf(javaFilesInDirectory); + } + + private long lastModified(ImmutableSet<File> files) { + long result = 0; + for (File file : files) { + if (file.lastModified() > result) + result = file.lastModified(); + } + return result; + } + + private void checkParameters() { + checkNotNull(project, "project"); + checkNotNull(projectHelper, "projectHelper"); + checkNotNull(thriftExecutable, "thriftExecutable"); + checkNotNull(generator, "generator"); + final File thriftSourceRoot = getThriftSourceRoot(); + checkNotNull(thriftSourceRoot); + checkArgument(!thriftSourceRoot.isFile(), "thriftSourceRoot is a file, not a directory"); + checkNotNull(temporaryThriftFileDirectory, "temporaryThriftFileDirectory"); + checkState(!temporaryThriftFileDirectory.isFile(), "temporaryThriftFileDirectory is a file, not a directory"); + final File outputDirectory = getOutputDirectory(); + checkNotNull(outputDirectory); + checkState(!outputDirectory.isFile(), "the outputDirectory is a file, not a directory"); + } + + protected abstract File getThriftSourceRoot(); + + protected abstract List<Artifact> getDependencyArtifacts(); + + protected abstract File getOutputDirectory(); + + protected abstract void attachFiles(); + + /** + * Gets the {@link File} for each dependency artifact. + * + * @return A set of all dependency artifacts. + */ + private ImmutableSet<File> getDependencyArtifactFiles() { + Set<File> dependencyArtifactFiles = newHashSet(); + for (Artifact artifact : getDependencyArtifacts()) { + dependencyArtifactFiles.add(artifact.getFile()); + } + return ImmutableSet.copyOf(dependencyArtifactFiles); + } + + /** + * @throws IOException + */ + ImmutableSet<File> makeThriftPathFromJars(File temporaryThriftFileDirectory, Iterable<File> classpathElementFiles) + throws IOException, MojoExecutionException { + checkNotNull(classpathElementFiles, "classpathElementFiles"); + // clean the temporary directory to ensure that stale files aren't used + if (temporaryThriftFileDirectory.exists()) { + cleanDirectory(temporaryThriftFileDirectory); + } + + Set<File> thriftDirectories = newHashSet(); + + for (File classpathElementFile : classpathElementFiles) { + // for some reason under IAM, we receive poms as dependent files + // I am excluding .xml rather than including .jar as there may be other extensions in use (sar, har, zip) + if (classpathElementFile.isFile() && classpathElementFile.canRead() && + !classpathElementFile.getName().endsWith(".xml")) { + + // create the jar file. the constructor validates. + JarFile classpathJar; + try { + classpathJar = new JarFile(classpathElementFile); + } catch (IOException e) { + throw new IllegalArgumentException(format( + "%s was not a readable artifact", classpathElementFile)); + } + + /** + * Copy each .thrift file found in the JAR into a temporary directory, preserving the + * directory path it had relative to its containing JAR. Add the resulting root directory + * (unique for each JAR processed) to the set of thrift include directories to use when + * compiling. + */ + for (JarEntry jarEntry : list(classpathJar.entries())) { + final String jarEntryName = jarEntry.getName(); + if (jarEntry.getName().endsWith(THRIFT_FILE_SUFFIX)) { + final String truncatedJarPath = truncatePath(classpathJar.getName()); + final File thriftRootDirectory = new File(temporaryThriftFileDirectory, truncatedJarPath); + final File uncompressedCopy = + new File(thriftRootDirectory, jarEntryName); + uncompressedCopy.getParentFile().mkdirs(); + copyStreamToFile(new RawInputStreamFacade(classpathJar + .getInputStream(jarEntry)), uncompressedCopy); + thriftDirectories.add(thriftRootDirectory); + } + } + + } else if (classpathElementFile.isDirectory()) { + File[] thriftFiles = classpathElementFile.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(THRIFT_FILE_SUFFIX); + } + }); + + if (thriftFiles.length > 0) { + thriftDirectories.add(classpathElementFile); + } + } + } + + return ImmutableSet.copyOf(thriftDirectories); + } + + ImmutableSet<File> findThriftFilesInDirectory(File directory) throws IOException { + checkNotNull(directory); + checkArgument(directory.isDirectory(), "%s is not a directory", directory); + List<File> thriftFilesInDirectory = getFiles(directory, + Joiner.on(",").join(includes), + Joiner.on(",").join(excludes)); + return ImmutableSet.copyOf(thriftFilesInDirectory); + } + + /** + * Truncates the path of jar files so that they are relative to the local repository. + * + * @param jarPath the full path of a jar file. + * @return the truncated path relative to the local repository or root of the drive. + */ + String truncatePath(final String jarPath) throws MojoExecutionException { + + if (hashDependentPaths) { + try { + return toHexString(MessageDigest.getInstance("MD5").digest(jarPath.getBytes())); + } catch (NoSuchAlgorithmException e) { + throw new MojoExecutionException("Failed to expand dependent jar", e); + } + } + + String repository = localRepository.getBasedir().replace('\\', '/'); + if (!repository.endsWith("/")) { + repository += "/"; + } + + String path = jarPath.replace('\\', '/'); + int repositoryIndex = path.indexOf(repository); + if (repositoryIndex != -1) { + path = path.substring(repositoryIndex + repository.length()); + } + + // By now the path should be good, but do a final check to fix windows machines. + int colonIndex = path.indexOf(':'); + if (colonIndex != -1) { + // 2 = :\ in C:\ + path = path.substring(colonIndex + 2); + } + + return path; + } + + private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); + + public static String toHexString(byte[] byteArray) { + final StringBuilder hexString = new StringBuilder(2 * byteArray.length); + for (final byte b : byteArray) { + hexString.append(HEX_CHARS[(b & 0xF0) >> 4]).append(HEX_CHARS[b & 0x0F]); + } + return hexString.toString(); + } +} diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/Thrift.java b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/Thrift.java new file mode 100644 index 000000000..6eea95448 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/Thrift.java @@ -0,0 +1,262 @@ +/* + * 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.thrift.maven; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.codehaus.plexus.util.cli.CommandLineException; +import org.codehaus.plexus.util.cli.CommandLineUtils; +import org.codehaus.plexus.util.cli.Commandline; +import java.io.File; +import java.util.List; +import java.util.Set; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Lists.newLinkedList; +import static com.google.common.collect.Sets.newHashSet; + +/** + * This class represents an invokable configuration of the {@code thrift} + * compiler. The actual executable is invoked using the plexus + * {@link Commandline}. + * <p/> + * This class currently only supports generating java source files. + */ +final class Thrift { + + final static String GENERATED_JAVA = "gen-java"; + + private final String executable; + private final String generator; + private final ImmutableSet<File> thriftPathElements; + private final ImmutableSet<File> thriftFiles; + private final File javaOutputDirectory; + private final CommandLineUtils.StringStreamConsumer output; + private final CommandLineUtils.StringStreamConsumer error; + + /** + * Constructs a new instance. This should only be used by the {@link Builder}. + * + * @param executable The path to the {@code thrift} executable. + * @param generator The value for the {@code --gen} option. + * @param thriftPath The directories in which to search for imports. + * @param thriftFiles The thrift source files to compile. + * @param javaOutputDirectory The directory into which the java source files + * will be generated. + */ + private Thrift(String executable, String generator, ImmutableSet<File> thriftPath, + ImmutableSet<File> thriftFiles, File javaOutputDirectory) { + this.executable = checkNotNull(executable, "executable"); + this.generator = checkNotNull(generator, "generator"); + this.thriftPathElements = checkNotNull(thriftPath, "thriftPath"); + this.thriftFiles = checkNotNull(thriftFiles, "thriftFiles"); + this.javaOutputDirectory = checkNotNull(javaOutputDirectory, "javaOutputDirectory"); + this.error = new CommandLineUtils.StringStreamConsumer(); + this.output = new CommandLineUtils.StringStreamConsumer(); + } + + /** + * Invokes the {@code thrift} compiler using the configuration specified at + * construction. + * + * @return The exit status of {@code thrift}. + * @throws CommandLineException + */ + public int compile() throws CommandLineException { + + for (File thriftFile : thriftFiles) { + Commandline cl = new Commandline(); + cl.setExecutable(executable); + cl.addArguments(buildThriftCommand(thriftFile).toArray(new String[]{})); + final int result = CommandLineUtils.executeCommandLine(cl, null, output, error); + + if (result != 0) { + return result; + } + } + + // result will always be 0 here. + return 0; + } + + /** + * Creates the command line arguments. + * <p/> + * This method has been made visible for testing only. + * + * @param thriftFile + * @return A list consisting of the executable followed by any arguments. + */ + ImmutableList<String> buildThriftCommand(final File thriftFile) { + final List<String> command = newLinkedList(); + // add the executable + for (File thriftPathElement : thriftPathElements) { + command.add("-I"); + command.add(thriftPathElement.toString()); + } + command.add("-out"); + command.add(javaOutputDirectory.toString()); + command.add("--gen"); + command.add(generator); + command.add(thriftFile.toString()); + return ImmutableList.copyOf(command); + } + + /** + * @return the output + */ + public String getOutput() { + return output.getOutput(); + } + + /** + * @return the error + */ + public String getError() { + return error.getOutput(); + } + + /** + * This class builds {@link Thrift} instances. + */ + static final class Builder { + private final String executable; + private final File javaOutputDirectory; + private Set<File> thriftPathElements; + private Set<File> thriftFiles; + private String generator; + + /** + * Constructs a new builder. The two parameters are present as they are + * required for all {@link Thrift} instances. + * + * @param executable The path to the {@code thrift} executable. + * @param javaOutputDirectory The directory into which the java source files + * will be generated. + * @throws NullPointerException If either of the arguments are {@code null}. + * @throws IllegalArgumentException If the {@code javaOutputDirectory} is + * not a directory. + */ + public Builder(String executable, File javaOutputDirectory) { + this.executable = checkNotNull(executable, "executable"); + this.javaOutputDirectory = checkNotNull(javaOutputDirectory); + checkArgument(javaOutputDirectory.isDirectory()); + this.thriftFiles = newHashSet(); + this.thriftPathElements = newHashSet(); + } + + /** + * Adds a thrift file to be compiled. Thrift files must be on the thriftpath + * and this method will fail if a thrift file is added without first adding a + * parent directory to the thriftpath. + * + * @param thriftFile + * @return The builder. + * @throws IllegalStateException If a thrift file is added without first + * adding a parent directory to the thriftpath. + * @throws NullPointerException If {@code thriftFile} is {@code null}. + */ + public Builder addThriftFile(File thriftFile) { + checkNotNull(thriftFile); + checkArgument(thriftFile.isFile()); + checkArgument(thriftFile.getName().endsWith(".thrift")); + checkThriftFileIsInThriftPath(thriftFile); + thriftFiles.add(thriftFile); + return this; + } + + /** + * Adds the option string for the Thrift executable's {@code --gen} parameter. + * + * @param generator + * @return The builder + * @throws NullPointerException If {@code generator} is {@code null}. + */ + public Builder setGenerator(String generator) { + checkNotNull(generator); + this.generator = generator; + return this; + } + + private void checkThriftFileIsInThriftPath(File thriftFile) { + assert thriftFile.isFile(); + checkState(checkThriftFileIsInThriftPathHelper(thriftFile.getParentFile())); + } + + private boolean checkThriftFileIsInThriftPathHelper(File directory) { + assert directory.isDirectory(); + if (thriftPathElements.contains(directory)) { + return true; + } else { + final File parentDirectory = directory.getParentFile(); + return (parentDirectory == null) ? false + : checkThriftFileIsInThriftPathHelper(parentDirectory); + } + } + + /** + * @see #addThriftFile(File) + */ + public Builder addThriftFiles(Iterable<File> thriftFiles) { + for (File thriftFile : thriftFiles) { + addThriftFile(thriftFile); + } + return this; + } + + /** + * Adds the {@code thriftPathElement} to the thriftPath. + * + * @param thriftPathElement A directory to be searched for imported thrift message + * buffer definitions. + * @return The builder. + * @throws NullPointerException If {@code thriftPathElement} is {@code null}. + * @throws IllegalArgumentException If {@code thriftPathElement} is not a + * directory. + */ + public Builder addThriftPathElement(File thriftPathElement) { + checkNotNull(thriftPathElement); + checkArgument(thriftPathElement.isDirectory()); + thriftPathElements.add(thriftPathElement); + return this; + } + + /** + * @see #addThriftPathElement(File) + */ + public Builder addThriftPathElements(Iterable<File> thriftPathElements) { + for (File thriftPathElement : thriftPathElements) { + addThriftPathElement(thriftPathElement); + } + return this; + } + + /** + * @return A configured {@link Thrift} instance. + * @throws IllegalStateException If no thrift files have been added. + */ + public Thrift build() { + checkState(!thriftFiles.isEmpty()); + return new Thrift(executable, generator, ImmutableSet.copyOf(thriftPathElements), + ImmutableSet.copyOf(thriftFiles), javaOutputDirectory); + } + } +} diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java new file mode 100644 index 000000000..b4f75714b --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftCompileMojo.java @@ -0,0 +1,78 @@ +/* + * 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.thrift.maven; + +import java.io.File; +import java.util.List; +import org.apache.maven.artifact.Artifact; +import com.google.common.collect.ImmutableList; + +/** + * This mojo executes the {@code thrift} compiler for generating java sources + * from thrift definitions. It also searches dependency artifacts for + * thrift files and includes them in the thriftPath so that they can be + * referenced. Finally, it adds the thrift files to the project as resources so + * that they are included in the final artifact. + * + * @phase generate-sources + * @goal compile + * @requiresDependencyResolution compile + */ +public final class ThriftCompileMojo extends AbstractThriftMojo { + + /** + * The source directories containing the sources to be compiled. + * + * @parameter default-value="${basedir}/src/main/thrift" + * @required + */ + private File thriftSourceRoot; + + /** + * This is the directory into which the {@code .java} will be created. + * + * @parameter default-value="${project.build.directory}/generated-sources/thrift" + * @required + */ + private File outputDirectory; + + @Override + protected List<Artifact> getDependencyArtifacts() { + List<Artifact> compileArtifacts = project.getCompileArtifacts(); + return compileArtifacts; + } + + @Override + protected File getOutputDirectory() { + return outputDirectory; + } + + @Override + protected File getThriftSourceRoot() { + return thriftSourceRoot; + } + + @Override + protected void attachFiles() { + project.addCompileSourceRoot(outputDirectory.getAbsolutePath()); + projectHelper.addResource(project, thriftSourceRoot.getAbsolutePath(), + ImmutableList.of("**/*.thrift"), null); + } +} diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java new file mode 100644 index 000000000..1b1d99e0d --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/main/java/org/apache/thrift/maven/ThriftTestCompileMojo.java @@ -0,0 +1,93 @@ +/* + * 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.thrift.maven; + +import java.io.File; +import java.util.List; +import org.apache.maven.artifact.Artifact; +import com.google.common.collect.ImmutableList; +import org.apache.maven.artifact.repository.ArtifactRepository; + +/** + * @phase generate-test-sources + * @goal testCompile + * @requiresDependencyResolution test + */ +public final class ThriftTestCompileMojo extends AbstractThriftMojo { + + /** + * The source directories containing the sources to be compiled. + * + * @parameter default-value="${basedir}/src/test/thrift" + * @required + */ + private File thriftTestSourceRoot; + + /** + * This is the directory into which the {@code .java} will be created. + * + * @parameter default-value="${project.build.directory}/generated-test-sources/thrift" + * @required + */ + private File outputDirectory; + + @Override + protected void attachFiles() { + project.addTestCompileSourceRoot(outputDirectory.getAbsolutePath()); + projectHelper.addTestResource(project, thriftTestSourceRoot.getAbsolutePath(), + ImmutableList.of("**/*.thrift"), null); + } + + @Override + protected List<Artifact> getDependencyArtifacts() { + // TODO(gak): maven-project needs generics + @SuppressWarnings("unchecked") + List<Artifact> testArtifacts = project.getTestArtifacts(); + return testArtifacts; + } + + @Override + protected File getOutputDirectory() { + return outputDirectory; + } + + @Override + protected File getThriftSourceRoot() { + return thriftTestSourceRoot; + } + + /** + * Set the local maven ArtifactRepository. Exposed only to allow testing outside of Maven itself. + * + * @param localRepository local ArtifactRepository + */ + public void setLocalMavenRepository(final ArtifactRepository localRepository) { + this.localRepository = localRepository; + } + + /** + * Set the option to hash dependent JAR paths. Exposed only to allow testing outside of Maven itself. + * + * @param hashDependentPaths whether or not to hash paths to dependent JARs + */ + public void setHashDependentPaths(final boolean hashDependentPaths) { + this.hashDependentPaths = hashDependentPaths; + } +} diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestAbstractThriftMojo.java b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestAbstractThriftMojo.java new file mode 100644 index 000000000..7c90a990e --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestAbstractThriftMojo.java @@ -0,0 +1,102 @@ +/* + * 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.thrift.maven; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.io.File; +import java.util.Set; + +import static junit.framework.TestCase.assertEquals; + + +public class TestAbstractThriftMojo { + + private ThriftTestCompileMojo mojo; + private File testRootDir; + private ArtifactRepository mavenRepository; + + + @Before + public void setUp() throws Exception { + final File tmpDir = new File(System.getProperty("java.io.tmpdir")); + testRootDir = new File(tmpDir, "thrift-test"); + + // the truncatePath method assumes a maven repository, but it only cares about the base dir + mavenRepository = Mockito.mock(ArtifactRepository.class); + Mockito.when(mavenRepository.getBasedir()).thenReturn("/test/maven/repo/basedir"); + + mojo = new ThriftTestCompileMojo(); + mojo.setLocalMavenRepository(mavenRepository); + } + + @Test + public void testMakeThriftPathFromJars() throws Throwable { + final File temporaryThriftFileDirectory = testRootDir; + + // The SharedIdl.jar file contains the same idl/shared.thrift and idl/tutorial.thrift hierarchy + // used by other tests. It's used here to represent a dependency of the project maven is building, + // one that is contributing .thrift IDL files as well as any other artifacts. + final Iterable<File> classpathElementFiles = Lists.newArrayList( + new File("target/SharedIdl.jar") + ); + + final Set<File> thriftDirectories = mojo.makeThriftPathFromJars(temporaryThriftFileDirectory, classpathElementFiles); + + // The results should be a path to a directory named after the JAR itself (assuming no path hashing, + // but see below for a separate test of that) representing the root of a hierarchy containing thrift + // files, suitable for providing to the thrift compiler as an include directory. In this case, that + // means it points to the directory containing the "idl" hierarchy rather than to the idl directory + // itself. + final Set<File> expected = Sets.newHashSet( + new File(testRootDir, "target/SharedIdl.jar") + ); + + assertEquals("makeThriftPathFromJars should return thrift IDL base path from within JAR", expected, thriftDirectories); + } + + @Test + public void testTruncatePath() throws Throwable { + // JAR path is unrelated to maven repo, and should be unchanged + assertEquals("/path/to/somejar.jar", mojo.truncatePath("/path/to/somejar.jar")); + + // JAR path is within maven repo, and should be made relative to the repo + assertEquals("path/to/somejar.jar", mojo.truncatePath("/test/maven/repo/basedir/path/to/somejar.jar")); + + // JAR path contains forward slashes that should be normalized + assertEquals("/path/to/somejar.jar", mojo.truncatePath("\\path\\to\\somejar.jar")); + } + + @Test + public void testTruncatePathWithDependentPathHashing() throws Throwable { + mojo.setHashDependentPaths(true); + + // hashDependentPaths set to true, the JAR path is immediately hashed (MD5) and converted to a hex string + + assertEquals("1c85950987b23493462cf3c261d9510a", mojo.truncatePath("/path/to/somejar.jar")); + assertEquals("39fc2b4c34cb6cb0da38bed5d8b5fc67", mojo.truncatePath("/test/maven/repo/basedir/path/to/somejar.jar")); + assertEquals("25b6924f5b0e19486d0ff88448e999d5", mojo.truncatePath("\\path\\to\\somejar.jar")); + } + +} diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestThrift.java b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestThrift.java new file mode 100644 index 000000000..7c7891edf --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/java/org/apache/thrift/maven/TestThrift.java @@ -0,0 +1,163 @@ +/* + * 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.thrift.maven; + +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.cli.CommandLineException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class TestThrift { + + private File testRootDir; + private File idlDir; + private File genJavaDir; + private Thrift.Builder builder; + + @Before + public void setup() throws Exception { + final File tmpDir = new File(System.getProperty("java.io.tmpdir")); + testRootDir = new File(tmpDir, "thrift-test"); + + if (testRootDir.exists()) { + FileUtils.cleanDirectory(testRootDir); + } else { + assertTrue("Failed to create output directory for test: " + testRootDir.getPath(), testRootDir.mkdir()); + } + + File testResourceDir = new File("src/test/resources"); + assertTrue("Unable to find test resources", testRootDir.exists()); + + String thriftExecutable = System.getProperty("thriftExecutable", "thrift"); + if (!(new File(thriftExecutable).exists())) { + thriftExecutable = "thrift"; + } + System.out.println("Thrift compiler: " + thriftExecutable); + + idlDir = new File(testResourceDir, "idl"); + genJavaDir = new File(testRootDir, Thrift.GENERATED_JAVA); + builder = new Thrift.Builder(thriftExecutable, testRootDir); + builder + .setGenerator("java") + .addThriftPathElement(idlDir); + } + + @Test + public void testThriftCompile() throws Exception { + executeThriftCompile(); + } + + @Test + public void testThriftCompileWithGeneratorOption() throws Exception { + builder.setGenerator("java:private-members"); + executeThriftCompile(); + } + + private void executeThriftCompile() throws CommandLineException { + final File thriftFile = new File(idlDir, "shared.thrift"); + + builder.addThriftFile(thriftFile); + + final Thrift thrift = builder.build(); + + assertTrue("File not found: shared.thrift", thriftFile.exists()); + assertFalse("gen-java directory should not exist", genJavaDir.exists()); + + // execute the compile + final int result = thrift.compile(); + assertEquals(0, result); + + assertFalse("gen-java directory was not removed", genJavaDir.exists()); + assertTrue("generated java code doesn't exist", + new File(testRootDir, "shared/SharedService.java").exists()); + } + + @Test + public void testThriftMultipleFileCompile() throws Exception { + final File sharedThrift = new File(idlDir, "shared.thrift"); + final File tutorialThrift = new File(idlDir, "tutorial.thrift"); + + builder.addThriftFile(sharedThrift); + builder.addThriftFile(tutorialThrift); + + final Thrift thrift = builder.build(); + + assertTrue("File not found: shared.thrift", sharedThrift.exists()); + assertFalse("gen-java directory should not exist", genJavaDir.exists()); + + // execute the compile + final int result = thrift.compile(); + assertEquals(0, result); + + assertFalse("gen-java directory was not removed", genJavaDir.exists()); + assertTrue("generated java code doesn't exist", + new File(testRootDir, "shared/SharedService.java").exists()); + assertTrue("generated java code doesn't exist", + new File(testRootDir, "tutorial/InvalidOperation.java").exists()); + } + + @Test + public void testBadCompile() throws Exception { + final File thriftFile = new File(testRootDir, "missing.thrift"); + builder.addThriftPathElement(testRootDir); + + // Hacking around checks in addThrift file. + assertTrue(thriftFile.createNewFile()); + builder.addThriftFile(thriftFile); + assertTrue(thriftFile.delete()); + + final Thrift thrift = builder.build(); + + assertTrue(!thriftFile.exists()); + assertFalse("gen-java directory should not exist", genJavaDir.exists()); + + // execute the compile + final int result = thrift.compile(); + assertEquals(1, result); + } + + @Test + public void testFileInPathPreCondition() throws Exception { + final File thriftFile = new File(testRootDir, "missing.thrift"); + + // Hacking around checks in addThrift file. + assertTrue(thriftFile.createNewFile()); + try { + builder.addThriftFile(thriftFile); + fail("Expected IllegalStateException"); + } catch (IllegalStateException e) { + } + } + + @After + public void cleanup() throws Exception { + if (testRootDir.exists()) { + FileUtils.cleanDirectory(testRootDir); + assertTrue("Failed to delete output directory for test: " + testRootDir.getPath(), testRootDir.delete()); + } + } +} diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/resources/idl/shared.thrift b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/resources/idl/shared.thrift new file mode 100644 index 000000000..475e7f803 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/resources/idl/shared.thrift @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/** + * This Thrift file can be included by other Thrift files that want to share + * these definitions. + */ + +namespace cpp shared +namespace java shared +namespace perl shared + +struct SharedStruct { + 1: i32 key + 2: string value +} + +service SharedService { + SharedStruct getStruct(1: i32 key) +} diff --git a/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/resources/idl/tutorial.thrift b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/resources/idl/tutorial.thrift new file mode 100644 index 000000000..86e433dd3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift-maven-plugin/src/test/resources/idl/tutorial.thrift @@ -0,0 +1,152 @@ +/* + * 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. + */ + +# Thrift Tutorial +# Mark Slee (mcslee@facebook.com) +# +# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The +# first thing to notice is that .thrift files support standard shell comments. +# This lets you make your thrift file executable and include your Thrift build +# step on the top line. And you can place comments like this anywhere you like. +# +# Before running this file, you will need to have installed the thrift compiler +# into /usr/local/bin. + +/** + * The first thing to know about are types. The available types in Thrift are: + * + * bool Boolean, one byte + * byte Signed byte + * i16 Signed 16-bit integer + * i32 Signed 32-bit integer + * i64 Signed 64-bit integer + * double 64-bit floating point value + * string String + * binary Blob (byte array) + * map<t1,t2> Map from one type to another + * list<t1> Ordered list of one type + * set<t1> Set of unique elements of one type + * + * Did you also notice that Thrift supports C style comments? + */ + +// Just in case you were wondering... yes. We support simple C comments too. + +/** + * Thrift files can reference other Thrift files to include common struct + * and service definitions. These are found using the current path, or by + * searching relative to any paths specified with the -I compiler flag. + * + * Included objects are accessed using the name of the .thrift file as a + * prefix. i.e. shared.SharedObject + */ +include "shared.thrift" + +/** + * Thrift files can namespace, package, or prefix their output in various + * target languages. + */ +namespace cpp tutorial +namespace java tutorial +namespace php tutorial +namespace perl tutorial +namespace smalltalk.category Thrift.Tutorial + +/** + * Thrift lets you do typedefs to get pretty names for your types. Standard + * C style here. + */ +typedef i32 MyInteger + +/** + * Thrift also lets you define constants for use across languages. Complex + * types and structs are specified using JSON notation. + */ +const i32 INT32CONSTANT = 9853 +const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} + +/** + * You can define enums, which are just 32 bit integers. Values are optional + * and start at 1 if not supplied, C style again. + */ +enum Operation { + ADD = 1, + SUBTRACT = 2, + MULTIPLY = 3, + DIVIDE = 4 +} + +/** + * Structs are the basic complex data structures. They are comprised of fields + * which each have an integer identifier, a type, a symbolic name, and an + * optional default value. + * + * Fields can be declared "optional", which ensures they will not be included + * in the serialized output if they aren't set. Note that this requires some + * manual management in some languages. + */ +struct Work { + 1: i32 num1 = 0, + 2: i32 num2, + 3: Operation op, + 4: optional string comment, +} + +/** + * Structs can also be exceptions, if they are nasty. + */ +exception InvalidOperation { + 1: i32 what, + 2: string why +} + +/** + * Ahh, now onto the cool part, defining a service. Services just need a name + * and can optionally inherit from another service using the extends keyword. + */ +service Calculator extends shared.SharedService { + + /** + * A method definition looks like C code. It has a return type, arguments, + * and optionally a list of exceptions that it may throw. Note that argument + * lists and exception lists are specified using the exact same syntax as + * field lists in struct or exception definitions. + */ + + void ping(), + + i32 add(1:i32 num1, 2:i32 num2), + + i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), + + /** + * This method has a oneway modifier. That means the client only makes + * a request and does not listen for any response at all. Oneway methods + * must be void. + */ + oneway void zip() + +} + +/** + * That just about covers the basics. Take a look in the test/ folder for more + * detailed examples. After you run this file, your generated code shows up + * in folders with names gen-<language>. The generated code isn't too scary + * to look at. It even has pretty indentation. + */ diff --git a/src/jaegertracing/thrift/contrib/thrift.el b/src/jaegertracing/thrift/contrib/thrift.el new file mode 100644 index 000000000..941a99fe4 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift.el @@ -0,0 +1,140 @@ +;;; thrift.el --- Major mode for Apache Thrift files + +;; Keywords: files + +;; 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. +;; + +;;; Commentary: + +;; + +;;; Code: + +(require 'font-lock) + +(defvar thrift-mode-hook nil) +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.thrift\\'" . thrift-mode)) + +(defvar thrift-indent-level 2 + "Defines 2 spaces for thrift indentation.") + +;; syntax coloring +(defconst thrift-font-lock-keywords + (list + '("\\<\\(include\\|struct\\|exception\\|typedef\\|const\\|enum\\|service\\|extends\\|void\\|oneway\\|throws\\|optional\\|required\\)\\>" . font-lock-keyword-face) ;; keywords + '("\\<\\(bool\\|byte\\|i16\\|i32\\|i64\\|double\\|string\\|binary\\|map\\|list\\|set\\)\\>" . font-lock-type-face) ;; built-in types + '("\\<\\([0-9]+\\)\\>" . font-lock-variable-name-face) ;; ordinals + '("\\<\\(\\w+\\)\\s-*(" (1 font-lock-function-name-face)) ;; functions + ) + "Thrift Keywords.") + +;; indentation +(defun thrift-indent-line () + "Indent current line as Thrift code." + (interactive) + (beginning-of-line) + (if (bobp) + (indent-line-to 0) + (let ((not-indented t) cur-indent) + (if (looking-at "^[ \t]*\\(}\\|throws\\)") + (if (looking-at "^[ \t]*}") + (progn + (save-excursion + (forward-line -1) + (setq cur-indent (- (current-indentation) thrift-indent-level))) + (if (< cur-indent 0) + (setq cur-indent 0))) + (progn + (save-excursion + (forward-line -1) + (if (looking-at "^[ \t]*[\\.<>[:word:]]+[ \t]+[\\.<>[:word:]]+[ \t]*(") + (setq cur-indent (+ (current-indentation) thrift-indent-level)) + (setq cur-indent (current-indentation)))))) + (save-excursion + (while not-indented + (forward-line -1) + (if (looking-at "^[ \t]*}") + (progn + (setq cur-indent (current-indentation)) + (setq not-indented nil)) + (if (looking-at "^.*{[^}]*$") + (progn + (setq cur-indent (+ (current-indentation) thrift-indent-level)) + (setq not-indented nil)) + (if (bobp) + (setq not-indented nil))) + (if (looking-at "^[ \t]*throws") + (progn + (setq cur-indent (- (current-indentation) thrift-indent-level)) + (if (< cur-indent 0) + (setq cur-indent 0)) + (setq not-indented nil)) + (if (bobp) + (setq not-indented nil))) + (if (looking-at "^[ \t]*[\\.<>[:word:]]+[ \t]+[\\.<>[:word:]]+[ \t]*([^)]*$") + (progn + (setq cur-indent (+ (current-indentation) thrift-indent-level)) + (setq not-indented nil)) + (if (bobp) + (setq not-indented nil))) + (if (looking-at "^[ \t]*\\/\\*") + (progn + (setq cur-indent (+ (current-indentation) 1)) + (setq not-indented nil)) + (if (bobp) + (setq not-indented nil))) + (if (looking-at "^[ \t]*\\*\\/") + (progn + (setq cur-indent (- (current-indentation) 1)) + (setq not-indented nil)) + (if (bobp) + (setq not-indented nil))) + )))) + (if cur-indent + (indent-line-to cur-indent) + (indent-line-to 0))))) + +;; C/C++- and sh-style comments; also allowing underscore in words +(defvar thrift-mode-syntax-table + (let ((thrift-mode-syntax-table (make-syntax-table))) + (modify-syntax-entry ?_ "w" thrift-mode-syntax-table) + (modify-syntax-entry ?# "<" thrift-mode-syntax-table) ; sh-style comments + (modify-syntax-entry ?/ ". 124" thrift-mode-syntax-table) ; c/c++-style comments + (modify-syntax-entry ?* ". 23b" thrift-mode-syntax-table) + (modify-syntax-entry ?\n ">" thrift-mode-syntax-table) + thrift-mode-syntax-table) + "Syntax table for thrift-mode") + +;;;###autoload +(defun thrift-mode () + "Mode for editing Thrift files." + (interactive) + (kill-all-local-variables) + (set-syntax-table thrift-mode-syntax-table) + (set (make-local-variable 'font-lock-defaults) '(thrift-font-lock-keywords)) + (setq major-mode 'thrift-mode) + (setq mode-name "Thrift") + (run-hooks 'thrift-mode-hook) + (set (make-local-variable 'indent-line-function) 'thrift-indent-line) + ) + +(provide 'thrift) +;;; thrift.el ends here + diff --git a/src/jaegertracing/thrift/contrib/thrift.spec b/src/jaegertracing/thrift/contrib/thrift.spec new file mode 100644 index 000000000..cbb08fba5 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift.spec @@ -0,0 +1,253 @@ +# +# 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. +# + +%define without_java 1 +%define without_python 1 +%define without_tests 1 + +%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} +%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} + +Name: thrift +License: Apache License v2.0 +Group: Development +Summary: RPC and serialization framework +Version: 0.13.0 +Release: 0 +URL: http://thrift.apache.org +Packager: Thrift Developers <dev@thrift.apache.org> +Source0: %{name}-%{version}.tar.gz + +BuildRequires: gcc >= 3.4.6 +BuildRequires: gcc-c++ + +%if 0%{!?without_java:1} +BuildRequires: java-devel >= 0:1.5.0 +BuildRequires: ant >= 0:1.6.5 +%endif + +%if 0%{!?without_python:1} +BuildRequires: python-devel +%endif + +%if 0%{!?without_ruby:1} +%define gem_name %{name} +BuildRequires: ruby-devel +BuildRequires: rubygems-devel +%endif + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%description +Thrift is a software framework for scalable cross-language services +development. It combines a powerful software stack with a code generation +engine to build services that work efficiently and seamlessly between C++, +Java, C#, Python, Ruby, Perl, PHP, Smalltalk, Erlang, OCaml, Haskell, and +other languages. + +%files +%defattr(-,root,root) +%{_bindir}/thrift + + +%package lib-cpp +Summary: Thrift C++ library +Group: Libraries + +%description lib-cpp +C++ libraries for Thrift. + +%files lib-cpp +%defattr(-,root,root) +%{_libdir}/libthrift*.so.* +%{_libdir}/libthrift*.so + + +%package lib-cpp-devel +Summary: Thrift C++ library development files +Group: Libraries +Requires: %{name} = %{version}-%{release} +Requires: boost-devel +%if 0%{!?without_libevent:1} +Requires: libevent-devel >= 1.2 +%endif +%if 0%{!?without_zlib:1} +Requires: zlib-devel +%endif + +%description lib-cpp-devel +C++ static libraries and headers for Thrift. + +%files lib-cpp-devel +%defattr(-,root,root) +%{_includedir}/thrift/ +%{_libdir}/libthrift*.*a +%{_libdir}/pkgconfig/thrift*.pc + + +%if 0%{!?without_java:1} +%package lib-java +Summary: Thrift Java library +Group: Libraries +Requires: java >= 0:1.5.0 + +%description lib-java +Java libraries for Thrift. + +%files lib-java +%defattr(-,root,root) +%{_javadir}/* +%endif + + +%if 0%{!?without_python:1} +%package lib-python +Summary: Thrift Python library +Group: Libraries + +%description lib-python +Python libraries for Thrift. + +%files lib-python +%defattr(-,root,root) +%{python_sitearch}/* +%endif + + +%if 0%{!?without_ruby:1} +%package -n rubygem-%{gem_name} +Summary: Thrift Ruby library +Group: Libraries +Obsoletes: %{name}-lib-ruby + +%description -n rubygem-%{gem_name} +Ruby libraries for Thrift. + +%files -n rubygem-%{gem_name} +%defattr(-,root,root) +%{gem_dir}/* +%endif + + +%if 0%{!?without_php:1} +%package lib-php +Summary: Thrift PHP library +Group: Libraries + +%description lib-php +PHP libraries for Thrift. + +%files lib-php +%defattr(-,root,root) +/usr/lib/php/* +%endif + + +%prep +%setup -q + +%build +[[ -e Makefile.in ]] || ./bootstrap.sh +export GEM_HOME=${PWD}/.gem-home +export RUBYLIB=${PWD}/lib/rb/lib +%configure \ + %{?without_libevent: --without-libevent } \ + %{?without_zlib: --without-zlib } \ + %{?without_tests: --without-tests } \ + %{?without_java: --without-java } \ + %{?without_python: --without-python } \ + %{?without_ruby: --without-ruby } \ + %{?without_php: --without-php } \ + %{!?without_php: PHP_PREFIX=${RPM_BUILD_ROOT}/usr/lib/php } \ + --without-csharp \ + --without-erlang \ + +%if 0%{!?without_ruby:1} +eval $(grep "^WITH_RUBY_TRUE" config.log) +if [[ "${WITH_RUBY_TRUE}" != "" ]]; then + set +x + echo "" + echo "configure determined that ruby requirements are missing (bundler gem?), either install missing components" >&2 + echo "or disable the ruby sub-packages as follows:" >&2 + echo " rpmbuild -D'%without_ruby 1' ..." >&2 + echo "" + exit 1 +fi +%endif + +make %{?_smp_mflags} + +%if 0%{!?without_java:1} +cd lib/java +%ant +cd ../.. +%endif + +%if 0%{!?without_python:1} +cd lib/py +CFLAGS="%{optflags}" %{__python} setup.py build +cd ../.. +%endif + +%if 0%{!?without_ruby:1} +%gem_install -n lib/rb/thrift*.gem +%endif + +%install +export GEM_HOME=${PWD}/.gem-home +export RUBYLIB=${PWD}/lib/rb/lib +%makeinstall +ln -s libthrift-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthrift.so.0 +ln -s libthriftnb-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthriftnb.so.0 +ln -s libthriftz-%{version}.so ${RPM_BUILD_ROOT}%{_libdir}/libthriftz.so.0 + +%if 0%{!?without_java:1} +mkdir -p $RPM_BUILD_ROOT%{_javadir} +cp -p lib/java/build/*.jar $RPM_BUILD_ROOT%{_javadir} +%endif + +%if 0%{!?without_python:1} +cd lib/py +%{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT +cd ../.. +%endif + +%if 0%{!?without_ruby:1} +mkdir -p %{buildroot}%{gem_dir} +cp -a ./%{gem_dir}/* %{buildroot}%{gem_dir}/ +%endif + +%clean +rm -rf ${RPM_BUILD_ROOT} + + +%post +umask 007 +/sbin/ldconfig > /dev/null 2>&1 + + +%postun +umask 007 +/sbin/ldconfig > /dev/null 2>&1 + +%changelog +* Wed Aug 21 2013 Thrift Dev <dev@thrift.apache.org> +- Thrift 0.9.1 release. +* Wed Oct 10 2012 Thrift Dev <dev@thrift.apache.org> +- Thrift 0.9.0 release. diff --git a/src/jaegertracing/thrift/contrib/thrift.vim b/src/jaegertracing/thrift/contrib/thrift.vim new file mode 100644 index 000000000..623195577 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift.vim @@ -0,0 +1,91 @@ +" Vim syntax file +" Language: Thrift +" Maintainer: Martin Smith <martin@facebook.com> +" Last Change: $Date: $ +" Copy to ~/.vim/ +" Add to ~/.vimrc +" au BufRead,BufNewFile *.thrift set filetype=thrift +" au! Syntax thrift source ~/.vim/thrift.vim +" +" $Id: $ +" +" 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. +" + +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +" Todo +syn keyword thriftTodo TODO todo FIXME fixme XXX xxx contained + +" Comments +syn match thriftComment "#.*" contains=thriftTodo +syn region thriftComment start="/\*" end="\*/" contains=thriftTodo +syn match thriftComment "//.\{-}\(?>\|$\)\@=" + +" String +syn region thriftStringDouble matchgroup=None start=+"+ end=+"+ + +" Number +syn match thriftNumber "-\=\<\d\+\>" contained + +" Keywords +syn keyword thriftKeyword namespace +syn keyword thriftKeyword xsd_all xsd_optional xsd_nillable xsd_attrs +syn keyword thriftKeyword include cpp_include cpp_type const optional required +syn keyword thriftBasicTypes void bool byte i8 i16 i32 i64 double string binary +syn keyword thriftStructure map list set struct typedef exception enum throws union + +" Special +syn match thriftSpecial "\d\+:" + +" Structure +syn keyword thriftStructure service oneway extends +"async" { return tok_async; } +"exception" { return tok_xception; } +"extends" { return tok_extends; } +"throws" { return tok_throws; } +"service" { return tok_service; } +"enum" { return tok_enum; } +"const" { return tok_const; } + +if version >= 508 || !exists("did_thrift_syn_inits") + if version < 508 + let did_thrift_syn_inits = 1 + command! -nargs=+ HiLink hi link <args> + else + command! -nargs=+ HiLink hi def link <args> + endif + + HiLink thriftComment Comment + HiLink thriftKeyword Special + HiLink thriftBasicTypes Type + HiLink thriftStructure StorageClass + HiLink thriftTodo Todo + HiLink thriftString String + HiLink thriftNumber Number + HiLink thriftSpecial Special + HiLink thriftStructure Structure + + delcommand HiLink +endif + +let b:current_syntax = "thrift" diff --git a/src/jaegertracing/thrift/contrib/thrift_dump.cpp b/src/jaegertracing/thrift/contrib/thrift_dump.cpp new file mode 100644 index 000000000..59c8ac863 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/thrift_dump.cpp @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#include <cstdlib> +#include <iostream> + +#include <thrift/transport/TBufferTransports.h> +#include <thrift/transport/TFDTransport.h> +#include <thrift/protocol/TBinaryProtocol.h> +#include <thrift/protocol/TDebugProtocol.h> +#include <thrift/protocol/TProtocolTap.h> + +using namespace std; +using boost::shared_ptr; +using namespace apache::thrift::transport; +using namespace apache::thrift::protocol; + +void usage() { + fprintf(stderr, + "usage: thrift_dump {-b|-f|-s} < input > ouput\n" + " -b TBufferedTransport messages\n" + " -f TFramedTransport messages\n" + " -s Raw structures\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + usage(); + } + + shared_ptr<TTransport> stdin_trans(new TFDTransport(STDIN_FILENO)); + shared_ptr<TTransport> itrans; + + if (argv[1] == std::string("-b") || argv[1] == std::string("-s")) { + itrans.reset(new TBufferedTransport(stdin_trans)); + } else if (argv[1] == std::string("-f")) { + itrans.reset(new TFramedTransport(stdin_trans)); + } else { + usage(); + } + + shared_ptr<TProtocol> iprot(new TBinaryProtocol(itrans)); + shared_ptr<TProtocol> oprot( + new TDebugProtocol( + shared_ptr<TTransport>(new TBufferedTransport( + shared_ptr<TTransport>(new TFDTransport(STDOUT_FILENO)))))); + + TProtocolTap tap(iprot, oprot); + + try { + if (argv[1] == std::string("-s")) { + for (;;) { + tap.skip(T_STRUCT); + } + } else { + std::string name; + TMessageType messageType; + int32_t seqid; + for (;;) { + tap.readMessageBegin(name, messageType, seqid); + tap.skip(T_STRUCT); + tap.readMessageEnd(); + } + } + } catch (TProtocolException exn) { + cout << "Protocol Exception: " << exn.what() << endl; + } catch (...) { + oprot->getTransport()->flush(); + } + + cout << endl; + + return 0; +} diff --git a/src/jaegertracing/thrift/contrib/transport-sample/Makefile b/src/jaegertracing/thrift/contrib/transport-sample/Makefile new file mode 100644 index 000000000..89e03b8ef --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/Makefile @@ -0,0 +1,25 @@ +THRIFT_DIR =../.. +INCS_DIRS =-I${THRIFT_DIR}/lib/cpp/src -I. +THRIFT_LIB =${THRIFT_DIR}/lib/cpp/.libs/libthrift.a +BOOST_LIB = +CPP_DEFS = +CPP_OPTS =-Wall -O2 + +GEN_SRC = gen-cpp/SampleService.cpp \ + gen-cpp/Sample_types.cpp \ + gen-cpp/SampleCallback.cpp \ + gen-cpp/Sample_constants.cpp +GEN_INC = -Igen-cpp + +default: server client +.PHONY: server client + +server: + g++ ${CPP_OPTS} ${CPP_DEFS} -o server/server ${GEN_INC} ${INCS_DIRS} server/server.cpp ${GEN_SRC} ${THRIFT_LIB} ${BOOST_LIB} + +client: + g++ ${CPP_OPTS} ${CPP_DEFS} -o client/client ${GEN_INC} ${INCS_DIRS} client/client.cpp ${GEN_SRC} ${THRIFT_LIB} ${BOOST_LIB} + +clean: + $(RM) -r client/client server/server + diff --git a/src/jaegertracing/thrift/contrib/transport-sample/README.md b/src/jaegertracing/thrift/contrib/transport-sample/README.md new file mode 100644 index 000000000..a1dfc0a36 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/README.md @@ -0,0 +1,61 @@ +Thrift transport sample project +------------------------------- + +This cross-platform project has been built with Windows Visual Studio 10 and +OSX 10.7.1's g++. The client and server support socket and pipe transports +through command-line switches. + +Windows supports both named & anonymous pipes; *NIX gets only named +'pipes' at this time. + +Windows-only at this time: +The client & server are double-ended. Both sides run a server and client to +enable full duplex bidirectional event signaling. They are simple command +line apps. The server runs until it's aborted (Ctl-C). The client connects to +the server, informs the server of its listening pipe/port, runs some more RPCs +and exits. The server also makes RPC calls to the client to demonstrate +bidirectional operation. + +Prequisites: +Boost -- tested with Boost 1.47, other versions may work. +libthrift library -- build the library under "thrift/lib/cpp/" +thrift IDL compiler -- download from http://thrift.apache.org/download/ + or build from "thrift/compiler/cpp". The IDL compiler version should + match the thrift source distribution's version. For instance, thrift-0.9.0 + has a different directory structure than thrift-0.8.0 and the generated + files are not compatible. + +Note: Bulding the thrift IDL compiler and library are beyond the scope +of this article. Please refer to the Thrift documentation in the respective +directories and online. + + +Microsoft Windows with Visual Studio 10 +---------------------------------------- +Copy the IDL compiler 'thrift.exe' to this project folder or to a location in the path. +Run thriftme.bat to generate the interface source from the thrift files. + +Open transport-sample.sln and... +Adapt the Boost paths for the client and server projects. Right-click on each project, select +Properties, then: +Configuration Properties -> C/C++ -> General -> Additional Include Directories +Configuration Properties -> Linker -> General -> Additional Include Directories + +The stock path assumes that Boost is located at the same level as the thrift repo root. + +Run the following in separate command prompts from the Release or Debug +build folder: + server.exe -np test + client.exe -np test + + +*NIX flavors +------------ +Build the thrift cpp library. +Build the IDL compiler and copy it to this project folder. +Run thriftme.sh to generate the interface source from the thrift files. +Run 'make' + +Run the following in separate shells: + server/server -np /tmp/test + client/client -np /tmp/test diff --git a/src/jaegertracing/thrift/contrib/transport-sample/Sample.thrift b/src/jaegertracing/thrift/contrib/transport-sample/Sample.thrift new file mode 100644 index 000000000..3040e251c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/Sample.thrift @@ -0,0 +1,39 @@ +/* + transport-sample thrift IDL file . + Execute thriftme.bat under Windows to generate the cpp stubs from this IDL. + */ + +// See thrift/tutorial/tutorial.thrift and shared.thrift for more extensive examples. + + +namespace cpp Sample +namespace java Sample +namespace perl Sample + +//This struct is not used in the sample. Shown here for illustrative purposes only. +// +struct SampleStruct +{ + 1: i32 key + 2: string value +} + + +//A service contains the RPC(s). +// +service SampleService +{ + string HelloThere(1:string HelloString), + void ServerDoSomething(), + + //Client calls this to tell server which port to connect back on. + void ClientSideListenPort(1:i16 Port), + //Named pipe version + void ClientSidePipeName(1:string name), +} + +//Sample RPC on the 'client' side that the master server can call. +service SampleCallback +{ + void pingclient(), +} diff --git a/src/jaegertracing/thrift/contrib/transport-sample/ThriftCommon.cpp b/src/jaegertracing/thrift/contrib/transport-sample/ThriftCommon.cpp new file mode 100644 index 000000000..60ebf7a00 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/ThriftCommon.cpp @@ -0,0 +1,37 @@ +// ThriftCommon.cpp : Common functions for sample Thrift client and server +// + +#include "ThriftCommon.h" + +namespace thriftcommon +{ + //---------------------------------------------------------------------------- + //Launch child process and pass R/W anonymous pipe handles on cmd line. + //This is a simple example and does not include elevation or other + //advanced features. + // + bool LaunchAnonPipeChild(std::string app, boost::shared_ptr<TServerTransport> transport) + { +#ifdef _WIN32 + PROCESS_INFORMATION pi; + STARTUPINFOA si; + GetStartupInfoA(&si); //set startupinfo for the spawned process + char handles[MAX_PATH]; //Stores pipe handles converted to text + + sprintf(handles, "%s %d %d", app.c_str(), + (int)boost::shared_dynamic_cast<TPipeServer>(transport)->getClientRdPipeHandle(), + (int)boost::shared_dynamic_cast<TPipeServer>(transport)->getClientWrtPipeHandle()); + + //spawn the child process + if (!CreateProcessA(NULL, handles, NULL,NULL,TRUE,0,NULL,NULL,&si,&pi)) + { + GlobalOutput.perror("TPipeServer CreateProcess failed, GLE=", GetLastError()); + return false; + } + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); +#endif + return true; + } +} diff --git a/src/jaegertracing/thrift/contrib/transport-sample/ThriftCommon.h b/src/jaegertracing/thrift/contrib/transport-sample/ThriftCommon.h new file mode 100644 index 000000000..078ad4474 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/ThriftCommon.h @@ -0,0 +1,205 @@ +// ThriftCommon.h : Common includes, namespaces and templates +// for sample Thrift client and server +// +// Add the following paths to the Project's properties: +// +// Configuration Properties -> C/C++ -> General-> Additional Include Directories -- +// ../;../../../lib/cpp/src;../../../../boost;../../../../boost/boost/tr1; +// +// Configuration Properties -> Linker -> General -> Additional Library Directories -- +// ../../../lib/cpp/$(Configuration);../../../../Boost/lib +// +// Configuration Properties -> Linker -> Input -> Additional Dependencies -- +// libthrift.lib +// +// ... adjust relative paths as necessary. +// + +#ifdef _WIN32 //thrift is crashing when using boost threads on Mac OSX +#else +# include <sys/socket.h> +# include <netinet/in.h> +#endif + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Required Includes +//'server' side #includes +#include <thrift/concurrency/ThreadManager.h> +#include <thrift/concurrency/ThreadFactory.h> +#include <thrift/server/TThreadPoolServer.h> +#include <thrift/server/TSimpleServer.h> +//'client' side #includes +#include <thrift/transport/TPipeServer.h> +#include <thrift/transport/TPipe.h> +#include <thrift/transport/TBufferTransports.h> +#include <thrift/transport/TSocket.h> +#include <thrift/transport/TTransport.h> + +#include <thrift/protocol/TBinaryProtocol.h> + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Required Namespaces +//'server' side namespaces +using namespace apache::thrift::server; +using namespace apache::thrift::concurrency; +//common namespaces +using namespace apache::thrift; +using namespace apache::thrift::protocol; +using namespace apache::thrift::transport; +//using namespace boost; //using ns boost can introduce type conflicts +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +namespace thriftcommon +{ + //---------------------------------------------------------------------------- + // + //Start the thrift 'server' (both server & client side run one for bidir event signaling) + // *** This function template will block *** + // + template <class MyHandler, class MyProcessor> + void RunThriftServer (boost::shared_ptr<MyHandler> hndlr, + int NumThreads, + boost::shared_ptr<TServerTransport> transport, + boost::shared_ptr<TServer> &server) + { +#ifdef _WIN32 + if (!hndlr.get()) + throw std::exception("RunThriftServer() invalid handler"); + if (!transport.get()) + throw std::exception("RunThriftServer() invalid transport"); +#else + if ( !hndlr.get() || !transport.get() ) + throw std::exception(); +#endif + + boost::shared_ptr<MyHandler> handler(hndlr); + boost::shared_ptr<TProcessor> processor(new MyProcessor(handler)); + boost::shared_ptr<TTransportFactory> tfactory(new TBufferedTransportFactory()); + boost::shared_ptr<TProtocolFactory> pfactory(new TBinaryProtocolFactory()); + + if(NumThreads <= 1) + { //Single-threaded server + server.reset(new TSimpleServer(processor, transport, tfactory, pfactory)); + } + else + { //Multi-threaded server + boost::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(NumThreads); + boost::shared_ptr<ThreadFactory> threadFactory = boost::shared_ptr<ThreadFactory>(new ThreadFactory()); + threadManager->threadFactory(threadFactory); + threadManager->start(); + server.reset(new TThreadPoolServer(processor, transport, tfactory, pfactory, threadManager)); + } + + printf("Starting the 'server'...\n"); + server->serve(); + printf("done.\n"); + } + + // Thrift server wrapper function that accepts a pipe name. + // A handler must be passed in to this version. + template <class MyHandler, class MyProcessor> + void RunThriftServer (boost::shared_ptr<MyHandler> hndlr, int NumThreads, std::string pipename, boost::shared_ptr<TServer> &svr) + { +#ifndef _WIN32 //Mac, *nix + unlink(pipename.c_str()); +#endif + boost::shared_ptr<TServerTransport> transport(new TPipeServer(pipename, 1024, NumThreads)); //Named pipe + RunThriftServer<MyHandler, MyProcessor>(hndlr, NumThreads, transport, svr); + } + + // Thrift server wrapper function that accepts a pipe name. + // This version instantiates its own handler. + template <class MyHandler, class MyProcessor> + void RunThriftServer (int NumThreads, std::string pipename) + { + boost::shared_ptr<MyHandler> handler(new MyHandler()); + boost::shared_ptr<TServer> server; + + RunThriftServer<MyHandler, MyProcessor>(handler, NumThreads, pipename, server); + } + + // Thrift server wrapper function that accepts a socket port number. + // A handler must be passed in to this version. + template <class MyHandler, class MyProcessor> + void RunThriftServer (boost::shared_ptr<MyHandler> hndlr, int NumThreads, int Port) + { + boost::shared_ptr<TServerTransport> transport(new TServerSocket(Port)); + boost::shared_ptr<TServer> server; + RunThriftServer<MyHandler, MyProcessor>(hndlr, NumThreads, transport, server); + } + + // Thrift server wrapper function that accepts a socket port number. + // This version instantiates its own handler. + template <class MyHandler, class MyProcessor> + void RunThriftServer (int NumThreads, int Port) + { + boost::shared_ptr<MyHandler> handler(new MyHandler()); + + RunThriftServer<MyHandler, MyProcessor>(handler, NumThreads, Port); + } + + // + template <class MyHandler, class MyProcessor> + void RunThriftServer (boost::shared_ptr<MyHandler> hndlr, int NumThreads, boost::shared_ptr<TServerTransport> transport) + { + boost::shared_ptr<TServer> server; + RunThriftServer<MyHandler, MyProcessor>(hndlr, NumThreads, transport, server); + } + + //---------------------------------------------------------------------------- + //Connect to thrift 'server' - Socket version + //(both server & client side run one for bidir event signaling) + // + template <class MyClient, class MyTransport> + void ConnectToServer (boost::shared_ptr<MyClient> &client, boost::shared_ptr<MyTransport> &transport, int Port) + { + //Client side connection using sockets transport. + boost::shared_ptr<TTransport> socket(new TSocket("localhost", Port)); + transport.reset(new TBufferedTransport(socket)); + boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); + + client.reset(new MyClient(protocol)); + } + + //Connect to thrift 'server' - Named Pipe version + template <class MyClient, class MyTransport> + void ConnectToServer (boost::shared_ptr<MyClient> &client, boost::shared_ptr<MyTransport> &transport, std::string pipename) + { + //Client side connection using Named Pipe transport. + boost::shared_ptr<TTransport> pipe(new TPipe(pipename)); + transport.reset(new TBufferedTransport(pipe)); + boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); + + client.reset(new MyClient(protocol)); + } + + //Connect to thrift 'server' - Anonymous Pipe version + //Currently only supported under Windows +#ifdef _WIN32 + template <class MyClient, class MyTransport> + void ConnectToServer (boost::shared_ptr<MyClient> &client, boost::shared_ptr<MyTransport> &transport, HANDLE RdPipe, HANDLE WrtPipe) + { + //Client side connection using sockets transport. +#ifdef _WIN32 + boost::shared_ptr<TTransport> pipe(new TPipe((int)RdPipe, (int)WrtPipe)); + transport.reset(new TBufferedTransport(pipe)); +#else + boost::shared_ptr<TTransport> socket(new TSocket("localhost")); + transport.reset(new TBufferedTransport(socket)); +#endif + boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport)); + + client.reset(new MyClient(protocol)); + } +#endif + + //---------------------------------------------------------------------------- + //Launch child process and pass R/W anonymous pipe handles on cmd line. + //Currently only supported under Windows +#ifdef _WIN32 + bool LaunchAnonPipeChild(std::string app, boost::shared_ptr<TServerTransport> transport); +#endif +} diff --git a/src/jaegertracing/thrift/contrib/transport-sample/client/ReadMe.txt b/src/jaegertracing/thrift/contrib/transport-sample/client/ReadMe.txt new file mode 100644 index 000000000..6c49a963a --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/client/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : client Project Overview +======================================================================== + +AppWizard has created this client application for you. + +This file contains a summary of what you will find in each of the files that +make up your client application. + + +client.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +client.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +client.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named client.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/src/jaegertracing/thrift/contrib/transport-sample/client/client.cpp b/src/jaegertracing/thrift/contrib/transport-sample/client/client.cpp new file mode 100644 index 000000000..45fbef1d8 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/client/client.cpp @@ -0,0 +1,195 @@ +// client->cpp : Defines the entry point for the console application. +// +// sample client command line app using Thrift IPC. +// Quick n Dirty example, may not have very robust error handling +// for the sake of simplicity. + +#ifdef _WIN32 +# include "stdafx.h" +#else +# include "config.h" +#endif + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//Include this before the generated includes +#include "ThriftCommon.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//Tailor these to your generated files +#include "../gen-cpp/SampleService.h" +#include "../gen-cpp/SampleCallback.h" + +using namespace Sample; //declared in .thrift file +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +void ClientListenerThreadProc(); +bool bSocket = false; +bool bAnonPipe = false; +int srvPort; +std::string pipename; +std::string pipename_client; +#ifdef _WIN32 + HANDLE hConsole; +#endif + +//Customized version of printf that changes the text color +//This depends on hConsole global being initialized +void hlprintf(const char* _Format, ...) +{ +#ifdef _WIN32 + SetConsoleTextAttribute(hConsole, 0xE); +#endif + va_list ap; + int r; + va_start (ap, _Format); + r = vprintf (_Format, ap); + va_end (ap); +#ifdef _WIN32 + SetConsoleTextAttribute(hConsole, 7); +#endif +} + +//----------------------------------------------------------------------------- +// Client-side RPC implementations: Called by the server to the client for +// bidirectional eventing. +// +class SampleCallbackHandler : virtual public SampleCallbackIf { + public: + SampleCallbackHandler() { + // initialization goes here + } + + void pingclient() + { + hlprintf("<<<Ping received from server (server-to-client event).\n"); + } + +}; +//----------------------------------------------------------------------------- + + +#ifdef _WIN32 +int _tmain(int argc, _TCHAR* argv[]) +#else +int main(int argc, char **argv) +#endif +{ + //Process cmd line args to determine named vs anon pipes. + bool usage = false; +#ifdef _WIN32 + HANDLE ReadPipe, WritePipe; + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); +#endif + + //Process command line params + if(argc > 1) + { + if(_tcscmp(argv[1], TEXT("-sp")) == 0) + { //Socket Port specified + srvPort = _tstoi(argv[2]); + bSocket = true; + } + else if(_tcscmp(argv[1], TEXT("-np")) == 0) + { //Named Pipe specified +#ifdef _WIN32 + std::wstring wpipe(argv[2]); + pipename.resize(wpipe.length()); + std::copy(wpipe.begin(), wpipe.end(), pipename.begin()); +#else + pipename = argv[2]; +#endif + pipename_client = pipename + "_client"; + } + else if(argc == 3) + { //Anonymous Pipe specified +#ifdef _WIN32 + ReadPipe = (HANDLE)_tstoi(argv[1]); + WritePipe = (HANDLE)_tstoi(argv[2]); + bAnonPipe = true; +#else + printf("Anonymous pipes not (yet) supported under *NIX\n"); +#endif + } + else + usage = true; + } + else + usage = true; + + if(usage) + { + hlprintf("Thrift sample client usage:\n\n"); + hlprintf("Socket Port to connect to: -sp <port#>\n"); + hlprintf("Named Pipe to connect to: -np <pipename> (e.g. affpipe)\n"); + hlprintf("Anonymous Pipe (must be launched by anon pipe creator):\n"); + hlprintf(" <Read Handle> <Write Handle>\n"); + return 0; + } + + //Client side connection to server. + boost::shared_ptr<SampleServiceClient> client; //Client class from Thrift-generated code. + boost::shared_ptr<TTransport> transport; + + if(bSocket) + { //Socket transport +#ifdef _WIN32 + TWinsockSingleton::create(); +#endif + hlprintf("Using socket transport port %d\n", srvPort); + thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, srvPort); + } + else if(!bAnonPipe) + { + hlprintf("Using Named Pipe %s\n", pipename.c_str()); + thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, pipename); + } + else + { +#ifdef _WIN32 + hlprintf("Using Anonymous Pipe transport\n"); + thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, ReadPipe, WritePipe); +#endif + } + +#ifdef _WIN32 + //Start a thread to receive inbound connection from server for 2-way event signaling. + boost::thread ClientListenerThread(ClientListenerThreadProc); +#endif + + try { + transport->open(); + + //Notify server what to connect back on. + if(bSocket) + client->ClientSideListenPort(srvPort + 1); //Socket + else if(!bAnonPipe) + client->ClientSidePipeName(pipename_client); //Named Pipe + + //Run some more RPCs + std::string hellostr = "Hello how are you?"; + std::string returnstr; + client->HelloThere(returnstr, hellostr); + hlprintf("\n>>>Sent: %s\n", hellostr.c_str()); + hlprintf("<<<Received: %s\n", returnstr.c_str()); + + hlprintf("\n>>>Calling ServerDoSomething() which delays for 5 seconds.\n"); + client->ServerDoSomething(); + hlprintf(">>>ServerDoSomething() done.\n\n"); + + transport->close(); + } catch (TException &tx) { + hlprintf("ERROR: %s\n", tx.what()); + } + + return 0; +} + + +//Thread Routine +void ClientListenerThreadProc() +{ + if(bSocket) + thriftcommon::RunThriftServer<SampleCallbackHandler, SampleCallbackProcessor>(1, srvPort + 1); + else if(!bAnonPipe) + thriftcommon::RunThriftServer<SampleCallbackHandler, SampleCallbackProcessor>(1, pipename_client); +} diff --git a/src/jaegertracing/thrift/contrib/transport-sample/client/client.vcxproj b/src/jaegertracing/thrift/contrib/transport-sample/client/client.vcxproj new file mode 100644 index 000000000..779c339d7 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/client/client.vcxproj @@ -0,0 +1,105 @@ +?<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{85FBFB54-530B-498F-9F38-44BA204FAE6A}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>client</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../boost;../../../../boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../boost;../../../../boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <None Include="ReadMe.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\gen-cpp\SampleCallback.h" /> + <ClInclude Include="..\gen-cpp\SampleService.h" /> + <ClInclude Include="..\gen-cpp\Sample_constants.h" /> + <ClInclude Include="..\gen-cpp\Sample_types.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\ThriftCommon.cpp" /> + <ClCompile Include="..\gen-cpp\SampleCallback.cpp" /> + <ClCompile Include="..\gen-cpp\SampleService.cpp" /> + <ClCompile Include="..\gen-cpp\Sample_constants.cpp" /> + <ClCompile Include="..\gen-cpp\Sample_types.cpp" /> + <ClCompile Include="client.cpp" /> + <ClCompile Include="stdafx.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/src/jaegertracing/thrift/contrib/transport-sample/client/client.vcxproj.filters b/src/jaegertracing/thrift/contrib/transport-sample/client/client.vcxproj.filters new file mode 100644 index 000000000..3ec7bdefa --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/client/client.vcxproj.filters @@ -0,0 +1,66 @@ +?<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Source Files\gen-cpp"> + <UniqueIdentifier>{1265b3dc-91de-416f-aba6-7b750de4221e}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <None Include="ReadMe.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="stdafx.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="targetver.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\Sample_types.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\SampleService.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\Sample_constants.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\SampleCallback.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="stdafx.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="client.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\SampleService.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\Sample_constants.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\Sample_types.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\SampleCallback.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\ThriftCommon.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> diff --git a/src/jaegertracing/thrift/contrib/transport-sample/client/stdafx.cpp b/src/jaegertracing/thrift/contrib/transport-sample/client/stdafx.cpp new file mode 100644 index 000000000..4bd151ef0 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/client/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// client.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/src/jaegertracing/thrift/contrib/transport-sample/client/stdafx.h b/src/jaegertracing/thrift/contrib/transport-sample/client/stdafx.h new file mode 100644 index 000000000..b005a839d --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/client/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include <stdio.h> +#include <tchar.h> + + + +// TODO: reference additional headers your program requires here diff --git a/src/jaegertracing/thrift/contrib/transport-sample/client/targetver.h b/src/jaegertracing/thrift/contrib/transport-sample/client/targetver.h new file mode 100644 index 000000000..87c0086de --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/client/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include <SDKDDKVer.h> diff --git a/src/jaegertracing/thrift/contrib/transport-sample/config.h b/src/jaegertracing/thrift/contrib/transport-sample/config.h new file mode 100644 index 000000000..a20d78513 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/config.h @@ -0,0 +1,24 @@ +//Missing definitions for *NIX systems. This sample project +//was initially created on Windows. + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#define TEXT(str) str + +inline int Sleep(int ms) +{ + return sleep(ms/1000); //sleep() param is in seconds +} + +inline int _tcscmp(const char* str1, const char* str2) +{ + return strcmp(str1, str2); +} + +inline int _tstoi(const char* str) +{ + return atoi(str); +} + diff --git a/src/jaegertracing/thrift/contrib/transport-sample/server/ReadMe.txt b/src/jaegertracing/thrift/contrib/transport-sample/server/ReadMe.txt new file mode 100644 index 000000000..53c0ee59b --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/server/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : server Project Overview +======================================================================== + +AppWizard has created this server application for you. + +This file contains a summary of what you will find in each of the files that +make up your server application. + + +server.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +server.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +server.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named server.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/src/jaegertracing/thrift/contrib/transport-sample/server/server.cpp b/src/jaegertracing/thrift/contrib/transport-sample/server/server.cpp new file mode 100644 index 000000000..dba8368b7 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/server/server.cpp @@ -0,0 +1,168 @@ +// server.cpp : Defines the entry point for the console application. +// +// sample server command line app using Thrift IPC. +// +// This is a simple demonstration of full duplex RPC. That is, each +// side runs both a client and server to enable bidirectional event +// signaling. +// + +#ifdef _WIN32 +# include "stdafx.h" +#else +# include "config.h" +#endif + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//Include this before the generated includes +#include "ThriftCommon.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//Tailor these to your generated files +#include "../gen-cpp/SampleService.h" +#include "../gen-cpp/SampleCallback.h" + +using namespace Sample; //declared in .thrift file +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +int16_t ClientPort_; +std::string ClientPipeName_; +void S2CThreadProc(); + +//----------------------------------------------------------------------------- +// RPC implementations +// +class SampleServiceHandler : virtual public SampleServiceIf { + public: + SampleServiceHandler() { + // Your initialization goes here + } + + void HelloThere(std::string& _return, const std::string& HelloString) { + // Your implementation goes here + printf("<<<HelloThere() received string: %s\n", HelloString.c_str()); + _return = "Good thank you."; + } + + void ServerDoSomething() { + // Your implementation goes here + printf("ServerDoSomething(): Simulating work for 5 seconds\n"); + Sleep(5000); + printf("ServerDoSomething(): Done\n"); + } + + void ClientSideListenPort(const int16_t ClientListenPort) + { + ClientPort_ = ClientListenPort; + ClientPipeName_ = ""; +#ifdef _WIN32 + printf(">>>Connecting to client on port %d\n", ClientPort_); + boost::thread Connect2ClientThread(S2CThreadProc); +#endif + } + + void ClientSidePipeName(const std::string& ClientPipeName) + { + ClientPipeName_ = ClientPipeName; + ClientPort_ = 0; +#ifdef _WIN32 + printf(">>>Connecting to client pipe %s\n", ClientPipeName_.c_str()); + boost::thread Connect2ClientThread(S2CThreadProc); +#endif + } +}; +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +int _tmain(int argc, _TCHAR* argv[]) +#else +int main(int argc, char **argv) +#endif +{ + int port; + std::string pipename; //e.g. "affpipe" + + bool usage = false; + + //Process command line params + if(argc > 1) + { + if(_tcscmp(argv[1], TEXT("-sp")) == 0) + { //Socket Port specified + port = _tstoi(argv[2]); +#ifdef _WIN32 + TWinsockSingleton::create(); +#endif + // Start the thrift server which is a blocking call. + thriftcommon::RunThriftServer<SampleServiceHandler, SampleServiceProcessor>(10, port); + } + else if(_tcscmp(argv[1], TEXT("-np")) == 0) + { //Named Pipe specified +#ifdef _WIN32 + std::wstring wpipe(argv[2]); + pipename.resize(wpipe.length()); + std::copy(wpipe.begin(), wpipe.end(), pipename.begin()); +#else + pipename = argv[2]; +#endif + printf("Using Named Pipe %s\n", pipename.c_str()); + + //Thrift over Named Pipe. + thriftcommon::RunThriftServer<SampleServiceHandler, SampleServiceProcessor>(10, pipename); + } + else if(_tcscmp(argv[1], TEXT("-ap")) == 0) + { //Anonymous Pipe specified + //This is more involved because the child needs to be launched + //after the transport is created but before the blocking server + //call. +#ifdef _WIN32 + boost::shared_ptr<TServerTransport> transport(new TPipeServer()); //Anonymous pipe + thriftcommon::LaunchAnonPipeChild(".\\client.exe", transport); + boost::shared_ptr<SampleServiceHandler> handler(new SampleServiceHandler()); + thriftcommon::RunThriftServer<SampleServiceHandler, SampleServiceProcessor>(handler, 10, transport); +#else + printf("Anonymous pipes not (yet) supported under *NIX\n"); +#endif + } + else + usage = true; + } + else + usage = true; + + if(usage) + { + printf("Thrift sample server usage:\n\n"); + printf("Socket Port : -sp <port#>\n"); + printf("Named Pipe : -np <pipename> (e.g. affpipe)\n"); + printf("Anonymous Pipe: -ap\n"); + } + return 0; +} + + +//Thread Routine that connects to the 'client'. +void S2CThreadProc() +{ + //Master server's connection to client-side's server. + boost::shared_ptr<SampleCallbackClient> clientsrv; //Client class from Thrift-generated code. + boost::shared_ptr<TTransport> transport; + if(ClientPort_ != 0) + thriftcommon::ConnectToServer<SampleCallbackClient, TTransport>(clientsrv, transport, ClientPort_); + if(!ClientPipeName_.empty()) + thriftcommon::ConnectToServer<SampleCallbackClient, TTransport>(clientsrv, transport, ClientPipeName_); + + try { + transport->open(); + + clientsrv->pingclient(); + Sleep(1500); + clientsrv->pingclient(); + Sleep(1500); + clientsrv->pingclient(); + + transport->close(); + } catch (TException &tx) { + printf("ERROR: %s\n", tx.what()); + } +} + diff --git a/src/jaegertracing/thrift/contrib/transport-sample/server/server.vcxproj b/src/jaegertracing/thrift/contrib/transport-sample/server/server.vcxproj new file mode 100644 index 000000000..8e39b260e --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/server/server.vcxproj @@ -0,0 +1,106 @@ +?<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{72FCAF29-506D-4164-9FA6-F54C5C28E79D}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>server</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../Boost/;../../../../Boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../;../../../lib/cpp/src;../../../../Boost/;../../../../Boost/boost/tr1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <AdditionalLibraryDirectories>../../../lib/cpp/$(Configuration);../../../../Boost/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>libthrift.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <None Include="ReadMe.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\gen-cpp\SampleCallback.h" /> + <ClInclude Include="..\gen-cpp\SampleService.h" /> + <ClInclude Include="..\gen-cpp\Sample_constants.h" /> + <ClInclude Include="..\gen-cpp\Sample_types.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\ThriftCommon.cpp" /> + <ClCompile Include="..\gen-cpp\SampleCallback.cpp" /> + <ClCompile Include="..\gen-cpp\SampleService.cpp" /> + <ClCompile Include="..\gen-cpp\Sample_constants.cpp" /> + <ClCompile Include="..\gen-cpp\Sample_types.cpp" /> + <ClCompile Include="server.cpp" /> + <ClCompile Include="stdafx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + </ClCompile> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/src/jaegertracing/thrift/contrib/transport-sample/server/server.vcxproj.filters b/src/jaegertracing/thrift/contrib/transport-sample/server/server.vcxproj.filters new file mode 100644 index 000000000..8bb6dfb73 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/server/server.vcxproj.filters @@ -0,0 +1,66 @@ +?<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Source Files\gen-cpp"> + <UniqueIdentifier>{dab66db8-bc45-4518-aad2-7a75696226e3}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <None Include="ReadMe.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="stdafx.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="targetver.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\Sample_types.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\SampleService.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\Sample_constants.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + <ClInclude Include="..\gen-cpp\SampleCallback.h"> + <Filter>Source Files\gen-cpp</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="stdafx.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="server.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\Sample_types.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\SampleService.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\Sample_constants.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\gen-cpp\SampleCallback.cpp"> + <Filter>Source Files\gen-cpp</Filter> + </ClCompile> + <ClCompile Include="..\ThriftCommon.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> diff --git a/src/jaegertracing/thrift/contrib/transport-sample/server/stdafx.cpp b/src/jaegertracing/thrift/contrib/transport-sample/server/stdafx.cpp new file mode 100644 index 000000000..c25ff612a --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// server.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/src/jaegertracing/thrift/contrib/transport-sample/server/stdafx.h b/src/jaegertracing/thrift/contrib/transport-sample/server/stdafx.h new file mode 100644 index 000000000..b005a839d --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/server/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include <stdio.h> +#include <tchar.h> + + + +// TODO: reference additional headers your program requires here diff --git a/src/jaegertracing/thrift/contrib/transport-sample/server/targetver.h b/src/jaegertracing/thrift/contrib/transport-sample/server/targetver.h new file mode 100644 index 000000000..87c0086de --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/server/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include <SDKDDKVer.h> diff --git a/src/jaegertracing/thrift/contrib/transport-sample/thriftme.bat b/src/jaegertracing/thrift/contrib/transport-sample/thriftme.bat new file mode 100644 index 000000000..4b1ef78c8 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/thriftme.bat @@ -0,0 +1 @@ +thrift.exe --gen cpp Sample.thrift diff --git a/src/jaegertracing/thrift/contrib/transport-sample/thriftme.sh b/src/jaegertracing/thrift/contrib/transport-sample/thriftme.sh new file mode 100644 index 000000000..3b18f909e --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/thriftme.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +THRIFT_COMPILER=./thrift +OUTPUT_FOLDER=$PWD + +if [ ! -e "${THRIFT_COMPILER}" ] +then + THRIFT_COMPILER=thrift + command -v ${THRIFT_COMPILER} >/dev/null 2>&1 + if [ $? -eq 1 ]; then + echo + echo "thrift compiler not found." + echo + exit + fi +fi + +${THRIFT_COMPILER} --gen cpp Sample.thrift + +echo +echo "Files have been generated in gen-cpp." + +exit + diff --git a/src/jaegertracing/thrift/contrib/transport-sample/transport-sample.sln b/src/jaegertracing/thrift/contrib/transport-sample/transport-sample.sln new file mode 100644 index 000000000..a9fa1efa1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/transport-sample/transport-sample.sln @@ -0,0 +1,26 @@ +? +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server\server.vcxproj", "{72FCAF29-506D-4164-9FA6-F54C5C28E79D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{85FBFB54-530B-498F-9F38-44BA204FAE6A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Debug|Win32.ActiveCfg = Debug|Win32 + {72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Debug|Win32.Build.0 = Debug|Win32 + {72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Release|Win32.ActiveCfg = Release|Win32 + {72FCAF29-506D-4164-9FA6-F54C5C28E79D}.Release|Win32.Build.0 = Release|Win32 + {85FBFB54-530B-498F-9F38-44BA204FAE6A}.Debug|Win32.ActiveCfg = Debug|Win32 + {85FBFB54-530B-498F-9F38-44BA204FAE6A}.Debug|Win32.Build.0 = Debug|Win32 + {85FBFB54-530B-498F-9F38-44BA204FAE6A}.Release|Win32.ActiveCfg = Release|Win32 + {85FBFB54-530B-498F-9F38-44BA204FAE6A}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/jaegertracing/thrift/contrib/vagrant/centos-6.5/README.md b/src/jaegertracing/thrift/contrib/vagrant/centos-6.5/README.md new file mode 100644 index 000000000..55583f901 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/vagrant/centos-6.5/README.md @@ -0,0 +1,61 @@ +Apache Thrift Centos 6.5 Vagrant Support +======================================== +This directory is the Vagrant project directory for Apache Thrift running on Centos 6.5. The Vagrantfile in this directory configures a Vagrant provisioned VM launched under VirtualBox. To use this project you must have a recent version of VirtualBox and Vagrant installed (in that order). To run the VM, open a shell, clone Apache Thrift, change to this directory and enter the Vagrant up command. + + $ git clone https://github.com/apache/thrift + $ cd thrift/contrib/vagrant/centos-6.5 + $ vagrant up + +This will download and launch the base box VM under VirtualBox and run the Apache Thrift provisioning script. This will take up to an hour depending on your hardware and network. Once complete you can login to the box with Vagrant ssh. The thrift source tree from your host os is mounted at /thrift. + + $ vagrant ssh + [vagrant@thrift ~]$ cd /thrift + [vagrant@thrift thrift]$ compiler/cpp/thrift --version + Thrift version <version> + +The provisioning script (inside the Vagrantfile) runs ./bootstrap.sh, ./configure, make and make check, but does not install thrift. To install thrift run "make install". + +The Vagrant base box used here is a minimal Centos 6.5 VirtualBox with 2GB RAM and 2 CPUs. For more Vagrant information: https://www.vagrantup.com. A summary of the base box preparation follows: + +root password: vagrant + +#Create the vagrant user and give it sudo permission +adduser vagrant +passwd vagrant +visudo : vagrant ALL=(ALL) NOPASSWD: ALL + #Defaults requiretty + +#Shut down the firewall and disable it +service iptables stop +chkconfig iptables off + +#Setup the vagrant ssh public key to allow vagrant to ssh +mkdir /home/vagrant/.ssh +chmod 700 /home/vagrant/.ssh +cd /home/vagrant/.ssh +wget --no-check-certificate 'https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub' -O authorized_keys +chmod 600 /home/vagrant/.ssh/authorized_keys +chown -R vagrant /home/vagrant/.ssh + +#Install EPEL (Extra Packages for Enterprise Linux) but protect the base +#repositories so that EPEL does not mask base packages +yum -y install yum-plugin-protectbase +rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm + +#Install perl, dynamic kernel modules, dev tools and kernel headers to support +#Virtual box additions +yum -y install perl +yum -y --enablerepo epel install dkms +yum -y groupinstall "Development Tools" +yum -y install kernel-devel + +#Update everything and reboot +yum update +reboot + +#Install the VirtualBox Guest additions (using VirtualBox iso) +mount /dev/cdrom /mnt +/mnt/VBoxLinuxAdditions.run +umount /mnt + +See the Vagrantfile for further details diff --git a/src/jaegertracing/thrift/contrib/vagrant/centos-6.5/Vagrantfile b/src/jaegertracing/thrift/contrib/vagrant/centos-6.5/Vagrantfile new file mode 100644 index 000000000..51a2239bc --- /dev/null +++ b/src/jaegertracing/thrift/contrib/vagrant/centos-6.5/Vagrantfile @@ -0,0 +1,274 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# 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. + +# APACHE THRIFT PROVISIONING SCRIPT +############################################################## +# This script is used to configure the base Centos 6.5 +# Vagrant box for Apache Thrift compiler and lib builds. +# The base box is Centos 6.5 with no additional packages +# except those required to support VirtualBox Guest tools: +# perl, dkms, kernel-devel and the "Development Tools" group. +# The epel repo was also added along with the +# yum-plugin-protectbase package to prefer base repo packages. +# The script below provisions ALL languages. This will take +# time. You can greatly reduce the build time by commenting +# out the LIB provisioning for uneeded language libraries. +# Expect full provisioning to take 30 minutes on a fast +# machine with an excellent Internet connection (and another +# 15 minutes for the build). +# +# Machine accounts: +# - User: vagrant/vagrant +# - Admin: root/vagrant +# Vagrant public ssh key also installed +############################################################## + +$build_and_test = <<SCRIPT +echo "Provisioning system to compile and test Apache Thrift." +date > /etc/vagrant.provision_begin + +# Apache Thrift compiler dependencies +##################################### + +#install an updated autoconf +wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz +tar xvf autoconf-2.69.tar.gz +cd autoconf-2.69 +./configure --prefix=/usr +make +sudo make install +cd .. + +#install an updated automake +wget http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz +tar xvf automake-1.14.tar.gz +cd automake-1.14 +./configure --prefix=/usr +make +sudo make install +cd .. + +#install an updated bison +wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz +tar xvf bison-2.5.1.tar.gz +cd bison-2.5.1 +./configure --prefix=/usr +make +sudo make install +cd .. + +# C++98 LIB Dependencies +##################################### +sudo yum -y install libevent-devel zlib-devel openssl-devel + +#Install an updated Boost library +wget http://sourceforge.net/projects/boost/files/boost/1.55.0/boost_1_55_0.tar.gz +tar xvf boost_1_55_0.tar.gz +cd boost_1_55_0 +./bootstrap.sh +sudo ./b2 install + +# Java LIB Dependencies +##################################### +sudo yum install -y ant junit ant-nodeps ant-junit java-1.8.0-openjdk-devel + +# Python LIB Dependencies +##################################### +sudo yum install -y python-devel python-setuptools python-twisted + +# Ruby LIB Dependencies +##################################### +sudo yum install -y ruby ruby-devel rubygems +sudo gem install bundler rake + +# Node.js LIB Dependencies +##################################### +sudo yum install -y nodejs nodejs-devel npm + +# Perl LIB Dependencies +##################################### +sudo yum install -y perl-Bit-Vector perl-Class-Accessor perl-ExtUtils-MakeMaker perl-Test-Simple + +# PHP LIB Dependencies +##################################### +sudo yum install -y php php-devel php-pear re2c + +# GLibC LIB Dependencies +##################################### +sudo yum install -y glib2-devel + +# Erlang LIB Dependencies +##################################### +sudo yum install -y erlang-kernel erlang-erts erlang-stdlib erlang-eunit erlang-rebar + +# Lua LIB Dependencies +##################################### +sudo yum install -y lua-devel + +# Go LIB Dependencies +##################################### +sudo yum install -y golang golang-pkg-linux-amd64 + +# C# LIB Dependencies +##################################### +sudo yum install -y mono-core mono-devel mono-web-devel mono-extras mingw32-binutils mingw32-runtime mingw32-nsis + +# Haskell LIB Dependencies +##################################### +wget http://sherkin.justhub.org/el6/RPMS/x86_64/justhub-release-2.0-4.0.el6.x86_64.rpm +sudo rpm -ivh justhub-release-2.0-4.0.el6.x86_64.rpm +sudo yum -y install haskell +sudo cabal update +sudo cabal install cabal-install + +# Build and Test Apache Thrift +##################################### +date > /etc/vagrant.provision_end +echo "Starting Apache Thrift build..." +cd /thrift +sh bootstrap.sh + +# At the time of this file's creation Ruby, Python, Go and Lua fail +# their unit tests in this environment. To build and test any of these +# libraries uncomment the appropriate --without switches below. + +sh configure --without-ruby --without-go --without-lua --without-python +make +echo "Starting Apache Thrift tests..." +make check +echo "Finished building and testing Apache Thrift." +echo 'Use "make install" to install the compiler and libraries.' +date > /etc/vagrant.make_end + +SCRIPT + +Vagrant.configure("2") do |config| + # Every Vagrant virtual environment requires a box to build off of. + ##### Centos 6.5 minimal system with VirtualBox Guest Additions + ##### Box maintained by ra@apache.org, see README.md for box config + config.vm.box = "RandyAbernethy/thrift-centos-6.5-64" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + ##### This box will never change + config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # config.vm.network "forwarded_port", guest: 80, host: 8080 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # If true, then any SSH connections made will enable agent forwarding. + # Default value: false + # config.ssh.forward_agent = true + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + ##### By convention the thrift source tree is mapped to /thrift + config.vm.synced_folder "../../../", "/thrift" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + ##### The machine needs 2 CPUs and 2GB RAM for reasonable performance + config.vm.provider "virtualbox" do |vb| + vb.customize ["modifyvm", :id, "--memory", "2048"] + vb.customize ["modifyvm", :id, "--cpus", "2"] + end + + # Enable provisioning with CFEngine. CFEngine Community packages are + # automatically installed. For example, configure the host as a + # policy server and optionally a policy file to run: + # + # config.vm.provision "cfengine" do |cf| + # cf.am_policy_hub = true + # # cf.run_file = "motd.cf" + # end + # + # You can also configure and bootstrap a client to an existing + # policy server: + # + # config.vm.provision "cfengine" do |cf| + # cf.policy_server_address = "10.0.2.15" + # end + + # Enable provisioning with Puppet stand alone. Puppet manifests + # are contained in a directory path relative to this Vagrantfile. + # You will need to create the manifests directory and a manifest in + # the file default.pp in the manifests_path directory. + # + # config.vm.provision "puppet" do |puppet| + # puppet.manifests_path = "manifests" + # puppet.manifest_file = "default.pp" + # end + + # Enable provisioning with chef solo, specifying a cookbooks path, roles + # path, and data_bags path (all relative to this Vagrantfile), and adding + # some recipes and/or roles. + # + # config.vm.provision "chef_solo" do |chef| + # chef.cookbooks_path = "../my-recipes/cookbooks" + # chef.roles_path = "../my-recipes/roles" + # chef.data_bags_path = "../my-recipes/data_bags" + # chef.add_recipe "mysql" + # chef.add_role "web" + # + # # You may also specify custom JSON attributes: + # chef.json = { mysql_password: "foo" } + # end + + # Enable provisioning with chef server, specifying the chef server URL, + # and the path to the validation key (relative to this Vagrantfile). + # + # The Opscode Platform uses HTTPS. Substitute your organization for + # ORGNAME in the URL and validation key. + # + # If you have your own Chef Server, use the appropriate URL, which may be + # HTTP instead of HTTPS depending on your configuration. Also change the + # validation key to validation.pem. + # + # config.vm.provision "chef_client" do |chef| + # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" + # chef.validation_key_path = "ORGNAME-validator.pem" + # end + # + # If you're using the Opscode platform, your validator client is + # ORGNAME-validator, replacing ORGNAME with your organization name. + # + # If you have your own Chef Server, the default validation client name is + # chef-validator, unless you changed the configuration. + # + # chef.validation_client_name = "ORGNAME-validator" + + ##### Run the Apache Thrift provisioning script (declared above) + config.vm.provision :shell, :inline => $build_and_test +end diff --git a/src/jaegertracing/thrift/contrib/zeromq/Makefile b/src/jaegertracing/thrift/contrib/zeromq/Makefile new file mode 100644 index 000000000..ee398e22c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/Makefile @@ -0,0 +1,39 @@ +THRIFT = thrift + +CXXFLAGS += -g3 -O0 + +GENNAMES = Storage storage_types +GENHEADERS = $(addsuffix .h, $(GENNAMES)) +GENSRCS = $(addsuffix .cpp, $(GENNAMES)) +GENOBJS = $(addsuffix .o, $(GENNAMES)) + +PYLIBS = storage/__init__.py + +PROGS = test-client test-server test-sender test-receiver + +all: $(PYLIBS) $(PROGS) + +test-client: test-client.o TZmqClient.o $(GENOBJS) + $(CXX) $^ -o $@ -lzmq -lthrift +test-server: test-server.o TZmqServer.o $(GENOBJS) + $(CXX) $^ -o $@ -lzmq -lthrift +test-sender: test-sender.o TZmqClient.o $(GENOBJS) + $(CXX) $^ -o $@ -lzmq -lthrift +test-receiver: test-receiver.o TZmqServer.o $(GENOBJS) + $(CXX) $^ -o $@ -lzmq -lthrift + +test-client.o test-server.o test-sender.o test-receiver.o: $(GENSRCS) + +storage/__init__.py: storage.thrift + $(RM) $(dir $@) + $(THRIFT) --gen py $< + mv gen-py/$(dir $@) . + +$(GENSRCS): storage.thrift + $(THRIFT) --gen cpp $< + mv $(addprefix gen-cpp/, $(GENSRCS) $(GENHEADERS)) . + +clean: + $(RM) -r *.o $(PROGS) storage $(GENSRCS) $(GENHEADERS) + +.PHONY: clean diff --git a/src/jaegertracing/thrift/contrib/zeromq/README.md b/src/jaegertracing/thrift/contrib/zeromq/README.md new file mode 100644 index 000000000..9e0b5bd32 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/README.md @@ -0,0 +1,30 @@ +This directory contains some glue code to allow Thrift RPCs to be sent over +ZeroMQ. Included are client and server implementations for Python and C++, +along with a simple demo interface (with a working client and server for +each language). + +Thrift was designed for stream-based interfaces like TCP, but ZeroMQ is +message-based, so there is a small impedance mismatch. Most of issues are +hidden from developers, but one cannot be: oneway methods have to be handled +differently from normal ones. ZeroMQ requires the messaging pattern to be +declared at socket creation time, so an application cannot decide on a +message-by-message basis whether to send a reply. Therefore, this +implementation makes it the client's responsibility to ensure that ZMQ_REQ +sockets are used for normal methods and ZMQ_DOWNSTREAM sockets are used for +oneway methods. In addition, services that expose both types of methods +have to expose two servers (on two ports), but the TZmqMultiServer makes it +easy to run the two together in the same thread. + +This code was tested with ZeroMQ 2.0.7 and pyzmq afabbb5b9bd3. + +To build, simply install Thrift and ZeroMQ, then run "make". If you install +in a non-standard location, make sure to set THRIFT to the location of the +Thrift code generator on the make command line and PKG_CONFIG_PATH to a path +that includes the pkgconfig files for both Thrift and ZeroMQ. The test +servers take no arguments. Run the test clients with no arguments to +retrieve the stored value or with an integer argument to increment it by +that amount. + +This code is not quite what I would consider production-ready. It doesn't +support all of the normal hooks into Thrift, and its performance is +sub-optimal because it does some unnecessary copying. diff --git a/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.cpp b/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.cpp new file mode 100644 index 000000000..56278f325 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.cpp @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#include "TZmqClient.h" +#include <cstring> + +namespace apache { namespace thrift { namespace transport { + +uint32_t TZmqClient::read_virt(uint8_t* buf, uint32_t len) { + if (rbuf_.available_read() == 0) { + (void)sock_.recv(&msg_); + rbuf_.resetBuffer((uint8_t*)msg_.data(), msg_.size()); + } + return rbuf_.read(buf, len); +} + +void TZmqClient::write_virt(const uint8_t* buf, uint32_t len) { + return wbuf_.write(buf, len); +} + +uint32_t TZmqClient::writeEnd() { + uint8_t* buf; + uint32_t size; + wbuf_.getBuffer(&buf, &size); + zmq::message_t msg(size); + std::memcpy(msg.data(), buf, size); + (void)sock_.send(msg); + wbuf_.resetBuffer(true); + return size; +} + +}}} // apache::thrift::transport diff --git a/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.h b/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.h new file mode 100644 index 000000000..df16e03af --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef _THRIFT_TRANSPORT_TZMQCLIENT_H_ +#define _THRIFT_TRANSPORT_TZMQCLIENT_H_ 1 + +#include <zmq.hpp> +#include <thrift/transport/TBufferTransports.h> + +namespace apache { namespace thrift { namespace transport { + +class TZmqClient : public TTransport { + public: + TZmqClient(zmq::context_t& ctx, const std::string& endpoint, int type) + : sock_(ctx, type) + , endpoint_(endpoint) + , wbuf_() + , rbuf_() + , msg_() + , zmq_type_(type) + {} + + void open() { + if(zmq_type_ == ZMQ_PUB) { + sock_.bind(endpoint_.c_str()); + } + else { + sock_.connect(endpoint_.c_str()); + } + } + + uint32_t read_virt(uint8_t* buf, uint32_t len); + + void write_virt(const uint8_t* buf, uint32_t len); + + uint32_t writeEnd(); + + protected: + zmq::socket_t sock_; + std::string endpoint_; + TMemoryBuffer wbuf_; + TMemoryBuffer rbuf_; + zmq::message_t msg_; + int zmq_type_; +}; + +}}} // apache::thrift::transport + +#endif // #ifndef _THRIFT_TRANSPORT_TZMQCLIENT_H_ diff --git a/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.py b/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.py new file mode 100644 index 000000000..1bd60a1e5 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/TZmqClient.py @@ -0,0 +1,64 @@ +# +# 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. +# +import zmq +from cStringIO import StringIO +from thrift.transport.TTransport import TTransportBase, CReadableTransport + + +class TZmqClient(TTransportBase, CReadableTransport): + def __init__(self, ctx, endpoint, sock_type): + self._sock = ctx.socket(sock_type) + self._endpoint = endpoint + self._wbuf = StringIO() + self._rbuf = StringIO() + + def open(self): + self._sock.connect(self._endpoint) + + def read(self, size): + ret = self._rbuf.read(size) + if len(ret) != 0: + return ret + self._read_message() + return self._rbuf.read(size) + + def _read_message(self): + msg = self._sock.recv() + self._rbuf = StringIO(msg) + + def write(self, buf): + self._wbuf.write(buf) + + def flush(self): + msg = self._wbuf.getvalue() + self._wbuf = StringIO() + self._sock.send(msg) + + # Implement the CReadableTransport interface. + @property + def cstringio_buf(self): + return self._rbuf + + # NOTE: This will probably not actually work. + def cstringio_refill(self, prefix, reqlen): + while len(prefix) < reqlen: + self.read_message() + prefix += self._rbuf.getvalue() + self._rbuf = StringIO(prefix) + return self._rbuf diff --git a/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.cpp b/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.cpp new file mode 100644 index 000000000..88660a330 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.cpp @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#include "TZmqServer.h" +#include <thrift/transport/TBufferTransports.h> +#include <boost/scoped_ptr.hpp> + +using apache::thrift::std::shared_ptr; +using apache::thrift::transport::TMemoryBuffer; +using apache::thrift::protocol::TProtocol; + +namespace apache { namespace thrift { namespace server { + +bool TZmqServer::serveOne(int recv_flags) { + zmq::message_t msg; + bool received = sock_.recv(&msg, recv_flags); + if (!received) { + return false; + } + shared_ptr<TMemoryBuffer> inputTransport(new TMemoryBuffer((uint8_t*)msg.data(), msg.size())); + shared_ptr<TMemoryBuffer> outputTransport(new TMemoryBuffer()); + shared_ptr<TProtocol> inputProtocol( + inputProtocolFactory_->getProtocol(inputTransport)); + shared_ptr<TProtocol> outputProtocol( + outputProtocolFactory_->getProtocol(outputTransport)); + shared_ptr<TMemoryBuffer> transport(new TMemoryBuffer); + + processor_->process(inputProtocol, outputProtocol, NULL); + + if (zmq_type_ == ZMQ_REP) { + uint8_t* buf; + uint32_t size; + outputTransport->getBuffer(&buf, &size); + msg.rebuild(size); + std::memcpy(msg.data(), buf, size); + (void)sock_.send(msg); + } + + return true; +} + + +void TZmqMultiServer::serveOne(long timeout) { + boost::scoped_ptr<zmq::pollitem_t> items(setupPoll()); + serveActive(items.get(), timeout); +} + + +void TZmqMultiServer::serveForever() { + boost::scoped_ptr<zmq::pollitem_t> items(setupPoll()); + while (true) { + serveActive(items.get(), -1); + } +} + + +zmq::pollitem_t* TZmqMultiServer::setupPoll() { + zmq::pollitem_t* items = new zmq::pollitem_t[servers_.size()]; + for (int i = 0; i < servers_.size(); ++i) { + items[i].socket = servers_[i]->getSocket(); + items[i].events = ZMQ_POLLIN; + } + return items; +} + +void TZmqMultiServer::serveActive(zmq::pollitem_t* items, long timeout) { + int rc = zmq::poll(items, servers_.size(), timeout); + if (rc == 0) { + return; + } + for (int i = 0; i < servers_.size(); ++i) { + if ((items[i].revents & ZMQ_POLLIN) != 0) { + // Should we pass ZMQ_NOBLOCK here to be safe? + servers_[i]->serveOne(); + } + } +} + + +}}} // apache::thrift::server diff --git a/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.h b/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.h new file mode 100644 index 000000000..ecd13b424 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#ifndef _THRIFT_SERVER_TZMQSERVER_H_ +#define _THRIFT_SERVER_TZMQSERVER_H_ 1 + +#include <memory> +#include <zmq.hpp> +#include <thrift/server/TServer.h> + +namespace apache { namespace thrift { namespace server { + +class TZmqServer : public TServer { + public: + TZmqServer( + std::shared_ptr<TProcessor> processor, + zmq::context_t& ctx, const std::string& endpoint, int type) + : TServer(processor) + , processor_(processor) + , zmq_type_(type) + , sock_(ctx, type) + { + if(zmq_type_ == ZMQ_SUB) { + sock_.setsockopt(ZMQ_SUBSCRIBE, "", 0) ; // listen to all messages + sock_.connect(endpoint.c_str()) ; + } + else { + sock_.bind(endpoint.c_str()); + } + } + + bool serveOne(int recv_flags = 0); + void serve() { + while (true) { + serveOne(); + } + } + + zmq::socket_t& getSocket() { + return sock_; + } + + private: + std::shared_ptr<TProcessor> processor_; + int zmq_type_; + zmq::socket_t sock_; +}; + + +class TZmqMultiServer { + public: + void serveOne(long timeout = -1); + void serveForever(); + + std::vector<TZmqServer*>& servers() { + return servers_; + } + + private: + zmq::pollitem_t* setupPoll(); + void serveActive(zmq::pollitem_t* items, long timeout); + std::vector<TZmqServer*> servers_; +}; + + +}}} // apache::thrift::server + +#endif // #ifndef _THRIFT_SERVER_TZMQSERVER_H_ diff --git a/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.py b/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.py new file mode 100644 index 000000000..15c1543ac --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/TZmqServer.py @@ -0,0 +1,79 @@ +# +# 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. +# +import logging +import zmq +import thrift.server.TServer +import thrift.transport.TTransport + + +class TZmqServer(thrift.server.TServer.TServer): + def __init__(self, processor, ctx, endpoint, sock_type): + thrift.server.TServer.TServer.__init__(self, processor, None) + self.zmq_type = sock_type + self.socket = ctx.socket(sock_type) + self.socket.bind(endpoint) + + def serveOne(self): + msg = self.socket.recv() + itrans = thrift.transport.TTransport.TMemoryBuffer(msg) + otrans = thrift.transport.TTransport.TMemoryBuffer() + iprot = self.inputProtocolFactory.getProtocol(itrans) + oprot = self.outputProtocolFactory.getProtocol(otrans) + + try: + self.processor.process(iprot, oprot) + except Exception: + logging.exception("Exception while processing request") + # Fall through and send back a response, even if empty or incomplete. + + if self.zmq_type == zmq.REP: + msg = otrans.getvalue() + self.socket.send(msg) + + def serve(self): + while True: + self.serveOne() + + +class TZmqMultiServer(object): + def __init__(self): + self.servers = [] + + def serveOne(self, timeout=-1): + self._serveActive(self._setupPoll(), timeout) + + def serveForever(self): + poll_info = self._setupPoll() + while True: + self._serveActive(poll_info, -1) + + def _setupPoll(self): + server_map = {} + poller = zmq.Poller() + for server in self.servers: + server_map[server.socket] = server + poller.register(server.socket, zmq.POLLIN) + return (server_map, poller) + + def _serveActive(self, poll_info, timeout): + (server_map, poller) = poll_info + ready = dict(poller.poll()) + for sock, state in ready.items(): + assert (state & zmq.POLLIN) != 0 + server_map[sock].serveOne() diff --git a/src/jaegertracing/thrift/contrib/zeromq/csharp/AssemblyInfo.cs b/src/jaegertracing/thrift/contrib/zeromq/csharp/AssemblyInfo.cs new file mode 100644 index 000000000..12cd434f3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/csharp/AssemblyInfo.cs @@ -0,0 +1,46 @@ +/** + * 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. + */ + +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("ZmqServer")] +[assembly: AssemblyDescription("Zmq Examples")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The Apache Software Foundation")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("The Apache Software Foundation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/src/jaegertracing/thrift/contrib/zeromq/csharp/Main.cs b/src/jaegertracing/thrift/contrib/zeromq/csharp/Main.cs new file mode 100644 index 000000000..e66cfe080 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/csharp/Main.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading; +using Thrift.Protocol; +using ZMQ; +using ZmqServer; +using ZmqClient; + +namespace ZmqServer +{ + class MainClass + { + public static void Main (string[] args) + { + new Thread(Server.serve).Start(); + Client.work(); + } + + static class Server{ + public static void serve(){ + StorageHandler s=new StorageHandler(); + Storage.Processor p=new Storage.Processor(s); + + ZMQ.Context c=new ZMQ.Context(); + + TZmqServer tzs=new TZmqServer(p,c,"tcp://127.0.0.1:9090",ZMQ.SocketType.PAIR); + tzs.Serve(); + } + + class StorageHandler:Storage.Iface{ + int val=0; + + public void incr(int amount){ + val+=amount; + Console.WriteLine("incr({0})",amount); + } + + public int get(){ + return val; + } + } + } + + static class Client{ + public static void work() + { + Context ctx=new Context(); + TZmqClient tzc=new TZmqClient(ctx,"tcp://127.0.0.1:9090",SocketType.PAIR); + TBinaryProtocol p=new TBinaryProtocol(tzc); + + Storage.Client client=new Storage.Client(p); + tzc.Open(); + + Console.WriteLine(client.@get()); + client.incr(1); + client.incr(41); + Console.WriteLine(client.@get()); + } + } + } +} diff --git a/src/jaegertracing/thrift/contrib/zeromq/csharp/TZmqClient.cs b/src/jaegertracing/thrift/contrib/zeromq/csharp/TZmqClient.cs new file mode 100644 index 000000000..e9ab5166a --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/csharp/TZmqClient.cs @@ -0,0 +1,78 @@ +using System; +using ZMQ; +using System.IO; +using Thrift.Transport; + +namespace ZmqClient +{ + public class TZmqClient : TTransport + { + Socket _sock; + String _endpoint; + MemoryStream _wbuf = new MemoryStream (); + MemoryStream _rbuf = new MemoryStream (); + + void debug (string msg) + { + //Uncomment to enable debug +// Console.WriteLine (msg); + } + + public TZmqClient (Context ctx, String endpoint, SocketType sockType) + { + _sock = ctx.Socket (sockType); + _endpoint = endpoint; + } + + public override void Open () + { + _sock.Connect (_endpoint); + } + + public override void Close () + { + throw new NotImplementedException (); + } + + public override bool IsOpen { + get { + throw new NotImplementedException (); + } + } + + public override int Read (byte[] buf, int off, int len) + { + debug ("Client_Read"); + if (off != 0 || len != buf.Length) + throw new NotImplementedException (); + + if (_rbuf.Length == 0) { + //Fill the Buffer with the complete ZMQ Message which needs to be(?!) the complete Thrift response + debug ("Client_Read Filling buffer.."); + byte[] tmpBuf = _sock.Recv (); + debug (string.Format("Client_Read filled with {0}b",tmpBuf.Length)); + _rbuf.Write (tmpBuf, 0, tmpBuf.Length); + _rbuf.Position = 0; //For reading + } + int ret = _rbuf.Read (buf, 0, len); + if (_rbuf.Length == _rbuf.Position) //Finished reading + _rbuf.SetLength (0); + debug (string.Format ("Client_Read return {0}b, remaining {1}b", ret, _rbuf.Length - _rbuf.Position)); + return ret; + } + + public override void Write (byte[] buf, int off, int len) + { + debug ("Client_Write"); + _wbuf.Write (buf, off, len); + } + + public override void Flush () + { + debug ("Client_Flush"); + _sock.Send (_wbuf.GetBuffer ()); + _wbuf = new MemoryStream (); + } + } +} + diff --git a/src/jaegertracing/thrift/contrib/zeromq/csharp/TZmqServer.cs b/src/jaegertracing/thrift/contrib/zeromq/csharp/TZmqServer.cs new file mode 100644 index 000000000..535c623d0 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/csharp/TZmqServer.cs @@ -0,0 +1,56 @@ +using System; +using Thrift; +using Thrift.Server; +using Thrift.Transport; +using Thrift.Protocol; +using ZMQ; +using System.IO; + +using System.Collections.Generic; + +namespace ZmqServer +{ + public class TZmqServer + { + Socket _socket ; + TProcessor _processor; + + void debug (string msg) + { + //Uncomment to enable debug +// Console.WriteLine (msg); + } + + public TZmqServer (TProcessor processor, Context ctx, String endpoint, SocketType sockType) + { + new TSimpleServer (processor,null); + _socket = ctx.Socket (sockType); + _socket.Bind (endpoint); + _processor = processor; + } + + public void ServeOne () + { + debug ("Server_ServeOne"); + Byte[] msg = _socket.Recv (); + MemoryStream istream = new MemoryStream (msg); + MemoryStream ostream = new MemoryStream (); + TProtocol tProtocol = new TBinaryProtocol (new TStreamTransport (istream, ostream)); + _processor.Process (tProtocol, tProtocol); + + if (ostream.Length != 0) { + byte[] newBuf = new byte[ostream.Length]; + Array.Copy (ostream.GetBuffer (), newBuf, ostream.Length); + debug (string.Format ("Server_ServeOne sending {0}b", ostream.Length)); + _socket.Send (newBuf); + } + } + + public void Serve () + { + while (true) + ServeOne (); + } + } +} + diff --git a/src/jaegertracing/thrift/contrib/zeromq/csharp/ThriftZMQ.csproj b/src/jaegertracing/thrift/contrib/zeromq/csharp/ThriftZMQ.csproj new file mode 100755 index 000000000..80ad1dbd6 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/csharp/ThriftZMQ.csproj @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProductVersion>9.0.21022</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}</ProjectGuid> + <OutputType>Exe</OutputType> + <RootNamespace>ZmqServer</RootNamespace> + <AssemblyName>ThriftZMQ</AssemblyName> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>3.5</OldToolsVersion> + <UpgradeBackupLocation /> + <PublishUrl>publish\</PublishUrl> + <Install>true</Install> + <InstallFrom>Disk</InstallFrom> + <UpdateEnabled>false</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>1.0.0.0</ApplicationVersion> + <IsWebBootstrapper>false</IsWebBootstrapper> + <UseApplicationTrust>false</UseApplicationTrust> + <BootstrapperEnabled>true</BootstrapperEnabled> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <PlatformTarget>x86</PlatformTarget> + <Externalconsole>true</Externalconsole> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <DebugType>none</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <PlatformTarget>x86</PlatformTarget> + <Externalconsole>true</Externalconsole> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <ItemGroup> + <Reference Include="clrzmq, Version=2.1.0.0, Culture=neutral, processorArchitecture=x86"> + <SpecificVersion>False</SpecificVersion> + <HintPath>.\clrzmq.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="Thrift, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\..\lib\csharp\Thrift.dll</HintPath> + </Reference> + </ItemGroup> + <ItemGroup> + <Compile Include="Main.cs" /> + <Compile Include="AssemblyInfo.cs" /> + <Compile Include="TZmqServer.cs" /> + <Compile Include="TZmqClient.cs" /> + <Compile Include="..\gen-csharp\Storage.cs" /> + </ItemGroup> + <ItemGroup> + <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1</ProductName> + <Install>true</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1"> + <Visible>False</Visible> + <ProductName>Windows Installer 3.1</ProductName> + <Install>true</Install> + </BootstrapperPackage> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project> diff --git a/src/jaegertracing/thrift/contrib/zeromq/csharp/ThriftZMQ.sln b/src/jaegertracing/thrift/contrib/zeromq/csharp/ThriftZMQ.sln new file mode 100755 index 000000000..6af57b60c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/csharp/ThriftZMQ.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThriftZMQ", "ThriftZMQ.csproj", "{17C63B90-DFD7-42AC-A7B0-749E6876C0A1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thrift", "..\..\..\lib\csharp\src\Thrift.csproj", "{499EB63C-D74C-47E8-AE48-A2FC94538E9D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Any CPU.ActiveCfg = Debug|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.ActiveCfg = Debug|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Debug|x86.Build.0 = Debug|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Any CPU.ActiveCfg = Release|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|Mixed Platforms.Build.0 = Release|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.ActiveCfg = Release|x86 + {17C63B90-DFD7-42AC-A7B0-749E6876C0A1}.Release|x86.Build.0 = Release|x86 + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Debug|x86.ActiveCfg = Debug|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Any CPU.Build.0 = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {499EB63C-D74C-47E8-AE48-A2FC94538E9D}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/jaegertracing/thrift/contrib/zeromq/storage.thrift b/src/jaegertracing/thrift/contrib/zeromq/storage.thrift new file mode 100644 index 000000000..a1ea96752 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/storage.thrift @@ -0,0 +1,4 @@ +service Storage { + oneway void incr(1: i32 amount); + i32 get(); +} diff --git a/src/jaegertracing/thrift/contrib/zeromq/test-client.cpp b/src/jaegertracing/thrift/contrib/zeromq/test-client.cpp new file mode 100644 index 000000000..159c25030 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/test-client.cpp @@ -0,0 +1,40 @@ +#include <iostream> +#include <cstdlib> +#include <thrift/protocol/TBinaryProtocol.h> + +#include "zmq.hpp" +#include "TZmqClient.h" +#include "Storage.h" + +using apache::thrift::std::shared_ptr; +using apache::thrift::transport::TZmqClient; +using apache::thrift::protocol::TBinaryProtocol; + +int main(int argc, char** argv) { + const char* endpoint = "tcp://127.0.0.1:9090"; + int socktype = ZMQ_REQ; + int incr = 0; + if (argc > 1) { + incr = atoi(argv[1]); + if (incr) { + socktype = ZMQ_PUSH; + endpoint = "tcp://127.0.0.1:9091"; + } + } + + zmq::context_t ctx(1); + shared_ptr<TZmqClient> transport(new TZmqClient(ctx, endpoint, socktype)); + shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport)); + StorageClient client(protocol); + transport->open(); + + if (incr) { + client.incr(incr); + usleep(50000); + } else { + int value = client.get(); + std::cout << value << std::endl; + } + + return 0; +} diff --git a/src/jaegertracing/thrift/contrib/zeromq/test-client.py b/src/jaegertracing/thrift/contrib/zeromq/test-client.py new file mode 100755 index 000000000..d51216e45 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/test-client.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +import sys +import time +import zmq +import TZmqClient +import thrift.protocol.TBinaryProtocol +import storage.ttypes +import storage.Storage + + +def main(args): + endpoint = "tcp://127.0.0.1:9090" + socktype = zmq.REQ + incr = 0 + if len(args) > 1: + incr = int(args[1]) + if incr: + socktype = zmq.PUSH + endpoint = "tcp://127.0.0.1:9091" + + ctx = zmq.Context() + transport = TZmqClient.TZmqClient(ctx, endpoint, socktype) + protocol = thrift.protocol.TBinaryProtocol.TBinaryProtocolAccelerated(transport) + client = storage.Storage.Client(protocol) + transport.open() + + if incr: + client.incr(incr) + time.sleep(0.05) + else: + value = client.get() + print(value) + + +if __name__ == "__main__": + main(sys.argv) diff --git a/src/jaegertracing/thrift/contrib/zeromq/test-receiver.cpp b/src/jaegertracing/thrift/contrib/zeromq/test-receiver.cpp new file mode 100644 index 000000000..d465bff63 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/test-receiver.cpp @@ -0,0 +1,40 @@ +#include "zmq.hpp" +#include "TZmqServer.h" +#include "Storage.h" + +using apache::thrift::std::shared_ptr; +using apache::thrift::TProcessor; +using apache::thrift::server::TZmqServer; +using apache::thrift::server::TZmqMultiServer; + +class StorageHandler : virtual public StorageIf { + public: + StorageHandler() + : value_(0) + {} + + void incr(const int32_t amount) { + value_ += amount; + printf("value_: %i\n", value_) ; + } + + int32_t get() { + return value_; + } + + private: + int32_t value_; + +}; + + +int main(int argc, char *argv[]) { + shared_ptr<StorageHandler> handler(new StorageHandler()); + shared_ptr<TProcessor> processor(new StorageProcessor(handler)); + + zmq::context_t ctx(1); + TZmqServer oneway_server(processor, ctx, "epgm://eth0;239.192.1.1:5555", ZMQ_SUB); + oneway_server.serve(); + + return 0; +} diff --git a/src/jaegertracing/thrift/contrib/zeromq/test-sender.cpp b/src/jaegertracing/thrift/contrib/zeromq/test-sender.cpp new file mode 100644 index 000000000..5c086a11f --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/test-sender.cpp @@ -0,0 +1,32 @@ +#include <iostream> +#include <cstdlib> +#include <thrift/protocol/TBinaryProtocol.h> + +#include "zmq.hpp" +#include "TZmqClient.h" +#include "Storage.h" + +using apache::thrift::std::shared_ptr; +using apache::thrift::transport::TZmqClient; +using apache::thrift::protocol::TBinaryProtocol; + +int main(int argc, char** argv) { + const char* endpoint = "epgm://eth0;239.192.1.1:5555"; + int socktype = ZMQ_PUB; + int incr = 1; + if (argc > 1) { + incr = atoi(argv[1]); + } + + zmq::context_t ctx(1); + shared_ptr<TZmqClient> transport(new TZmqClient(ctx, endpoint, socktype)); + shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport)); + StorageClient client(protocol); + + transport->open(); + + client.incr(incr); + usleep(50000); + + return 0; +} diff --git a/src/jaegertracing/thrift/contrib/zeromq/test-server.cpp b/src/jaegertracing/thrift/contrib/zeromq/test-server.cpp new file mode 100644 index 000000000..e6f1b2083 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/test-server.cpp @@ -0,0 +1,43 @@ +#include "zmq.hpp" +#include "TZmqServer.h" +#include "Storage.h" + +using apache::thrift::std::shared_ptr; +using apache::thrift::TProcessor; +using apache::thrift::server::TZmqServer; +using apache::thrift::server::TZmqMultiServer; + +class StorageHandler : virtual public StorageIf { + public: + StorageHandler() + : value_(0) + {} + + void incr(const int32_t amount) { + value_ += amount; + } + + int32_t get() { + return value_; + } + + private: + int32_t value_; + +}; + + +int main(int argc, char *argv[]) { + shared_ptr<StorageHandler> handler(new StorageHandler()); + shared_ptr<TProcessor> processor(new StorageProcessor(handler)); + + zmq::context_t ctx(1); + TZmqServer reqrep_server(processor, ctx, "tcp://0.0.0.0:9090", ZMQ_REP); + TZmqServer oneway_server(processor, ctx, "tcp://0.0.0.0:9091", ZMQ_PULL); + TZmqMultiServer multiserver; + multiserver.servers().push_back(&reqrep_server); + multiserver.servers().push_back(&oneway_server); + multiserver.serveForever(); + + return 0; +} diff --git a/src/jaegertracing/thrift/contrib/zeromq/test-server.py b/src/jaegertracing/thrift/contrib/zeromq/test-server.py new file mode 100755 index 000000000..d89b37ba2 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/zeromq/test-server.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +import zmq +import TZmqServer +import storage.ttypes +import storage.Storage + + +class StorageHandler(storage.Storage.Iface): + def __init__(self): + self.value = 0 + + def incr(self, amount): + self.value += amount + + def get(self): + return self.value + + +def main(): + handler = StorageHandler() + processor = storage.Storage.Processor(handler) + + ctx = zmq.Context() + reqrep_server = TZmqServer.TZmqServer(processor, ctx, "tcp://0.0.0.0:9090", zmq.REP) + oneway_server = TZmqServer.TZmqServer(processor, ctx, "tcp://0.0.0.0:9091", zmq.PULL) + multiserver = TZmqServer.TZmqMultiServer() + multiserver.servers.append(reqrep_server) + multiserver.servers.append(oneway_server) + multiserver.serveForever() + + +if __name__ == "__main__": + main() |