2015年6月24日 星期三

使用 GitHub 工具 SourceTree 問題

最近 在學習使用 GitHub, SourceTree是不少人推薦的Client工具
一開始使用都很順暢,但最近由於公司網路問題 導致我必須設定Proxy Server
才可以對外連線

就在此時悲劇發生了,我在SourceTree無法Push新的檔案至我的 BitBucket <Git路徑>
教學請參考 BitBucket & SourceTree教學

我使用 command line的方式來執行 push,但發生如下圖的錯誤


一開始我以為是驗證問題,所以我使用下面指令更改成 http

在重新執行一次 一樣出現類似上面的錯誤,只是443改為80

於是透過網路查詢 發現 若是驗證錯誤 會有類似 Http 401的錯誤
所以當下直覺是網路問題(我用瀏覽器連結都正常,可開啟BitBucket)

最後看到這篇回答,想到有可能是 proxy的問題

於是我修改我的proxy於cmd,如下圖

在重新執行一次 push 指令,就可以成功上傳到至BitBucket了
真是折煞人啊~*

初探 D3.js Multi Line Chart

最近因為客戶有將統計資料繪圖的需求
而開始研究D3.js 之前我大多使用 jQuery or JQWidgets的套件來繪圖
聽說使用D3前懂點 JQuery是好事,廢話不多說來切入今天的主題吧!
----------------------------------------------------------------------------------------
首先 D3是 Data Driven Document,所以data來源格式非常重要
現在大多是使用 JSON格式,且流行用Restful的模式
故我程式的範例也是使用 JSON來呼叫
而客戶又有 Mouserover & Legend的需求,這部分讓D3用起來更Complex

一開始的學習我建議可以參考d3 Line Chart教學
而這個網址是我在JSFiddle建立的範例,修改之前的教學http://jsfiddle.net/YenYu/hxn9L3cz/1/

以下為我的程式碼及預設的測試資料

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>MultiLine Chart</title>
<style>

#chart {
  font: 16px Arial;
  font-weight: 50;
  background: #fff;
}

text { 
  color: #000;
  stroke: #000;
  fill: #000;
}

path {
stroke: DodgerBlue;
stroke-width: 1;
fill: none;
}

.axis line {
  fill: none;
  stroke: lightgray;
  shape-rendering: crispEdges;
}

.x.axis path {
  display: #fafafa;
}

.x.axis .minor {
  stroke-opacity: .5;
}

.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}

.overlay {
  fill: none;
  pointer-events: all;
}

.focus circle {
  fill: none;
  stroke: #0078ff;
}

.legend {
    font-size: 16px;
    font-weight: normal;
}

</style>
</head>
<body>
<div id="chart"></div>
</body>
<!--<script src="http://d3js.org/d3.v3.js"></script> -->
<script src="js/d3.min.js"></script>
<script>

var margin = {top: 50, right: 80, bottom: 50, left: 50},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var parseDate = d3.time.format("%Y%m%d").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left;


var x = d3.time.scale()
    .range([0, width]);

var y = d3.scale.linear()
    .range([height, 0]);

var color = d3.scale.category10();

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom").orient('bottom').tickSize(-height).tickSubdivide(false);

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var line = d3.svg.line()
    .interpolate("linear")
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.count); });

var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");   

