'업무/코딩'에 해당하는 글 2건

이틀에 걸쳐 안드로이드에서 나오는 로그를 파일로 저장하기 위한 삽질을 수행하였다. –_-;;

분명히 헤메는 사람이 있을테니 그런 사람들을 위해 기록을 남겨 놓는다.

logback은 log4j와 같은 건데 안드로이드 용 log4j가 동작이 잘 안되서 이걸 썼다.

 

참고 싸이트는 아래와 같다.

 

http://ismydream.tistory.com/145

http://tony19.github.io/logback-android/

http://logback.qos.ch/manual/appenders.html

http://mantdu.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%A0%80%EC%9E%A5%EC%86%8C-%EA%B2%BD%EB%A1%9C-%EC%96%BB%EC%9D%84%EC%8B%9C-emulater0-%ED%95%B4%EA%B2%B0%EB%B2%95

 

위 글에 적힌 대로 다 따라 하면 된다.

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

 

이거 맨 위에 넣어주고

 

org.slf4j.Logger Log = LoggerFactory.getLogger(getClass());

 

이거 선언하고

 

assets 폴더 밑에 logback.xml 파일 하나 만들어서 (확장자가 xml이어야 한다. 도스 창에서 파일 하나 루트에서 만든 다음에 파일 탐색기에서 끌어다 이클립스 해당 폴더로 던지면 복사되어서 들어간다.)

 

<configuration>
  <appender name="FILE" class= "ch.qos.logback.core.FileAppender" >
    <!-- lazy initialization: don't create the file until 1st write -->
    <lazy >true </lazy >

     <file > /storage/emulated/0/aaa/log.txt </file >
    <encoder >
      <pattern >%d{HH:mm:ss.SSS} %msg%n </pattern>
    </encoder >
  </appender >

  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root >
</configuration>

 

이 내용 집어 넣고

 

안드로이드매니피스트에

 

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

 

이거 넣어주면

 

        //Log.debug("" + "\t" + "99999");

 

이런식으로 써주면 로그 파일이 생성되게 된다.

자 그럼 삽질의 포인트가 무엇이냐?

 

파일이 어디에 저장될 것이냐의 문제인데, 안드로이드 내부의 절대 경로를 얻어야 한다.

 

String storage = null;

storage = Environment.getExternalStorageDirectory().getAbsolutePath();

Log.debug(storage);*/

 

이렇게 해주면 안드로이드 외부저장소 절대 경로를 얻을 수 있다.

지금 logback.xml 이 파일 쓰기 상태니까 이걸 logcat으로 내보내기 위해

 

<configuration>

<!-- Create a logcat appender -->

<appender name="logcat" class= "ch.qos.logback.classic.android.LogcatAppender" >

<encoder >

<pattern >%msg </pattern>

</encoder >

</appender >

<!-- Write INFO (and higher-level) messages to logcat -->

<root level="DEBUG">

<appender-ref ref="logcat" />

</root >

</configuration>

 

이 내용으로 잠시 교채해주고 tag: (메인 액티비티 내용 중에서 일부 텍스트)를 이용해서 필터링 하면 외부 저장소 절대 경로를 얻을 수 있다.

 

그리고 로그 파일을 함부로 지우면 안된다.  해당 앱을 끄더라도 안드로이드 파일 탐색기에서 새로 고침하거나 상위 폴더 올라갔다가 내려오기를 반복하면서 파일 사이즈가 증가하는지 확인해야 한다. 만약 지우면 어떻게 되냐고? 파일이 안 써진다.

 

앱을 확실하게 끄려면 홈키를 길게 눌러서 끄기 바란다.

 

그리고 로그 파일 추출하고 나면, 로그 파일을 그냥 지우지 말고, 내용만 완전히 지워서 파일 사이즈를 0으로 나둬야 쓰기가 잘된다. 미리 파일 싸이즈가 0인 동일 이름의 파일을 준비해뒀다가, 바꿔치기 하는게 제일 좋다.

 

삽질한 이유는 어디에 저장을 해야 하는지 몰라서 : 외부 저장소의 절대 경로에 저장해야 한다.

그리고 앱이 완전히 꺼지지도 않았는데 지워서 : 앱 완전히 꺼야 한다.

지우더라도 내용만 지워야 하는데 파일까지 지워서 : 내용만 지우고 파일 남겨둬야 한다.

 

이러면 쉽게 logcat을 이용해서 안드로이드에서 로그 파일을 저장할 수 있다.


WRITTEN BY
가별이
내가 천사의 말 한다 해도

,

최근 출시된 안드로이드에서 TCP 소켓 통신을 하려다가 3가지 문제에 부딪혔다.


1. 소켓이 열리지 않는다.

2. 소켓은 열렸는데 죽는다.

3. 바이트 단위로 데이터를 보내고 싶은데 잘 모르겠다.




1. 소켓이 열리지 않는 것은, 참조한 샘플 소스가 대부분 옛날 소스이기 때문이다. 소켓을 생성할 때 쓰레드로 띄우지 않으면 소켓이 열리지 않는다.

//선언부

    private Socket socket;

    private BufferedReader networkReader;

    private BufferedWriter networkWriter;

    private DataOutputStream outStream;

    private String msg = "zxcf";    

    private String ip = "192.168.7.101"; // IP

    private int port = 1470; // PORT번호


    int tcp_flag = 0;

//OnCreate

        MainThread thread = new MainThread();

        thread.setDaemon(true);

        thread.start();


아래쪽에 붙일 것

    public void setSocket(String ip, int port) throws IOException {

        try {

        socket = new Socket(ip, port);

            networkWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            tcp_flag = 1;

            outStream = new DataOutputStream(this.socket.getOutputStream()); 

            //networkReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        } catch (IOException e) {

            System.out.println(e);

            e.printStackTrace();

        }

    }

    

    class MainThread extends Thread {

    public void run (){

    try{

    setSocket(ip, port);    

    } catch (IOException e1) {

    e1.printStackTrace();

    }

    }

    }




2. 보통 샘플들이 소켓을 열고 나서, 글자를 입력하고 버튼을 눌러야먄 동작한다. 그런데 만약 당신이 소켓을 열자마자 동시에 통신을 하려고 하면 앱이 뻗어버린다. (죽어버린다.) 한참 고민하다가 로그를 한줄마다 다 삽입해서 원인을 확인했다.


1번을 적용한 경우에 소켓은 쓰레드에서 열리고 onCreate는 별도로 진행하게 된다. 문제는 소켓이 열리기 전에 tcp 통신을 시도하려고 하면 죽게 된다. 그래서 소켓이 열린 후에 플래그를 바뀌고, 플래그에 따라 통신을 시도하면 된다.


if ( tcp_flag == 1) {

PrintWriter out = new PrintWriter(networkWriter, true);

byte headerbuf[] = new byte[16];

byte[] serialbuf = Build.SERIAL.getBytes();

headerbuf[0] = (byte)0xaa;

headerbuf[1] = (byte)0xaa;

headerbuf[2] = (byte)0xF;

headerbuf[3] = (byte)Build.SERIAL.length();

headerbuf[4] = serialbuf[0];

headerbuf[5] = serialbuf[1];

headerbuf[6] = serialbuf[2];

headerbuf[7] = serialbuf[3];

headerbuf[8] = serialbuf[4];

headerbuf[9] = serialbuf[5];

headerbuf[10] = serialbuf[6];

headerbuf[11] = serialbuf[7];

headerbuf[12] =   (byte) (Integer.parseInt(CurrentZone) - 10000);

headerbuf[13] =   (byte) (10006 - 10000);

headerbuf[14] = (byte)0xfa;

headerbuf[15] = (byte)0xfa;

 

// Send Header

try {

outStream.write(headerbuf);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

try {

outStream.flush();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


즉 플래그가 바뀐 상태에서 소켓 통신을 시도해야만 가능하다.


3. 대부분 TCP 통신 샘플 소스 코드는 println만 지원하므로 DataOutputStream을 이용하는 샘플을 찾아보면 쉽게 할 수 있다.

'업무 > 코딩' 카테고리의 다른 글

logback android 삽질 후기  (0) 2014.11.28

WRITTEN BY
가별이
내가 천사의 말 한다 해도

,