d3.json("http://192.168.73.1:2013/JQuery_Test/data/data2.txt", function(error, data) {

 //color.domain(d3.keys(data,function(d){d.name}));
  
  var unusualSummary = data.map(function(j) {
    return {
      name: j.name,
      values: j.values.map(function(d) {
        return {date: parseDate(d.date), count: d.count};
      })
    };
  });
console.log('data: ' + JSON.stringify(data));
  x.domain([
  d3.min(unusualSummary, function(c) { return d3.min(c.values, function(v) { return v.date; }); }),
    d3.max(unusualSummary, function(c) { return d3.max(c.values, function(v) { return v.date; }); })
  ]);

  y.domain([
    0,d3.max(unusualSummary, function(c) { return d3.max(c.values, function(v) { return parseInt(v.count); }); }) + 1
  ]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
      .append("text")
      .attr("x", 850)
      .style("text-anchor", "middle")
      .text("日期 ");

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
      .append("text")
      .attr("transform", "rotate(0)")
      .attr("x", 7)
      .attr("y", -7)
      .attr("dy", ".71em")
      .style("text-anchor", "start")
      .text("次數 ");

  var statstic = svg.selectAll(".statstic")
      .data(unusualSummary)
      .enter().append("g")
      .attr("class", "statstic");

  var lSpace = width/data.length;
      
  data.forEach(function(d,i) {
 
                        statstic.append('path')
                        .attr('d', function(d){return line(d.values,x,y);})
                        .style('stroke', function(d,j) { 
                                return color(d.name);
                        })
                        .attr('stroke-width', 2)
                        .attr('id', 'line_'+d.name)
                        .attr('fill', 'none');
                        console.log('d name part I: ' + d.name);
                         statstic.append("text")
                            .attr("x", (lSpace/2)+i*lSpace)
                            .attr("y", height+30)                     
                            .style("fill", color(d.name))
                            .attr("class","legend")                                                
                            .text(d.name+" ---").style("stroke", color(d.name));
                        
                    });

  var focus = svg.append("g")
      .attr("class", "focus")
      .style("display", "none");

for(var i=0;i<unusualSummary.length;i++){
              focus.append("g")
                .attr("class", "focus"+i)
                .append("circle")
                .attr("r", 6.5);
              svg.select(".focus"+i)
                .append("text")
                .attr("x", 9)
                .attr("dy", ".35em");
          }


 statstic.append("rect")
      .attr("class", "overlay")
      .attr("width", width)
      .attr("height", height)
      .on("mouseover", function() { focus.style("display", null); })
      .on("mouseout", function() { focus.style("display", "none");})
      .on("mousemove", mousemove);
  
  function mousemove() {
//alert('length: ' + unusualSummary.length);
var x0 = x.invert(d3.mouse(this)[0]);               
   for(var k=0;k<unusualSummary.length;k++){
  
   var i  = bisectDate(unusualSummary[k].values, x0, 1);
   
   var d0 = unusualSummary[k].values[i - 1];
   
   var d1 = unusualSummary[k].values[i];
  
   var d = x0 - d0.date > d1.date - x0 ? d1 : d0;
   
var format = d3.time.format('%e %b');
var selectedFocus = svg.selectAll(".focus"+k);
selectedFocus.attr("transform", "translate(" + x(d.date) + "," + y(d.count) + ")");
    selectedFocus.select("text").text(format(d.date)+","+d.count+"次");
    
   
   }
                
    
  }   
  
});
</script>
</html>

我的Data範例如下,請自己在WebContent下建一個js的目錄放置js檔及測試檔
[
  {
    "name":"系統A", 
"values":[{"date":"20111001", "count":"1"},
         {"date":"20111002", "count":"2"},
              {"date":"20111003", "count":"3"},
              {"date":"20111004", "count":"4"},
              {"date":"20111005", "count":"5"},
              {"date":"20111006", "count":"6"}]
  },
  {
    "name":"系統B", 
"values":[{"date":"20111001", "count":"2"},
              {"date":"20111002", "count":"4"},   
              {"date":"20111003", "count":"6"},
              {"date":"20111004", "count":"8"},
              {"date":"20111005", "count":"10"},
              {"date":"20111006", "count":"12"}]
  },
  {
    "name":"系統C", 
"values":[{"date":"20111001", "count":"3"},
              {"date":"20111002", "count":"6"},   
              {"date":"20111003", "count":"9"},
              {"date":"20111004", "count":"12"},
              {"date":"20111005", "count":"15"},
              {"date":"20111006", "count":"18"}]
  },
  {
    "name":"系統D", 
"values":[{"date":"20111001", "count":"4"},
              {"date":"20111002", "count":"8"},   
              {"date":"20111003", "count":"12"},
              {"date":"20111004", "count":"16"},
              {"date":"20111005", "count":"20"},
              {"date":"20111006", "count":"30"}]
  }

]  

最後呈現的結果為




2015年3月2日 星期一

測試檔案上傳及下載的WebService with Java

最近為了撰寫有關檔案upload and download的WS先試寫了Sample Code with Java

WebService 程式如下

     @WebMethod
      public void upload(@WebParam(name = "fileName")String fileName, byte[] imageBytes) {
       
      String filePath = "d:/MsgServerUpload/" + fileName;
       
      try {
          FileOutputStream fos = new FileOutputStream(filePath);
          BufferedOutputStream outputStream = new BufferedOutputStream(fos);
          outputStream.write(imageBytes);
          outputStream.close();
           
          System.out.println("Received file: " + filePath);
           
      } catch (IOException ex) {
        System.out.println("Exception from here");
          System.err.println(ex);
          throw new WebServiceException(ex);
      }
}
 
     @WebMethod
      public byte[] download(String fileName) {
      String filePath = "d:/MsgServerDownload/" + fileName;
      System.out.println("Sending file: " + filePath);
       
      try {
          File file = new File(filePath);
          FileInputStream fis = new FileInputStream(file);
          BufferedInputStream inputStream = new BufferedInputStream(fis);
          byte[] fileBytes = new byte[(int) file.length()];
          inputStream.read(fileBytes);
          inputStream.close();
           
          return fileBytes;
      } catch (IOException ex) {
          System.err.println(ex);
          throw new WebServiceException(ex);
      }      
  }

請容許我稍微解釋一下這2個Method的路徑,d:/MsgServerUpload/ 是指 user在呼叫WS後,會將使用者上傳的的檔案放在Web Server的該路徑下,也就是說上傳的檔案都會放在這裡啦!
那d:/MsgServerDownload/當然是我在Server上放的要供使用者download的目錄
也就是,使用者upload or download的路徑我都事先預設好了,當然你的Web Server下要有該目錄喔!

接著我們可以寫個Java版的測試WS是否可呼叫成功
完整的程式碼如下,我用的方式必須先將WS利用NetBean開WS Build成WSClient.jar才能呼叫API

package com.sti.ws.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.namespace.QName;

import com.sti.web.msg.webservice.Exception_Exception;
import com.sti.web.msg.webservice.MSGWebService;
import com.sti.web.msg.webservice.MSGWebService_Service;


public class TestWS {

    public static void main(String[] args) {
   MSGWebService msgws = getMsgWS();
   try {
    String fileName = "test.txt";
   
       String filePath = "d:/YourLocalFileFolder/" + fileName;
       File file = new File(filePath);
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream inputStream = new BufferedInputStream(fis);
            byte[] imageBytes = new byte[(int) file.length()];
            inputStream.read(imageBytes);
             
            msgws.upload(file.getName(), imageBytes);
            
            inputStream.close();
            System.out.println("File uploaded: " + filePath);
        } catch (IOException ex) {
        ex.printStackTrace();
            System.err.println(ex);
        }
   
   
   try {
   //指定要download的檔名
   String fileName = "test1.txt";
   //要求download到哪裡
        String filePath = "d:/YourLocalDownloadFolder/" + fileName;
        byte[] fileBytes = msgws.download(fileName);
         
      
            FileOutputStream fos = new FileOutputStream(filePath);
            BufferedOutputStream outputStream = new BufferedOutputStream(fos);
            outputStream.write(fileBytes);
            outputStream.close();
             
            System.out.println("File downloaded: " + filePath);
        } catch (IOException ex) {
            System.err.println(ex);
        }*/
   
   
    }

private final static String MSGWS_WSDL_LOCATION;
private final static String MSGWS_QName;
private final static String MSGWS_qname;

static {
MSGWS_WSDL_LOCATION = "http://192.168.73.1:7001/YourWebService?wsdl";
MSGWS_QName = "http://webservice.msg.web.sti.com/";
MSGWS_qname = "MSGWebService";
}

public static MSGWebService getMsgWS() {
if(MSGWS_WSDL_LOCATION == null || "".equals(MSGWS_WSDL_LOCATION)) {
} else {
try {
URL url = new URL(MSGWS_WSDL_LOCATION);
QName qname = new QName(MSGWS_QName, MSGWS_qname);
MSGWebService service = new MSGWebService_Service(url, qname).getMSGWebServicePort();
System.out.println("OK");
return service;
} catch(MalformedURLException me) {
System.out.println("Fail");
me.printStackTrace();
System.out.println(me.getMessage());
}
}
return null;
}

}

我在範例測試程式裡,將我Local下的 test.txt檔案上傳,上傳成功後,您會發現你的Web Server下的d:/MsgServerUpload/有你剛才上傳的檔案,
而在download的範例程式,我假設在Web Server的d:/MsgServerDownload/目錄下
有一個檔案叫做 test1.txt,注意你必須先做好一個檔案放至此目錄下
接著指定我要download到我Local的d:/YourLocalDownloadFolder/ 路徑下就會出現一個叫做test1.txt的檔案了

為什麼我要分開目錄呢,是為了區別來自於不同的程式,你可以把WS程式的目錄指向同一個,也就是說自己Local上傳的檔案,也可以透過WS自己DownLoad回來。

Cheers




2014年12月18日 星期四

解決 Splunk Forwader 傳送 WLS Log to Splunk Server 中文亂碼問題

這個問題困擾了我很久,雖然有比較不好的解法(效率較差,such as FTP)
但現在單純修改 Splunk Forwarder內的設定即可

一開始看官網,很容易會以為是要修改 Splunk Server上的設定
實際上是要修改 Splunk Forwarder的設定即可
首先至 Splunk Forwarder安裝的目錄下 /etc/system/default
複製一份 props.conf 至 /etc/system/local [這是 Splunk 官方的建議]
就是以後修改,以修改此 props.conf為主,不要修改 default.conf

在檔案的最下方,新增如下2行(注意大小寫)

[wls_log]
CHARSET = BIG5

*****這兩行的意思是,傳輸 sourcetype=wls_log的檔案,將編碼設定 BIG5*****

將Splunk Forwarder停止
登入至Splunk Server,刪除先前由此台WLS Log Server所傳進來的檔案

sourcetype=wls_log | delete  (注意,admin必須事先設定擁有刪除的權限)

重新啟動 Splunk Server

啟動 Splunk Forwarder

建立一筆有中文的 Log, 至Splunk Server查詢吧!

2014年11月30日 星期日

Using Oracle jrockit jConsole monitor WebLogic with remoto server

最近在研究使用jmx來monitor WebLogic
首先我使用的WebLogic版本是10.3.3,安裝時設定成 Production mode
若有安裝過的話,通常 Oracle建議 Production mode使用 jrockit ,developer mode則用 jdk
因此我們現在應該是透過 jrockit 來 monitor,首先找到 jConsole的執行檔
它位於你安裝 jrockit 所在的目錄下/bin裡面

找到後,你可以直接點二下執行,但這是採用 Local 的方式去monitor,會抓取你目前的 java instance,這邊我們不討論。

那麼該如何使用 remote 的方式去 monitor 呢?
首先至你想要 monitor 的 WLS Server 開啟 WLS Admin Console-->伺服器-->your server name-->通訊協定-->啟用 IIOP(勾選)-->點選進階後設定 IIOP預設帳密,如圖


接著在你的 cmd 下 使用指令呼叫 jConsole吧!
我這邊示範是基本的呼叫方式,呼叫完後一樣會出現 jConsole的視窗
請在上面打上
service:jmx:iiop://hostname:port/jndi/weblogic.management.mbeanservers.runtime
請自行替換你的 hostname and port,下面就是你剛剛設定的IIOP帳密
如圖:

如果看到上圖畫面,就代表你成功嘍!,接著你就可以點選你想要看的資訊了。



2014年11月25日 星期二

處理Splunk 與 WebLogic Log 時間不一致問題

最近使用Splunk導入WebLogic時發現時間不夠一致,甚至假設我自己撰寫程式來印出Log時,在Log檔裡顯示的時間是正確的,但在Splunk中卻被視為同一時間,由於我的Splunk Search非常依賴時間來做查詢條件,因此為了解決這種問題,我決定為WLS Log的時間新增一個欄位(Field)叫作 log_time。
另外WLS Log在我的Log File中原本時間顯示為中文,但是進入Splunk時,卻變成了亂碼,這個問題我試過不少方法也暫時無法解決(我是透過Forwarder,Splunk & WLS不同台機器)。
於是我試圖先讓WLS Log時間變成單純的數字日期,而不在出現中文。




步驟依序如上面圖示,至WebLogic AdminConsole中點選 伺服器-->欲修改的Log伺服器所在位置-->點選日誌記錄-->進階,在「日期格式樣式」把原本有中文 時分秒的設定 改成
 yyyy/M/d HH'-'mm'-'ss'-' z
重新啟動 Server,再至Log檔觀察,就可以發現時間格式改變了。
實際至Splunk 觀察也是一樣,另外我已經定義好 log_time 欄位的 pattern了如圖
如上圖所示,藍色是Splunk定義的時間,而紅色部分是Log的真實時間,以及我定義log_time欄位的時間,而為了使用我定義的時間來做查詢,在程式呼叫curl指令時需要將時間作轉換,注意"2014-11/26" 與 "10-37-33"之間是有空白的。
程式如下

Calendar calendar1 = Calendar.getInstance();
System.out.println("calendar1 : " + calendar1.getTime());
calendar1.add(Calendar.MINUTE, -5);
System.out.println("calendar2 : " + calendar1.getTime());
Date date = calendar1.getTime();
SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH-mm-ss");
String date1 = DATE_FORMAT.format(date);
System.out.println("Date1 : " + date1);
String[] tokens = date1.split(" ");
    for (String token:tokens) {
  System.out.println(token);
}
String finalDate = tokens[0]+"\\%20"+tokens[1];
System.out.println("finalDate: " + finalDate);
String log_time = "2014/11/25\\%2014-21-02";

注意我在程式碼第三行,已將實際時間減5分鐘,因為我的目的是查詢現在時間與前5分鐘之間的Log(假設Splunk時間若正確等同於Splunk執行earliest="-5m"),而最後得到的樣式就會像程式最後一行一樣  "2014/11/25\\%2014-21-02";
細心的你會發現我們中間的空白是使用\\%20取代,這是在Windows執行Java的作法

之後就是Splunk厲害的地方,他可以使用String表示時間後,依然可以比較時間,如下圖

因此我們可以放心的使用log_time當作時間基準查詢了,另外介紹Windows2003時間同步
我將Splunk Server與 WLS Server同步至我的DC Server
w32tm /config /manualpeerlist:dc.test.com.tw /syncfromflags:MANUAL
w32tm /config /update
w32tm /resync

讓時間更一致,WLS Log實在不夠精準,看來目前使用自定義的欄位查詢最精準。

**********************更好的方式  最新更新*******************************
修改WLS Date Format Pattern,修改成  yy/M/d HH':'mm':'ss  like as  14/12/12 16:52:09
重新啟動 WLS Server,則Splunk就可以認出正確的時間格式,並將其傳入 _time default index中,已 _time 的時間正確的話 ,就可以 如常的 使用 Splunk Time Modifier 
ex: earliest="-5m" or latest








Java Call Splunk Restful Service with curl On Linux

之前文章已經實現了使用Java搭配Curl and openssl 來呼叫 Splunk Restful API
但那是透過 CMD 也就是 Windows平台,現在假設我們程式需要佈署在Linux平台上
則語法也會不同。首先在Linux平台上有個好處,那就是大多數已經內建了curl
但是使用Java呼叫curl時,我必須先知道 curl 需在哪執行,你可以在Linux 下執行which curl
一樣使用ProcessBuilder
程式範例如下:
import java.io.*;
import java.util.*;

public class ProcessBuilderTest {
  public static void main(String args[]) 
     throws InterruptedException,IOException 
  {
  final List<String> commands = new ArrayList<String>();                

commands.add("/usr/bin/curl"); 
 commands.add("-k"); 
 commands.add("-u"); 
 commands.add("admin:hello"); 
 commands.add("-s"); 
 commands.add("https://localhost:8089/services/search/jobs/"+sid+"/results/");

ProcessBuilder builder = new ProcessBuilder(commands);
File dir = new File("/home");
builder.directory(dir);

    final Process process = builder.start();
    
    InputStream is = process.getInputStream();
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
    String line;
    while ((line = br.readLine()) != null) {
      System.out.println(line);
    }
    System.out.println("Program terminated!");
  }
}

如上面程式所示,只要能先得到Splunk Restful 回傳的 SID後加入程式,即可得到與Splunk Server上搜尋一樣的結果。
此外由於程式可能需要同時於Windows及Linux執行,所以可以使用下面程式來判別以決定command的組合模式
private static String OS = System.getProperty("os.name").toLowerCase();

private static boolean isWindows() {  
return (OS.indexOf("win") >= 0);
}
private static boolean isUnix() { 
return (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0 );

當然Windows與Linux上指令上還有一些小差別,另外Linux可以使用空白,但Windows要使用%20或一些需要使用跳脫字元的用法,才可正確執行呼叫CURL,歡迎大家一起研究討論。

}